diff --git a/element.go b/element.go index 03bd8b8ae3ba91dc140b803ebecbae4f7e61d55c..5f2aae58bbba236b139c17f03e8809e58e0b441e 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 de4dd76fa2451a129ca93981214c7ecf04bca66a..34e9f6eb8153d9ca14c1399d17fb65d2dcdab4d0 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 055746354544222ba1ce9c00945bfd4fbc8d1bb0..89c32d8f6a4b542491127d39ae0fb46c3276a1d4 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 8da3acfbd85202a4b8d45646d44aa5256285044f..347f7e9dad1eb7f8093c40cecfdb47b649868742 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 {