lib/ibe: Implementation of BB2-IBE
Implementation of the second variant of the Boneh-Boyen IBE
scheme (BB2 from Section 5.1 of this paper:
http://crypto.stanford.edu/~dabo/papers/bbibe.pdf). The BB2 IBE
scheme is slightly more efficient compared to the BB1 scheme:
smaller public keys and only requires a single pairing for
decryption.
Performance comparison between BB1 and BB2 (on my laptop):
BenchmarkExtractBB1-8 100 21191388 ns/op
BenchmarkExtractBB2-8 200 7351737 ns/op
BenchmarkEncryptBB1-8 50 24873136 ns/op
BenchmarkEncryptBB2-8 50 24948942 ns/op
BenchmarkDecryptBB1-8 20 58252346 ns/op
BenchmarkDecryptBB2-8 30 41771732 ns/op
Change-Id: I720b98f5b87510d5bda14ece85cd43c1aba9b718
diff --git a/ibe/.api b/ibe/.api
index e561c43..0d242a4 100644
--- a/ibe/.api
+++ b/ibe/.api
@@ -1,6 +1,7 @@
pkg ibe, func MarshalParams(Params) ([]byte, error)
pkg ibe, func MarshalPrivateKey(PrivateKey) ([]byte, error)
pkg ibe, func SetupBB1() (Master, error)
+pkg ibe, func SetupBB2() (Master, error)
pkg ibe, func UnmarshalParams([]byte) (Params, error)
pkg ibe, func UnmarshalPrivateKey(Params, []byte) (PrivateKey, error)
pkg ibe, type Master interface { Extract, Params }
diff --git a/ibe/bb1.go b/ibe/bb1.go
index 117b6c5..63ce0bf 100644
--- a/ibe/bb1.go
+++ b/ibe/bb1.go
@@ -161,9 +161,9 @@
// 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 {
- if msize, Csize := len(m), len(C); Csize != msize+e.CiphertextOverhead() {
- return fmt.Errorf("provided plaintext and ciphertext are of sizes (%d, %d), ciphertext size should be %d", msize, Csize, e.CiphertextOverhead())
+func checkSizes(m, C []byte, params Params) error {
+ if msize, Csize := len(m), len(C); Csize != msize+params.CiphertextOverhead() {
+ return fmt.Errorf("provided plaintext and ciphertext are of sizes (%d, %d), ciphertext size should be %d", msize, Csize, params.CiphertextOverhead())
}
return nil
}
@@ -215,7 +215,7 @@
}
func (e *bb1params) Encrypt(id string, m, C []byte) error {
- if err := e.checkSizes(m, C); err != nil {
+ if err := checkSizes(m, C, e); err != nil {
return err
}
@@ -270,7 +270,7 @@
}
func (k *bb1PrivateKey) Decrypt(C, m []byte) error {
- if err := k.params.checkSizes(m, C); err != nil {
+ if err := checkSizes(m, C, k.params); err != nil {
return err
}
var (
diff --git a/ibe/bb2.go b/ibe/bb2.go
new file mode 100644
index 0000000..fab0caf
--- /dev/null
+++ b/ibe/bb2.go
@@ -0,0 +1,282 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file defines an implementation of the IBE interfaces using the
+// Boneh-Boyen scheme (BB2). The Fujisaki-Okamoto transformation is applied to
+// obtain CCA2-security. The paper defining this algorithm (see comments for
+// SetupBB2) uses multiplicative groups while the bn256 package used in the
+// implementation here defines an additive group. The comments follow the
+// notation in the paper while the code uses the bn256 library. For example,
+// g^i corresponds to G1.ScalarBaseMult(i).
+
+// The ciphertexts in the resulting CCA2-secure IBE scheme will consist of
+// two parts: an IBE encryption of a symmetric key (called the 'kem' - key
+// encapsulation mechanism) and a symmetric encryption of the payload
+// (called the 'dem' - data encapsulation mechanism).
+
+package ibe
+
+import (
+ "bytes"
+ "crypto/rand"
+ "fmt"
+ "math/big"
+
+ "golang.org/x/crypto/bn256"
+ "golang.org/x/crypto/nacl/secretbox"
+)
+
+// Setup creates an ibe.Master based on the BB2 scheme described in "Efficient
+// Selective Identity-Based Encryption Without Random Oracles" by Dan Boneh and
+// Xavier Boyen (http://crypto.stanford.edu/~dabo/papers/bbibe.pdf).
+//
+// Specifically, a variant of Section 5.1 (from the section labeled Hash-BDHI
+// construction in Section 5.1) of the paper is implemented.
+//
+// In addition, we apply the Fujisaki-Okamoto transformation to the BB-IBE
+// scheme (http://link.springer.com/chapter/10.1007%2F3-540-48405-1_34)
+// in order to obtain CCA2-security (in the random oracle model). The resulting
+// scheme is a CCA2-secure hybrid encryption scheme where BB-IBE is used to
+// encrypt a nonce used to derive a symmetric key, and NaCl/secretbox is used
+// to encrypt the data under the symmetric key.
+//
+// The BB2 scheme uses approximately 30% less CPU for the Decrypt operation
+// compared to the BB1 scheme, and public keys are more compact (3 group
+// elements vs. 5 group elements). The main disadvantage is that it relies on
+// a more complicated assumption on bilinear groups (the hash bilinear Diffie-
+// Hellman inversion assumption). This assumption holds in the generic group
+// model, and to date, there are no known attacks on the assumption other than
+// the generic ones.
+func SetupBB2() (Master, error) {
+ var (
+ m = &bb2master{
+ params: newbb2params(),
+ hHat: new(bn256.G2),
+ }
+ g = new(bn256.G1).ScalarBaseMult(big.NewInt(1)) // generator for G1
+ pk = m.params // shorthand
+ hHat = m.hHat // shorthand
+ )
+
+ // Pick a random exponent r and set hHat = gHat^r
+ r, err := random()
+ if err != nil {
+ return nil, err
+ }
+ hHat.ScalarBaseMult(r)
+
+ // Pick exponent x for master secret key and compute g^x
+ m.x, err = random()
+ if err != nil {
+ return nil, err
+ }
+ pk.X.ScalarBaseMult(m.x)
+
+ // Pick exponent y for master secret key and compute g^y
+ m.y, err = random()
+ if err != nil {
+ return nil, err
+ }
+ pk.Y.ScalarBaseMult(m.y)
+
+ pk.v = bn256.Pair(g, hHat)
+ return m, nil
+}
+
+type bb2master struct {
+ params *bb2params // Public params
+ x *big.Int // Master key component
+ y *big.Int // Master key component
+ hHat *bn256.G2 // Master key component
+}
+
+func (m *bb2master) Extract(id string) (PrivateKey, error) {
+ var (
+ ret = &bb2PrivateKey{
+ params: m.params,
+ r: nil,
+ K: new(bn256.G2),
+ }
+ // some shorthands
+ hHat = m.hHat
+ z = new(big.Int)
+ sum = new(big.Int)
+ invSum = new(big.Int)
+ zero = big.NewInt(0)
+ )
+
+ // z = x + H(id) (mod p)
+ z.Add(m.x, val2bignum(idPrefix, []byte(id)))
+ z.Mod(z, bn256.Order)
+
+ for {
+ r, err := random()
+ if err != nil {
+ return nil, err
+ }
+ // sum = x + r y + H(id) = z + r y (mod p)
+ sum.Mul(r, m.y)
+ sum.Add(z, sum)
+ sum.Mod(sum, bn256.Order)
+ if sum.Cmp(zero) != 0 {
+ ret.r = r
+ break
+ }
+ }
+
+ invSum.ModInverse(sum, bn256.Order)
+ ret.K.ScalarMult(hHat, invSum)
+ return ret, nil
+}
+
+func (m *bb2master) Params() Params { return m.params }
+
+type bb2params struct {
+ X, Y *bn256.G1
+ v *bn256.GT
+}
+
+func newbb2params() *bb2params {
+ return &bb2params{
+ X: new(bn256.G1),
+ Y: new(bn256.G1),
+ v: new(bn256.GT),
+ }
+}
+
+func (e *bb2params) encapsulateKeyStart(sigma *[encKeySize]byte, s *big.Int, C []byte) error {
+ if len(C) != encKeySize+marshaledG1Size {
+ return fmt.Errorf("provided buffer has size %d, must be %d", len(C), encKeySize+marshaledG1Size)
+ }
+
+ var (
+ 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]
+ )
+ vs.ScalarMult(e.v, s)
+ pad := hashval(ibePrefix, vs.Marshal())
+ // A = sigma ⊕ H(v^s)
+ for i := range sigma {
+ A[i] = sigma[i] ^ pad[i]
+ }
+ // B = Y^s
+ if err := marshalG1(B, tmpG1.ScalarMult(e.Y, s)); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (e *bb2params) Encrypt(id string, m, C []byte) error {
+ if err := checkSizes(m, C, e); err != nil {
+ return err
+ }
+
+ // Choose a random nonce for the Fujisaki-Okamoto transform
+ var sigma [encKeySize]byte
+ if _, err := rand.Read(sigma[:]); err != nil {
+ return err
+ }
+
+ var (
+ s = computeKemRandomness(&sigma, m) // H_1(sigma, m)
+ symKey = computeDemKey(&sigma) // H_2(sigma)
+
+ tmpG1 = new(bn256.G1)
+ // Ciphertext C = (kem, dem)
+ kem = C[0:kemSize]
+ dem = C[kemSize:]
+ )
+
+ // kem = (A, B, C1). Invoke encasulateKeyStart to compute (A, B)
+ if err := e.encapsulateKeyStart(&sigma, s, kem[0:encKeySize+marshaledG1Size]); err != nil {
+ return err
+ }
+ C1 := kem[encKeySize+marshaledG1Size:]
+
+ // C1 = (X g^H(id))^s
+ tmpG1.ScalarBaseMult(val2bignum(idPrefix, []byte(id)))
+ tmpG1.Add(tmpG1, e.X)
+ tmpG1.ScalarMult(tmpG1, s)
+ if err := marshalG1(C1, tmpG1); err != nil {
+ return err
+ }
+
+ // Nonce for symmetric encryption can be all-zeroes string, because
+ // we only require one-time semantic security of the underlying symmetric
+ // scheme in the Fujisaki-Okamoto transformation.
+ var nonce [nonceSize]byte
+ if tmp := secretbox.Seal(dem[0:0], m, &nonce, symKey); &tmp[0] != &dem[0] {
+ return fmt.Errorf("output of Seal has unexpected length: expected %d, received %d", len(dem), len(tmp))
+ }
+
+ return nil
+}
+
+func (e *bb2params) CiphertextOverhead() int {
+ return kemSize + secretbox.Overhead
+}
+
+type bb2PrivateKey struct {
+ params *bb2params // public params
+ r *big.Int
+ K *bn256.G2
+}
+
+func (k *bb2PrivateKey) Decrypt(C, m []byte) error {
+ if err := checkSizes(m, C, k.params); err != nil {
+ return err
+ }
+ var (
+ 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
+ }
+ if _, ok := C1.Unmarshal(C[encKeySize+marshaledG1Size : encKeySize+2*marshaledG1Size]); !ok {
+ return errBadCiphertext
+ }
+
+ // sigma = A ⊕ H(e(B^r C, K)
+ var tmpG1 = new(bn256.G1)
+ tmpG1.ScalarMult(B, k.r)
+ tmpG1.Add(tmpG1, C1)
+ var hash = hashval(ibePrefix, bn256.Pair(tmpG1, k.K).Marshal())
+
+ var sigma [encKeySize]byte
+ for i := range sigma {
+ sigma[i] = A[i] ^ hash[i]
+ }
+
+ symKey := computeDemKey(&sigma)
+
+ var nonce [nonceSize]byte
+ if tmp, success := secretbox.Open(m[0:0], D, &nonce, symKey); !success || (&tmp[0] != &m[0]) {
+ return errBadCiphertext
+ }
+
+ // Check that consistent randomness was used to encrypt the symmetric key. It suffices
+ // to check that the first two components of the KEM portion matches, since given the
+ // message and the secret identity key, the first two components uniquely determine the third.
+
+ // First, derive the randomness used for the KEM.
+ s := computeKemRandomness(&sigma, m)
+
+ // Check the first two components
+ var kemChkBuf [encKeySize + marshaledG1Size]byte
+ k.params.encapsulateKeyStart(&sigma, s, kemChkBuf[:])
+
+ if !bytes.Equal(kemChkBuf[:], C[0:encKeySize+marshaledG1Size]) {
+ return errBadCiphertext
+ }
+ return nil
+}
+
+func (k *bb2PrivateKey) Params() Params { return k.params }
diff --git a/ibe/bb1_test.go b/ibe/bb_test.go
similarity index 65%
rename from ibe/bb1_test.go
rename to ibe/bb_test.go
index fd13fa7..6959413 100644
--- a/ibe/bb1_test.go
+++ b/ibe/bb_test.go
@@ -11,6 +11,8 @@
"testing"
)
+type SetupFunc func() (Master, error)
+
func TestHashVal(t *testing.T) {
var (
prefix0 = [1]byte{0x00}
@@ -29,11 +31,12 @@
}
}
-func TestBB1Correctness(t *testing.T) {
- master, err := SetupBB1()
+func testBBCorrectness(t *testing.T, setup SetupFunc) {
+ master, err := setup()
if err != nil {
t.Fatal(err)
}
+
const (
alice = "alice"
bob = "bob"
@@ -89,15 +92,19 @@
}
}
+func TestBB1Correctness(t *testing.T) { testBBCorrectness(t, SetupBB1) }
+func TestBB2Correctness(t *testing.T) { testBBCorrectness(t, SetupBB2) }
+
// Applying the Fujisaki-Okamoto transformation to the BB1 IBE
// scheme yields a CCA2-secure encryption scheme. Since CCA2-security
// implies non-malleability, we verify that a tampered ciphertext
// does not properly decrypt in this test case.
-func TestBB1NonMalleability(t *testing.T) {
- master, err := SetupBB1()
+func testBBNonMalleability(t *testing.T, setup SetupFunc) {
+ master, err := setup()
if err != nil {
t.Fatal(err)
}
+
const alice = "alice"
aliceSK, err := master.Extract(alice)
if err != nil {
@@ -124,26 +131,30 @@
}
}
-var (
- bb1 Master
- bb1SK PrivateKey
- benchmarkmlen = 64
- benchmarkm = make([]byte, benchmarkmlen)
- bb1C []byte
-)
+func TestBB1NonMalleability(t *testing.T) { testBBNonMalleability(t, SetupBB1) }
+func TestBB2NonMalleability(t *testing.T) { testBBNonMalleability(t, SetupBB2) }
-func TestBB1Marshaling(t *testing.T) {
- bb1P := bb1.Params()
- pbytes, err := MarshalParams(bb1P)
+func testMarshaling(t *testing.T, setup SetupFunc) {
+ master, err := setup()
if err != nil {
t.Fatal(err)
}
- skbytes, err := MarshalPrivateKey(bb1SK)
+
+ bbParams := master.Params()
+ bbSK, err := master.Extract("alice")
+ if err != nil {
+ t.Fatal(err)
+ }
+ pbytes, err := MarshalParams(bbParams)
+ if err != nil {
+ t.Fatal(err)
+ }
+ skbytes, err := MarshalPrivateKey(bbSK)
if err != nil {
t.Fatal(err)
}
m := []byte("01234567899876543210123456789012")
- overhead := bb1P.CiphertextOverhead()
+ overhead := bbParams.CiphertextOverhead()
var (
C1 = make([]byte, len(m)+overhead)
C2 = make([]byte, len(m)+overhead)
@@ -151,9 +162,9 @@
m2 = make([]byte, len(m))
)
// Encrypt with the original params, decrypt with the unmarshaled key.
- if err := bb1P.Encrypt("alice", m, C1); err != nil {
+ if err := bbParams.Encrypt("alice", m, C1); err != nil {
t.Error(err)
- } else if sk, err := UnmarshalPrivateKey(bb1P, skbytes); err != nil {
+ } else if sk, err := UnmarshalPrivateKey(bbParams, skbytes); err != nil {
t.Error(err)
} else if err := sk.Decrypt(C1, m2); err != nil {
t.Error(err)
@@ -165,7 +176,7 @@
t.Error(err)
} else if err := p.Encrypt("alice", m, C2); err != nil {
t.Error(err)
- } else if err := bb1SK.Decrypt(C2, m1); err != nil {
+ } else if err := bbSK.Decrypt(C2, m1); err != nil {
t.Error(err)
} else if !bytes.Equal(m, m1) {
t.Errorf("Got %q, want %q", m, m1)
@@ -175,14 +186,14 @@
if _, err := UnmarshalParams(pbytes[:len(pbytes)-1]); err == nil {
t.Errorf("UnmarshalParams succeeded on truncated input")
}
- if _, err := UnmarshalPrivateKey(bb1P, skbytes[:len(skbytes)-1]); err == nil {
+ if _, err := UnmarshalPrivateKey(bbParams, skbytes[:len(skbytes)-1]); err == nil {
t.Errorf("UnmarshalPrivateKey succeeded on truncated input")
}
// Extension errors
if _, err := UnmarshalParams(append(pbytes, 0)); err == nil {
t.Errorf("UnmarshalParams succeeded on extended input")
}
- if _, err := UnmarshalPrivateKey(bb1P, append(skbytes, 0)); err == nil {
+ if _, err := UnmarshalPrivateKey(bbParams, append(skbytes, 0)); err == nil {
t.Errorf("UnmarshalPrivateKey succeeded on extended input")
}
// Zero length (no valid header either)
@@ -192,42 +203,62 @@
if _, err := UnmarshalParams([]byte{}); err == nil {
t.Errorf("UnmarshalParams succeeded on zero length input")
}
- if _, err := UnmarshalPrivateKey(bb1P, nil); err == nil {
+ if _, err := UnmarshalPrivateKey(bbParams, nil); err == nil {
t.Errorf("UnmarshalPrivateKey succeeded on nil input")
}
- if _, err := UnmarshalPrivateKey(bb1P, []byte{}); err == nil {
+ if _, err := UnmarshalPrivateKey(bbParams, []byte{}); err == nil {
t.Errorf("UnmarshalPrivateKey succeeded on zero length input")
}
}
-func init() {
- var err error
- if bb1, err = SetupBB1(); err != nil {
+func TestBB1Marshaling(t *testing.T) { testMarshaling(t, SetupBB1) }
+func TestBB2Marshaling(t *testing.T) { testMarshaling(t, SetupBB2) }
+
+var (
+ benchmarkmlen = 64
+ benchmarkm = make([]byte, benchmarkmlen)
+ bb1, bb1SK, bb1C = initSchemeParams(SetupBB1)
+ bb2, bb2SK, bb2C = initSchemeParams(SetupBB2)
+)
+
+func initSchemeParams(setup SetupFunc) (Master, PrivateKey, []byte) {
+ var (
+ err error
+ bbParams Master
+ bbSK PrivateKey
+ bbC []byte
+ )
+ if bbParams, err = setup(); err != nil {
panic(err)
}
- if bb1SK, err = bb1.Extract("alice"); err != nil {
+ if bbSK, err = bbParams.Extract("alice"); err != nil {
panic(err)
}
if _, err := rand.Read(benchmarkm[:]); err != nil {
panic(err)
}
- overhead := bb1.Params().CiphertextOverhead()
- bb1C = make([]byte, benchmarkmlen+overhead)
- if err := bb1.Params().Encrypt("alice", benchmarkm, bb1C); err != nil {
+ overhead := bbParams.Params().CiphertextOverhead()
+ bbC = make([]byte, benchmarkmlen+overhead)
+ if err := bbParams.Params().Encrypt("alice", benchmarkm, bbC); err != nil {
panic(err)
}
+
+ return bbParams, bbSK, bbC
}
-func BenchmarkExtractBB1(b *testing.B) {
+func benchmarkExtractBB(b *testing.B, bb Master) {
for i := 0; i < b.N; i++ {
- if _, err := bb1.Extract("alice"); err != nil {
+ if _, err := bb.Extract("alice"); err != nil {
b.Fatal(err)
}
}
}
-func BenchmarkEncryptBB(b *testing.B) {
- p := bb1.Params()
+func BenchmarkExtractBB1(b *testing.B) { benchmarkExtractBB(b, bb1) }
+func BenchmarkExtractBB2(b *testing.B) { benchmarkExtractBB(b, bb2) }
+
+func benchmarkEncryptBB(b *testing.B, bb Master) {
+ p := bb.Params()
C := make([]byte, benchmarkmlen+p.CiphertextOverhead())
for i := 0; i < b.N; i++ {
if err := p.Encrypt("alice", benchmarkm, C); err != nil {
@@ -236,11 +267,17 @@
}
}
-func BenchmarkDecryptBB(b *testing.B) {
+func BenchmarkEncryptBB1(b *testing.B) { benchmarkEncryptBB(b, bb1) }
+func BenchmarkEncryptBB2(b *testing.B) { benchmarkEncryptBB(b, bb2) }
+
+func benchmarkDecryptBB(b *testing.B, bbSK PrivateKey, bbC []byte) {
m := make([]byte, benchmarkmlen)
for i := 0; i < b.N; i++ {
- if err := bb1SK.Decrypt(bb1C, m); err != nil {
+ if err := bbSK.Decrypt(bbC, m); err != nil {
b.Fatal(err)
}
}
}
+
+func BenchmarkDecryptBB1(b *testing.B) { benchmarkDecryptBB(b, bb1SK, bb1C) }
+func BenchmarkDecryptBB2(b *testing.B) { benchmarkDecryptBB(b, bb2SK, bb2C) }
diff --git a/ibe/marshal.go b/ibe/marshal.go
index 77859c7..de6dc70 100644
--- a/ibe/marshal.go
+++ b/ibe/marshal.go
@@ -17,16 +17,30 @@
type marshaledType byte
const (
+ // size of field element (256 bits = 32 bytes)
+ fieldElemSize = 32
+
// types of encoded bytes, 1 byte
typeBB1Params marshaledType = 0
typeBB1PrivateKey = 1
+ typeBB2Params = 2
+ typeBB2PrivateKey = 3
// Sizes excluding the magic number and type header.
headerSize = 3
marshaledBB1ParamsSize = 2*marshaledG1Size + 2*marshaledG2Size + marshaledGTSize
marshaledBB1PrivateKeySize = 2 * marshaledG2Size
+ marshaledBB2ParamsSize = 2*marshaledG1Size + marshaledGTSize
+ marshaledBB2PrivateKeySize = fieldElemSize + marshaledG2Size
)
+func writeFieldElement(elem *big.Int) []byte {
+ elemBytes := elem.Bytes()
+ ret := make([]byte, fieldElemSize)
+ copy(ret[fieldElemSize-len(elemBytes):], elemBytes)
+ return ret
+}
+
func writeHeader(typ marshaledType) []byte {
ret := make([]byte, headerSize)
copy(ret, magicNumber)
@@ -63,6 +77,17 @@
ret = append(ret, field...)
}
return ret, nil
+ case *bb2params:
+ ret := make([]byte, 0, headerSize+marshaledBB2ParamsSize)
+ for _, field := range [][]byte{
+ writeHeader(typeBB2Params),
+ p.X.Marshal(),
+ p.Y.Marshal(),
+ p.v.Marshal(),
+ } {
+ ret = append(ret, field...)
+ }
+ return ret, nil
default:
return nil, fmt.Errorf("MarshalParams for %T for implemented yet", p)
}
@@ -105,6 +130,21 @@
return nil, fmt.Errorf("failed to unmarshal v")
}
return p, nil
+ case typeBB2Params:
+ if len(data) != marshaledBB2ParamsSize {
+ return nil, fmt.Errorf("invalid size")
+ }
+ p := newbb2params()
+ if _, ok := p.X.Unmarshal(advance(marshaledG1Size)); !ok {
+ return nil, fmt.Errorf("failed to unmarshal X")
+ }
+ if _, ok := p.Y.Unmarshal(advance(marshaledG1Size)); !ok {
+ return nil, fmt.Errorf("failed to unmarshal Y")
+ }
+ if _, ok := p.v.Unmarshal(advance(marshaledGTSize)); !ok {
+ return nil, fmt.Errorf("failed to unmarshal v")
+ }
+ return p, nil
default:
return nil, fmt.Errorf("unrecognized Params type (%d)", typ)
}
@@ -123,6 +163,16 @@
ret = append(ret, field...)
}
return ret, nil
+ case *bb2PrivateKey:
+ ret := make([]byte, 0, headerSize+marshaledBB2PrivateKeySize)
+ for _, field := range [][]byte{
+ writeHeader(typeBB2PrivateKey),
+ writeFieldElement(k.r),
+ k.K.Marshal(),
+ } {
+ ret = append(ret, field...)
+ }
+ return ret, nil
default:
return nil, fmt.Errorf("MarshalPrivateKey for %T for implemented yet", k)
}
@@ -162,6 +212,25 @@
*(k.params) = *p
}
return k, nil
+ case typeBB2PrivateKey:
+ if len(data) != marshaledBB2PrivateKeySize {
+ return nil, fmt.Errorf("invalid size")
+ }
+ k := &bb2PrivateKey{
+ r: new(big.Int),
+ K: new(bn256.G2),
+ }
+ k.r.SetBytes(advance(fieldElemSize))
+ if _, ok := k.K.Unmarshal(advance(marshaledG2Size)); !ok {
+ return nil, fmt.Errorf("failed to unmarshal K")
+ }
+ if p, ok := params.(*bb2params); !ok {
+ return nil, fmt.Errorf("params type %T incompatible with %T", params, k)
+ } else {
+ k.params = new(bb2params)
+ *(k.params) = *p
+ }
+ return k, nil
default:
return nil, fmt.Errorf("unrecognized private key type (%d)", typ)
}