From e2429d3baa83635bd58f5b52487c2b405946fc3a Mon Sep 17 00:00:00 2001
From: Nik <njunger@uwaterloo.ca>
Date: Thu, 29 Jan 2015 02:14:53 -0500
Subject: [PATCH] Pairings. Checked no longer embeds unchecked

---
 element.go           |  84 +++++++++++++----
 element_checked.go   | 216 ++++++++++++++++++++++++++++++++++---------
 element_fmt.go       |  10 +-
 element_unchecked.go |  77 ++++++++++++---
 4 files changed, 308 insertions(+), 79 deletions(-)

diff --git a/element.go b/element.go
index 03bd8b8..5f2aae5 100644
--- a/element.go
+++ b/element.go
@@ -77,12 +77,21 @@ type Element interface {
 	Pow3Zn(x, i, y, j, z, k Element) Element
 
 	PreparePower() Power
+	PowerBig(Power, *big.Int) Element
+	PowerZn(Power, Element) Element
 
 	BruteForceDL(g, h Element) Element
 	PollardRhoDL(g, h Element) Element
 
 	Rand() Element
 
+	Pair(x, y Element) Element
+	ProdPair(elements ...Element) Element
+	ProdPairSlice(x, y []Element) Element
+
+	PreparePairer() Pairer
+	PairerPair(Pairer, Element) Element
+
 	impl() *elementImpl
 }
 
@@ -92,25 +101,11 @@ type elementImpl struct {
 }
 
 type checkedElement struct {
-	elementImpl
+	unchecked elementImpl
 	fieldPtr  *C.struct_field_s
 	isInteger bool
 }
 
-type Power interface {
-	PowBig(i *big.Int) Element
-	PowZn(i Element) Element
-}
-
-type powerImpl struct {
-	target *elementImpl
-	data   *C.struct_element_pp_s
-}
-
-type checkedPower struct {
-	powerImpl
-}
-
 func (pairing *pairingImpl) NewG1() Element                 { return makeChecked(pairing, G1, pairing.data.G1) }
 func (pairing *pairingImpl) NewG2() Element                 { return makeChecked(pairing, G2, pairing.data.G2) }
 func (pairing *pairingImpl) NewGT() Element                 { return makeChecked(pairing, GT, &pairing.data.GT[0]) }
@@ -153,18 +148,67 @@ func makeChecked(pairing *pairingImpl, field Field, fieldPtr *C.struct_field_s)
 		fieldPtr:  fieldPtr,
 		isInteger: field == Zr,
 	}
-	initElement(&element.elementImpl, pairing, true, field)
+	initElement(&element.unchecked, pairing, true, field)
 	return element
 }
 
+type Power interface {
+	PowBig(i *big.Int) Element
+	PowZn(i Element) Element
+}
+
+type powerImpl struct {
+	target Element
+	data   *C.struct_element_pp_s
+}
+
+func (power *powerImpl) PowBig(i *big.Int) Element {
+	return power.target.PowerBig(power, i)
+}
+
+func (power *powerImpl) PowZn(i Element) Element {
+	return power.target.PowerZn(power, i)
+}
+
 func clearPower(power *powerImpl) {
 	println("clearpower")
 	C.element_pp_clear(power.data)
 }
 
