"x/lib": Marshal IBE master

This CL adds methods to marshal and unmarshal the private
component of an IBE Master. These methods will be used by
a service that hosts an IBE master object for issuing
IBE private keys.

Change-Id: Iaee881fe24c5b01d6205b2b12be628e81641af88
diff --git a/ibe/.api b/ibe/.api
index 0d242a4..4140a05 100644
--- a/ibe/.api
+++ b/ibe/.api
@@ -1,7 +1,9 @@
+pkg ibe, func MarshalMasterKey(Master) ([]byte, error)
 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 UnmarshalMasterKey(Params, []byte) (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/bb_test.go b/ibe/bb_test.go
index 6959413..6973497 100644
--- a/ibe/bb_test.go
+++ b/ibe/bb_test.go
@@ -153,6 +153,10 @@
 	if err != nil {
 		t.Fatal(err)
 	}
+	mkbytes, err := MarshalMasterKey(master)
+	if err != nil {
+		t.Fatal(err)
+	}
 	m := []byte("01234567899876543210123456789012")
 	overhead := bbParams.CiphertextOverhead()
 	var (
@@ -161,6 +165,19 @@
 		m1 = make([]byte, len(m))
 		m2 = make([]byte, len(m))
 	)
+	// Encrypt with the original params, decrypt with key extracted from unmarshaled
+	// master key.
+	if err := bbParams.Encrypt("alice", m, C1); err != nil {
+		t.Error(err)
+	} else if mk, err := UnmarshalMasterKey(bbParams, mkbytes); err != nil {
+		t.Error(err)
+	} else if bbSK, err := mk.Extract("alice"); err != nil {
+		t.Error(err)
+	} else if err := bbSK.Decrypt(C1, m2); err != nil {
+		t.Error(err)
+	} else if !bytes.Equal(m, m2) {
+		t.Errorf("Got %q, want %q", m, m2)
+	}
 	// Encrypt with the original params, decrypt with the unmarshaled key.
 	if err := bbParams.Encrypt("alice", m, C1); err != nil {
 		t.Error(err)
@@ -189,6 +206,9 @@
 	if _, err := UnmarshalPrivateKey(bbParams, skbytes[:len(skbytes)-1]); err == nil {
 		t.Errorf("UnmarshalPrivateKey succeeded on truncated input")
 	}
+	if _, err := UnmarshalMasterKey(bbParams, mkbytes[:len(mkbytes)-1]); err == nil {
+		t.Errorf("UnmarshalMasterKey succeeded on truncated input")
+	}
 	// Extension errors
 	if _, err := UnmarshalParams(append(pbytes, 0)); err == nil {
 		t.Errorf("UnmarshalParams succeeded on extended input")
@@ -196,6 +216,9 @@
 	if _, err := UnmarshalPrivateKey(bbParams, append(skbytes, 0)); err == nil {
 		t.Errorf("UnmarshalPrivateKey succeeded on extended input")
 	}
+	if _, err := UnmarshalMasterKey(bbParams, append(mkbytes, 0)); err == nil {
+		t.Errorf("UnmarshalMasterKey succeeded on extended input")
+	}
 	// Zero length (no valid header either)
 	if _, err := UnmarshalParams(nil); err == nil {
 		t.Errorf("UnmarshalParams succeeded on nil input")
@@ -209,6 +232,12 @@
 	if _, err := UnmarshalPrivateKey(bbParams, []byte{}); err == nil {
 		t.Errorf("UnmarshalPrivateKey succeeded on zero length input")
 	}
+	if _, err := UnmarshalMasterKey(bbParams, nil); err == nil {
+		t.Errorf("UnmarshalMasterKey succeeded on nil input")
+	}
+	if _, err := UnmarshalMasterKey(bbParams, []byte{}); err == nil {
+		t.Errorf("UnmarshalMasterKey succeeded on zero length input")
+	}
 }
 
 func TestBB1Marshaling(t *testing.T) { testMarshaling(t, SetupBB1) }
diff --git a/ibe/marshal.go b/ibe/marshal.go
index de6dc70..707d731 100644
--- a/ibe/marshal.go
+++ b/ibe/marshal.go
@@ -23,15 +23,19 @@
 	// types of encoded bytes, 1 byte
 	typeBB1Params     marshaledType = 0
 	typeBB1PrivateKey               = 1
-	typeBB2Params                   = 2
-	typeBB2PrivateKey               = 3
+	typeBB1MasterKey                = 2
+	typeBB2Params                   = 3
+	typeBB2PrivateKey               = 4
+	typeBB2MasterKey                = 5
 
 	// Sizes excluding the magic number and type header.
 	headerSize                 = 3
 	marshaledBB1ParamsSize     = 2*marshaledG1Size + 2*marshaledG2Size + marshaledGTSize
 	marshaledBB1PrivateKeySize = 2 * marshaledG2Size
+	marshaledBB1MasterKeySize  = marshaledG2Size
 	marshaledBB2ParamsSize     = 2*marshaledG1Size + marshaledGTSize
 	marshaledBB2PrivateKeySize = fieldElemSize + marshaledG2Size
+	marshaledBB2MasterKeySize  = 2*fieldElemSize + marshaledG2Size
 )
 
 func writeFieldElement(elem *big.Int) []byte {
@@ -174,7 +178,7 @@
 		}
 		return ret, nil
 	default:
-		return nil, fmt.Errorf("MarshalPrivateKey for %T for implemented yet", k)
+		return nil, fmt.Errorf("MarshalPrivateKey for %T not implemented yet", k)
 	}
 }
 
