Merge "x/lib/ibe: Marshaling/Unmarshaling functions."
diff --git a/ibe/.api b/ibe/.api
index dcdc2f2..7bbaf0c 100644
--- a/ibe/.api
+++ b/ibe/.api
@@ -1,4 +1,8 @@
+pkg ibe, func MarshalParams(Params) ([]byte, error)
+pkg ibe, func MarshalPrivateKey(PrivateKey) ([]byte, error)
pkg ibe, func SetupBB1() (Master, error)
+pkg ibe, func UnmarshalParams([]byte) (Params, error)
+pkg ibe, func UnmarshalPrivateKey(Params, []byte) (PrivateKey, error)
pkg ibe, type Ciphertext [160]byte
pkg ibe, type Master interface { Extract, Params }
pkg ibe, type Master interface, Extract(string) (PrivateKey, error)
diff --git a/ibe/bb1.go b/ibe/bb1.go
index 782f163..71e6937 100644
--- a/ibe/bb1.go
+++ b/ibe/bb1.go
@@ -23,7 +23,11 @@
var errBadCiphertext = errors.New("invalid ciphertext")
-const marshaledG1Size = 64
+const (
+ marshaledG1Size = 2 * 32
+ marshaledG2Size = 4 * 32
+ marshaledGTSize = 12 * 32
+)
// Setup creates an ibe.Master based on the BB1 scheme described in "Efficient
// Selective Identity-Based Encryption Without Random Oracles" by Dan Boneh and
diff --git a/ibe/bb1_test.go b/ibe/bb1_test.go
index cbd5854..8a8f4e8 100644
--- a/ibe/bb1_test.go
+++ b/ibe/bb1_test.go
@@ -80,6 +80,72 @@
bb1C Ciphertext
)
+func TestBB1Marshaling(t *testing.T) {
+ bb1P := bb1.Params()
+ pbytes, err := MarshalParams(bb1P)
+ if err != nil {
+ t.Fatal(err)
+ }
+ skbytes, err := MarshalPrivateKey(bb1SK)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var m Plaintext
+ if n := copy(m[:], []byte("01234567899876543210123456789012")); n != len(m) {
+ t.Fatalf("%v vs. %v", n, len(m))
+ }
+ var C1, C2 Ciphertext
+ var m1, m2 Plaintext
+ // Encrypt with the original params, decrypt with the unmarshaled key.
+ if err := bb1P.Encrypt("alice", &m, &C1); err != nil {
+ t.Error(err)
+ } else if sk, err := UnmarshalPrivateKey(bb1P, skbytes); err != nil {
+ t.Error(err)
+ } else if err := sk.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 unmarshaled params, decrypt with the original key.
+ if p, err := UnmarshalParams(pbytes); err != nil {
+ 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 {
+ t.Error(err)
+ } else if !bytes.Equal(m[:], m1[:]) {
+ t.Errorf("Got %q, want %q", m, m1)
+ }
+
+ // Truncation errors
+ 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 {
+ 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 {
+ t.Errorf("UnmarshalPrivateKey succeeded on extended input")
+ }
+ // Zero length (no valid header either)
+ if _, err := UnmarshalParams(nil); err == nil {
+ t.Errorf("UnmarshalParams succeeded on nil input")
+ }
+ if _, err := UnmarshalParams([]byte{}); err == nil {
+ t.Errorf("UnmarshalParams succeeded on zero length input")
+ }
+ if _, err := UnmarshalPrivateKey(bb1P, nil); err == nil {
+ t.Errorf("UnmarshalPrivateKey succeeded on nil input")
+ }
+ if _, err := UnmarshalPrivateKey(bb1P, []byte{}); err == nil {
+ t.Errorf("UnmarshalPrivateKey succeeded on zero length input")
+ }
+}
+
func init() {
var err error
if bb1, err = SetupBB1(); err != nil {
diff --git a/ibe/marshal.go b/ibe/marshal.go
new file mode 100644
index 0000000..ca6bae4
--- /dev/null
+++ b/ibe/marshal.go
@@ -0,0 +1,165 @@
+// Copyright 2015 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.
+
+package ibe
+
+import (
+ "bytes"
+ "fmt"
+ "math/big"
+
+ "golang.org/x/crypto/bn256"
+)
+
+var magicNumber = []byte{0x1b, 0xe0} // prefix that appears in the marshaled form: 2 bytes
+
+type marshaledType byte
+
+const (
+ // types of encoded bytes, 1 byte
+ typeBB1Params marshaledType = 0
+ typeBB1PrivateKey = 1
+
+ // Sizes excluding the magic number and type header.
+ headerSize = 3
+ marshaledBB1ParamsSize = 2*marshaledG1Size + 2*marshaledG2Size + marshaledGTSize
+ marshaledBB1PrivateKeySize = 2 * marshaledG2Size
+)
+
+func writeHeader(typ marshaledType) []byte {
+ ret := make([]byte, headerSize)
+ copy(ret, magicNumber)
+ ret[len(magicNumber)] = byte(typ)
+ return ret
+}
+
+// readHeader parses hdr and returns the message type and the remainder of the
+// message, excluding the header.
+func readHeader(hdr []byte) (marshaledType, []byte, error) {
+ if len(hdr) < headerSize {
+ return 0, nil, fmt.Errorf("header is too small")
+ }
+ if !bytes.Equal(hdr[0:len(magicNumber)], magicNumber) {
+ return 0, nil, fmt.Errorf("invalid magic number")
+ }
+ return marshaledType(hdr[len(magicNumber)]), hdr[headerSize:], nil
+}
+
+// MarshalParams encodes p into a byte slice.
+func MarshalParams(p Params) ([]byte, error) {
+ switch p := p.(type) {
+ case *bb1params:
+ ret := make([]byte, 0, headerSize+marshaledBB1ParamsSize)
+ // g and gHat are the generators, do not need to be marshaled.
+ for _, field := range [][]byte{
+ writeHeader(typeBB1Params),
+ p.g1.Marshal(),
+ p.h.Marshal(),
+ p.g1Hat.Marshal(),
+ p.hHat.Marshal(),
+ p.v.Marshal(),
+ } {
+ ret = append(ret, field...)
+ }
+ return ret, nil
+ default:
+ return nil, fmt.Errorf("MarshalParams for %T for implemented yet", p)
+ }
+}
+
+// UnmarshalParams parses an encoded Params object.
+func UnmarshalParams(data []byte) (Params, 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 typeBB1Params:
+ if len(data) != marshaledBB1ParamsSize {
+ return nil, fmt.Errorf("invalid size")
+ }
+ p := &bb1params{v: new(bn256.GT)}
+ one := big.NewInt(1)
+ p.g.ScalarBaseMult(one)
+ p.gHat.ScalarBaseMult(one)
+ if _, ok := p.g1.Unmarshal(advance(marshaledG1Size)); !ok {
+ return nil, fmt.Errorf("failed to unmarshal g1")
+ }
+ if _, ok := p.h.Unmarshal(advance(marshaledG1Size)); !ok {
+ return nil, fmt.Errorf("failed to unmarshal h")
+ }
+ if _, ok := p.g1Hat.Unmarshal(advance(marshaledG2Size)); !ok {
+ return nil, fmt.Errorf("failed to unmarshal g1Hat")
+ }
+ if _, ok := p.hHat.Unmarshal(advance(marshaledG2Size)); !ok {
+ return nil, fmt.Errorf("failed to unmarshal hHat")
+ }
+ 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)
+ }
+}
+
+// MarshalPrivateKey encodes the private component of k into a byte slice.
+func MarshalPrivateKey(k PrivateKey) ([]byte, error) {
+ switch k := k.(type) {
+ case *bb1PrivateKey:
+ ret := make([]byte, 0, headerSize+marshaledBB1PrivateKeySize)
+ for _, field := range [][]byte{
+ writeHeader(typeBB1PrivateKey),
+ k.d0.Marshal(),
+ k.d1.Marshal(),
+ } {
+ ret = append(ret, field...)
+ }
+ return ret, nil
+ default:
+ return nil, fmt.Errorf("MarshalPrivateKey for %T for implemented yet", k)
+ }
+}
+
+// UnmarshalPrivateKey parses an encoded PrivateKey object.
+func UnmarshalPrivateKey(params Params, data []byte) (PrivateKey, 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 typeBB1PrivateKey:
+ if len(data) != marshaledBB1PrivateKeySize {
+ return nil, fmt.Errorf("invalid size")
+ }
+ k := new(bb1PrivateKey)
+ if _, ok := k.d0.Unmarshal(advance(marshaledG2Size)); !ok {
+ return nil, fmt.Errorf("failed to unmarshal d0")
+ }
+ if _, ok := k.d1.Unmarshal(advance(marshaledG2Size)); !ok {
+ return nil, fmt.Errorf("failed to unmarshal d1")
+ }
+ if p, ok := params.(*bb1params); !ok {
+ return nil, fmt.Errorf("params type %T incompatible with %T", params, k)
+ } else {
+ k.params = new(bb1params)
+ *(k.params) = *p
+ }
+ return k, nil
+ default:
+ return nil, fmt.Errorf("unrecognized private key type (%d)", typ)
+ }
+}