-func initPower(power *powerImpl, target *elementImpl) {
-	power.target = target
-	power.data = &C.struct_element_pp_s{}
-	C.element_pp_init(power.data, target.data)
+func initPower(target Element) Power {
+	power := &powerImpl{
+		target: target,
+		data:   &C.struct_element_pp_s{},
+	}
+	C.element_pp_init(power.data, target.impl().data)
 	runtime.SetFinalizer(power, clearPower)
+	return power
+}
+
+type Pairer interface {
+	Pair(target Element, x Element) Element
+}
+
+type pairerImpl struct {
+	source Element
+	data   *C.struct_pairing_pp_s
+}
+
+func (pairer *pairerImpl) Pair(target Element, x Element) Element {
+	return target.PairerPair(pairer, x)
+}
+
+func clearPairer(pairer *pairerImpl) {
+	println("clearpairer")
+	C.pairing_pp_clear(pairer.data)
+}
+
+func initPairer(source Element) Pairer {
+	pairer := &pairerImpl{
+		source: source,
+		data:   &C.struct_pairing_pp_s{},
+	}
+	C.pairing_pp_init(pairer.data, source.impl().data, source.impl().pairing.data)
+	runtime.SetFinalizer(pairer, clearPairer)
+	return pairer
 }
diff --git a/element_checked.go b/element_checked.go
index de4dd76..34e9f6e 100644
--- a/element_checked.go
+++ b/element_checked.go
@@ -19,7 +19,7 @@ var (
 	ErrInternal     = errors.New("a severe internal error has lead to possible memory corruption")
 )
 
-func (el *checkedElement) impl() *elementImpl { return &el.elementImpl }
+func (el *checkedElement) impl() *elementImpl { return &el.unchecked }
 
 func element2Checked(x Element) *checkedElement {
 	checked, ok := x.(*checkedElement)
@@ -29,13 +29,17 @@ func element2Checked(x Element) *checkedElement {
 	return checked
 }
 
-func (el *checkedElement) checkCompatible(other Element) {
-	otherChecked := element2Checked(other)
-	if el.fieldPtr != otherChecked.fieldPtr {
+func checkFieldsMatch(f1, f2 *C.struct_field_s) {
+	if f1 != f2 {
 		panic(ErrIncompatible)
 	}
 }
 
+func (el *checkedElement) checkCompatible(other Element) {
+	otherChecked := element2Checked(other)
+	checkFieldsMatch(el.fieldPtr, otherChecked.fieldPtr)
+}
+
 func (el *checkedElement) checkAllCompatible(elements ...Element) {
 	for _, other := range elements {
 		el.checkCompatible(other)
@@ -51,31 +55,73 @@ func (el *checkedElement) checkInteger() {
 func (el *checkedElement) NewFieldElement() Element {
 	newElement := &checkedElement{}
 	*newElement = *el
-	initElement(&newElement.elementImpl, el.pairing, false, G1)
-	C.element_init_same_as(newElement.elementImpl.data, el.data)
+	initElement(&newElement.unchecked, el.unchecked.pairing, false, G1)
+	C.element_init_same_as(newElement.unchecked.data, el.unchecked.data)
 	return newElement
 }
 
+func (el *checkedElement) Set0() Element {
+	el.unchecked.Set0()
+	return el
+}
+
+func (el *checkedElement) Set1() Element {
+	el.unchecked.Set1()
+	return el
+}
+
 func (el *checkedElement) SetInt32(i int32) Element {
 	el.checkInteger()
-	return el.elementImpl.SetInt32(i)
+	el.unchecked.SetInt32(i)
+	return el
 }
 
 func (el *checkedElement) SetBig(i *big.Int) Element {
 	el.checkInteger()
-	return el.elementImpl.SetBig(i)
+	el.unchecked.SetBig(i)
+	return el
 }
 
 func (el *checkedElement) Set(src Element) Element {
 	el.checkCompatible(src)
-	return el.elementImpl.Set(src)
+	el.unchecked.Set(src)
+	return el
+}
+
+func (el *checkedElement) SetFromHash(hash []byte) Element {
+	el.unchecked.SetFromHash(hash)
+	return el
+}
+
+func (el *checkedElement) SetBytes(buf []byte) Element {
+	el.unchecked.SetBytes(buf)
+	return el
+}
+
+func (el *checkedElement) SetXBytes(buf []byte) Element {
+	el.unchecked.SetXBytes(buf)
+	return el
+}
+
+func (el *checkedElement) SetCompressedBytes(buf []byte) Element {
+	el.unchecked.SetCompressedBytes(buf)
+	return el
+}
+
+func (el *checkedElement) SetString(s string, base int) (Element, bool) {
+	_, ok := el.unchecked.SetString(s, base)
+	return el, ok
 }
 
 func (el *checkedElement) BigInt() *big.Int {
 	el.checkInteger()
-	return el.elementImpl.BigInt()
+	return el.unchecked.BigInt()
 }
 
+func (el *checkedElement) BytesLen() int           { return el.unchecked.BytesLen() }
+func (el *checkedElement) XBytesLen() int          { return el.unchecked.XBytesLen() }
+func (el *checkedElement) CompressedBytesLen() int { return el.unchecked.CompressedBytesLen() }
+
 func checkedWrite(bytesWritten C.int, buffer []byte) []byte {
 	if int64(bytesWritten) > int64(len(buffer)) {
 		panic(ErrInternal)
@@ -85,124 +131,150 @@ func checkedWrite(bytesWritten C.int, buffer []byte) []byte {
 
 func (el *checkedElement) Bytes() []byte {
 	buf := make([]byte, el.BytesLen())
-	return checkedWrite(el.elementImpl.writeBytes(buf), buf)
+	return checkedWrite(el.unchecked.writeBytes(buf), buf)
 }
 
 func (el *checkedElement) XBytes() []byte {
 	buf := make([]byte, el.XBytesLen())
-	return checkedWrite(el.elementImpl.writeXBytes(buf), buf)
+	return checkedWrite(el.unchecked.writeXBytes(buf), buf)
 }
 
 func (el *checkedElement) CompressedBytes() []byte {
 	buf := make([]byte, el.CompressedBytesLen())
-	return checkedWrite(el.elementImpl.writeCompressedBytes(buf), buf)
+	return checkedWrite(el.unchecked.writeCompressedBytes(buf), buf)
 }
 
+func (el *checkedElement) Len() int { return el.unchecked.Len() }
+
 func (el *checkedElement) Item(i int) Element {
 	if i >= el.Len() {
 		panic(ErrOutOfRange)
 	}
-	uncheckedData := el.elementImpl.Item(i).(*elementImpl)
+	uncheckedData := el.unchecked.Item(i).(*elementImpl)
 	item := &checkedElement{
 		fieldPtr:  uncheckedData.data.field,
 		isInteger: uncheckedData.Len() == 0,
 	}
-	item.elementImpl = *uncheckedData
+	item.unchecked = *uncheckedData
 	return item
 }
 
+func (el *checkedElement) X() *big.Int    { return el.unchecked.X() }
+func (el *checkedElement) Y() *big.Int    { return el.unchecked.Y() }
+func (el *checkedElement) Is0() bool      { return el.unchecked.Is0() }
+func (el *checkedElement) Is1() bool      { return el.unchecked.Is1() }
+func (el *checkedElement) IsSquare() bool { return el.unchecked.IsSquare() }
+func (el *checkedElement) Sign() int      { return el.unchecked.Sign() }
+
 func (el *checkedElement) Cmp(x Element) int {
 	el.checkCompatible(x)
-	return el.elementImpl.Cmp(x)
+	return el.unchecked.Cmp(x)
 }
 
 func (el *checkedElement) Add(x Element, y Element) Element {
 	el.checkAllCompatible(x, y)
-	return el.elementImpl.Add(x, y)
+	el.unchecked.Add(x, y)
+	return el
 }
 
 func (el *checkedElement) Sub(x, y Element) Element {
 	el.checkAllCompatible(x, y)
-	return el.elementImpl.Sub(x, y)
+	el.unchecked.Sub(x, y)
+	return el
 }
 
 func (el *checkedElement) Mul(x, y Element) Element {
 	el.checkAllCompatible(x, y)
-	return el.elementImpl.Mul(x, y)
+	el.unchecked.Mul(x, y)
+	return el
 }
 
 func (el *checkedElement) MulBig(x Element, i *big.Int) Element {
 	el.checkCompatible(x)
-	return el.elementImpl.MulBig(x, i)
+	el.unchecked.MulBig(x, i)
+	return el
 }
 
 func (el *checkedElement) MulInt32(x Element, i int32) Element {
 	el.checkCompatible(x)
-	return el.elementImpl.MulInt32(x, i)
+	el.unchecked.MulInt32(x, i)
+	return el
 }
 
 func (el *checkedElement) MulZn(x, y Element) Element {
 	el.checkCompatible(x)
 	element2Checked(y).checkInteger()
-	return el.elementImpl.MulZn(x, y)
+	el.unchecked.MulZn(x, y)
+	return el
 }
 
 func (el *checkedElement) Div(x, y Element) Element {
 	el.checkAllCompatible(x, y)
-	return el.elementImpl.Div(x, y)
+	el.unchecked.Div(x, y)
+	return el
 }
 
 func (el *checkedElement) Double(x Element) Element {
 	el.checkCompatible(x)
-	return el.elementImpl.Double(x)
+	el.unchecked.Double(x)
+	return el
 }
 
 func (el *checkedElement) Halve(x Element) Element {
 	el.checkCompatible(x)
-	return el.elementImpl.Halve(x)
+	el.unchecked.Halve(x)
+	return el
 }
 
 func (el *checkedElement) Square(x Element) Element {
 	el.checkCompatible(x)
-	return el.elementImpl.Square(x)
+	el.unchecked.Square(x)
+	return el
 }
 
 func (el *checkedElement) Neg(x Element) Element {
 	el.checkCompatible(x)
-	return el.elementImpl.Neg(x)
+	el.unchecked.Neg(x)
+	return el
 }
 
 func (el *checkedElement) Invert(x Element) Element {
 	el.checkCompatible(x)
-	return el.elementImpl.Invert(x)
+	el.unchecked.Invert(x)
+	return el
 }
 
 func (el *checkedElement) PowBig(x Element, i *big.Int) Element {
 	el.checkCompatible(x)
-	return el.elementImpl.PowBig(x, i)
+	el.unchecked.PowBig(x, i)
+	return el
 }
 
 func (el *checkedElement) PowZn(x, i Element) Element {
 	el.checkCompatible(x)
 	element2Checked(i).checkInteger()
-	return el.elementImpl.PowZn(x, i)
+	el.unchecked.PowZn(x, i)
+	return el
 }
 
 func (el *checkedElement) Pow2Big(x Element, i *big.Int, y Element, j *big.Int) Element {
 	el.checkAllCompatible(x, y)
-	return el.elementImpl.Pow2Big(x, i, y, j)
+	el.unchecked.Pow2Big(x, i, y, j)
+	return el
 }
 
 func (el *checkedElement) Pow2Zn(x, i, y, j Element) Element {
 	el.checkAllCompatible(x, y)
 	element2Checked(i).checkInteger()
 	element2Checked(j).checkInteger()
-	return el.elementImpl.Pow2Zn(x, i, y, j)
+	el.unchecked.Pow2Zn(x, i, y, j)
+	return el
 }
 
 func (el *checkedElement) Pow3Big(x Element, i *big.Int, y Element, j *big.Int, z Element, k *big.Int) Element {
 	el.checkAllCompatible(x, y, z)
-	return el.elementImpl.Pow3Big(x, i, y, j, z, k)
+	el.unchecked.Pow3Big(x, i, y, j, z, k)
+	return el
 }
 
 func (el *checkedElement) Pow3Zn(x, i, y, j, z, k Element) Element {
@@ -210,28 +282,88 @@ func (el *checkedElement) Pow3Zn(x, i, y, j, z, k Element) Element {
 	element2Checked(i).checkInteger()
 	element2Checked(j).checkInteger()
 	element2Checked(k).checkInteger()
-	return el.elementImpl.Pow3Zn(x, i, y, j, z, k)
+	el.unchecked.Pow3Zn(x, i, y, j, z, k)
+	return el
 }
 
-func (el *checkedElement) PreparePower() Power {
-	power := &checkedPower{}
-	initPower(&power.powerImpl, &el.elementImpl)
-	return power
+func (el *checkedElement) PreparePower() Power { return initPower(el) }
+
+func (el *checkedElement) PowerBig(power Power, i *big.Int) Element {
+	el.unchecked.PowerBig(power, i)
+	return el
 }
 
-func (power *checkedPower) PowZn(i Element) Element {
+func (el *checkedElement) PowerZn(power Power, i Element) Element {
 	element2Checked(i).checkInteger()
-	return power.powerImpl.PowZn(i)
+	el.unchecked.PowerZn(power, i)
+	return el
+}
+
+func (el *checkedElement) Pair(x, y Element) Element {
+	pairing := el.unchecked.pairing.data
+	checkFieldsMatch(el.fieldPtr, &pairing.GT[0])
+	checkFieldsMatch(element2Checked(x).fieldPtr, pairing.G1)
+	checkFieldsMatch(element2Checked(y).fieldPtr, pairing.G2)
+	el.unchecked.Pair(x, y)
+	return el
+}
+
+func (el *checkedElement) ProdPair(elements ...Element) Element {
+	pairing := el.unchecked.pairing.data
+	checkFieldsMatch(el.fieldPtr, &pairing.GT[0])
+	n := len(elements)
+	for i := 1; i < n; i += 2 {
+		checkFieldsMatch(element2Checked(elements[i-1]).fieldPtr, pairing.G1)
+		checkFieldsMatch(element2Checked(elements[i]).fieldPtr, pairing.G2)
+	}
+	el.unchecked.ProdPair(elements...)
+	return el
+}
+
+func (el *checkedElement) ProdPairSlice(x, y []Element) Element {
+	pairing := el.unchecked.pairing.data
+	checkFieldsMatch(el.fieldPtr, &pairing.GT[0])
+	n := len(x)
+	for i := 1; i < n; i++ {
+		checkFieldsMatch(element2Checked(x[i]).fieldPtr, pairing.G1)
+	}
+	n = len(y)
+	for i := 1; i < n; i++ {
+		checkFieldsMatch(element2Checked(y[i]).fieldPtr, pairing.G2)
+
+	}
+	el.unchecked.ProdPairSlice(x, y)
+	return el
+}
+
+func (el *checkedElement) PreparePairer() Pairer { return initPairer(el) }
+
+func (el *checkedElement) PairerPair(pairer Pairer, x Element) Element {
+	in1 := element2Checked(pairer.(*pairerImpl).source)
+	in2 := element2Checked(x)
+	pairing := el.unchecked.pairing.data
+	checkFieldsMatch(in1.fieldPtr, pairing.G1)
+	checkFieldsMatch(in2.fieldPtr, pairing.G2)
+	checkFieldsMatch(el.fieldPtr, &pairing.GT[0])
+	el.unchecked.PairerPair(pairer, x)
+	return el
 }
 
 func (el *checkedElement) BruteForceDL(g, h Element) Element {
 	el.checkInteger()
 	element2Checked(g).checkCompatible(h)
-	return el.elementImpl.BruteForceDL(g, h)
+	el.unchecked.BruteForceDL(g, h)
+	return el
 }
 
 func (el *checkedElement) PollardRhoDL(g, h Element) Element {
 	el.checkInteger()
 	element2Checked(g).checkCompatible(h)
-	return el.elementImpl.PollardRhoDL(g, h)
+	el.unchecked.PollardRhoDL(g, h)
+	return el
+}
+
+func (el *checkedElement) Rand() Element {
+	el.unchecked.Rand()
+	return el
 }
diff --git a/element_fmt.go b/element_fmt.go
index 0557463..89c32d8 100644
--- a/element_fmt.go
+++ b/element_fmt.go
@@ -86,9 +86,9 @@ func (el *elementImpl) Format(f fmt.State, c rune) {
 
 func (el *checkedElement) Format(f fmt.State, c rune) {
 	if c == 'v' && f.Flag('#') {
-		fmt.Fprintf(f, "pbc.Element{Checked: true, Integer: %t, Field: %p, Pairing: %p, Addr: %p}", el.isInteger, el.fieldPtr, el.pairing, el)
+		fmt.Fprintf(f, "pbc.Element{Checked: true, Integer: %t, Field: %p, Pairing: %p, Addr: %p}", el.isInteger, el.fieldPtr, el.unchecked.pairing, el)
 	} else {
-		el.elementImpl.Format(f, c)
+		el.unchecked.Format(f, c)
 	}
 }
 
@@ -96,6 +96,8 @@ func (el *elementImpl) String() string {
 	return fmt.Sprintf("%s", el)
 }
 
+func (el *checkedElement) String() string { return el.unchecked.String() }
+
 func (el *elementImpl) Scan(state fmt.ScanState, verb rune) error {
 	if verb != 's' && verb != 'v' {
 		return ErrBadVerb
@@ -182,3 +184,7 @@ ReadLoop:
 	}
 	return nil
 }
+
+func (el *checkedElement) Scan(state fmt.ScanState, verb rune) error {
+	return el.unchecked.Scan(state, verb)
+}
diff --git a/element_unchecked.go b/element_unchecked.go
index 8da3acf..347f7e9 100644
--- a/element_unchecked.go
+++ b/element_unchecked.go
@@ -7,10 +7,13 @@ package pbc
 import "C"
 
 import (
+	"errors"
 	"math/big"
 	"unsafe"
 )
 
+var ErrBadPairList = errors.New("pairing product list is in an invalid format")
+
 func (el *elementImpl) impl() *elementImpl { return el }
 
 func (el *elementImpl) NewFieldElement() Element {
@@ -45,6 +48,11 @@ func (el *elementImpl) Set(src Element) Element {
 	return el
 }
 
+func (el *elementImpl) SetFromHash(hash []byte) Element {
+	C.element_from_hash(el.data, unsafe.Pointer(&hash[0]), C.int(len(hash)))
+	return el
+}
+
 func (el *elementImpl) SetBytes(buf []byte) Element {
 	C.element_from_bytes(el.data, (*C.uchar)(unsafe.Pointer(&buf[0])))
 	return el
@@ -60,11 +68,6 @@ func (el *elementImpl) SetCompressedBytes(buf []byte) Element {
 	return el
 }
 
-func (el *elementImpl) SetFromHash(hash []byte) Element {
-	C.element_from_hash(el.data, unsafe.Pointer(&hash[0]), C.int(len(hash)))
-	return el
-}
-
 func (el *elementImpl) SetString(s string, base int) (Element, bool) {
 	cstr := C.CString(s)
 	defer C.free(unsafe.Pointer(cstr))
@@ -262,20 +265,64 @@ func (el *elementImpl) Pow3Zn(x, i, y, j, z, k Element) Element {
 	return el
 }
 
-func (el *elementImpl) PreparePower() Power {
-	power := &powerImpl{}
-	initPower(power, el)
-	return power
+func (el *elementImpl) PreparePower() Power { return initPower(el) }
+
+func (el *elementImpl) PowerBig(power Power, i *big.Int) Element {
+	C.element_pp_pow(el.data, &big2mpz(i)[0], power.(*powerImpl).data)
+	return el
+}
+
+func (el *elementImpl) PowerZn(power Power, i Element) Element {
+	C.element_pp_pow_zn(el.data, i.impl().data, power.(*powerImpl).data)
+	return el
+}
+
+func (el *elementImpl) Pair(x, y Element) Element {
+	C.element_pairing(el.data, x.impl().data, y.impl().data)
+	return el
 }
 
-func (power *powerImpl) PowBig(i *big.Int) Element {
-	C.element_pp_pow(power.target.data, &big2mpz(i)[0], power.data)
-	return power.target
+func (el *elementImpl) doProdPair(in1, in2 []C.struct_element_s) Element {
+	x := (*C.element_t)(unsafe.Pointer(&in1[0]))
+	y := (*C.element_t)(unsafe.Pointer(&in2[0]))
+	C.element_prod_pairing(el.data, x, y, C.int(len(in1)))
+	return el
 }
 
-func (power *powerImpl) PowZn(i Element) Element {
-	C.element_pp_pow_zn(power.target.data, i.impl().data, power.data)
-	return power.target
+func (el *elementImpl) ProdPair(elements ...Element) Element {
+	n := len(elements)
+	if n%2 != 0 {
+		panic(ErrBadPairList)
+	}
+	half := n / 2
+	in1 := make([]C.struct_element_s, half)
+	in2 := make([]C.struct_element_s, half)
+	for i, j := 0, 0; j < n; i, j = i+1, j+2 {
+		in1[i] = *elements[j].impl().data
+		in2[i] = *elements[j+1].impl().data
+	}
+	return el.doProdPair(in1, in2)
+}
+
+func (el *elementImpl) ProdPairSlice(x, y []Element) Element {
+	n := len(x)
+	if n != len(y) {
+		panic(ErrBadPairList)
+	}
+	in1 := make([]C.struct_element_s, n)
+	in2 := make([]C.struct_element_s, n)
+	for i := 0; i < n; i++ {
+		in1[i] = *x[i].impl().data
+		in2[i] = *y[i].impl().data
+	}
+	return el.doProdPair(in1, in2)
+}
+
+func (el *elementImpl) PreparePairer() Pairer { return initPairer(el) }
+
+func (el *elementImpl) PairerPair(pairer Pairer, x Element) Element {
+	C.pairing_pp_apply(el.data, x.impl().data, pairer.(*pairerImpl).data)
+	return el
 }
 
 func (el *elementImpl) BruteForceDL(g, h Element) Element {
-- 
GitLab