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)
 	}