Skip to content

Commit

Permalink
Start filling out high-level API
Browse files Browse the repository at this point in the history
  • Loading branch information
chris-wood committed Oct 13, 2023
1 parent a00adb5 commit 5007a76
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 50 deletions.
109 changes: 75 additions & 34 deletions bbs/bbs.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ func (s Signature) Encode() []byte {
return append(AEnc, eEnc...)
}

// XXX(caw): rename this function
func octetsToSignature(data []byte) (Signature, error) {
func UnmarshalSignature(data []byte) (Signature, error) {
// 1. expected_len = octet_point_length + octet_scalar_length
expectedLen := octetPointLen + octetScalarLen
// 2. if length(signature_octets) != expected_len, return INVALID
Expand Down Expand Up @@ -85,7 +84,6 @@ func octetsToSignature(data []byte) (Signature, error) {
}, nil
}

// (Abar, Bbar, r2^, r3^, (m^_j1, ..., m^_jU), c)
type Proof struct {
Abar *pairing.G1
Bbar *pairing.G1
Expand All @@ -95,14 +93,66 @@ type Proof struct {
c *pairing.Scalar
}

func (p Proof) Encode() []byte {
ABarEnc := p.Abar.BytesCompressed()
BBarEnc := p.Bbar.BytesCompressed()
r2hEnc, err := p.r2h.MarshalBinary()
if err != nil {
panic(err)
}
r3hEnc, err := p.r3h.MarshalBinary()
if err != nil {
panic(err)
}
cEnc, err := p.c.MarshalBinary()
if err != nil {
panic(err)
}

result := append(ABarEnc, BBarEnc...)
result = append(result, r2hEnc...)
result = append(result, r3hEnc...)
for i := 0; i < len(p.commitments); i++ {
commitmentEnc, err := p.commitments[i].MarshalBinary()
if err != nil {
panic(err)
}
result = append(result, commitmentEnc...)
}
result = append(result, cEnc...)
return result
}

type SecretKey struct {
sk *pairing.Scalar
}

type PublicKey []byte

func (s SecretKey) Public() PublicKey {
W := pairing.G2Generator()
W.ScalarMult(s.sk, W)

// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bbs-signatures-03#section-6.2.2-3
return W.BytesCompressed()
}

func (s SecretKey) Encode() []byte {
enc, err := s.sk.MarshalBinary()
if err != nil {
panic(err)
}
return enc
}

// Key generation
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bbs-signatures-03#name-key-generation-operations
func keyGen(ikm []byte, keyInfo, keyDst []byte) (*pairing.Scalar, error) {
func KeyGen(ikm []byte, keyInfo, keyDst []byte) (SecretKey, error) {
if len(ikm) < 32 {
return nil, fmt.Errorf("bbs: invalid keyGen ikm")
return SecretKey{}, fmt.Errorf("bbs: invalid keyGen ikm")
}
if len(keyInfo) > 65535 {
return nil, fmt.Errorf("bbs: invalid keyGen keyInfo")
return SecretKey{}, fmt.Errorf("bbs: invalid keyGen keyInfo")
}
if keyDst == nil {
// keyDst = ciphersuite_id || "KEYGEN_DST_"
Expand All @@ -120,15 +170,9 @@ func keyGen(ikm []byte, keyInfo, keyDst []byte) (*pairing.Scalar, error) {
// if SK is INVALID, return INVALID
// XXX(caw): what does it mean for SK to be invalid if hash_to_scalar never returns an invalid scalar?

return sk, nil
}

func publicKey(sk *pairing.Scalar) []byte {
W := pairing.G2Generator()
W.ScalarMult(sk, W)

// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bbs-signatures-03#section-6.2.2-3
return W.BytesCompressed()
return SecretKey{
sk: sk,
}, nil
}

// Domain calculation
Expand Down Expand Up @@ -168,7 +212,6 @@ func encodeInt(x int) []byte {
}

func concat(x, y []byte) []byte {
// fmt.Println(hex.EncodeToString(y))
return append(x, y...)
}

Expand Down Expand Up @@ -214,8 +257,8 @@ func calculateChallenge(Abar, Bbar, C *pairing.G1, indexArray []int, msgArray []
challengeInput = concat(challengeInput, encodeInt(len(ph)))
challengeInput = concat(challengeInput, ph)

dst := []byte("TODO")
return hashToScalar(challengeInput, dst), nil
// XXX(caw): this should have an explicit DST
return hashToScalar(challengeInput, nil), nil
}

// Generators calculation
Expand All @@ -230,6 +273,9 @@ func hashToGenerators(count int, generatorSeed []byte) []*pairing.G1 {
// ABORT if:

// 1. count > 2^64 - 1
if uint64(count) > ^uint64(0) {
panic("invalid invocation")
}

// Procedure:

Expand Down Expand Up @@ -267,7 +313,7 @@ func hashToCurveG1(seed []byte, dst []byte) *pairing.G1 {

// Signature generation
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bbs-signatures-03#name-signature-generation-sign
func rawSign(sk *pairing.Scalar, pk []byte, header []byte, messages [][]byte) (Signature, error) {
func rawSign(sk SecretKey, pk []byte, header []byte, messages [][]byte) (Signature, error) {
// Deserialization:

// 1. L = length(messages)
Expand All @@ -285,7 +331,7 @@ func rawSign(sk *pairing.Scalar, pk []byte, header []byte, messages [][]byte) (S
domain := calculateDomain(pk, generators[0], generators[1:], header)

// e_input = serialize((SK, domain, msg_1, ..., msg_L))
skEnc, err := sk.MarshalBinary()
skEnc, err := sk.sk.MarshalBinary()
if err != nil {
return Signature{}, err
}
Expand Down Expand Up @@ -319,7 +365,7 @@ func rawSign(sk *pairing.Scalar, pk []byte, header []byte, messages [][]byte) (S

// 5. A = B * (1 / (SK + e))
skE := &pairing.Scalar{}
skE.Add(sk, e)
skE.Add(sk.sk, e)
skEInv := &pairing.Scalar{}
skEInv.Inv(skE)
A := &pairing.G1{}
Expand All @@ -332,7 +378,7 @@ func rawSign(sk *pairing.Scalar, pk []byte, header []byte, messages [][]byte) (S
}, nil
}

func sign(sk *pairing.Scalar, pk []byte, header []byte, messages [][]byte) ([]byte, error) {
func Sign(sk SecretKey, pk []byte, header []byte, messages [][]byte) ([]byte, error) {
sig, err := rawSign(sk, pk, header, messages)
if err != nil {
return nil, err
Expand Down Expand Up @@ -392,19 +438,14 @@ func rawVerify(pk []byte, signature Signature, header []byte, messages [][]byte)

}

func verify(pk, signature, header []byte, messages [][]byte) error {
// Deserialization:

func Verify(pk PublicKey, signature, header []byte, messages [][]byte) error {
// 1. signature_result = octets_to_signature(signature)
// 2. if signature_result is INVALID, return INVALID
// 3. (A, e) = signature_result
// 4. W = octets_to_pubkey(PK)
// 5. if W is INVALID, return INVALID
// 6. L = length(messages)
// 7. (msg_1, ..., msg_L) = messages_to_scalars(messages)

// XXX(caw): invoke rawVerify with the deserialized values
return nil
sig, err := UnmarshalSignature(signature)
if err != nil {
return err
}

return rawVerify(pk, sig, header, messages)
}

// Random scalars
Expand Down
75 changes: 59 additions & 16 deletions bbs/bbs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,16 @@ func TestKeyGen(t *testing.T) {
expectedSkEnc := mustDecodeHex("60e55110f76883a13d030b2f6bd11883422d5abde717569fc0731f51237169fc")
expectedPkEnc := mustDecodeHex("a820f230f6ae38503b86c70dc50b61c58a77e45c39ab25c0652bbaa8fa136f2851bd4781c9dcde39fc9d1d52c9e60268061e7d7632171d91aa8d460acee0e96f1e7c4cfb12d3ff9ab5d5dc91c277db75c845d649ef3c4f63aebc364cd55ded0c")

sk, err := keyGen(ikm, keyInfo, nil)
if err != nil {
t.Fatal(err)
}
skEnc, err := sk.MarshalBinary()
sk, err := KeyGen(ikm, keyInfo, nil)
if err != nil {
t.Fatal(err)
}
skEnc := sk.Encode()
if !bytes.Equal(skEnc, expectedSkEnc) {
t.Fatalf("derived secret key mismatch, got %s, wanted %s", hex.EncodeToString(skEnc), hex.EncodeToString(expectedSkEnc))
}

pkEnc := publicKey(sk)
pkEnc := sk.Public()
if !bytes.Equal(pkEnc, expectedPkEnc) {
t.Fatalf("derived public key mismatch, got %s, wanted %s", hex.EncodeToString(pkEnc), hex.EncodeToString(expectedPkEnc))
}
Expand Down Expand Up @@ -158,12 +155,12 @@ func TestSingleMessageSignature(t *testing.T) {
ikm := mustDecodeHex("746869732d49532d6a7573742d616e2d546573742d494b4d2d746f2d67656e65726174652d246528724074232d6b6579")
keyInfo := mustDecodeHex("746869732d49532d736f6d652d6b65792d6d657461646174612d746f2d62652d757365642d696e2d746573742d6b65792d67656e")

sk, err := keyGen(ikm, keyInfo, nil)
sk, err := KeyGen(ikm, keyInfo, nil)
if err != nil {
t.Fatal(err)
}

sig, err := rawSign(sk, publicKey(sk), header, messages)
sig, err := rawSign(sk, sk.Public(), header, messages)
if err != nil {
t.Fatal(err)
}
Expand All @@ -183,12 +180,12 @@ func TestMultiMessageSignature(t *testing.T) {
ikm := mustDecodeHex("746869732d49532d6a7573742d616e2d546573742d494b4d2d746f2d67656e65726174652d246528724074232d6b6579")
keyInfo := mustDecodeHex("746869732d49532d736f6d652d6b65792d6d657461646174612d746f2d62652d757365642d696e2d746573742d6b65792d67656e")

sk, err := keyGen(ikm, keyInfo, nil)
sk, err := KeyGen(ikm, keyInfo, nil)
if err != nil {
t.Fatal(err)
}

sig, err := rawSign(sk, publicKey(sk), header, messages)
sig, err := rawSign(sk, sk.Public(), header, messages)
if err != nil {
t.Fatal(err)
}
Expand All @@ -199,12 +196,12 @@ func TestMultiMessageSignature(t *testing.T) {
}
}

func TestRoundTrip(t *testing.T) {
func TestRawRoundTrip(t *testing.T) {
ikm := make([]byte, 32)
keyInfo := []byte{}
keyDst := []byte{}

sk, err := keyGen(ikm, keyInfo, keyDst)
sk, err := KeyGen(ikm, keyInfo, keyDst)
if err != nil {
t.Fatal(err)
}
Expand All @@ -219,12 +216,12 @@ func TestRoundTrip(t *testing.T) {
messages[1] = []byte("bar")
messages[1] = []byte("baz")

sig, err := rawSign(sk, publicKey(sk), header, messages)
sig, err := rawSign(sk, sk.Public(), header, messages)
if err != nil {
t.Fatal(err)
}

err = rawVerify(publicKey(sk), sig, header, messages)
err = rawVerify(sk.Public(), sig, header, messages)
if err != nil {
t.Fatal(err)
}
Expand All @@ -234,13 +231,59 @@ func TestRoundTrip(t *testing.T) {
for i := 0; i < len(disclosedIndexes); i++ {
disclosedMessages[i] = messages[disclosedIndexes[i]]
}
proof, err := rawProofGen(publicKey(sk), sig, header, ph, messages, disclosedIndexes)
proof, err := rawProofGen(sk.Public(), sig, header, ph, messages, disclosedIndexes)
if err != nil {
t.Fatal(err)
}

err = rawProofVerify(publicKey(sk), proof, header, ph, disclosedMessages, disclosedIndexes)
err = rawProofVerify(sk.Public(), proof, header, ph, disclosedMessages, disclosedIndexes)
if err != nil {
t.Fatal(err)
}
}

func TestRoundTrip(t *testing.T) {
ikm := make([]byte, 32)
keyInfo := []byte{}
keyDst := []byte{}

sk, err := KeyGen(ikm, keyInfo, keyDst)
if err != nil {
t.Fatal(err)
}

header := []byte("test header")

messages := make([][]byte, 5)
messages[0] = []byte("hello")
messages[1] = []byte("world")
messages[1] = []byte("foo")
messages[1] = []byte("bar")
messages[1] = []byte("baz")

sig, err := Sign(sk, sk.Public(), header, messages)
if err != nil {
t.Fatal(err)
}

err = Verify(sk.Public(), sig, header, messages)
if err != nil {
t.Fatal(err)
}

// ph := []byte("presentation header")
// disclosedIndexes := []int{0, 1}
// disclosedMessages := make([][]byte, len(disclosedIndexes))
// for i := 0; i < len(disclosedIndexes); i++ {
// disclosedMessages[i] = messages[disclosedIndexes[i]]
// }
// proof, err := rawProofGen(sk.Public(), sig, header, ph, messages, disclosedIndexes)
// if err != nil {
// t.Fatal(err)
// }

// err = rawProofVerify(sk.Public(), proof, header, ph, disclosedMessages, disclosedIndexes)
// if err != nil {
// t.Fatal(err)
// }
}

0 comments on commit 5007a76

Please sign in to comment.