@@ -235,3 +239,87 @@
 		return nil, fmt.Errorf("unrecognized private key type (%d)", typ)
 	}
 }
+
+// MarshalMasterKey encodes the private component of m into a byte slice.
+func MarshalMasterKey(m Master) ([]byte, error) {
+	switch m := m.(type) {
+	case *bb1master:
+		ret := make([]byte, 0, headerSize+marshaledBB1MasterKeySize)
+		for _, field := range [][]byte{
+			writeHeader(typeBB1MasterKey),
+			m.g0Hat.Marshal(),
+		} {
+			ret = append(ret, field...)
+		}
+		return ret, nil
+	case *bb2master:
+		ret := make([]byte, 0, headerSize+marshaledBB2MasterKeySize)
+		for _, field := range [][]byte{
+			writeHeader(typeBB2MasterKey),
+			writeFieldElement(m.x),
+			writeFieldElement(m.y),
+			m.hHat.Marshal(),
+		} {
+			ret = append(ret, field...)
+		}
+		return ret, nil
+	default:
+		return nil, fmt.Errorf("MarshalMasterKey for %T not implemented yet", m)
+	}
+}
+
+// UnmarshalMasterKey parses an encoded Master object.
+func UnmarshalMasterKey(params Params, data []byte) (Master, error) {
+	var typ marshaledType
+	var err error
+	if typ, data, err = readHeader(data); err != nil {
+		return nil, err
+	}
+	advance := func(n int) []byte {
+		ret := data[0:n]
+		data = data[n:]
+		return ret
+	}
+	switch typ {
+	case typeBB1MasterKey:
+		if len(data) != marshaledBB1MasterKeySize {
+			return nil, fmt.Errorf("invalid size")
+		}
+		m := &bb1master{
+			g0Hat: new(bn256.G2),
+		}
+		if _, ok := m.g0Hat.Unmarshal(advance(marshaledG2Size)); !ok {
+			return nil, fmt.Errorf("failed to unmarshal g0Hat")
+		}
+		p, ok := params.(*bb1params)
+		if !ok {
+			return nil, fmt.Errorf("params type %T incompatible with %T", params, m)
+		}
+		m.params = new(bb1params)
+		*(m.params) = *p
+		return m, nil
+	case typeBB2MasterKey:
+		if len(data) != marshaledBB2MasterKeySize {
+			return nil, fmt.Errorf("invalid size")
+		}
+		m := &bb2master{
+			x:    new(big.Int),
+			y:    new(big.Int),
+			hHat: new(bn256.G2),
+		}
+		m.x.SetBytes(advance(fieldElemSize))
+		m.y.SetBytes(advance(fieldElemSize))
+		if _, ok := m.hHat.Unmarshal(advance(marshaledG2Size)); !ok {
+			return nil, fmt.Errorf("failed to unmarshal hHat")
+		}
+		p, ok := params.(*bb2params)
+		if !ok {
+			return nil, fmt.Errorf("params type %T incompatible with %T", params, m)
+		}
+		m.params = new(bb2params)
+		*(m.params) = *p
+		return m, nil
+	default:
+		return nil, fmt.Errorf("unrecognized master key type (%d)", typ)
+	}
+}