diff --git a/doc.go b/doc.go index ef6fe62a8262f08587dbd928757518e83c167d55..a8783a1b9cd1cf3a2fbbb6cb15d7ca538ea85f8e 100644 --- a/doc.go +++ b/doc.go @@ -1 +1,78 @@ -package pbc \ No newline at end of file +/* + Package pbc provides structures for building pairing-based cryptosystems. It + is a wrapper around the Pairing-Based Cryptography (PBC) Library authored by + Ben Lynn (https://crypto.stanford.edu/pbc/). + + This wrapper provides access to all PBC functions. It supports generation of + various types of elliptic curves and pairings, element initialization, I/O, + and arithmetic. These features can be used to quickly build pairing-based or + conventional cryptosystems. + + The PBC library is designed to be extremely fast. Internally, it uses GMP + for arbitrary-precision arithmetic. It also includes a wide variety of + optimizations that make pairing-based cryptography highly efficient. To + improve performance, PBC does not perform type checking to ensure that + operations actually make sense. The Go wrapper provides the ability to add + compatibility checks to most operations, or to use unchecked elements to + maximize performance. + + Since this library provides low-level access to pairing primitives, it is + very easy to construct insecure systems. This library is intended to be used + by cryptographers or to implement well-analyzed cryptosystems. + + Pairings + + Cryptographic pairings are defined over three mathematical groups: G1, G2, + and GT, where each group is typically of the same order r. Additionally, a + bilinear map e maps a pair of elements — one from G1 and another from G2 — + to an element in GT. This map e has the following additional property: + + For some generator g in G1, generator h in G2, and x and y in Zr: + e(gˣ, hʸ) = e(g,h)ˣʸ + + If G1 == G2, then a pairing is said to be symmetric. Otherwise, it is + asymmetric. Pairings can be used to construct a variety of efficient + cryptosystems. + + Supported Pairings + + The PBC library currently supports 5 different types of pairings, each with + configurable parameters. These types are designated alphabetically, roughly + in chronological order of introduction. Type A, D, E, F, and G pairings are + implemented in the library. Each type has different time and space + requirements. For more information about the types, see the documentation + for the corresponding generator calls, or the PBC manual page at + https://crypto.stanford.edu/pbc/manual/ch08s03.html. + + Dependencies + + This package must be compiled using cgo. It also requires the installation + of GMP and PBC. During the build process, this package will attempt to + include <gmp.h> and <pbc/pbc.h>, and then dynamically link to GMP and PBC. + It also expects a POSIX-like environment for several C functions. For this + reason, this package cannot be used in Windows without a POSIX compatibility + layer and a gcc compiler. + + Most systems include a package for GMP. To install GMP in Debian / Ubuntu: + + sudo apt-get install libgmp-dev + + For an RPM installation with YUM: + + sudo yum install gmp + + For installation with FINK (http://www.finkproject.org/) on Mac OS X: + + sudo fink install gmp gmp-shlibs + + For more information or to compile from source, visit https://gmplib.org/ + + To install the PBC library, download the appropriate files for your system + from https://crypto.stanford.edu/pbc/download.html. The source can be + compiled and installed using the usual GNU Build System: + + ./configure + make + make install +*/ +package pbc diff --git a/doc_test.go b/doc_test.go new file mode 100644 index 0000000000000000000000000000000000000000..121f8cd7463dd2f7357cf446dd361b2990444adb --- /dev/null +++ b/doc_test.go @@ -0,0 +1,22 @@ +package pbc + +// 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) + + pairing := params.NewPairing() + + // Initialize group elements. pbc automatically handles garbage collection. + g := pairing.NewG1() + h := pairing.NewG2() + x := pairing.NewGT() + + // Generate random group elements and pair them + g.Rand() + h.Rand() + fmt.Printf("g = %v\nh = %v\n", g, h) + x.Pair(g, h) + fmt.Printf("e(g,h) = %v\n", x) +} diff --git a/element.go b/element.go index 4e02c13f71e23f1787251155c501c476d6d4fbe2..92febd6330cddc7e030fe56328a55364ec925f4f 100644 --- a/element.go +++ b/element.go @@ -13,29 +13,33 @@ import ( ) 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 - SetBytes([]byte) Element - SetXBytes([]byte) Element - SetCompressedBytes([]byte) 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 @@ -43,19 +47,30 @@ type Element interface { 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 @@ -69,6 +84,7 @@ type Element interface { 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 @@ -76,117 +92,73 @@ type Element interface { 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 - impl() *elementImpl -} - -type elementImpl struct { - pairing *pairingImpl - data *C.struct_element_s -} - -type checkedElement struct { - unchecked elementImpl - fieldPtr *C.struct_field_s - isInteger bool -} - -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 makeElement(pairing, field) } + // Pairing returns the pairing associated with this element. + Pairing() Pairing -func clearElement(element *elementImpl) { - println("clearelement") - C.element_clear(element.data) -} - -func initElement(element *elementImpl, pairing *pairingImpl, initialize bool, field Field) { - element.data = &C.struct_element_s{} - element.pairing = pairing - if initialize { - switch field { - case G1: - C.element_init_G1(element.data, pairing.data) - case G2: - C.element_init_G2(element.data, pairing.data) - case GT: - C.element_init_GT(element.data, pairing.data) - case Zr: - C.element_init_Zr(element.data, pairing.data) - default: - panic(ErrUnknownField) - } - } - runtime.SetFinalizer(element, clearElement) -} - -func makeElement(pairing *pairingImpl, field Field) *elementImpl { - element := &elementImpl{} - initElement(element, pairing, true, field) - return element -} - -func makeChecked(pairing *pairingImpl, field Field, fieldPtr *C.struct_field_s) *checkedElement { - element := &checkedElement{ - fieldPtr: fieldPtr, - isInteger: field == Zr, - } - initElement(&element.unchecked, pairing, true, field) - return element + 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(i *big.Int) Element - PowZn(i Element) Element + PowBig(target Element, i *big.Int) Element + PowZn(target Element, i Element) Element } type powerImpl struct { - target Element - data *C.struct_element_pp_s + data *C.struct_element_pp_s } -func (power *powerImpl) PowBig(i *big.Int) Element { - return power.target.PowerBig(power, i) +func (power *powerImpl) PowBig(target Element, i *big.Int) Element { + return target.PowerBig(power, i) } -func (power *powerImpl) PowZn(i Element) Element { - return power.target.PowerZn(power, i) +func (power *powerImpl) PowZn(target Element, i Element) Element { + return target.PowerZn(power, i) } func clearPower(power *powerImpl) { - println("clearpower") C.element_pp_clear(power.data) } -func initPower(target Element) Power { +func initPower(source Element) Power { power := &powerImpl{ - target: target, - data: &C.struct_element_pp_s{}, + data: &C.struct_element_pp_s{}, } - C.element_pp_init(power.data, target.impl().data) + 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, x Element) Element + Pair(target Element, y Element) Element } type pairerImpl struct { @@ -194,12 +166,11 @@ type pairerImpl struct { data *C.struct_pairing_pp_s } -func (pairer *pairerImpl) Pair(target Element, x Element) Element { - return target.PairerPair(pairer, x) +func (pairer *pairerImpl) Pair(target Element, y Element) Element { + return target.PairerPair(pairer, y) } func clearPairer(pairer *pairerImpl) { - println("clearpairer") C.pairing_pp_clear(pairer.data) } @@ -208,7 +179,7 @@ func initPairer(source Element) Pairer { source: source, data: &C.struct_pairing_pp_s{}, } - C.pairing_pp_init(pairer.data, source.impl().data, source.impl().pairing.data) + C.pairing_pp_init(pairer.data, source.data(), source.Pairing().(*pairingImpl).data) runtime.SetFinalizer(pairer, clearPairer) return pairer } diff --git a/element_checked.go b/element_checked.go index e0c915bd541b958e063f32bbee538f2a0d5c7b83..07d200991bebadb079117c682e85b7043d0dd551 100644 --- a/element_checked.go +++ b/element_checked.go @@ -10,7 +10,24 @@ import ( "math/big" ) -func (el *checkedElement) impl() *elementImpl { return &el.unchecked } +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) @@ -46,8 +63,8 @@ func (el *checkedElement) checkInteger() { func (el *checkedElement) NewFieldElement() Element { newElement := &checkedElement{} *newElement = *el - initElement(&newElement.unchecked, el.unchecked.pairing, false, G1) - C.element_init_same_as(newElement.unchecked.data, el.unchecked.data) + initUnchecked(&newElement.unchecked, el.unchecked.pairing, false, G1) + C.element_init_same_as(newElement.unchecked.d, el.unchecked.d) return newElement } @@ -146,9 +163,9 @@ func (el *checkedElement) Item(i int) Element { if i >= el.Len() { panic(ErrOutOfRange) } - uncheckedData := el.unchecked.Item(i).(*elementImpl) + uncheckedData := el.unchecked.Item(i).(*uncheckedElement) item := &checkedElement{ - fieldPtr: uncheckedData.data.field, + fieldPtr: uncheckedData.d.field, isInteger: uncheckedData.Len() == 0, } item.unchecked = *uncheckedData @@ -336,14 +353,14 @@ func (el *checkedElement) ProdPairSlice(x, y []Element) Element { func (el *checkedElement) PreparePairer() Pairer { return initPairer(el) } -func (el *checkedElement) PairerPair(pairer Pairer, x Element) Element { +func (el *checkedElement) PairerPair(pairer Pairer, y Element) Element { in1 := element2Checked(pairer.(*pairerImpl).source) - in2 := element2Checked(x) + 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, x) + el.unchecked.PairerPair(pairer, y) return el } diff --git a/element_fmt.go b/element_fmt.go index 3ed783065dce6d1f411e8696246cae92700e0937..3c528cf5875197048b48689d2ac94541f95d2ac1 100644 --- a/element_fmt.go +++ b/element_fmt.go @@ -20,11 +20,11 @@ import ( "unsafe" ) -func (el *elementImpl) errorFormat(f fmt.State, c rune, err string) { +func (el *uncheckedElement) errorFormat(f fmt.State, c rune, err string) { fmt.Fprintf(f, "%%!%c(%s pbc.Element)", c, err) } -func (el *elementImpl) nativeFormat(f fmt.State, c rune) { +func (el *uncheckedElement) 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 *elementImpl) 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.data) == 0 { + if C.element_out_str_wrapper(&buf, &bufLen, C.int(base), el.d) == 0 { el.errorFormat(f, c, "INTERNALERROR") return } @@ -44,14 +44,14 @@ func (el *elementImpl) nativeFormat(f fmt.State, c rune) { fmt.Fprintf(f, "%s", str) } -func (el *elementImpl) customFormat(f fmt.State, c rune) { +func (el *uncheckedElement) 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).impl().customFormat(f, c) + el.Item(i).(*uncheckedElement).customFormat(f, c) if i+1 < count { fmt.Fprintf(f, ", ") } @@ -60,7 +60,7 @@ func (el *elementImpl) customFormat(f fmt.State, c rune) { } } -func (el *elementImpl) Format(f fmt.State, c rune) { +func (el *uncheckedElement) Format(f fmt.State, c rune) { switch c { case 'v': if f.Flag('#') { @@ -85,13 +85,13 @@ func (el *checkedElement) Format(f fmt.State, c rune) { } } -func (el *elementImpl) String() string { +func (el *uncheckedElement) 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 { +func (el *uncheckedElement) Scan(state fmt.ScanState, verb rune) error { if verb != 's' && verb != 'v' { return ErrBadVerb } diff --git a/element_unchecked.go b/element_unchecked.go index 86757b3e7e864aa8a35081f4181122c146055d1a..5ab103d03e825d0eaf5f1c7c595faff6d5fe952c 100644 --- a/element_unchecked.go +++ b/element_unchecked.go @@ -8,49 +8,87 @@ import "C" import ( "hash" "math/big" + "runtime" "unsafe" ) -func (el *elementImpl) impl() *elementImpl { return el } +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 *elementImpl) NewFieldElement() Element { - newElement := &elementImpl{} - initElement(newElement, el.pairing, false, G1) - C.element_init_same_as(newElement.data, el.data) +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 *elementImpl) Set0() Element { - C.element_set0(el.data) +func (el *uncheckedElement) Set0() Element { + C.element_set0(el.d) return el } -func (el *elementImpl) Set1() Element { - C.element_set1(el.data) +func (el *uncheckedElement) Set1() Element { + C.element_set1(el.d) return el } -func (el *elementImpl) SetInt32(i int32) Element { - C.element_set_si(el.data, C.long(i)) +func (el *uncheckedElement) SetInt32(i int32) Element { + C.element_set_si(el.d, C.long(i)) return el } -func (el *elementImpl) SetBig(i *big.Int) Element { - C.element_set_mpz(el.data, &big2mpz(i)[0]) +func (el *uncheckedElement) SetBig(i *big.Int) Element { + C.element_set_mpz(el.d, &big2mpz(i)[0]) return el } -func (el *elementImpl) Set(src Element) Element { - C.element_set(el.data, src.impl().data) +func (el *uncheckedElement) Set(src Element) Element { + C.element_set(el.d, src.data()) return el } -func (el *elementImpl) SetFromHash(hash []byte) Element { - C.element_from_hash(el.data, unsafe.Pointer(&hash[0]), C.int(len(hash))) +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 *elementImpl) SetFromStringHash(s string, h hash.Hash) Element { +func (el *uncheckedElement) SetFromStringHash(s string, h hash.Hash) Element { h.Reset() if _, err := h.Write([]byte(s)); err != nil { panic(ErrHashFailure) @@ -58,108 +96,108 @@ func (el *elementImpl) SetFromStringHash(s string, h hash.Hash) Element { return el.SetFromHash(h.Sum([]byte{})) } -func (el *elementImpl) SetBytes(buf []byte) Element { - C.element_from_bytes(el.data, (*C.uchar)(unsafe.Pointer(&buf[0]))) +func (el *uncheckedElement) SetBytes(buf []byte) Element { + C.element_from_bytes(el.d, (*C.uchar)(unsafe.Pointer(&buf[0]))) return el } -func (el *elementImpl) SetXBytes(buf []byte) Element { - C.element_from_bytes_x_only(el.data, (*C.uchar)(unsafe.Pointer(&buf[0]))) +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 *elementImpl) SetCompressedBytes(buf []byte) Element { - C.element_from_bytes_compressed(el.data, (*C.uchar)(unsafe.Pointer(&buf[0]))) +func (el *uncheckedElement) SetCompressedBytes(buf []byte) Element { + C.element_from_bytes_compressed(el.d, (*C.uchar)(unsafe.Pointer(&buf[0]))) return el } -func (el *elementImpl) SetString(s string, base int) (Element, bool) { +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.data, cstr, C.int(base)); ok == 0 { + if ok := C.element_set_str(el.d, cstr, C.int(base)); ok == 0 { return nil, false } return el, true } -func (el *elementImpl) BigInt() *big.Int { +func (el *uncheckedElement) BigInt() *big.Int { mpz := newMpz() - C.element_to_mpz(&mpz[0], el.data) + C.element_to_mpz(&mpz[0], el.d) return mpz2big(mpz) } -func (el *elementImpl) BytesLen() int { - return int(C.element_length_in_bytes(el.data)) +func (el *uncheckedElement) BytesLen() int { + return int(C.element_length_in_bytes(el.d)) } -func (el *elementImpl) writeBytes(buf []byte) C.int { - return C.element_to_bytes((*C.uchar)(unsafe.Pointer(&buf[0])), el.data) +func (el *uncheckedElement) writeBytes(buf []byte) C.int { + return C.element_to_bytes((*C.uchar)(unsafe.Pointer(&buf[0])), el.d) } -func (el *elementImpl) Bytes() []byte { +func (el *uncheckedElement) Bytes() []byte { buf := make([]byte, el.BytesLen()) el.writeBytes(buf) return buf } -func (el *elementImpl) XBytesLen() int { - return int(C.element_length_in_bytes_x_only(el.data)) +func (el *uncheckedElement) XBytesLen() int { + return int(C.element_length_in_bytes_x_only(el.d)) } -func (el *elementImpl) writeXBytes(buf []byte) C.int { - return C.element_to_bytes_x_only((*C.uchar)(unsafe.Pointer(&buf[0])), el.data) +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 *elementImpl) XBytes() []byte { +func (el *uncheckedElement) XBytes() []byte { buf := make([]byte, el.XBytesLen()) el.writeXBytes(buf) return buf } -func (el *elementImpl) CompressedBytesLen() int { - return int(C.element_length_in_bytes_compressed(el.data)) +func (el *uncheckedElement) CompressedBytesLen() int { + return int(C.element_length_in_bytes_compressed(el.d)) } -func (el *elementImpl) writeCompressedBytes(buf []byte) C.int { - return C.element_to_bytes_compressed((*C.uchar)(unsafe.Pointer(&buf[0])), el.data) +func (el *uncheckedElement) writeCompressedBytes(buf []byte) C.int { + return C.element_to_bytes_compressed((*C.uchar)(unsafe.Pointer(&buf[0])), el.d) } -func (el *elementImpl) CompressedBytes() []byte { +func (el *uncheckedElement) CompressedBytes() []byte { buf := make([]byte, el.CompressedBytesLen()) el.writeCompressedBytes(buf) return buf } -func (el *elementImpl) Len() int { - return int(C.element_item_count(el.data)) +func (el *uncheckedElement) Len() int { + return int(C.element_item_count(el.d)) } -func (el *elementImpl) Item(i int) Element { - return &elementImpl{ +func (el *uncheckedElement) Item(i int) Element { + return &uncheckedElement{ pairing: el.pairing, - data: C.element_item(el.data, C.int(i)), + d: C.element_item(el.d, C.int(i)), } } -func (el *elementImpl) X() *big.Int { +func (el *uncheckedElement) X() *big.Int { return el.Item(0).BigInt() } -func (el *elementImpl) Y() *big.Int { +func (el *uncheckedElement) Y() *big.Int { return el.Item(1).BigInt() } -func (el *elementImpl) Is0() bool { - return C.element_is0(el.data) != 0 +func (el *uncheckedElement) Is0() bool { + return C.element_is0(el.d) != 0 } -func (el *elementImpl) Is1() bool { - return C.element_is1(el.data) != 0 +func (el *uncheckedElement) Is1() bool { + return C.element_is1(el.d) != 0 } -func (el *elementImpl) IsSquare() bool { - return C.element_is_sqr(el.data) != 0 +func (el *uncheckedElement) IsSquare() bool { + return C.element_is_sqr(el.d) != 0 } func normalizeSign(sign int64) int { @@ -172,131 +210,131 @@ func normalizeSign(sign int64) int { return 0 } -func (el *elementImpl) Sign() int { - return normalizeSign(int64(C.element_sign(el.data))) +func (el *uncheckedElement) Sign() int { + return normalizeSign(int64(C.element_sign(el.d))) } -func (el *elementImpl) Cmp(x Element) int { - return normalizeSign(int64(C.element_cmp(el.data, x.impl().data))) +func (el *uncheckedElement) Cmp(x Element) int { + return normalizeSign(int64(C.element_cmp(el.d, x.data()))) } -func (el *elementImpl) Equals(x Element) bool { return el.Cmp(x) == 0 } +func (el *uncheckedElement) Equals(x Element) bool { return el.Cmp(x) == 0 } -func (el *elementImpl) Add(x, y Element) Element { - C.element_add(el.data, x.impl().data, y.impl().data) +func (el *uncheckedElement) Add(x, y Element) Element { + C.element_add(el.d, x.data(), y.data()) return el } -func (el *elementImpl) Sub(x, y Element) Element { - C.element_sub(el.data, x.impl().data, y.impl().data) +func (el *uncheckedElement) Sub(x, y Element) Element { + C.element_sub(el.d, x.data(), y.data()) return el } -func (el *elementImpl) Mul(x, y Element) Element { - C.element_mul(el.data, x.impl().data, y.impl().data) +func (el *uncheckedElement) Mul(x, y Element) Element { + C.element_mul(el.d, x.data(), y.data()) return el } -func (el *elementImpl) MulBig(x Element, i *big.Int) Element { - C.element_mul_mpz(el.data, x.impl().data, &big2mpz(i)[0]) +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 *elementImpl) MulInt32(x Element, i int32) Element { - C.element_mul_si(el.data, x.impl().data, C.long(i)) +func (el *uncheckedElement) MulInt32(x Element, i int32) Element { + C.element_mul_si(el.d, x.data(), C.long(i)) return el } -func (el *elementImpl) MulZn(x, y Element) Element { - C.element_mul_zn(el.data, x.impl().data, y.impl().data) +func (el *uncheckedElement) MulZn(x, y Element) Element { + C.element_mul_zn(el.d, x.data(), y.data()) return el } -func (el *elementImpl) Div(x, y Element) Element { - C.element_div(el.data, x.impl().data, y.impl().data) +func (el *uncheckedElement) Div(x, y Element) Element { + C.element_div(el.d, x.data(), y.data()) return el } -func (el *elementImpl) Double(x Element) Element { - C.element_double(el.data, x.impl().data) +func (el *uncheckedElement) Double(x Element) Element { + C.element_double(el.d, x.data()) return el } -func (el *elementImpl) Halve(x Element) Element { - C.element_halve(el.data, x.impl().data) +func (el *uncheckedElement) Halve(x Element) Element { + C.element_halve(el.d, x.data()) return el } -func (el *elementImpl) Square(x Element) Element { - C.element_square(el.data, x.impl().data) +func (el *uncheckedElement) Square(x Element) Element { + C.element_square(el.d, x.data()) return el } -func (el *elementImpl) Neg(x Element) Element { - C.element_neg(el.data, x.impl().data) +func (el *uncheckedElement) Neg(x Element) Element { + C.element_neg(el.d, x.data()) return el } -func (el *elementImpl) Invert(x Element) Element { - C.element_invert(el.data, x.impl().data) +func (el *uncheckedElement) Invert(x Element) Element { + C.element_invert(el.d, x.data()) return el } -func (el *elementImpl) PowBig(x Element, i *big.Int) Element { - C.element_pow_mpz(el.data, x.impl().data, &big2mpz(i)[0]) +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 *elementImpl) PowZn(x, i Element) Element { - C.element_pow_zn(el.data, x.impl().data, i.impl().data) +func (el *uncheckedElement) PowZn(x, i Element) Element { + C.element_pow_zn(el.d, x.data(), i.data()) return el } -func (el *elementImpl) Pow2Big(x Element, i *big.Int, y Element, j *big.Int) Element { - C.element_pow2_mpz(el.data, x.impl().data, &big2mpz(i)[0], y.impl().data, &big2mpz(j)[0]) +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 *elementImpl) Pow2Zn(x, i, y, j Element) Element { - C.element_pow2_zn(el.data, x.impl().data, i.impl().data, y.impl().data, j.impl().data) +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 *elementImpl) Pow3Big(x Element, i *big.Int, y Element, j *big.Int, z Element, k *big.Int) Element { - C.element_pow3_mpz(el.data, x.impl().data, &big2mpz(i)[0], y.impl().data, &big2mpz(j)[0], z.impl().data, &big2mpz(k)[0]) +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 *elementImpl) Pow3Zn(x, i, y, j, z, k Element) Element { - C.element_pow3_zn(el.data, x.impl().data, i.impl().data, y.impl().data, j.impl().data, z.impl().data, k.impl().data) +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 *elementImpl) PreparePower() Power { return initPower(el) } +func (el *uncheckedElement) 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) +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 *elementImpl) PowerZn(power Power, i Element) Element { - C.element_pp_pow_zn(el.data, i.impl().data, power.(*powerImpl).data) +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 *elementImpl) Pair(x, y Element) Element { - C.pairing_apply(el.data, x.impl().data, y.impl().data, el.pairing.data) +func (el *uncheckedElement) Pair(x, y Element) Element { + C.pairing_apply(el.d, x.data(), y.data(), el.pairing.data) return el } -func (el *elementImpl) doProdPair(in1, in2 []C.struct_element_s) Element { +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.data, x, y, C.int(len(in1))) + C.element_prod_pairing(el.d, x, y, C.int(len(in1))) return el } -func (el *elementImpl) ProdPair(elements ...Element) Element { +func (el *uncheckedElement) ProdPair(elements ...Element) Element { n := len(elements) if n%2 != 0 { panic(ErrBadPairList) @@ -305,13 +343,13 @@ func (el *elementImpl) ProdPair(elements ...Element) Element { 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 + in1[i] = *elements[j].data() + in2[i] = *elements[j+1].data() } return el.doProdPair(in1, in2) } -func (el *elementImpl) ProdPairSlice(x, y []Element) Element { +func (el *uncheckedElement) ProdPairSlice(x, y []Element) Element { n := len(x) if n != len(y) { panic(ErrBadPairList) @@ -319,30 +357,30 @@ func (el *elementImpl) ProdPairSlice(x, y []Element) Element { 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 + in1[i] = *x[i].data() + in2[i] = *y[i].data() } return el.doProdPair(in1, in2) } -func (el *elementImpl) PreparePairer() Pairer { return initPairer(el) } +func (el *uncheckedElement) 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) +func (el *uncheckedElement) PairerPair(pairer Pairer, y Element) Element { + C.pairing_pp_apply(el.d, y.data(), pairer.(*pairerImpl).data) return el } -func (el *elementImpl) BruteForceDL(g, h Element) Element { - C.element_dlog_brute_force(el.data, g.impl().data, h.impl().data) +func (el *uncheckedElement) BruteForceDL(g, h Element) Element { + C.element_dlog_brute_force(el.d, g.data(), h.data()) return el } -func (el *elementImpl) PollardRhoDL(g, h Element) Element { - C.element_dlog_pollard_rho(el.data, g.impl().data, h.impl().data) +func (el *uncheckedElement) PollardRhoDL(g, h Element) Element { + C.element_dlog_pollard_rho(el.d, g.data(), h.data()) return el } -func (el *elementImpl) Rand() Element { - C.element_random(el.data) +func (el *uncheckedElement) Rand() Element { + C.element_random(el.d) return el } diff --git a/errors.go b/errors.go index 8ad9ad44216d52733b38f5fd00ba51c6114313ad..5dcb89367a4b26034e9a2b46f94aa3ae3c7c3101 100644 --- a/errors.go +++ b/errors.go @@ -4,6 +4,7 @@ import "errors" var ( ErrInvalidParamString = errors.New("invalid pairing parameters") + ErrNoSuitableCurves = errors.New("no suitable curves were found") ErrUnknownField = errors.New("unchecked element initialized in unknown field") ErrIllegalOp = errors.New("operation is illegal for elements of this type") ErrUncheckedOp = errors.New("unchecked element passed to checked operation") diff --git a/generation.go b/generation.go index b3b33a6cf5b600d1c4057692061504917c66c71d..8de154d7552d660993184287ca8c7928c2a489d4 100644 --- a/generation.go +++ b/generation.go @@ -1,15 +1,28 @@ package pbc /* +#include <stdint.h> #include <pbc/pbc.h> -int acceptPairingD(pbc_cm_t cm, void* p) { - pbc_param_init_d_gen((pbc_param_ptr)p, cm); - return 1; -} +typedef struct { + int typeD; + pbc_param_ptr params; + uint32_t rbits; + uint32_t qbits; +} check_pairing_settings_t; + +int checkPairing(pbc_cm_t cm, void* p) { + check_pairing_settings_t* settings = (check_pairing_settings_t*)p; -int acceptPairingG(pbc_cm_t cm, void* p) { - pbc_param_init_g_gen((pbc_param_ptr)p, cm); + unsigned int rbits = (unsigned int)mpz_sizeinbase(cm->r, 2); + unsigned int qbits = (unsigned int)mpz_sizeinbase(cm->q, 2); + if (rbits < settings->rbits || qbits < settings->qbits) return 0; + + if (settings->typeD) { + pbc_param_init_d_gen(settings->params, cm); + } else { + pbc_param_init_g_gen(settings->params, cm); + } return 1; } */ @@ -20,38 +33,122 @@ import ( "unsafe" ) +// GenerateA generates a pairing on the curve y^2 = x^3 + x over the field F_q +// for some prime q = 3 mod 4. Type A pairings are symmetric (i.e., G1 == G2). +// Type A pairings are best used when speed of computation is the primary +// concern. +// +// To be secure, generic discrete log algorithms must be infeasible in groups of +// order r, and finite field discrete log algorithms must be infeasible in +// groups of order q^2. +// +// For example: +// params := pbc.GenerateA(160, 512) func GenerateA(rbits uint32, qbits uint32) Params { params := makeParams() C.pbc_param_init_a_gen(params.data, C.int(rbits), C.int(qbits)) return params } -func GenerateA1(n *big.Int) Params { +// GenerateA1 generates a type A pairing given a fixed order for G1, G2, and GT. +// This form of pairing can be used to produce groups of composite order, where +// 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 { params := makeParams() - C.pbc_param_init_a1_gen(params.data, &big2mpz(n)[0]) + C.pbc_param_init_a1_gen(params.data, &big2mpz(r)[0]) return params } -func GenerateD(d uint32, bitlimit uint32) Params { - params := makeParams() - C.pbc_cm_search_d((*[0]byte)(C.acceptPairingD), unsafe.Pointer(params.data), C.uint(d), C.uint(bitlimit)) - return params +// GenerateD generates a pairing on a curve with embedding degree 6 whose order +// is h * r where r is prime and h is a small constant. Type D pairings are +// asymmetric, but have small group elements. This makes them well-suited for +// applications where message size is the primary concern, but speed is also +// important. +// +// Parameters are generated using the constant multiplication (CM) method for a +// given fundamental discriminant D. It is required that D > 0, no square of an +// odd prime divides D, and D = 0 or 3 mod 4. The bitlimit parameter sets a cap +// on the number of bits in the group order. It is possible that for some values +// of D, no suitable curves can be found. In this case, GenerateD returns nil +// and ErrNoSuitableCurves. +// +// The rbits and qbits parameters sit minimum sizes for group orders. To be +// secure, generic discrete log algorithms must be infeasible in groups of order +// r, and finite field discrete log algorithms must be infeasible in groups of +// order q^6. +// +// For example: +// params, err := pbc.GenerateD(9563, 160, 171, 500) +func GenerateD(d uint32, rbits uint32, qbits uint32, bitlimit uint32) (Params, error) { + return generateWithCM(true, d, rbits, qbits, bitlimit) } +// GenerateE generates a pairing entirely within a order r subgroup of an order +// q field. These pairings are symmetric, but serve little purpose beyond being +// mathematically interesting. Use of these pairings is not recommended unless +// new algorithms are discovered for solving discrete logs in elliptic curves as +// easily as for finite fields. +// +// For security, generic discrete log algorithms must be infeasible in groups of +// order r, and finite field discrete log algorithms must be infeasible in +// finite fields of order q. +// +// For example: +// params, err := pbc.GenerateE(160, 1024) func GenerateE(rbits uint32, qbits uint32) Params { params := makeParams() C.pbc_param_init_e_gen(params.data, C.int(rbits), C.int(qbits)) return params } +// GenerateF generates an asymmetric pairing with extremely small group +// elements. This is the best pairing to use when space is an overriding +// priority. However, type F pairings are slow compared to the other types. Type +// D pairings provide a more balanced alternative. +// +// The bits parameter specifies the approximate number of bits in the group +// order, r, and the order of the base field, q. For security, generic discrete +// log algorithms must be infeasible in groups of order r, and finite field +// discrete log algorithms must be infeasible in finite fields of order q^12. +// +// For example: +// params, err := pbc.GenerateF(160) func GenerateF(bits uint32) Params { params := makeParams() C.pbc_param_init_f_gen(params.data, C.int(bits)) return params } -func GenerateG(d uint32, bitlimit uint32) Params { +// GenerateG generates a pairing on a curve with embedding degree 10 whose order +// is h * r where r is prime and h is a small constant. Type G pairings are +// asymmetric, but have extremely small group elements. However, these pairings +// are even slower than type F pairings, making type F a better choice. +// +// Like type D pairings, parameters are generated using the constant +// multiplication (CM) method. See the GenerateD function for a description of +// the parameters. +// +// For example: +// params, err := pbc.GenerateG(9563, 160, 171, 500) +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) { params := makeParams() - C.pbc_cm_search_d((*[0]byte)(C.acceptPairingG), unsafe.Pointer(params.data), C.uint(d), C.uint(bitlimit)) - return params + settings := &C.check_pairing_settings_t{ + params: params.data, + rbits: C.uint32_t(rbits), + qbits: C.uint32_t(qbits), + } + if typeD { + settings.typeD = C.int(1) + } + res := C.pbc_cm_search_d((*[0]byte)(C.checkPairing), unsafe.Pointer(settings), C.uint(d), C.uint(bitlimit)) + if res != 1 { + return nil, ErrNoSuitableCurves + } + return params, nil } diff --git a/gmp_big.go b/gmp_big.go index 0668c77304693e4359f7d53c3424cc0a8e9b0dd2..11f5acb036a0f03e405640f42227d904f32697ea 100644 --- a/gmp_big.go +++ b/gmp_big.go @@ -15,7 +15,6 @@ var wordSize C.size_t var bitsPerWord C.size_t func clearMpz(x *C.mpz_t) { - println("clearmpz") C.mpz_clear(&x[0]) } @@ -26,6 +25,7 @@ func newMpz() *C.mpz_t { return out } +// big2thisMpz imports the value of num into out func big2thisMpz(num *big.Int, out *C.mpz_t) { words := num.Bits() if len(words) > 0 { @@ -33,12 +33,14 @@ func big2thisMpz(num *big.Int, out *C.mpz_t) { } } +// big2mpz allocates a new mpz_t and imports a big.Int value func big2mpz(num *big.Int) *C.mpz_t { out := newMpz() big2thisMpz(num, out) return out } +// mpz2thisBig imports the value of num into out func mpz2thisBig(num *C.mpz_t, out *big.Int) { wordsNeeded := (C.mpz_sizeinbase(&num[0], 2) + (bitsPerWord - 1)) / bitsPerWord words := make([]big.Word, wordsNeeded) @@ -47,6 +49,7 @@ func mpz2thisBig(num *C.mpz_t, out *big.Int) { out.SetBits(words) } +// mpz2big allocates a new big.Int and imports an mpz_t value func mpz2big(num *C.mpz_t) (out *big.Int) { out = &big.Int{} mpz2thisBig(num, out) diff --git a/pairing.go b/pairing.go index 0687a1ca305968f5460828e54dc2e2f6b49fc037..fb45fc6b279cb1a8a22efb182651e3ae6290ce65 100644 --- a/pairing.go +++ b/pairing.go @@ -11,6 +11,9 @@ import ( "runtime" ) +// Field denotes the various possible algebraic structures associated with a +// pairing. G1, G2, and GT are the groups involved in the pairing operation. Zr +// is the field of integers with order r, where r is the order of the groups. type Field int const ( @@ -20,9 +23,20 @@ const ( Zr Field = iota ) +// Pairing represents a pairing and its associated groups. The primary use of a +// pairing object is the initialization of group elements. Elements can be +// created in G1, G2, GT, or Zr. Additionally, elements can either be checked +// 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 @@ -32,10 +46,13 @@ type Pairing interface { 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 } @@ -43,24 +60,29 @@ type pairingImpl struct { data *C.struct_pairing_s } -func NewPairing(params io.Reader) (Pairing, error) { +// NewPairing instantiates a pairing from a set of parameters. +func NewPairing(params Params) Pairing { + pairing := makePairing() + C.pairing_init_pbc_param(pairing.data, params.(*paramsImpl).data) + return pairing +} + +// NewPairingFromReader loads pairing parameters from a Reader and instantiates +// a pairing. +func NewPairingFromReader(params io.Reader) (Pairing, error) { buf := new(bytes.Buffer) buf.ReadFrom(params) return NewPairingFromString(buf.String()) } +// NewPairingFromString loads pairing parameters from a string and instantiates +// a pairing. func NewPairingFromString(params string) (Pairing, error) { p, err := NewParamsFromString(params) if err != nil { return nil, err } - return NewPairingFromParams(p), nil -} - -func NewPairingFromParams(params Params) Pairing { - pairing := makePairing() - C.pairing_init_pbc_param(pairing.data, params.(*paramsImpl).data) - return pairing + return NewPairing(p), nil } func (pairing *pairingImpl) IsSymmetric() bool { @@ -99,8 +121,13 @@ func (pairing *pairingImpl) ZrLength() uint { return uint(C.pairing_length_in_bytes_Zr(pairing.data)) } +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 clearPairing(pairing *pairingImpl) { - println("clearpairing") C.pairing_clear(pairing.data) } diff --git a/params.go b/params.go index 5813f81e154a404c3a182178f7860e0885a00ed2..82212a44c39217952a4e2a0254c71ec90fc28ae7 100644 --- a/params.go +++ b/params.go @@ -15,10 +15,16 @@ import "C" import ( "io" + "io/ioutil" "runtime" "unsafe" ) +// Params represents the parameters required for creating a pairing. Parameters +// cn be generated using the generation functions or read from a Reader. +// 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) @@ -29,6 +35,16 @@ type paramsImpl struct { data *C.struct_pbc_param_s } +// NewParams loads pairing parameters from a Reader. +func NewParams(r io.Reader) (Params, error) { + b, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + return NewParamsFromString(string(b)) +} + +// NewParamsFromString loads pairing parameters from a string. func NewParamsFromString(s string) (Params, error) { cstr := C.CString(s) defer C.free(unsafe.Pointer(cstr)) @@ -40,8 +56,9 @@ func NewParamsFromString(s string) (Params, error) { return params, nil } +// NewPairing creates a Pairing using these parameters. func (params *paramsImpl) NewPairing() Pairing { - return NewPairingFromParams(params) + return NewPairing(params) } func (params *paramsImpl) WriteTo(w io.Writer) (n int64, err error) { @@ -61,7 +78,6 @@ func (params *paramsImpl) String() string { } func clearParams(params *paramsImpl) { - println("clearparams") C.pbc_param_clear(params.data) } diff --git a/utils.go b/utils.go index 656a5e17bfab9f68b812223c8a433a69597b6ceb..b990cea77f71361897951255d2cfa409d5214b89 100644 --- a/utils.go +++ b/utils.go @@ -18,8 +18,11 @@ import ( var logging bool +// Logging returns true if PBC will send status messages to stderr. func Logging() bool { return logging } +// SetLogging enables or disables sending PBC status messages to stderr. +// Messages are hidden by default. func SetLogging(log bool) { logging = log if log { @@ -29,14 +32,23 @@ func SetLogging(log bool) { } } +// RandomSource generates random numbers for consumption by PBC. Rand returns a +// random integer in [0,limit). type RandomSource interface { Rand(limit *big.Int) *big.Int } var randomProvider RandomSource +// RandomProvider returns the current random number source for use by PBC. func RandomProvider() RandomSource { return randomProvider } +// SetRandomProvider sets the random number source for use by PBC. If provider +// is nil, then PBC will use its internal random number generator, which is the +// default mode. If provider is non-nil, then requests for random numbers will +// be serviced by Go instead of the internal C functions. This is slower, but +// provides greater control. Several convenience functions are provided to set +// common sources of random numbers. func SetRandomProvider(provider RandomSource) { randomProvider = provider if provider == nil { @@ -76,8 +88,12 @@ func (provider randProvider) Rand(limit *big.Int) (result *big.Int) { return } +// SetCryptoRandom causes PBC to use the crypto/rand package with the globally +// shared rand.Reader as the source of random numbers. func SetCryptoRandom() { SetReaderRandom(cryptorand.Reader) } +// SetReaderRandom causes PBC to use the crypto/rand package to generate random +// numbers using the given reader as an entropy source. func SetReaderRandom(reader io.Reader) { if reader == nil { panic(ErrIllegalNil) @@ -85,8 +101,14 @@ func SetReaderRandom(reader io.Reader) { SetRandomProvider(&readerProvider{reader}) } +// SetRandRandom causes PBC to use the given source of random numbers. func SetRandRandom(rand *rand.Rand) { SetRandomProvider(&randProvider{rand}) } +// SetDefaultRandom causes PBC to use its internal source of random numbers. +// This is the default mode of operation. Internally, PBC will attempt to read +// from /dev/urandom if it exists, or from the Microsoft Crypto API on Windows. +// If neither of these sources is available, the library will fall back to an +// insecure PRNG. func SetDefaultRandom() { SetRandomProvider(nil) } func init() {