diff --git a/doc.go b/doc.go index a8783a1b9cd1cf3a2fbbb6cb15d7ca538ea85f8e..f6b74274511b76a82e6a483fda26b257d4d67a9f 100644 --- a/doc.go +++ b/doc.go @@ -61,7 +61,7 @@ sudo yum install gmp - For installation with FINK (http://www.finkproject.org/) on Mac OS X: + For installation with Fink (http://www.finkproject.org/) on Mac OS X: sudo fink install gmp gmp-shlibs diff --git a/element.go b/element.go index c20e9ffb5575f9e62074a6f77cabd1b902824b83..5408cd9c227976eda11953071b79224f68b61e4b 100644 --- a/element.go +++ b/element.go @@ -4,8 +4,65 @@ package pbc #include <pbc/pbc.h> */ import "C" + import "runtime" +// Element represents an element in one of the algebraic structures associated +// with a pairing. Arithmetic operations can be performed on elements to +// complete computations. Elements can also be paired using the associated +// pairing's bilinear map. Elements can be exported or imported in a variety of +// formats. +// +// The arithmetic methods for Elements generally follow the style of big.Int. A +// typical operation has a signature like this: +// +// func (el *Element) Add(x, y *Element) *Element +// +// This method stores x + y in el and returns el. Since these arithmetic +// operations return the targets, they can be used in method chaining: +// +// x.Add(a, b).Mul(x, c).Square(x) +// +// This assigns x = ((a+b)*c)^2. +// +// Whenever possible, the methods defined on Element use the same names as +// those in the math/big package. +// +// The addition and multiplication functions perform addition and +// multiplication operations in rings and fields. For groups of points on an +// elliptic curve, such as the G1 and G2 groups associated with pairings, both +// addition and multiplication represent the group operation (and similarly +// both 0 and 1 represent the identity element). It is recommended that +// programs choose one convention and stick with it to avoid confusion. +// +// Not all operations are valid for all elements. For example, pairing +// operations require an element from G1, and element from G2, and a target +// from GT. As another example, elements in a ring cannot be inverted in +// general. +// +// The PBC library does not attempt to detect invalid element operations. If an +// invalid operation is performed, several outcomes are possible. In the best +// case, the operation will be treated as a no-op. The target element might +// be set to a nonsensical value. In the worst case, the program may segfault. +// +// The pbc wrapper provides some protection against invalid operations. When +// elements are initialized by a Pairing, they can either be created as checked +// or unchecked. Unchecked elements do not perform any sanity checks; calls are +// passed directly to the C library, with the possible consequences mentioned +// above. Checked elements attempt to catch a variety of errors, such as when +// elements from mismatched algebraic structures or pairings. If an error is +// detected, the operation will panic with ErrIllegalOp, ErrUncheckedOp, +// ErrIncompatible, or a similar error. +// +// The decision on whether or not to check operations is based solely on +// whether or not the target element is checked. Thus, if an unchecked element +// is passed a checked element as part of an operation, the operation will not +// be checked. Checked elements expect that all arguments to their methods are +// also checked, and will panic with ErrUncheckedOp if not. +// +// Note that not all possible errors can be detected by checked elements; +// ultimately, it is the responsibility of the caller to ensure that the +// requested computations make sense. type Element struct { pairing *Pairing // Prevents garbage collection cptr *C.struct_element_s @@ -47,6 +104,7 @@ func makeCheckedElement(pairing *Pairing, field Field, fieldPtr *C.struct_field_ element.checked = true element.fieldPtr = fieldPtr element.isInteger = (field == Zr) + element.Set0() return element } @@ -79,3 +137,10 @@ func (el *Element) checkInteger() { panic(ErrIllegalOp) } } + +func (el *Element) checkPoint() { + el.ensureChecked() + if el.isInteger { + panic(ErrIllegalOp) + } +} diff --git a/element_arith.go b/element_arith.go index b2420175ddb28b7a24b7bc72ffe473f2c594c0b8..210e593a17f552172079bec12e6eb32413984b15 100644 --- a/element_arith.go +++ b/element_arith.go @@ -4,62 +4,79 @@ package pbc #include <pbc/pbc.h> */ import "C" + import ( "math/big" "runtime" "unsafe" ) +// Set0 sets el to zero and returns el. For curves, this sets the element to +// the infinite point (identity element). func (el *Element) Set0() *Element { C.element_set0(el.cptr) return el } +// Set1 sets el to one and returns el. For curves, this sets the element to the +// infinite point (identity element). func (el *Element) Set1() *Element { C.element_set1(el.cptr) return el } +// Rand sets el to a random value and returns el. For algebraic structures +// where this does not make sense, this is equivalent to Set0. 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 { +// Equals returns true if el == x. +// +// Requirements: +// el and x must be from the same algebraic structure. +func (el *Element) Equals(x *Element) bool { if el.checked { el.checkCompatible(x) } - return normalizeSign(int64(C.element_cmp(el.cptr, x.cptr))) + return int64(C.element_cmp(el.cptr, x.cptr)) == 0 } -func (el *Element) Equals(x *Element) bool { return el.Cmp(x) == 0 } - +// Is0 returns true if el is zero (or the identity element for curves). func (el *Element) Is0() bool { return C.element_is0(el.cptr) != 0 } +// Is1 returns true if el is one (or the identity element for curves). func (el *Element) Is1() bool { return C.element_is1(el.cptr) != 0 } +// IsSquare returns true if el is a perfect square (quadratic residue). func (el *Element) IsSquare() bool { return C.element_is_sqr(el.cptr) != 0 } +// Sign returns 0 if el is 0. If el is not 0, the behavior depends on the +// algebraic structure, but has the property that el.Sign() == !neg.Sign() +// where neg is the negation of el. func (el *Element) Sign() int { - return normalizeSign(int64(C.element_sign(el.cptr))) + sign := int64(C.element_sign(el.cptr)) + if sign > 0 { + return 1 + } + if sign < 0 { + return -1 + } + return 0 } +// Add sets el = x + y and returns el. For curve points, + denotes the group +// operation. +// +// Requirements: +// el, x, and y must be from the same algebraic structure. func (el *Element) Add(x, y *Element) *Element { if el.checked { el.checkAllCompatible(x, y) @@ -68,6 +85,11 @@ func (el *Element) Add(x, y *Element) *Element { return el } +// Sub sets el = x - y and returns el. More precisely, el = x + (-y). For curve +// points, + denotes the group operation. +// +// Requirements: +// el, x, and y must be from the same algebraic structure. func (el *Element) Sub(x, y *Element) *Element { if el.checked { el.checkAllCompatible(x, y) @@ -76,6 +98,11 @@ func (el *Element) Sub(x, y *Element) *Element { return el } +// Mul sets el = x * y and returns el. For curve points, * denotes the group +// operation. +// +// Requirements: +// el, x, and y must be from the same algebraic structure. func (el *Element) Mul(x, y *Element) *Element { if el.checked { el.checkAllCompatible(x, y) @@ -84,6 +111,11 @@ func (el *Element) Mul(x, y *Element) *Element { return el } +// MulBig sets el = i * x and returns el. More precisely, el = x + x + ... + x +// where there are i x's. For curve points, + denotes the group operation. +// +// Requirements: +// el and x must be from the same algebraic structure. func (el *Element) MulBig(x *Element, i *big.Int) *Element { if el.checked { el.checkCompatible(x) @@ -92,6 +124,12 @@ func (el *Element) MulBig(x *Element, i *big.Int) *Element { return el } +// MulInt32 sets el = i * x and returns el. More precisely, +// el = x + x + ... + x where there are i x's. For curve points, + denotes the +// group operation. +// +// Requirements: +// el and x must be from the same algebraic structure. func (el *Element) MulInt32(x *Element, i int32) *Element { if el.checked { el.checkCompatible(x) @@ -100,15 +138,27 @@ func (el *Element) MulInt32(x *Element, i int32) *Element { return el } -func (el *Element) MulZn(x, y *Element) *Element { +// MulZn sets el = i * x and returns el. More precisely, +// el = x + x + ... + x where there are i x's. For curve points, + denotes the +// group operation. +// +// Requirements: +// el and x must be from the same algebraic structure; and +// i must be an element of an integer mod ring (e.g., Zn for some n). +func (el *Element) MulZn(x, i *Element) *Element { if el.checked { el.checkCompatible(x) - y.checkInteger() + i.checkInteger() } - C.element_mul_zn(el.cptr, x.cptr, y.cptr) + C.element_mul_zn(el.cptr, x.cptr, i.cptr) return el } +// Div sets el = x / y and returns el. More precisely, el = x * (1/y). For +// curve points, * denotes the group operation. +// +// Requirements: +// el, x, and y must be from the same algebraic structure. func (el *Element) Div(x, y *Element) *Element { if el.checked { el.checkAllCompatible(x, y) @@ -117,6 +167,10 @@ func (el *Element) Div(x, y *Element) *Element { return el } +// Double sets el = x + x and returns el. +// +// Requirements: +// el and x must be from the same algebraic structure. func (el *Element) Double(x *Element) *Element { if el.checked { el.checkCompatible(x) @@ -125,6 +179,10 @@ func (el *Element) Double(x *Element) *Element { return el } +// Halve sets el = x / 2 and returns el. +// +// Requirements: +// el and x must be from the same algebraic structure. func (el *Element) Halve(x *Element) *Element { if el.checked { el.checkCompatible(x) @@ -133,6 +191,10 @@ func (el *Element) Halve(x *Element) *Element { return el } +// Square sets el = x * x and returns el. +// +// Requirements: +// el and x must be from the same algebraic structure. func (el *Element) Square(x *Element) *Element { if el.checked { el.checkCompatible(x) @@ -141,6 +203,10 @@ func (el *Element) Square(x *Element) *Element { return el } +// Neg sets el = -x and returns el. +// +// Requirements: +// el and x must be from the same algebraic structure. func (el *Element) Neg(x *Element) *Element { if el.checked { el.checkCompatible(x) @@ -149,6 +215,10 @@ func (el *Element) Neg(x *Element) *Element { return el } +// Invert sets el = 1/x and returns el. +// +// Requirements: +// el and x must be from the same algebraic structure. func (el *Element) Invert(x *Element) *Element { if el.checked { el.checkCompatible(x) @@ -157,6 +227,11 @@ func (el *Element) Invert(x *Element) *Element { return el } +// PowBig sets el = x^i and returns el. More precisely, el = x * x * ... * x +// where there are i x's. For curve points, * denotes the group operation. +// +// Requirements: +// el and x must be from the same algebraic structure. func (el *Element) PowBig(x *Element, i *big.Int) *Element { if el.checked { el.checkCompatible(x) @@ -165,6 +240,13 @@ func (el *Element) PowBig(x *Element, i *big.Int) *Element { return el } +// PowZn sets el = x^i and returns el. More precisely, el = x * x * ... * x +// where there are i x's. For curve points, * denotes the group operation. +// +// Requirements: +// el and x must be from the same algebraic structure; and +// i must be an element of an integer mod ring (e.g., Zn for some n, typically +// the order of the algebraic structure that x lies in). func (el *Element) PowZn(x, i *Element) *Element { if el.checked { el.checkCompatible(x) @@ -174,6 +256,11 @@ func (el *Element) PowZn(x, i *Element) *Element { return el } +// Pow2Big sets el = x^i * y^j and returns el. This is generally faster than +// performing separate exponentiations. +// +// Requirements: +// el, x, and y must be from the same algebraic structure. func (el *Element) Pow2Big(x *Element, i *big.Int, y *Element, j *big.Int) *Element { if el.checked { el.checkAllCompatible(x, y) @@ -182,6 +269,13 @@ func (el *Element) Pow2Big(x *Element, i *big.Int, y *Element, j *big.Int) *Elem return el } +// Pow2Zn sets el = x^i * y^j and returns el. This is generally faster than +// performing separate exponentiations. +// +// Requirements: +// el, x, and y must be from the same algebraic structure; and +// i and j must be elements of integer mod rings (e.g., Zn for some n, +// typically the order of the algebraic structures that x and y lie in). func (el *Element) Pow2Zn(x, i, y, j *Element) *Element { if el.checked { el.checkAllCompatible(x, y) @@ -192,6 +286,11 @@ func (el *Element) Pow2Zn(x, i, y, j *Element) *Element { return el } +// Pow3Big sets el = x^i * y^j * z^k and returns el. This is generally faster +// than performing separate exponentiations. +// +// Requirements: +// el, x, y, and z must be from the same algebraic structure. 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) @@ -200,6 +299,13 @@ func (el *Element) Pow3Big(x *Element, i *big.Int, y *Element, j *big.Int, z *El return el } +// Pow3Big sets el = x^i * y^j * z^k and returns el. This is generally faster +// than performing separate exponentiations. +// +// Requirements: +// el, x, y, and z must be from the same algebraic structure; and +// i, j, and k must be elements of integer mod rings (e.g., Zn for some n, +// typically the order of the algebraic structures that x, y, and z lie in). func (el *Element) Pow3Zn(x, i, y, j, z, k *Element) *Element { if el.checked { el.checkAllCompatible(x, y, z) @@ -214,18 +320,30 @@ func (el *Element) Pow3Zn(x, i, y, j, z, k *Element) *Element { // 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. +// x^i will be stored in target. Once a Power has been generated, the original +// element can be changed without affecting the pre-processed data. type Power struct { source *Element // Prevents garbage collection pp *C.struct_element_pp_s } +// Source returns the Element for which the pre-processed data was generated. func (power *Power) Source() *Element { return power.source } +// PowBig sets target = s^i where s was the source Element for the Power, and +// returns target. It is equivalent to target.PowerBig(power, i). +// +// Requirements: +// target and s must be from the same algebraic structure. func (power *Power) PowBig(target *Element, i *big.Int) *Element { return target.PowerBig(power, i) } +// PowZn sets target = s^i where s was the source Element for the Power, and +// returns target. It is equivalent to target.PowerZn(power, i). +// +// Requirements: +// target and s must be from the same algebraic structure. func (power *Power) PowZn(target *Element, i *Element) *Element { return target.PowerZn(power, i) } @@ -234,6 +352,9 @@ func clearPower(power *Power) { C.element_pp_clear(power.pp) } +// PreparePower generates pre-processing data for repeatedly exponentiating el. +// The returned Power can be used to raise el to a power several times, and is +// generally faster than repeatedly calling the standard Pow methods on el. func (el *Element) PreparePower() *Power { power := &Power{ source: el, @@ -244,19 +365,42 @@ func (el *Element) PreparePower() *Power { return power } +// PowerBig sets el = s^i where s was the source Element for the Power, and +// returns el. It is equivalent to power.PowBig(el, i). +// +// Requirements: +// el and s must be from the same algebraic structure. func (el *Element) PowerBig(power *Power, i *big.Int) *Element { + if el.checked { + el.checkCompatible(power.source) + } C.element_pp_pow(el.cptr, &big2mpz(i)[0], power.pp) return el } +// PowerZn sets el = s^i where s was the source Element for the Power, and +// returns el. It is equivalent to power.PowZn(el, i). +// +// Requirements: +// el and s must be from the same algebraic structure; and +// i must be an element of an integer mod ring (e.g., Zn for some n, typically +// the order of the algebraic structure that s lies in). func (el *Element) PowerZn(power *Power, i *Element) *Element { if el.checked { + el.checkCompatible(power.source) i.checkInteger() } C.element_pp_pow_zn(el.cptr, i.cptr, power.pp) return el } +// Pair sets el = e(x,y) where e denotes the pairing operation, and returns el. +// +// Requirements: +// el, x, and y must belong to the same pairing; +// el must belong to the pairing's GT group; +// x must belong to the pairing's G1 group (or G2 for symmetric pairings); and +// y must belong to the pairing's G2 group (or G1 for symmetric pairings). func (el *Element) Pair(x, y *Element) *Element { if el.checked { x.ensureChecked() @@ -277,6 +421,21 @@ func (el *Element) doProdPair(in1, in2 []C.struct_element_s) *Element { return el } +// ProdPair sets el to the product of several pairings, and returns el. The +// elements are paired in groups of two. +// +// For example: +// el.ProdPair(a,b,c,d,e,f) +// will set el = e(a,b) * e(c,d) * e(e,f). +// +// Requirements: +// all elements must belong to the same pairing; +// el must belong to the pairing's GT group; +// there must be an even number of parameters; +// odd numbered parameters must belong to the pairing's G1 group (or G2 for +// symmetric pairings); and +// even numbered parameters must belong to the pairing's G2 group (or G1 for +// symmetric pairings). func (el *Element) ProdPair(elements ...*Element) *Element { n := len(elements) if n%2 != 0 { @@ -302,6 +461,21 @@ func (el *Element) ProdPair(elements ...*Element) *Element { return el.doProdPair(in1, in2) } +// ProdPairSlice sets el to the product of several pairings, and returns el. +// Elements from x will be paired with elements in y having the same index. +// +// For example: +// el.ProdPairSlice([]*Element{a,b,c}, []*Element{d,e,f}) +// will set el = e(a,d) * e(b,e) * e(c,f). +// +// Requirements: +// all elements must belong to the same pairing; +// el must belong to the pairing's GT group; +// the slices must have the same number of elements; +// elements in x must belong to the pairing's G1 group (or G2 for symmetric +// pairings); and +// elements in y must belong to the pairing's G2 group (or G1 for symmetric +// pairings). func (el *Element) ProdPairSlice(x, y []*Element) *Element { n := len(x) if n != len(y) { @@ -332,14 +506,25 @@ func (el *Element) ProdPairSlice(x, y []*Element) *Element { // 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. +// target. Once a Pairer has been generated, the original element can be +// changed without affecting the pre-processed data. type Pairer struct { source *Element // Prevents garbage collection pp *C.struct_pairing_pp_s } +// Source returns the Element for which the pre-processed data was generated. func (pairer *Pairer) Source() *Element { return pairer.source } +// Pair sets target = e(s,y) and returns target, where e denotes the pairing +// operation, and s was the source Element for the Pairer. It is equivalent to +// target.PairerPair(pairer, y). +// +// Requirements: +// target, s, and y must belong to the same pairing; +// target must belong to the pairing's GT group; +// s must belong to the pairing's G1 group (or G2 for symmetric pairings); and +// y must belong to the pairing's G2 group (or G1 for symmetric pairings). func (pairer *Pairer) Pair(target *Element, y *Element) *Element { return target.PairerPair(pairer, y) } @@ -348,7 +533,16 @@ func clearPairer(pairer *Pairer) { C.pairing_pp_clear(pairer.pp) } +// PreparePairer generates pre-processing data for repeatedly pairing el. The +// returned Pairer can be used to pair el several times, and is generally +// faster than repeatedly calling Pair on el. +// +// Requirements: +// el must belong to the pairing's G1 group (or G2 for symmetric pairings). func (el *Element) PreparePairer() *Pairer { + if el.checked { + checkFieldsMatch(el.fieldPtr, el.pairing.cptr.G1) + } pairer := &Pairer{ source: el, pp: &C.struct_pairing_pp_s{}, @@ -358,6 +552,15 @@ func (el *Element) PreparePairer() *Pairer { return pairer } +// PairerPair sets el = e(s,y) and returns el, where e denotes the pairing +// operation, and s was the source Element for the Pairer. It is equivalent to +// pairer.Pair(el, y). +// +// Requirements: +// el, s, and y must belong to the same pairing; +// el must belong to the pairing's GT group; +// s must belong to the pairing's G1 group (or G2 for symmetric pairings); and +// y must belong to the pairing's G2 group (or G1 for symmetric pairings). func (el *Element) PairerPair(pairer *Pairer, y *Element) *Element { if el.checked { pairer.source.ensureChecked() diff --git a/element_fmt.go b/element_fmt.go index 410ad1ed887613b63fc2256605f02c31fb2b28ce..a6f67353be7b72baf5284c39c146d3bb16e12ed4 100644 --- a/element_fmt.go +++ b/element_fmt.go @@ -60,6 +60,19 @@ func (el *Element) customFormat(f fmt.State, c rune) { } } +// Format is a support routine for fmt.Formatter. It accepts many formats. The +// 'v' (value) and 's' (string) verbs will format the Element using the PBC +// library's internal formatting routines. These verbs accept variable widths +// to specify the base of the integers. Valid values are 2 to 36, inclusive. +// +// If the 'v' verb is used with the '#' (alternate format) flag, the output is +// metadata about the element in a pseudo-Go syntax. Checked elements will +// print more information than unchecked elements in this mode. +// +// If the 'd', 'b', 'o', 'x', or 'X' verbs are used, then the element is +// formatted within Go. The syntax approximates the PBC library's formatting, +// but integers are converted to big.Int for formatting. All of the verbs and +// flags that can be used in math/big will be used to format the elements. func (el *Element) Format(f fmt.State, c rune) { switch c { case 'v': @@ -81,10 +94,14 @@ func (el *Element) Format(f fmt.State, c rune) { } } +// String converts el to a string using the default PBC library format. func (el *Element) String() string { return fmt.Sprintf("%s", el) } +// SetString sets el to the value contained in s. Returns (el, true) if +// successful, and (nil, false) if an error occurs. s is expected to be in the +// same format produced by String(). func (el *Element) SetString(s string, base int) (*Element, bool) { cstr := C.CString(s) defer C.free(unsafe.Pointer(cstr)) @@ -95,16 +112,24 @@ func (el *Element) SetString(s string, base int) (*Element, bool) { return el, true } +// Scan is a support routine for fmt.Scanner. It accepts the verbs 's' and 'v' +// only; only strings produced in PBC library format can be scanned. The width +// is used to denote the base of integers in the data. func (el *Element) Scan(state fmt.ScanState, verb rune) error { + // Verify verbs if verb != 's' && verb != 'v' { return ErrBadVerb } + + // Verify base base, ok := state.Width() if !ok { base = 10 } else if base < 2 || base > 36 { return ErrBadVerb } + + // Compute valid integer symbols maxDigit := '9' maxAlpha := 'z' if base < 10 { @@ -116,6 +141,9 @@ func (el *Element) Scan(state fmt.ScanState, verb rune) error { state.SkipSpace() + // Validate the input using a state machine (passing PBC invalid input is + // likely to lead to bad outcomes) + tokensFound := make([]uint, 0, 5) inToken := false justDescended := false @@ -176,6 +204,8 @@ ReadLoop: } justDescended = (r == ']') } + + // The string seems valid; pass it to PBC if _, ok := el.SetString(buf.String(), base); !ok { return ErrBadInput } diff --git a/element_io.go b/element_io.go index 739a50998ef528df49abcd2c10b453a7390a7520..b57c5fdfe23114d38193cce3e1513fcd590ad0c1 100644 --- a/element_io.go +++ b/element_io.go @@ -4,12 +4,17 @@ package pbc #include <pbc/pbc.h> */ import "C" + import ( "hash" "math/big" "unsafe" ) +// BigInt converts the Element to a big.Int if such an operation makes sense. +// +// Requirements: +// el is expressible as an integer (e.g., an element of Zn, but not a point). func (el *Element) BigInt() *big.Int { if el.checked { el.checkInteger() @@ -19,6 +24,10 @@ func (el *Element) BigInt() *big.Int { return mpz2big(mpz) } +// Set sets the value of el to be the same as src. +// +// Requirements: +// el and src must be from the same algebraic structure. func (el *Element) Set(src *Element) *Element { if el.checked { el.checkCompatible(src) @@ -27,6 +36,11 @@ func (el *Element) Set(src *Element) *Element { return el } +// SetInt32 sets the value of el to the integer i. This operation is only valid +// for elements in integer fields (e.g., Zr for a pairing). +// +// Requirements: +// el must be an element of an integer mod ring (e.g., Zn for some n). func (el *Element) SetInt32(i int32) *Element { if el.checked { el.checkInteger() @@ -35,6 +49,11 @@ func (el *Element) SetInt32(i int32) *Element { return el } +// SetBig sets the value of el to the integer i. This operation is only valid +// for elements in integer fields (e.g., Zr for a pairing). +// +// Requirements: +// el must be an element of an integer mod ring (e.g., Zn for some n). func (el *Element) SetBig(i *big.Int) *Element { if el.checked { el.checkInteger() @@ -43,11 +62,14 @@ func (el *Element) SetBig(i *big.Int) *Element { return el } +// SetFromHash generates el deterministically from the bytes in hash. func (el *Element) SetFromHash(hash []byte) *Element { C.element_from_hash(el.cptr, unsafe.Pointer(&hash[0]), C.int(len(hash))) return el } +// SetFromStringHash hashes s with h and then calls SetFromHash. h may or may +// not be a cryptographic hash, depending on the higher level protocol. func (el *Element) SetFromStringHash(s string, h hash.Hash) *Element { h.Reset() if _, err := h.Write([]byte(s)); err != nil { @@ -56,10 +78,12 @@ func (el *Element) SetFromStringHash(s string, h hash.Hash) *Element { return el.SetFromHash(h.Sum([]byte{})) } +// BytesLen returns the number of bytes needed to represent el. func (el *Element) BytesLen() int { return int(C.element_length_in_bytes(el.cptr)) } +// Bytes exports el as a byte sequence. func (el *Element) Bytes() []byte { buf := make([]byte, el.BytesLen()) written := C.element_to_bytes((*C.uchar)(unsafe.Pointer(&buf[0])), el.cptr) @@ -69,16 +93,31 @@ func (el *Element) Bytes() []byte { return buf } +// SetBytes imports a sequence exported by Bytes() and sets the value of el. func (el *Element) SetBytes(buf []byte) *Element { C.element_from_bytes(el.cptr, (*C.uchar)(unsafe.Pointer(&buf[0]))) return el } +// XBytesLen returns the number of bytes needed to represent el's X coordinate. +// +// Requirements: +// el must be a point on an elliptic curve. func (el *Element) XBytesLen() int { + if el.checked { + el.checkPoint() + } return int(C.element_length_in_bytes_x_only(el.cptr)) } +// XBytes exports el's X coordinate as a byte sequence. +// +// Requirements: +// el must be a point on an elliptic curve. func (el *Element) XBytes() []byte { + if el.checked { + el.checkPoint() + } 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)) { @@ -87,16 +126,44 @@ func (el *Element) XBytes() []byte { return buf } +// SetXBytes imports a sequence exported by XBytes() and sets el to be a point +// on the curve with the given X coordinate. In general, this point is not +// unique. For each X coordinate, there exist two different points (for the +// pairings in PBC), and they are inverses of each other. An application can +// deal with this by either exporting the sign of the element along with the X +// coordinate, or by testing the value to see if it makes sense in the higher +// level protocol (and inverting it if it does not). +// +// Requirements: +// el must be a point on an elliptic curve. func (el *Element) SetXBytes(buf []byte) *Element { + if el.checked { + el.checkPoint() + } C.element_from_bytes_x_only(el.cptr, (*C.uchar)(unsafe.Pointer(&buf[0]))) return el } +// CompressedBytesLen returns the number of bytes needed to represent a +// compressed form of el. +// +// Requirements: +// el must be a point on an elliptic curve. func (el *Element) CompressedBytesLen() int { + if el.checked { + el.checkPoint() + } return int(C.element_length_in_bytes_compressed(el.cptr)) } +// CompressedBytes exports el in a compressed form as a byte sequence. +// +// Requirements: +// el must be a point on an elliptic curve. func (el *Element) CompressedBytes() []byte { + if el.checked { + el.checkPoint() + } 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)) { @@ -105,7 +172,15 @@ func (el *Element) CompressedBytes() []byte { return buf } +// SetCompressedBytes imports a sequence exported by CompressedBytes() and sets +// the value of el. +// +// Requirements: +// el must be a point on an elliptic curve. func (el *Element) SetCompressedBytes(buf []byte) *Element { + if el.checked { + el.checkPoint() + } 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 index 2b6fdaec624025c83eba8efd6792e8ce0138d1ad..51f11c9b7093ed31b8bc045d74a627611938784c 100644 --- a/element_misc.go +++ b/element_misc.go @@ -4,10 +4,14 @@ package pbc #include <pbc/pbc.h> */ import "C" + import "math/big" +// Pairing returns the pairing associated with this element. func (el *Element) Pairing() *Pairing { return el.pairing } +// NewFieldElement creates a new element in the same field as el. The new +// element will be unchecked if and only if el is unchecked. func (el *Element) NewFieldElement() *Element { newElement := makeUncheckedElement(el.pairing, false, G1) C.element_init_same_as(newElement.cptr, el.cptr) @@ -19,10 +23,17 @@ func (el *Element) NewFieldElement() *Element { return newElement } +// Len returns the length of this element. For points, this is the number of +// coordinates. For polynomials, it is the number of coefficients. For infinite +// points, it is zero. For all other values, it is zero. func (el *Element) Len() int { return int(C.element_item_count(el.cptr)) } +// Item returns the specified sub-element. For points, this returns a +// coordinate. For polynomials, it returns a coefficient. For other elements, +// this operation is invalid. i must be greater than or equal to 0 and less +// than el.Len(). Bounds checking is only performed for checked elements. func (el *Element) Item(i int) *Element { if el.checked && i >= el.Len() { panic(ErrOutOfRange) @@ -31,6 +42,9 @@ func (el *Element) Item(i int) *Element { pairing: el.pairing, cptr: C.element_item(el.cptr, C.int(i)), } + if newElement.cptr == nil { + panic(ErrOutOfRange) + } if el.checked { newElement.fieldPtr = newElement.cptr.field newElement.isInteger = (newElement.Len() == 0) @@ -38,14 +52,28 @@ func (el *Element) Item(i int) *Element { return newElement } +// X returns the X coordinate of el. Equivalent to el.Item(0).BigInt(). +// +// Requirements: +// el must be a point on an elliptic curve. func (el *Element) X() *big.Int { return el.Item(0).BigInt() } +// Y returns the Y coordinate of el. Equivalent to el.Item(1).BigInt(). +// +// Requirements: +// el must be a point on an elliptic curve. func (el *Element) Y() *big.Int { return el.Item(1).BigInt() } +// BruteForceDL sets el such that g^el = h using brute force. +// +// Requirements: +// g and h must be from the same algebraic structure; and +// el must be an element of an integer mod ring (e.g., Zn for some n, typically +// the order of the algebraic structure that g lies in). func (el *Element) BruteForceDL(g, h *Element) *Element { if el.checked { el.checkInteger() @@ -56,6 +84,12 @@ func (el *Element) BruteForceDL(g, h *Element) *Element { return el } +// PollardRhoDL sets el such that g^el = h using Pollard rho method. +// +// Requirements: +// g and h must be from the same algebraic structure; and +// el must be an element of an integer mod ring (e.g., Zn for some n, typically +// the order of the algebraic structure that g lies in). func (el *Element) PollardRhoDL(g, h *Element) *Element { if el.checked { el.checkInteger() diff --git a/doc_test.go b/example_test.go similarity index 53% rename from doc_test.go rename to example_test.go index 3bbe420c4903da1621e1f9e2414530a9e4265765..537f3b17ecd9dffa1873ad2ef612eecb8152b7ee 100644 --- a/doc_test.go +++ b/example_test.go @@ -1,12 +1,16 @@ -package pbc +package pbc_test -import "fmt" +import ( + "fmt" + + "github.com/Nik-U/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 := GenerateA(160, 512) + params := pbc.GenerateA(160, 512) pairing := params.NewPairing() @@ -23,3 +27,12 @@ func Example() { x.Pair(g, h) fmt.Printf("e(g,h) = %s\n", x) } + +func ExampleElement_Format() { + fmt.Printf("%v", element) // Print in PBC format + fmt.Printf("%s", element) // Same as above + fmt.Printf("%36v", element) // Print in PBC format, base 36 + fmt.Printf("%#v", element) // Print metadata about element + fmt.Printf("%d", element) // Print with Go + fmt.Printf("%010o", element) // Print with Go, zero-padded width-10 octal +} diff --git a/generation.go b/generation.go index e35ea3dc51a0546a410225ded97bfa92d1588128..9e2a9fb2bff53383e044b023fc644041ef3b81e2 100644 --- a/generation.go +++ b/generation.go @@ -44,6 +44,8 @@ import ( // // For example: // params := pbc.GenerateA(160, 512) +// +// More details: https://crypto.stanford.edu/pbc/manual/ch08s03.html func GenerateA(rbits uint32, qbits uint32) *Params { params := makeParams() C.pbc_param_init_a_gen(params.cptr, C.int(rbits), C.int(qbits)) @@ -55,6 +57,8 @@ 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. +// +// More details: https://crypto.stanford.edu/pbc/manual/ch08s03.html func GenerateA1(r *big.Int) *Params { params := makeParams() C.pbc_param_init_a1_gen(params.cptr, &big2mpz(r)[0]) @@ -81,6 +85,8 @@ func GenerateA1(r *big.Int) *Params { // // For example: // params, err := pbc.GenerateD(9563, 160, 171, 500) +// +// More details: https://crypto.stanford.edu/pbc/manual/ch08s06.html func GenerateD(d uint32, rbits uint32, qbits uint32, bitlimit uint32) (*Params, error) { return generateWithCM(true, d, rbits, qbits, bitlimit) } @@ -97,6 +103,8 @@ func GenerateD(d uint32, rbits uint32, qbits uint32, bitlimit uint32) (*Params, // // For example: // params, err := pbc.GenerateE(160, 1024) +// +// More details: https://crypto.stanford.edu/pbc/manual/ch08s07.html func GenerateE(rbits uint32, qbits uint32) *Params { params := makeParams() C.pbc_param_init_e_gen(params.cptr, C.int(rbits), C.int(qbits)) @@ -115,6 +123,8 @@ func GenerateE(rbits uint32, qbits uint32) *Params { // // For example: // params, err := pbc.GenerateF(160) +// +// More details: https://crypto.stanford.edu/pbc/manual/ch08s08.html func GenerateF(bits uint32) *Params { params := makeParams() C.pbc_param_init_f_gen(params.cptr, C.int(bits)) @@ -132,6 +142,8 @@ func GenerateF(bits uint32) *Params { // // For example: // params, err := pbc.GenerateG(9563, 160, 171, 500) +// +// More details: https://crypto.stanford.edu/pbc/manual/ch08s09.html func GenerateG(d uint32, rbits uint32, qbits uint32, bitlimit uint32) (*Params, error) { return generateWithCM(false, d, qbits, rbits, bitlimit) } diff --git a/pairing.go b/pairing.go index e7f532c3d9210fa165a539ef0765f4831e4c0d57..9d49331d277be565caa6b0bc204dba0c7ec3f65c 100644 --- a/pairing.go +++ b/pairing.go @@ -25,10 +25,8 @@ const ( // 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. +// created in G1, G2, GT, or Zr. Additionally, elements can be checked or +// unchecked. See the Element type for more details. type Pairing struct { cptr *C.struct_pairing_s } @@ -63,55 +61,71 @@ func (pairing *Pairing) IsSymmetric() bool { return C.pairing_is_symmetric(pairing.cptr) != 0 } +// G1Length returns the size of elements in G1, in bytes. func (pairing *Pairing) G1Length() uint { return uint(C.pairing_length_in_bytes_G1(pairing.cptr)) } +// G1XLength returns the size of X coordinates of elements in G1, in bytes. func (pairing *Pairing) G1XLength() uint { return uint(C.pairing_length_in_bytes_x_only_G1(pairing.cptr)) } +// G1CompressedLength returns the size of compressed elements in G1, in bytes. func (pairing *Pairing) G1CompressedLength() uint { return uint(C.pairing_length_in_bytes_compressed_G1(pairing.cptr)) } +// G2Length returns the size of elements in G2, in bytes. func (pairing *Pairing) G2Length() uint { return uint(C.pairing_length_in_bytes_G2(pairing.cptr)) } +// G2XLength returns the size of X coordinates of elements in G2, in bytes. func (pairing *Pairing) G2XLength() uint { return uint(C.pairing_length_in_bytes_x_only_G2(pairing.cptr)) } +// G2CompressedLength returns the size of compressed elements in G2, in bytes. func (pairing *Pairing) G2CompressedLength() uint { return uint(C.pairing_length_in_bytes_compressed_G2(pairing.cptr)) } +// GTLength returns the size of elements in GT, in bytes. func (pairing *Pairing) GTLength() uint { return uint(C.pairing_length_in_bytes_GT(pairing.cptr)) } +// ZrLength returns the size of elements in Zr, in bytes. func (pairing *Pairing) ZrLength() uint { return uint(C.pairing_length_in_bytes_Zr(pairing.cptr)) } +// NewG1 creates a new checked element in G1. func (pairing *Pairing) NewG1() *Element { return makeCheckedElement(pairing, G1, pairing.cptr.G1) } +// NewG2 creates a new checked element in G2. func (pairing *Pairing) NewG2() *Element { return makeCheckedElement(pairing, G2, pairing.cptr.G2) } +// NewGT creates a new checked element in GT. func (pairing *Pairing) NewGT() *Element { return makeCheckedElement(pairing, GT, &pairing.cptr.GT[0]) } +// NewZr creates a new checked element in Zr. func (pairing *Pairing) NewZr() *Element { return makeCheckedElement(pairing, Zr, &pairing.cptr.Zr[0]) } -func (pairing *Pairing) NewElement(field Field) *Element { +// NewUncheckedElement creates a new unchecked element in the target field. +// Unchecked elements are dangerous; see the Element documentation before +// deciding to use this method. It is safer to create elements using the NewG1, +// NewG2, NewGT, or NewZr methods. +func (pairing *Pairing) NewUncheckedElement(field Field) *Element { return makeUncheckedElement(pairing, true, field) } diff --git a/params.go b/params.go index 87fb87b1e956fa54d0ac68697eafa43a77d409d3..5d623af7ef95fe135ec29c31f1c33b91b72db2f2 100644 --- a/params.go +++ b/params.go @@ -21,10 +21,17 @@ import ( ) // Params represents the parameters required for creating a pairing. Parameters -// cn be generated using the generation functions or read from a Reader. +// can 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. +// +// For applications requiring fast computation, type A pairings are preferred. +// Applications requiring small message sizes should consider type D pairings. +// If speed is not a concern, type F pairings yield the smallest messages at +// the cost of additional computation. Applications requiring symmetric +// pairings should use type A. If a specific group order must be used (e.g., +// for composite orders), then type A1 pairings are required. type Params struct { cptr *C.struct_pbc_param_s } @@ -55,11 +62,13 @@ func (params *Params) NewPairing() *Pairing { return NewPairing(params) } +// WriteTo writes the pairing parameters to a Writer. func (params *Params) WriteTo(w io.Writer) (n int64, err error) { count, err := io.WriteString(w, params.String()) return int64(count), err } +// String returns a string representation of the pairing parameters. func (params *Params) String() string { var buf *C.char var bufLen C.size_t