diff --git a/doc_test.go b/doc_test.go index 121f8cd7463dd2f7357cf446dd361b2990444adb..3bbe420c4903da1621e1f9e2414530a9e4265765 100644 --- a/doc_test.go +++ b/doc_test.go @@ -1,10 +1,12 @@ package pbc +import "fmt" + // This example generates a pairing and some random group elements, then applies // the pairing operation. func Example() { // In a real application, generate this once and publish it - params := pbc.GenerateA(160, 512) + params := GenerateA(160, 512) pairing := params.NewPairing() @@ -16,7 +18,8 @@ func Example() { // Generate random group elements and pair them g.Rand() h.Rand() - fmt.Printf("g = %v\nh = %v\n", g, h) + fmt.Printf("g = %s\n", g) + fmt.Printf("h = %s\n", h) x.Pair(g, h) - fmt.Printf("e(g,h) = %v\n", x) + fmt.Printf("e(g,h) = %s\n", x) } diff --git a/element.go b/element.go index 92febd6330cddc7e030fe56328a55364ec925f4f..c20e9ffb5575f9e62074a6f77cabd1b902824b83 100644 --- a/element.go +++ b/element.go @@ -4,182 +4,78 @@ package pbc #include <pbc/pbc.h> */ import "C" +import "runtime" -import ( - "fmt" - "hash" - "math/big" - "runtime" -) +type Element struct { + pairing *Pairing // Prevents garbage collection + cptr *C.struct_element_s -type Element interface { - // NewFieldElement initializes a new element in the same group as this one. - // The returned element will be unchecked if and only if this element is. - NewFieldElement() Element - - // Methods to directly set the value of the element: - Set0() Element - Set1() Element - SetInt32(int32) Element - SetBig(*big.Int) Element - Set(Element) Element - - // Methods to hash a value into a group element: - SetFromHash([]byte) Element - SetFromStringHash(s string, h hash.Hash) Element - - // SetString sets the value from an exported string representation. - SetString(s string, base int) (Element, bool) - - // Methods to support the fmt package's Print and Scan functions: - Format(fmt.State, rune) - Scan(fmt.ScanState, rune) error - - // Methods to export the element in human-readable format: - BigInt() *big.Int - String() string - - // Methods to export the element as a sequence of bytes: - BytesLen() int - Bytes() []byte - XBytesLen() int - XBytes() []byte - CompressedBytesLen() int - CompressedBytes() []byte - - // Methods to import an element from a sequence of bytes: - SetBytes([]byte) Element - SetXBytes([]byte) Element - SetCompressedBytes([]byte) Element - - // Methods to retrieve sub-elements (coordinates for points, coefficients - // for polynomials): - Len() int - Item(int) Element - X() *big.Int - Y() *big.Int - - // Methods to determine the mathematical properties of the element: - Is0() bool - Is1() bool - IsSquare() bool - Sign() int - - // Methods to compare elements: - Cmp(x Element) int - Equals(x Element) bool - - // Methods to perform arithmetic operations. Not all operations are valid - // for all groups. - Add(x, y Element) Element - Sub(x, y Element) Element - Mul(x, y Element) Element - MulBig(x Element, i *big.Int) Element - MulInt32(x Element, i int32) Element - MulZn(x, y Element) Element - Div(x, y Element) Element - Double(x Element) Element - Halve(x Element) Element - Square(x Element) Element - Neg(x Element) Element - Invert(x Element) Element - - // Methods to exponentiate elements: - PowBig(x Element, i *big.Int) Element - PowZn(x, i Element) Element - Pow2Big(x Element, i *big.Int, y Element, j *big.Int) Element - Pow2Zn(x, i, y, j Element) Element - Pow3Big(x Element, i *big.Int, y Element, j *big.Int, z Element, k *big.Int) Element - Pow3Zn(x, i, y, j, z, k Element) Element - - // Methods to perform pre-processed exponentiation: - PreparePower() Power - PowerBig(Power, *big.Int) Element - PowerZn(Power, Element) Element - - // Methods to brute-force discrete logarithms in the group: - BruteForceDL(g, h Element) Element - PollardRhoDL(g, h Element) Element - - // Rand sets the element to a random group element. - Rand() Element - - // Pairing operations: - Pair(x, y Element) Element - ProdPair(elements ...Element) Element - ProdPairSlice(x, y []Element) Element - - // Methods to perform pre-processed pairing operations: - PreparePairer() Pairer - PairerPair(Pairer, Element) Element - - // Pairing returns the pairing associated with this element. - Pairing() Pairing - - data() *C.struct_element_s -} - -// Power stores pre-processed information to quickly exponentiate an element. -// A Power can be generated for Element x by calling x.PreparePower(). When -// PowBig or PowZn is called with Element target and integer i, the result of -// x^i will be stored in target. -type Power interface { - PowBig(target Element, i *big.Int) Element - PowZn(target Element, i Element) Element -} - -type powerImpl struct { - data *C.struct_element_pp_s + checked bool + fieldPtr *C.struct_field_s + isInteger bool } -func (power *powerImpl) PowBig(target Element, i *big.Int) Element { - return target.PowerBig(power, i) +func clearElement(element *Element) { + C.element_clear(element.cptr) } -func (power *powerImpl) PowZn(target Element, i Element) Element { - return target.PowerZn(power, i) +func makeUncheckedElement(pairing *Pairing, initialize bool, field Field) *Element { + element := &Element{ + cptr: &C.struct_element_s{}, + pairing: pairing, + } + if initialize { + switch field { + case G1: + C.element_init_G1(element.cptr, pairing.cptr) + case G2: + C.element_init_G2(element.cptr, pairing.cptr) + case GT: + C.element_init_GT(element.cptr, pairing.cptr) + case Zr: + C.element_init_Zr(element.cptr, pairing.cptr) + default: + panic(ErrUnknownField) + } + } + runtime.SetFinalizer(element, clearElement) + return element } -func clearPower(power *powerImpl) { - C.element_pp_clear(power.data) +func makeCheckedElement(pairing *Pairing, field Field, fieldPtr *C.struct_field_s) *Element { + element := makeUncheckedElement(pairing, true, field) + element.checked = true + element.fieldPtr = fieldPtr + element.isInteger = (field == Zr) + return element } -func initPower(source Element) Power { - power := &powerImpl{ - data: &C.struct_element_pp_s{}, +func checkFieldsMatch(f1, f2 *C.struct_field_s) { + if f1 != f2 { + panic(ErrIncompatible) } - C.element_pp_init(power.data, source.data()) - runtime.SetFinalizer(power, clearPower) - return power } -// Pairer stores pre-processed information to quickly pair an element. A Pairer -// can be generated for Element x by calling x.PreparePairer(). When Pair is -// called with Elements target and y, the result of e(x,y) will be stored in -// target. -type Pairer interface { - Pair(target Element, y Element) Element -} - -type pairerImpl struct { - source Element - data *C.struct_pairing_pp_s +func (el *Element) ensureChecked() { + if !el.checked { + panic(ErrUncheckedOp) + } } -func (pairer *pairerImpl) Pair(target Element, y Element) Element { - return target.PairerPair(pairer, y) +func (el *Element) checkCompatible(other *Element) { + other.ensureChecked() + checkFieldsMatch(el.fieldPtr, other.fieldPtr) } -func clearPairer(pairer *pairerImpl) { - C.pairing_pp_clear(pairer.data) +func (el *Element) checkAllCompatible(elements ...*Element) { + for _, other := range elements { + el.checkCompatible(other) + } } -func initPairer(source Element) Pairer { - pairer := &pairerImpl{ - source: source, - data: &C.struct_pairing_pp_s{}, +func (el *Element) checkInteger() { + el.ensureChecked() + if !el.isInteger { + panic(ErrIllegalOp) } - C.pairing_pp_init(pairer.data, source.data(), source.Pairing().(*pairingImpl).data) - runtime.SetFinalizer(pairer, clearPairer) - return pairer } diff --git a/element_arith.go b/element_arith.go new file mode 100644 index 0000000000000000000000000000000000000000..b2420175ddb28b7a24b7bc72ffe473f2c594c0b8 --- /dev/null +++ b/element_arith.go @@ -0,0 +1,372 @@ +package pbc + +/* +#include <pbc/pbc.h> +*/ +import "C" +import ( + "math/big" + "runtime" + "unsafe" +) + +func (el *Element) Set0() *Element { + C.element_set0(el.cptr) + return el +} + +func (el *Element) Set1() *Element { + C.element_set1(el.cptr) + return el +} + +func (el *Element) Rand() *Element { + C.element_random(el.cptr) + return el +} + +func normalizeSign(sign int64) int { + if sign > 0 { + return 1 + } + if sign < 0 { + return -1 + } + return 0 +} + +func (el *Element) Cmp(x *Element) int { + if el.checked { + el.checkCompatible(x) + } + return normalizeSign(int64(C.element_cmp(el.cptr, x.cptr))) +} + +func (el *Element) Equals(x *Element) bool { return el.Cmp(x) == 0 } + +func (el *Element) Is0() bool { + return C.element_is0(el.cptr) != 0 +} + +func (el *Element) Is1() bool { + return C.element_is1(el.cptr) != 0 +} + +func (el *Element) IsSquare() bool { + return C.element_is_sqr(el.cptr) != 0 +} + +func (el *Element) Sign() int { + return normalizeSign(int64(C.element_sign(el.cptr))) +} + +func (el *Element) Add(x, y *Element) *Element { + if el.checked { + el.checkAllCompatible(x, y) + } + C.element_add(el.cptr, x.cptr, y.cptr) + return el +} + +func (el *Element) Sub(x, y *Element) *Element { + if el.checked { + el.checkAllCompatible(x, y) + } + C.element_sub(el.cptr, x.cptr, y.cptr) + return el +} + +func (el *Element) Mul(x, y *Element) *Element { + if el.checked { + el.checkAllCompatible(x, y) + } + C.element_mul(el.cptr, x.cptr, y.cptr) + return el +} + +func (el *Element) MulBig(x *Element, i *big.Int) *Element { + if el.checked { + el.checkCompatible(x) + } + C.element_mul_mpz(el.cptr, x.cptr, &big2mpz(i)[0]) + return el +} + +func (el *Element) MulInt32(x *Element, i int32) *Element { + if el.checked { + el.checkCompatible(x) + } + C.element_mul_si(el.cptr, x.cptr, C.long(i)) + return el +} + +func (el *Element) MulZn(x, y *Element) *Element { + if el.checked { + el.checkCompatible(x) + y.checkInteger() + } + C.element_mul_zn(el.cptr, x.cptr, y.cptr) + return el +} + +func (el *Element) Div(x, y *Element) *Element { + if el.checked { + el.checkAllCompatible(x, y) + } + C.element_div(el.cptr, x.cptr, y.cptr) + return el +} + +func (el *Element) Double(x *Element) *Element { + if el.checked { + el.checkCompatible(x) + } + C.element_double(el.cptr, x.cptr) + return el +} + +func (el *Element) Halve(x *Element) *Element { + if el.checked { + el.checkCompatible(x) + } + C.element_halve(el.cptr, x.cptr) + return el +} + +func (el *Element) Square(x *Element) *Element { + if el.checked { + el.checkCompatible(x) + } + C.element_square(el.cptr, x.cptr) + return el +} + +func (el *Element) Neg(x *Element) *Element { + if el.checked { + el.checkCompatible(x) + } + C.element_neg(el.cptr, x.cptr) + return el +} + +func (el *Element) Invert(x *Element) *Element { + if el.checked { + el.checkCompatible(x) + } + C.element_invert(el.cptr, x.cptr) + return el +} + +func (el *Element) PowBig(x *Element, i *big.Int) *Element { + if el.checked { + el.checkCompatible(x) + } + C.element_pow_mpz(el.cptr, x.cptr, &big2mpz(i)[0]) + return el +} + +func (el *Element) PowZn(x, i *Element) *Element { + if el.checked { + el.checkCompatible(x) + i.checkInteger() + } + C.element_pow_zn(el.cptr, x.cptr, i.cptr) + return el +} + +func (el *Element) Pow2Big(x *Element, i *big.Int, y *Element, j *big.Int) *Element { + if el.checked { + el.checkAllCompatible(x, y) + } + C.element_pow2_mpz(el.cptr, x.cptr, &big2mpz(i)[0], y.cptr, &big2mpz(j)[0]) + return el +} + +func (el *Element) Pow2Zn(x, i, y, j *Element) *Element { + if el.checked { + el.checkAllCompatible(x, y) + i.checkInteger() + j.checkInteger() + } + C.element_pow2_zn(el.cptr, x.cptr, i.cptr, y.cptr, j.cptr) + return el +} + +func (el *Element) Pow3Big(x *Element, i *big.Int, y *Element, j *big.Int, z *Element, k *big.Int) *Element { + if el.checked { + el.checkAllCompatible(x, y, z) + } + C.element_pow3_mpz(el.cptr, x.cptr, &big2mpz(i)[0], y.cptr, &big2mpz(j)[0], z.cptr, &big2mpz(k)[0]) + return el +} + +func (el *Element) Pow3Zn(x, i, y, j, z, k *Element) *Element { + if el.checked { + el.checkAllCompatible(x, y, z) + i.checkInteger() + j.checkInteger() + k.checkInteger() + } + C.element_pow3_zn(el.cptr, x.cptr, i.cptr, y.cptr, j.cptr, z.cptr, k.cptr) + return el +} + +// Power stores pre-processed information to quickly exponentiate an element. +// A Power can be generated for Element x by calling x.PreparePower(). When +// PowBig or PowZn is called with Element target and integer i, the result of +// x^i will be stored in target. +type Power struct { + source *Element // Prevents garbage collection + pp *C.struct_element_pp_s +} + +func (power *Power) Source() *Element { return power.source } + +func (power *Power) PowBig(target *Element, i *big.Int) *Element { + return target.PowerBig(power, i) +} + +func (power *Power) PowZn(target *Element, i *Element) *Element { + return target.PowerZn(power, i) +} + +func clearPower(power *Power) { + C.element_pp_clear(power.pp) +} + +func (el *Element) PreparePower() *Power { + power := &Power{ + source: el, + pp: &C.struct_element_pp_s{}, + } + C.element_pp_init(power.pp, el.cptr) + runtime.SetFinalizer(power, clearPower) + return power +} + +func (el *Element) PowerBig(power *Power, i *big.Int) *Element { + C.element_pp_pow(el.cptr, &big2mpz(i)[0], power.pp) + return el +} + +func (el *Element) PowerZn(power *Power, i *Element) *Element { + if el.checked { + i.checkInteger() + } + C.element_pp_pow_zn(el.cptr, i.cptr, power.pp) + return el +} + +func (el *Element) Pair(x, y *Element) *Element { + if el.checked { + x.ensureChecked() + y.ensureChecked() + pairing := el.pairing.cptr + checkFieldsMatch(el.fieldPtr, &pairing.GT[0]) + checkFieldsMatch(x.fieldPtr, pairing.G1) + checkFieldsMatch(y.fieldPtr, pairing.G2) + } + C.pairing_apply(el.cptr, x.cptr, y.cptr, el.pairing.cptr) + return el +} + +func (el *Element) 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.cptr, x, y, C.int(len(in1))) + return el +} + +func (el *Element) ProdPair(elements ...*Element) *Element { + n := len(elements) + if n%2 != 0 { + panic(ErrBadPairList) + } + if el.checked { + pairing := el.pairing.cptr + checkFieldsMatch(el.fieldPtr, &pairing.GT[0]) + for i := 1; i < n; i += 2 { + elements[i-1].ensureChecked() + elements[i].ensureChecked() + checkFieldsMatch(elements[i-1].fieldPtr, pairing.G1) + checkFieldsMatch(elements[i].fieldPtr, pairing.G2) + } + } + 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].cptr + in2[i] = *elements[j+1].cptr + } + return el.doProdPair(in1, in2) +} + +func (el *Element) ProdPairSlice(x, y []*Element) *Element { + n := len(x) + if n != len(y) { + panic(ErrBadPairList) + } + if el.checked { + pairing := el.pairing.cptr + checkFieldsMatch(el.fieldPtr, &pairing.GT[0]) + for i := 1; i < n; i++ { + x[i].ensureChecked() + checkFieldsMatch(x[i].fieldPtr, pairing.G1) + } + n = len(y) + for i := 1; i < n; i++ { + y[i].ensureChecked() + checkFieldsMatch(y[i].fieldPtr, pairing.G2) + } + } + in1 := make([]C.struct_element_s, n) + in2 := make([]C.struct_element_s, n) + for i := 0; i < n; i++ { + in1[i] = *x[i].cptr + in2[i] = *y[i].cptr + } + return el.doProdPair(in1, in2) +} + +// Pairer stores pre-processed information to quickly pair an element. A Pairer +// can be generated for Element x by calling x.PreparePairer(). When Pair is +// called with Elements target and y, the result of e(x,y) will be stored in +// target. +type Pairer struct { + source *Element // Prevents garbage collection + pp *C.struct_pairing_pp_s +} + +func (pairer *Pairer) Source() *Element { return pairer.source } + +func (pairer *Pairer) Pair(target *Element, y *Element) *Element { + return target.PairerPair(pairer, y) +} + +func clearPairer(pairer *Pairer) { + C.pairing_pp_clear(pairer.pp) +} + +func (el *Element) PreparePairer() *Pairer { + pairer := &Pairer{ + source: el, + pp: &C.struct_pairing_pp_s{}, + } + C.pairing_pp_init(pairer.pp, el.cptr, el.pairing.cptr) + runtime.SetFinalizer(pairer, clearPairer) + return pairer +} + +func (el *Element) PairerPair(pairer *Pairer, y *Element) *Element { + if el.checked { + pairer.source.ensureChecked() + y.ensureChecked() + pairing := el.pairing.cptr + checkFieldsMatch(pairer.source.fieldPtr, pairing.G1) + checkFieldsMatch(y.fieldPtr, pairing.G2) + checkFieldsMatch(el.fieldPtr, &pairing.GT[0]) + } + C.pairing_pp_apply(el.cptr, y.cptr, pairer.pp) + return el +} diff --git a/element_checked.go b/element_checked.go deleted file mode 100644 index 07d200991bebadb079117c682e85b7043d0dd551..0000000000000000000000000000000000000000 --- a/element_checked.go +++ /dev/null @@ -1,384 +0,0 @@ -package pbc - -/* -#include <pbc/pbc.h> -*/ -import "C" - -import ( - "hash" - "math/big" -) - -type checkedElement struct { - unchecked uncheckedElement - fieldPtr *C.struct_field_s - isInteger bool -} - -func makeChecked(pairing *pairingImpl, field Field, fieldPtr *C.struct_field_s) *checkedElement { - element := &checkedElement{ - fieldPtr: fieldPtr, - isInteger: field == Zr, - } - initUnchecked(&element.unchecked, pairing, true, field) - return element -} - -func (el *checkedElement) data() *C.struct_element_s { return el.unchecked.d } - -func (el *checkedElement) Pairing() Pairing { return el.unchecked.pairing } - -func element2Checked(x Element) *checkedElement { - checked, ok := x.(*checkedElement) - if !ok { - panic(ErrUncheckedOp) - } - return checked -} - -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) - } -} - -func (el *checkedElement) checkInteger() { - if !el.isInteger { - panic(ErrIllegalOp) - } -} - -func (el *checkedElement) NewFieldElement() Element { - newElement := &checkedElement{} - *newElement = *el - initUnchecked(&newElement.unchecked, el.unchecked.pairing, false, G1) - C.element_init_same_as(newElement.unchecked.d, el.unchecked.d) - 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() - el.unchecked.SetInt32(i) - return el -} - -func (el *checkedElement) SetBig(i *big.Int) Element { - el.checkInteger() - el.unchecked.SetBig(i) - return el -} - -func (el *checkedElement) Set(src Element) Element { - el.checkCompatible(src) - el.unchecked.Set(src) - return el -} - -func (el *checkedElement) SetFromHash(hash []byte) Element { - el.unchecked.SetFromHash(hash) - return el -} - -func (el *checkedElement) SetFromStringHash(s string, h hash.Hash) Element { - el.unchecked.SetFromStringHash(s, h) - 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.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) - } - return buffer -} - -func (el *checkedElement) Bytes() []byte { - buf := make([]byte, el.BytesLen()) - return checkedWrite(el.unchecked.writeBytes(buf), buf) -} - -func (el *checkedElement) XBytes() []byte { - buf := make([]byte, el.XBytesLen()) - return checkedWrite(el.unchecked.writeXBytes(buf), buf) -} - -func (el *checkedElement) CompressedBytes() []byte { - buf := make([]byte, el.CompressedBytesLen()) - 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.unchecked.Item(i).(*uncheckedElement) - item := &checkedElement{ - fieldPtr: uncheckedData.d.field, - isInteger: uncheckedData.Len() == 0, - } - 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.unchecked.Cmp(x) -} - -func (el *checkedElement) Equals(x Element) bool { return el.unchecked.Equals(x) } - -func (el *checkedElement) Add(x Element, y Element) Element { - el.checkAllCompatible(x, y) - el.unchecked.Add(x, y) - return el -} - -func (el *checkedElement) Sub(x, y Element) Element { - el.checkAllCompatible(x, y) - el.unchecked.Sub(x, y) - return el -} - -func (el *checkedElement) Mul(x, y Element) Element { - el.checkAllCompatible(x, y) - el.unchecked.Mul(x, y) - return el -} - -func (el *checkedElement) MulBig(x Element, i *big.Int) Element { - el.checkCompatible(x) - el.unchecked.MulBig(x, i) - return el -} - -func (el *checkedElement) MulInt32(x Element, i int32) Element { - el.checkCompatible(x) - el.unchecked.MulInt32(x, i) - return el -} - -func (el *checkedElement) MulZn(x, y Element) Element { - el.checkCompatible(x) - element2Checked(y).checkInteger() - el.unchecked.MulZn(x, y) - return el -} - -func (el *checkedElement) Div(x, y Element) Element { - el.checkAllCompatible(x, y) - el.unchecked.Div(x, y) - return el -} - -func (el *checkedElement) Double(x Element) Element { - el.checkCompatible(x) - el.unchecked.Double(x) - return el -} - -func (el *checkedElement) Halve(x Element) Element { - el.checkCompatible(x) - el.unchecked.Halve(x) - return el -} - -func (el *checkedElement) Square(x Element) Element { - el.checkCompatible(x) - el.unchecked.Square(x) - return el -} - -func (el *checkedElement) Neg(x Element) Element { - el.checkCompatible(x) - el.unchecked.Neg(x) - return el -} - -func (el *checkedElement) Invert(x Element) Element { - el.checkCompatible(x) - el.unchecked.Invert(x) - return el -} - -func (el *checkedElement) PowBig(x Element, i *big.Int) Element { - el.checkCompatible(x) - el.unchecked.PowBig(x, i) - return el -} - -func (el *checkedElement) PowZn(x, i Element) Element { - el.checkCompatible(x) - element2Checked(i).checkInteger() - 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) - 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() - 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) - el.unchecked.Pow3Big(x, i, y, j, z, k) - return el -} - -func (el *checkedElement) Pow3Zn(x, i, y, j, z, k Element) Element { - el.checkAllCompatible(x, y, z) - element2Checked(i).checkInteger() - element2Checked(j).checkInteger() - element2Checked(k).checkInteger() - el.unchecked.Pow3Zn(x, i, y, j, z, k) - return el -} - -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 (el *checkedElement) PowerZn(power Power, i Element) Element { - element2Checked(i).checkInteger() - 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, y Element) Element { - in1 := element2Checked(pairer.(*pairerImpl).source) - in2 := element2Checked(y) - 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, y) - return el -} - -func (el *checkedElement) BruteForceDL(g, h Element) Element { - el.checkInteger() - element2Checked(g).checkCompatible(h) - el.unchecked.BruteForceDL(g, h) - return el -} - -func (el *checkedElement) PollardRhoDL(g, h Element) Element { - el.checkInteger() - element2Checked(g).checkCompatible(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 3c528cf5875197048b48689d2ac94541f95d2ac1..410ad1ed887613b63fc2256605f02c31fb2b28ce 100644 --- a/element_fmt.go +++ b/element_fmt.go @@ -20,11 +20,11 @@ import ( "unsafe" ) -func (el *uncheckedElement) errorFormat(f fmt.State, c rune, err string) { +func (el *Element) errorFormat(f fmt.State, c rune, err string) { fmt.Fprintf(f, "%%!%c(%s pbc.Element)", c, err) } -func (el *uncheckedElement) nativeFormat(f fmt.State, c rune) { +func (el *Element) nativeFormat(f fmt.State, c rune) { base := 10 if width, ok := f.Width(); ok { if width < 2 || width > 36 { @@ -35,7 +35,7 @@ func (el *uncheckedElement) nativeFormat(f fmt.State, c rune) { } var buf *C.char var bufLen C.size_t - if C.element_out_str_wrapper(&buf, &bufLen, C.int(base), el.d) == 0 { + if C.element_out_str_wrapper(&buf, &bufLen, C.int(base), el.cptr) == 0 { el.errorFormat(f, c, "INTERNALERROR") return } @@ -44,14 +44,14 @@ func (el *uncheckedElement) nativeFormat(f fmt.State, c rune) { fmt.Fprintf(f, "%s", str) } -func (el *uncheckedElement) customFormat(f fmt.State, c rune) { +func (el *Element) customFormat(f fmt.State, c rune) { count := el.Len() if count == 0 { el.BigInt().Format(f, c) } else { fmt.Fprintf(f, "[") for i := 0; i < count; i++ { - el.Item(i).(*uncheckedElement).customFormat(f, c) + el.Item(i).customFormat(f, c) if i+1 < count { fmt.Fprintf(f, ", ") } @@ -60,11 +60,15 @@ func (el *uncheckedElement) customFormat(f fmt.State, c rune) { } } -func (el *uncheckedElement) Format(f fmt.State, c rune) { +func (el *Element) Format(f fmt.State, c rune) { switch c { case 'v': if f.Flag('#') { - fmt.Fprintf(f, "pbc.Element{Checked: false, Pairing: %p, Addr: %p}", el.pairing, el) + if el.checked { + fmt.Fprintf(f, "pbc.Element{Checked: true, Integer: %t, Field: %p, Pairing: %p, Addr: %p}", el.isInteger, el.fieldPtr, el.pairing, el) + } else { + fmt.Fprintf(f, "pbc.Element{Checked: false, Pairing: %p, Addr: %p}", el.pairing, el) + } break } fallthrough @@ -77,21 +81,21 @@ func (el *uncheckedElement) 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.unchecked.pairing, el) - } else { - el.unchecked.Format(f, c) - } -} - -func (el *uncheckedElement) String() string { +func (el *Element) String() string { return fmt.Sprintf("%s", el) } -func (el *checkedElement) String() string { return el.unchecked.String() } +func (el *Element) SetString(s string, base int) (*Element, bool) { + cstr := C.CString(s) + defer C.free(unsafe.Pointer(cstr)) -func (el *uncheckedElement) Scan(state fmt.ScanState, verb rune) error { + if ok := C.element_set_str(el.cptr, cstr, C.int(base)); ok == 0 { + return nil, false + } + return el, true +} + +func (el *Element) Scan(state fmt.ScanState, verb rune) error { if verb != 's' && verb != 'v' { return ErrBadVerb } @@ -177,7 +181,3 @@ ReadLoop: } return nil } - -func (el *checkedElement) Scan(state fmt.ScanState, verb rune) error { - return el.unchecked.Scan(state, verb) -} diff --git a/element_io.go b/element_io.go new file mode 100644 index 0000000000000000000000000000000000000000..739a50998ef528df49abcd2c10b453a7390a7520 --- /dev/null +++ b/element_io.go @@ -0,0 +1,111 @@ +package pbc + +/* +#include <pbc/pbc.h> +*/ +import "C" +import ( + "hash" + "math/big" + "unsafe" +) + +func (el *Element) BigInt() *big.Int { + if el.checked { + el.checkInteger() + } + mpz := newMpz() + C.element_to_mpz(&mpz[0], el.cptr) + return mpz2big(mpz) +} + +func (el *Element) Set(src *Element) *Element { + if el.checked { + el.checkCompatible(src) + } + C.element_set(el.cptr, src.cptr) + return el +} + +func (el *Element) SetInt32(i int32) *Element { + if el.checked { + el.checkInteger() + } + C.element_set_si(el.cptr, C.long(i)) + return el +} + +func (el *Element) SetBig(i *big.Int) *Element { + if el.checked { + el.checkInteger() + } + C.element_set_mpz(el.cptr, &big2mpz(i)[0]) + return el +} + +func (el *Element) SetFromHash(hash []byte) *Element { + C.element_from_hash(el.cptr, unsafe.Pointer(&hash[0]), C.int(len(hash))) + return el +} + +func (el *Element) SetFromStringHash(s string, h hash.Hash) *Element { + h.Reset() + if _, err := h.Write([]byte(s)); err != nil { + panic(ErrHashFailure) + } + return el.SetFromHash(h.Sum([]byte{})) +} + +func (el *Element) BytesLen() int { + return int(C.element_length_in_bytes(el.cptr)) +} + +func (el *Element) Bytes() []byte { + buf := make([]byte, el.BytesLen()) + written := C.element_to_bytes((*C.uchar)(unsafe.Pointer(&buf[0])), el.cptr) + if int64(written) > int64(len(buf)) { + panic(ErrInternal) + } + return buf +} + +func (el *Element) SetBytes(buf []byte) *Element { + C.element_from_bytes(el.cptr, (*C.uchar)(unsafe.Pointer(&buf[0]))) + return el +} + +func (el *Element) XBytesLen() int { + return int(C.element_length_in_bytes_x_only(el.cptr)) +} + +func (el *Element) XBytes() []byte { + buf := make([]byte, el.XBytesLen()) + written := C.element_to_bytes_x_only((*C.uchar)(unsafe.Pointer(&buf[0])), el.cptr) + if int64(written) > int64(len(buf)) { + panic(ErrInternal) + } + return buf +} + +func (el *Element) SetXBytes(buf []byte) *Element { + C.element_from_bytes_x_only(el.cptr, (*C.uchar)(unsafe.Pointer(&buf[0]))) + return el +} + +func (el *Element) CompressedBytesLen() int { + return int(C.element_length_in_bytes_compressed(el.cptr)) +} + +func (el *Element) CompressedBytes() []byte { + buf := make([]byte, el.CompressedBytesLen()) + written := C.element_to_bytes_compressed((*C.uchar)(unsafe.Pointer(&buf[0])), el.cptr) + if int64(written) > int64(len(buf)) { + panic(ErrInternal) + } + return buf +} + +func (el *Element) SetCompressedBytes(buf []byte) *Element { + C.element_from_bytes_compressed(el.cptr, (*C.uchar)(unsafe.Pointer(&buf[0]))) + return el +} diff --git a/element_misc.go b/element_misc.go new file mode 100644 index 0000000000000000000000000000000000000000..2b6fdaec624025c83eba8efd6792e8ce0138d1ad --- /dev/null +++ b/element_misc.go @@ -0,0 +1,67 @@ +package pbc + +/* +#include <pbc/pbc.h> +*/ +import "C" +import "math/big" + +func (el *Element) Pairing() *Pairing { return el.pairing } + +func (el *Element) NewFieldElement() *Element { + newElement := makeUncheckedElement(el.pairing, false, G1) + C.element_init_same_as(newElement.cptr, el.cptr) + if el.checked { + newElement.checked = true + newElement.fieldPtr = el.fieldPtr + newElement.isInteger = el.isInteger + } + return newElement +} + +func (el *Element) Len() int { + return int(C.element_item_count(el.cptr)) +} + +func (el *Element) Item(i int) *Element { + if el.checked && i >= el.Len() { + panic(ErrOutOfRange) + } + newElement := &Element{ + pairing: el.pairing, + cptr: C.element_item(el.cptr, C.int(i)), + } + if el.checked { + newElement.fieldPtr = newElement.cptr.field + newElement.isInteger = (newElement.Len() == 0) + } + return newElement +} + +func (el *Element) X() *big.Int { + return el.Item(0).BigInt() +} + +func (el *Element) Y() *big.Int { + return el.Item(1).BigInt() +} + +func (el *Element) BruteForceDL(g, h *Element) *Element { + if el.checked { + el.checkInteger() + g.ensureChecked() + g.checkCompatible(h) + } + C.element_dlog_brute_force(el.cptr, g.cptr, h.cptr) + return el +} + +func (el *Element) PollardRhoDL(g, h *Element) *Element { + if el.checked { + el.checkInteger() + g.ensureChecked() + g.checkCompatible(h) + } + C.element_dlog_pollard_rho(el.cptr, g.cptr, h.cptr) + return el +} diff --git a/element_unchecked.go b/element_unchecked.go deleted file mode 100644 index 5ab103d03e825d0eaf5f1c7c595faff6d5fe952c..0000000000000000000000000000000000000000 --- a/element_unchecked.go +++ /dev/null @@ -1,386 +0,0 @@ -package pbc - -/* -#include <pbc/pbc.h> -*/ -import "C" - -import ( - "hash" - "math/big" - "runtime" - "unsafe" -) - -type uncheckedElement struct { - pairing *pairingImpl - d *C.struct_element_s -} - -func clearUnchecked(element *uncheckedElement) { - C.element_clear(element.d) -} - -func initUnchecked(element *uncheckedElement, pairing *pairingImpl, initialize bool, field Field) { - element.d = &C.struct_element_s{} - element.pairing = pairing - if initialize { - switch field { - case G1: - C.element_init_G1(element.d, pairing.data) - case G2: - C.element_init_G2(element.d, pairing.data) - case GT: - C.element_init_GT(element.d, pairing.data) - case Zr: - C.element_init_Zr(element.d, pairing.data) - default: - panic(ErrUnknownField) - } - } - runtime.SetFinalizer(element, clearUnchecked) -} - -func makeUnchecked(pairing *pairingImpl, field Field) *uncheckedElement { - element := &uncheckedElement{} - initUnchecked(element, pairing, true, field) - return element -} - -func (el *uncheckedElement) data() *C.struct_element_s { return el.d } - -func (el *uncheckedElement) Pairing() Pairing { return el.pairing } - -func (el *uncheckedElement) NewFieldElement() Element { - newElement := &uncheckedElement{} - initUnchecked(newElement, el.pairing, false, G1) - C.element_init_same_as(newElement.d, el.d) - return newElement -} - -func (el *uncheckedElement) Set0() Element { - C.element_set0(el.d) - return el -} - -func (el *uncheckedElement) Set1() Element { - C.element_set1(el.d) - return el -} - -func (el *uncheckedElement) SetInt32(i int32) Element { - C.element_set_si(el.d, C.long(i)) - return el -} - -func (el *uncheckedElement) SetBig(i *big.Int) Element { - C.element_set_mpz(el.d, &big2mpz(i)[0]) - return el -} - -func (el *uncheckedElement) Set(src Element) Element { - C.element_set(el.d, src.data()) - return el -} - -func (el *uncheckedElement) SetFromHash(hash []byte) Element { - C.element_from_hash(el.d, unsafe.Pointer(&hash[0]), C.int(len(hash))) - return el -} - -func (el *uncheckedElement) SetFromStringHash(s string, h hash.Hash) Element { - h.Reset() - if _, err := h.Write([]byte(s)); err != nil { - panic(ErrHashFailure) - } - return el.SetFromHash(h.Sum([]byte{})) -} - -func (el *uncheckedElement) SetBytes(buf []byte) Element { - C.element_from_bytes(el.d, (*C.uchar)(unsafe.Pointer(&buf[0]))) - return el -} - -func (el *uncheckedElement) SetXBytes(buf []byte) Element { - C.element_from_bytes_x_only(el.d, (*C.uchar)(unsafe.Pointer(&buf[0]))) - return el -} - -func (el *uncheckedElement) SetCompressedBytes(buf []byte) Element { - C.element_from_bytes_compressed(el.d, (*C.uchar)(unsafe.Pointer(&buf[0]))) - return el -} - -func (el *uncheckedElement) SetString(s string, base int) (Element, bool) { - cstr := C.CString(s) - defer C.free(unsafe.Pointer(cstr)) - - if ok := C.element_set_str(el.d, cstr, C.int(base)); ok == 0 { - return nil, false - } - return el, true -} - -func (el *uncheckedElement) BigInt() *big.Int { - mpz := newMpz() - C.element_to_mpz(&mpz[0], el.d) - return mpz2big(mpz) -} - -func (el *uncheckedElement) BytesLen() int { - return int(C.element_length_in_bytes(el.d)) -} - -func (el *uncheckedElement) writeBytes(buf []byte) C.int { - return C.element_to_bytes((*C.uchar)(unsafe.Pointer(&buf[0])), el.d) -} - -func (el *uncheckedElement) Bytes() []byte { - buf := make([]byte, el.BytesLen()) - el.writeBytes(buf) - return buf -} - -func (el *uncheckedElement) XBytesLen() int { - return int(C.element_length_in_bytes_x_only(el.d)) -} - -func (el *uncheckedElement) writeXBytes(buf []byte) C.int { - return C.element_to_bytes_x_only((*C.uchar)(unsafe.Pointer(&buf[0])), el.d) -} - -func (el *uncheckedElement) XBytes() []byte { - buf := make([]byte, el.XBytesLen()) - el.writeXBytes(buf) - return buf -} - -func (el *uncheckedElement) CompressedBytesLen() int { - return int(C.element_length_in_bytes_compressed(el.d)) -} - -func (el *uncheckedElement) writeCompressedBytes(buf []byte) C.int { - return C.element_to_bytes_compressed((*C.uchar)(unsafe.Pointer(&buf[0])), el.d) -} - -func (el *uncheckedElement) CompressedBytes() []byte { - buf := make([]byte, el.CompressedBytesLen()) - el.writeCompressedBytes(buf) - return buf -} - -func (el *uncheckedElement) Len() int { - return int(C.element_item_count(el.d)) -} - -func (el *uncheckedElement) Item(i int) Element { - return &uncheckedElement{ - pairing: el.pairing, - d: C.element_item(el.d, C.int(i)), - } -} - -func (el *uncheckedElement) X() *big.Int { - return el.Item(0).BigInt() -} - -func (el *uncheckedElement) Y() *big.Int { - return el.Item(1).BigInt() -} - -func (el *uncheckedElement) Is0() bool { - return C.element_is0(el.d) != 0 -} - -func (el *uncheckedElement) Is1() bool { - return C.element_is1(el.d) != 0 -} - -func (el *uncheckedElement) IsSquare() bool { - return C.element_is_sqr(el.d) != 0 -} - -func normalizeSign(sign int64) int { - if sign > 0 { - return 1 - } - if sign < 0 { - return -1 - } - return 0 -} - -func (el *uncheckedElement) Sign() int { - return normalizeSign(int64(C.element_sign(el.d))) -} - -func (el *uncheckedElement) Cmp(x Element) int { - return normalizeSign(int64(C.element_cmp(el.d, x.data()))) -} - -func (el *uncheckedElement) Equals(x Element) bool { return el.Cmp(x) == 0 } - -func (el *uncheckedElement) Add(x, y Element) Element { - C.element_add(el.d, x.data(), y.data()) - return el -} - -func (el *uncheckedElement) Sub(x, y Element) Element { - C.element_sub(el.d, x.data(), y.data()) - return el -} - -func (el *uncheckedElement) Mul(x, y Element) Element { - C.element_mul(el.d, x.data(), y.data()) - return el -} - -func (el *uncheckedElement) MulBig(x Element, i *big.Int) Element { - C.element_mul_mpz(el.d, x.data(), &big2mpz(i)[0]) - return el -} - -func (el *uncheckedElement) MulInt32(x Element, i int32) Element { - C.element_mul_si(el.d, x.data(), C.long(i)) - return el -} - -func (el *uncheckedElement) MulZn(x, y Element) Element { - C.element_mul_zn(el.d, x.data(), y.data()) - return el -} - -func (el *uncheckedElement) Div(x, y Element) Element { - C.element_div(el.d, x.data(), y.data()) - return el -} - -func (el *uncheckedElement) Double(x Element) Element { - C.element_double(el.d, x.data()) - return el -} - -func (el *uncheckedElement) Halve(x Element) Element { - C.element_halve(el.d, x.data()) - return el -} - -func (el *uncheckedElement) Square(x Element) Element { - C.element_square(el.d, x.data()) - return el -} - -func (el *uncheckedElement) Neg(x Element) Element { - C.element_neg(el.d, x.data()) - return el -} - -func (el *uncheckedElement) Invert(x Element) Element { - C.element_invert(el.d, x.data()) - return el -} - -func (el *uncheckedElement) PowBig(x Element, i *big.Int) Element { - C.element_pow_mpz(el.d, x.data(), &big2mpz(i)[0]) - return el -} - -func (el *uncheckedElement) PowZn(x, i Element) Element { - C.element_pow_zn(el.d, x.data(), i.data()) - return el -} - -func (el *uncheckedElement) Pow2Big(x Element, i *big.Int, y Element, j *big.Int) Element { - C.element_pow2_mpz(el.d, x.data(), &big2mpz(i)[0], y.data(), &big2mpz(j)[0]) - return el -} - -func (el *uncheckedElement) Pow2Zn(x, i, y, j Element) Element { - C.element_pow2_zn(el.d, x.data(), i.data(), y.data(), j.data()) - return el -} - -func (el *uncheckedElement) Pow3Big(x Element, i *big.Int, y Element, j *big.Int, z Element, k *big.Int) Element { - C.element_pow3_mpz(el.d, x.data(), &big2mpz(i)[0], y.data(), &big2mpz(j)[0], z.data(), &big2mpz(k)[0]) - return el -} - -func (el *uncheckedElement) Pow3Zn(x, i, y, j, z, k Element) Element { - C.element_pow3_zn(el.d, x.data(), i.data(), y.data(), j.data(), z.data(), k.data()) - return el -} - -func (el *uncheckedElement) PreparePower() Power { return initPower(el) } - -func (el *uncheckedElement) PowerBig(power Power, i *big.Int) Element { - C.element_pp_pow(el.d, &big2mpz(i)[0], power.(*powerImpl).data) - return el -} - -func (el *uncheckedElement) PowerZn(power Power, i Element) Element { - C.element_pp_pow_zn(el.d, i.data(), power.(*powerImpl).data) - return el -} - -func (el *uncheckedElement) Pair(x, y Element) Element { - C.pairing_apply(el.d, x.data(), y.data(), el.pairing.data) - return el -} - -func (el *uncheckedElement) 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.d, x, y, C.int(len(in1))) - return el -} - -func (el *uncheckedElement) 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].data() - in2[i] = *elements[j+1].data() - } - return el.doProdPair(in1, in2) -} - -func (el *uncheckedElement) 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].data() - in2[i] = *y[i].data() - } - return el.doProdPair(in1, in2) -} - -func (el *uncheckedElement) PreparePairer() Pairer { return initPairer(el) } - -func (el *uncheckedElement) PairerPair(pairer Pairer, y Element) Element { - C.pairing_pp_apply(el.d, y.data(), pairer.(*pairerImpl).data) - return el -} - -func (el *uncheckedElement) BruteForceDL(g, h Element) Element { - C.element_dlog_brute_force(el.d, g.data(), h.data()) - return el -} - -func (el *uncheckedElement) PollardRhoDL(g, h Element) Element { - C.element_dlog_pollard_rho(el.d, g.data(), h.data()) - return el -} - -func (el *uncheckedElement) Rand() Element { - C.element_random(el.d) - return el -} diff --git a/generation.go b/generation.go index 8de154d7552d660993184287ca8c7928c2a489d4..e35ea3dc51a0546a410225ded97bfa92d1588128 100644 --- a/generation.go +++ b/generation.go @@ -44,9 +44,9 @@ import ( // // For example: // params := pbc.GenerateA(160, 512) -func GenerateA(rbits uint32, qbits uint32) Params { +func GenerateA(rbits uint32, qbits uint32) *Params { params := makeParams() - C.pbc_param_init_a_gen(params.data, C.int(rbits), C.int(qbits)) + C.pbc_param_init_a_gen(params.cptr, C.int(rbits), C.int(qbits)) return params } @@ -55,9 +55,9 @@ func GenerateA(rbits uint32, qbits uint32) Params { // r is the product of two large primes. In this case, r should infeasible to // factor. Each prime should be at least 512 bits (causing r to be 1024 bits in // general), but preferably 1024 bits or more. -func GenerateA1(r *big.Int) Params { +func GenerateA1(r *big.Int) *Params { params := makeParams() - C.pbc_param_init_a1_gen(params.data, &big2mpz(r)[0]) + C.pbc_param_init_a1_gen(params.cptr, &big2mpz(r)[0]) return params } @@ -81,7 +81,7 @@ func GenerateA1(r *big.Int) Params { // // For example: // params, err := pbc.GenerateD(9563, 160, 171, 500) -func GenerateD(d uint32, rbits uint32, qbits uint32, bitlimit uint32) (Params, error) { +func GenerateD(d uint32, rbits uint32, qbits uint32, bitlimit uint32) (*Params, error) { return generateWithCM(true, d, rbits, qbits, bitlimit) } @@ -97,9 +97,9 @@ func GenerateD(d uint32, rbits uint32, qbits uint32, bitlimit uint32) (Params, e // // For example: // params, err := pbc.GenerateE(160, 1024) -func GenerateE(rbits uint32, qbits uint32) Params { +func GenerateE(rbits uint32, qbits uint32) *Params { params := makeParams() - C.pbc_param_init_e_gen(params.data, C.int(rbits), C.int(qbits)) + C.pbc_param_init_e_gen(params.cptr, C.int(rbits), C.int(qbits)) return params } @@ -115,9 +115,9 @@ func GenerateE(rbits uint32, qbits uint32) Params { // // For example: // params, err := pbc.GenerateF(160) -func GenerateF(bits uint32) Params { +func GenerateF(bits uint32) *Params { params := makeParams() - C.pbc_param_init_f_gen(params.data, C.int(bits)) + C.pbc_param_init_f_gen(params.cptr, C.int(bits)) return params } @@ -132,14 +132,14 @@ func GenerateF(bits uint32) Params { // // For example: // params, err := pbc.GenerateG(9563, 160, 171, 500) -func GenerateG(d uint32, rbits uint32, qbits uint32, bitlimit uint32) (Params, error) { +func GenerateG(d uint32, rbits uint32, qbits uint32, bitlimit uint32) (*Params, error) { return generateWithCM(false, d, qbits, rbits, bitlimit) } -func generateWithCM(typeD bool, d uint32, rbits uint32, qbits uint32, bitlimit uint32) (Params, error) { +func generateWithCM(typeD bool, d uint32, rbits uint32, qbits uint32, bitlimit uint32) (*Params, error) { params := makeParams() settings := &C.check_pairing_settings_t{ - params: params.data, + params: params.cptr, rbits: C.uint32_t(rbits), qbits: C.uint32_t(qbits), } diff --git a/pairing.go b/pairing.go index fb45fc6b279cb1a8a22efb182651e3ae6290ce65..e7f532c3d9210fa165a539ef0765f4831e4c0d57 100644 --- a/pairing.go +++ b/pairing.go @@ -29,47 +29,20 @@ const ( // or unchecked. Unchecked elements are slightly faster, but do not check to // ensure that operations make sense. Checked elements defend against a variety // of errors. For more details, see the Element documentation. -type Pairing interface { - // IsSymmetric returns true if G1 == G2 for this pairing. - IsSymmetric() bool - - // Various methods to return the sizes of group elements. - // *Length() returns the length of an element in bytes. - // *XLength() returns the length of an X coordinate only, in bytes. - // *CompressedLength() returns the length of a compressed element in bytes. - G1Length() uint - G1XLength() uint - G1CompressedLength() uint - G2Length() uint - G2XLength() uint - G2CompressedLength() uint - GTLength() uint - ZrLength() uint - - // Initialization methods for group elements. - NewG1() Element - NewG2() Element - NewGT() Element - NewZr() Element - - // Initializes an element without type checking. - NewElement(Field) Element -} - -type pairingImpl struct { - data *C.struct_pairing_s +type Pairing struct { + cptr *C.struct_pairing_s } // NewPairing instantiates a pairing from a set of parameters. -func NewPairing(params Params) Pairing { +func NewPairing(params *Params) *Pairing { pairing := makePairing() - C.pairing_init_pbc_param(pairing.data, params.(*paramsImpl).data) + C.pairing_init_pbc_param(pairing.cptr, params.cptr) return pairing } // NewPairingFromReader loads pairing parameters from a Reader and instantiates // a pairing. -func NewPairingFromReader(params io.Reader) (Pairing, error) { +func NewPairingFromReader(params io.Reader) (*Pairing, error) { buf := new(bytes.Buffer) buf.ReadFrom(params) return NewPairingFromString(buf.String()) @@ -77,7 +50,7 @@ func NewPairingFromReader(params io.Reader) (Pairing, error) { // NewPairingFromString loads pairing parameters from a string and instantiates // a pairing. -func NewPairingFromString(params string) (Pairing, error) { +func NewPairingFromString(params string) (*Pairing, error) { p, err := NewParamsFromString(params) if err != nil { return nil, err @@ -85,54 +58,69 @@ func NewPairingFromString(params string) (Pairing, error) { return NewPairing(p), nil } -func (pairing *pairingImpl) IsSymmetric() bool { - return C.pairing_is_symmetric(pairing.data) != 0 +// IsSymmetric returns true if G1 == G2 for this pairing. +func (pairing *Pairing) IsSymmetric() bool { + return C.pairing_is_symmetric(pairing.cptr) != 0 +} + +func (pairing *Pairing) G1Length() uint { + return uint(C.pairing_length_in_bytes_G1(pairing.cptr)) } -func (pairing *pairingImpl) G1Length() uint { - return uint(C.pairing_length_in_bytes_G1(pairing.data)) +func (pairing *Pairing) G1XLength() uint { + return uint(C.pairing_length_in_bytes_x_only_G1(pairing.cptr)) } -func (pairing *pairingImpl) G1XLength() uint { - return uint(C.pairing_length_in_bytes_x_only_G1(pairing.data)) +func (pairing *Pairing) G1CompressedLength() uint { + return uint(C.pairing_length_in_bytes_compressed_G1(pairing.cptr)) } -func (pairing *pairingImpl) G1CompressedLength() uint { - return uint(C.pairing_length_in_bytes_compressed_G1(pairing.data)) +func (pairing *Pairing) G2Length() uint { + return uint(C.pairing_length_in_bytes_G2(pairing.cptr)) } -func (pairing *pairingImpl) G2Length() uint { - return uint(C.pairing_length_in_bytes_G2(pairing.data)) +func (pairing *Pairing) G2XLength() uint { + return uint(C.pairing_length_in_bytes_x_only_G2(pairing.cptr)) } -func (pairing *pairingImpl) G2XLength() uint { - return uint(C.pairing_length_in_bytes_x_only_G2(pairing.data)) +func (pairing *Pairing) G2CompressedLength() uint { + return uint(C.pairing_length_in_bytes_compressed_G2(pairing.cptr)) } -func (pairing *pairingImpl) G2CompressedLength() uint { - return uint(C.pairing_length_in_bytes_compressed_G2(pairing.data)) +func (pairing *Pairing) GTLength() uint { + return uint(C.pairing_length_in_bytes_GT(pairing.cptr)) } -func (pairing *pairingImpl) GTLength() uint { - return uint(C.pairing_length_in_bytes_GT(pairing.data)) +func (pairing *Pairing) ZrLength() uint { + return uint(C.pairing_length_in_bytes_Zr(pairing.cptr)) } -func (pairing *pairingImpl) ZrLength() uint { - return uint(C.pairing_length_in_bytes_Zr(pairing.data)) +func (pairing *Pairing) NewG1() *Element { + return makeCheckedElement(pairing, G1, pairing.cptr.G1) } -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]) } -func (pairing *pairingImpl) NewZr() Element { return makeChecked(pairing, Zr, &pairing.data.Zr[0]) } -func (pairing *pairingImpl) NewElement(field Field) Element { return makeUnchecked(pairing, field) } +func (pairing *Pairing) NewG2() *Element { + return makeCheckedElement(pairing, G2, pairing.cptr.G2) +} + +func (pairing *Pairing) NewGT() *Element { + return makeCheckedElement(pairing, GT, &pairing.cptr.GT[0]) +} + +func (pairing *Pairing) NewZr() *Element { + return makeCheckedElement(pairing, Zr, &pairing.cptr.Zr[0]) +} + +func (pairing *Pairing) NewElement(field Field) *Element { + return makeUncheckedElement(pairing, true, field) +} -func clearPairing(pairing *pairingImpl) { - C.pairing_clear(pairing.data) +func clearPairing(pairing *Pairing) { + C.pairing_clear(pairing.cptr) } -func makePairing() *pairingImpl { - pairing := &pairingImpl{data: &C.struct_pairing_s{}} +func makePairing() *Pairing { + pairing := &Pairing{cptr: &C.struct_pairing_s{}} runtime.SetFinalizer(pairing, clearPairing) return pairing } diff --git a/params.go b/params.go index 82212a44c39217952a4e2a0254c71ec90fc28ae7..87fb87b1e956fa54d0ac68697eafa43a77d409d3 100644 --- a/params.go +++ b/params.go @@ -25,18 +25,12 @@ import ( // Normally, parameters are generated once using a generation program and then // distributed with the final application. Parameters can be exported for this // purpose using the WriteTo or String methods. -type Params interface { - NewPairing() Pairing - WriteTo(w io.Writer) (n int64, err error) - String() string -} - -type paramsImpl struct { - data *C.struct_pbc_param_s +type Params struct { + cptr *C.struct_pbc_param_s } // NewParams loads pairing parameters from a Reader. -func NewParams(r io.Reader) (Params, error) { +func NewParams(r io.Reader) (*Params, error) { b, err := ioutil.ReadAll(r) if err != nil { return nil, err @@ -45,31 +39,31 @@ func NewParams(r io.Reader) (Params, error) { } // NewParamsFromString loads pairing parameters from a string. -func NewParamsFromString(s string) (Params, error) { +func NewParamsFromString(s string) (*Params, error) { cstr := C.CString(s) defer C.free(unsafe.Pointer(cstr)) params := makeParams() - if ok := C.pbc_param_init_set_str(params.data, cstr); ok != 0 { + if ok := C.pbc_param_init_set_str(params.cptr, cstr); ok != 0 { return nil, ErrInvalidParamString } return params, nil } // NewPairing creates a Pairing using these parameters. -func (params *paramsImpl) NewPairing() Pairing { +func (params *Params) NewPairing() *Pairing { return NewPairing(params) } -func (params *paramsImpl) WriteTo(w io.Writer) (n int64, err error) { +func (params *Params) WriteTo(w io.Writer) (n int64, err error) { count, err := io.WriteString(w, params.String()) return int64(count), err } -func (params *paramsImpl) String() string { +func (params *Params) String() string { var buf *C.char var bufLen C.size_t - if C.param_out_str_wrapper(&buf, &bufLen, params.data) == 0 { + if C.param_out_str_wrapper(&buf, &bufLen, params.cptr) == 0 { return "" } str := C.GoStringN(buf, C.int(bufLen)) @@ -77,12 +71,12 @@ func (params *paramsImpl) String() string { return str } -func clearParams(params *paramsImpl) { - C.pbc_param_clear(params.data) +func clearParams(params *Params) { + C.pbc_param_clear(params.cptr) } -func makeParams() *paramsImpl { - params := ¶msImpl{data: &C.struct_pbc_param_s{}} +func makeParams() *Params { + params := &Params{cptr: &C.struct_pbc_param_s{}} runtime.SetFinalizer(params, clearParams) return params }