ibe: Avoid copies of bn256.{G1,G2,GT} objects
While the golang.org/x/crypto/bn256 implementation is amenable
to these object copies, other implementations such as
github.com/asimshankar/bn256 are not.
The motivation for this change was so that we experiment with switching
to the pairing implementation backed by
https://www.cryptojedi.org/crypto/#dclxvi
Without this patch, switching to github.com/asimshankar/bn256 causes
SIGSEGVs as copying the Go-objects might mess up the state in C.
For the curious: This change by itself shows no change in the
benchmarks, but switching to https://www.cryptojedi.org/crypto/#dclxvi
shows a considerable improvement on my amd64 machine:
BenchmarkExtractBB1-6 33ms 1ms (16x speedup)
BenchmarkEncryptBB-6 41ms 5ms (7x speedup)
BenchmarkDecryptBB-6 96ms 5ms (16x speedup)
Change-Id: I3409e2df62980c974f3917ef30e8422bfc4a8b37
diff --git a/ibe/bb1.go b/ibe/bb1.go
index 5e1c8d6..117b6c5 100644
--- a/ibe/bb1.go
+++ b/ibe/bb1.go
@@ -69,9 +69,9 @@
// to encrypt the data under the symmetric key.
func SetupBB1() (Master, error) {
var (
- m = &bb1master{params: new(bb1params)}
- pk = m.params // shorthand
- g0Hat = &(m.g0Hat) // shorthand
+ m = &bb1master{params: newbb1params(), g0Hat: new(bn256.G2)}
+ pk = m.params // shorthand
+ g0Hat = m.g0Hat // shorthand
)
// Set generators
@@ -102,13 +102,13 @@
alphabeta := new(big.Int).Mul(alpha, beta)
g0Hat.ScalarBaseMult(alphabeta.Mod(alphabeta, bn256.Order)) // g0Hat = gHat^*(alpha*beta)
- pk.v = bn256.Pair(&pk.g, g0Hat)
+ pk.v = bn256.Pair(pk.g, g0Hat)
return m, nil
}
type bb1master struct {
params *bb1params // Public params
- g0Hat bn256.G2 // Master key
+ g0Hat *bn256.G2 // Master key
}
func (m *bb1master) Extract(id string) (PrivateKey, error) {
@@ -118,12 +118,16 @@
}
var (
- ret = &bb1PrivateKey{params: m.params}
+ ret = &bb1PrivateKey{
+ params: m.params,
+ d0: new(bn256.G2),
+ d1: new(bn256.G2),
+ }
// A bunch of shorthands
- d0 = new(bn256.G2)
- g1Hat = &(m.params.g1Hat)
- g0Hat = &(m.g0Hat)
- hHat = &(m.params.hHat)
+ d0 = ret.d0
+ g1Hat = m.params.g1Hat
+ g0Hat = m.g0Hat
+ hHat = m.params.hHat
i = val2bignum(idPrefix, []byte(id))
)
// ret.d0 = g0Hat * (g1Hat^i * hHat)^r
@@ -138,11 +142,23 @@
func (m *bb1master) Params() Params { return m.params }
type bb1params struct {
- g, g1, h bn256.G1
- gHat, g1Hat, hHat bn256.G2
+ g, g1, h *bn256.G1
+ gHat, g1Hat, hHat *bn256.G2
v *bn256.GT
}
+func newbb1params() *bb1params {
+ return &bb1params{
+ g: new(bn256.G1),
+ g1: new(bn256.G1),
+ h: new(bn256.G1),
+ gHat: new(bn256.G2),
+ g1Hat: new(bn256.G2),
+ hHat: new(bn256.G2),
+ v: new(bn256.GT),
+ }
+}
+
// Helper method that checks that the ciphertext slice for a given message has
// the correct size: len(C) = len(m) + CiphertextOverhead()
func (e *bb1params) checkSizes(m, C []byte) error {
@@ -163,8 +179,8 @@
}
var (
- vs bn256.GT
- tmpG1 bn256.G1
+ vs = new(bn256.GT)
+ tmpG1 = new(bn256.G1)
// Ciphertext C = (A, B, C1) - this method computes the first two components
A = C[0:encKeySize]
B = C[encKeySize : encKeySize+marshaledG1Size]
@@ -213,7 +229,7 @@
s = computeKemRandomness(&sigma, m) // H_1(sigma, m)
symKey = computeDemKey(&sigma) // H_2(sigma)
- tmpG1 bn256.G1
+ tmpG1 = new(bn256.G1)
// Ciphertext C = (kem, dem)
kem = C[0:kemSize]
dem = C[kemSize:]
@@ -226,10 +242,10 @@
C1 := kem[encKeySize+marshaledG1Size:]
// C1 = (g1^H(id) h)^s
- tmpG1.ScalarMult(&e.g1, val2bignum(idPrefix, []byte(id)))
- tmpG1.Add(&tmpG1, &e.h)
- tmpG1.ScalarMult(&tmpG1, s)
- if err := marshalG1(C1, &tmpG1); err != nil {
+ tmpG1.ScalarMult(e.g1, val2bignum(idPrefix, []byte(id)))
+ tmpG1.Add(tmpG1, e.h)
+ tmpG1.ScalarMult(tmpG1, s)
+ if err := marshalG1(C1, tmpG1); err != nil {
return err
}
@@ -250,7 +266,7 @@
type bb1PrivateKey struct {
params *bb1params // public parameters
- d0, d1 bn256.G2
+ d0, d1 *bn256.G2
}
func (k *bb1PrivateKey) Decrypt(C, m []byte) error {
@@ -258,9 +274,10 @@
return err
}
var (
- A = C[0:encKeySize]
- B, C1 bn256.G1
- D = C[kemSize:]
+ A = C[0:encKeySize]
+ B = new(bn256.G1)
+ C1 = new(bn256.G1)
+ D = C[kemSize:]
)
if _, ok := B.Unmarshal(C[encKeySize : encKeySize+marshaledG1Size]); !ok {
return errBadCiphertext
@@ -270,8 +287,8 @@
}
// sigma = A ⊕ H(e(B, d0)/e(C1,d1))
var (
- numerator = bn256.Pair(&B, &k.d0)
- denominator = bn256.Pair(&C1, &k.d1)
+ numerator = bn256.Pair(B, k.d0)
+ denominator = bn256.Pair(C1, k.d1)
hash = hashval(ibePrefix, numerator.Add(numerator, denominator.Neg(denominator)).Marshal())
)
var sigma [encKeySize]byte
diff --git a/ibe/marshal.go b/ibe/marshal.go
index ca6bae4..77859c7 100644
--- a/ibe/marshal.go
+++ b/ibe/marshal.go
@@ -85,7 +85,7 @@
if len(data) != marshaledBB1ParamsSize {
return nil, fmt.Errorf("invalid size")
}
- p := &bb1params{v: new(bn256.GT)}
+ p := newbb1params()
one := big.NewInt(1)
p.g.ScalarBaseMult(one)
p.gHat.ScalarBaseMult(one)
@@ -145,7 +145,10 @@
if len(data) != marshaledBB1PrivateKeySize {
return nil, fmt.Errorf("invalid size")
}
- k := new(bb1PrivateKey)
+ k := &bb1PrivateKey{
+ d0: new(bn256.G2),
+ d1: new(bn256.G2),
+ }
if _, ok := k.d0.Unmarshal(advance(marshaledG2Size)); !ok {
return nil, fmt.Errorf("failed to unmarshal d0")
}