Skip to content
This repository has been archived by the owner on Mar 27, 2024. It is now read-only.

Commit

Permalink
feat: add BBS+ support to crypto.Crypto and webkms (#2574)
Browse files Browse the repository at this point in the history
closes #2295

Signed-off-by: Baha Shaaban <[email protected]>
  • Loading branch information
baha-ai authored Mar 1, 2021
1 parent dc1a9b3 commit 93c9922
Show file tree
Hide file tree
Showing 8 changed files with 898 additions and 6 deletions.
24 changes: 22 additions & 2 deletions pkg/crypto/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ type Crypto interface {
// VerifyMAC determines if mac is a correct authentication code (MAC) for data
// using a matching MAC primitive in kh key handle and returns nil if so, otherwise it returns an error.
VerifyMAC(mac, data []byte, kh interface{}) error

// WrapKey will execute key wrapping of cek using apu, apv and recipient public key 'recPubKey'.
// 'opts' allows setting the option sender key handle using WithSender() option. It allows ECDH-1PU key wrapping
// (aka Authcrypt). The absence of this option uses ECDH-ES key wrapping (aka Anoncrypt). Another option that can
Expand All @@ -53,7 +52,6 @@ type Crypto interface {
// error in case of errors
WrapKey(cek, apu, apv []byte, recPubKey *PublicKey,
opts ...WrapKeyOpts) (*RecipientWrappedKey, error)

// UnwrapKey unwraps a key in recWK using recipient private key kh.
// 'opts' allows setting the option sender key handle using WithSender() option. It allows ECDH-1PU key unwrapping
// (aka Authcrypt). The absence of this option uses ECDH-ES key unwrapping (aka Anoncrypt). There is no need to
Expand All @@ -62,6 +60,28 @@ type Crypto interface {
// unwrapped key in raw bytes
// error in case of errors
UnwrapKey(recWK *RecipientWrappedKey, kh interface{}, opts ...WrapKeyOpts) ([]byte, error)
// SignMulti will create a signature of messages using a matching signing primitive found in kh key handle of a
// private key.
// returns:
// signature in []byte
// error in case of errors
SignMulti(messages [][]byte, kh interface{}) ([]byte, error)
// VerifyMulti will verify a signature of messages using a matching signing primitive found in kh key handle of a
// public key.
// returns:
// error in case of errors or nil if signature verification was successful
VerifyMulti(messages [][]byte, signature []byte, kh interface{}) error
// VerifyProof will verify a signature proof (generated e.g. by Verifier's DeriveProof() call) for revealedMessages
// using a matching signing primitive found in kh key handle of a public key.
// returns:
// error in case of errors or nil if signature proof verification was successful
VerifyProof(revealedMessages [][]byte, proof, nonce []byte, kh interface{}) error
// DeriveProof will create a signature proof for a list of revealed messages using BBS signature (can be built using
// a Signer's SignMulti() call) and a matching signing primitive found in kh key handle of a public key.
// returns:
// signature proof in []byte
// error in case of errors
DeriveProof(messages [][]byte, bbsSignature, nonce []byte, revealedIndexes []int, kh interface{}) ([]byte, error)
}

// DefKeySize is the default key size for crypto primitives.
Expand Down
5 changes: 3 additions & 2 deletions pkg/crypto/primitive/bbs12381g2pub/bbs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ SPDX-License-Identifier: Apache-2.0
*/

// Package bbs12381g2pub contains BBS+ signing primitives and keys. Although it can be used directly, it is recommended
// to use BBS+ keys created by the kms along with the tinkcrypto BBS+ package primitives bbs.Signer and bbs.Verifier
// imported from: "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/bbs"
// to use BBS+ keys created by the kms along with the framework's Crypto service.
// The default local Crypto service is found at: "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto"
// while the remote Crypto service is found at: "github.com/hyperledger/aries-framework-go/pkg/crypto/webkms"
package bbs12381g2pub

import (
Expand Down
94 changes: 94 additions & 0 deletions pkg/crypto/tinkcrypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"golang.org/x/crypto/chacha20poly1305"

cryptoapi "github.com/hyperledger/aries-framework-go/pkg/crypto"
"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/bbs"
)

const (
Expand Down Expand Up @@ -276,3 +277,96 @@ func (t *Crypto) UnwrapKey(recWK *cryptoapi.RecipientWrappedKey, recipientKH int

return key, nil
}

// SignMulti will create a BBS+ signature of messages using the signer's private key in signerKH handle.
// returns:
// signature in []byte
// error in case of errors
func (t *Crypto) SignMulti(messages [][]byte, signerKH interface{}) ([]byte, error) {
keyHandle, ok := signerKH.(*keyset.Handle)
if !ok {
return nil, errBadKeyHandleFormat
}

signer, err := bbs.NewSigner(keyHandle)
if err != nil {
return nil, fmt.Errorf("create new BBS+ signer: %w", err)
}

s, err := signer.Sign(messages)
if err != nil {
return nil, fmt.Errorf("BBS+ sign msg: %w", err)
}

return s, nil
}

// VerifyMulti will BBS+ verify a signature of messages against the signer's public key in signerPubKH handle.
// returns:
// error in case of errors or nil if signature verification was successful
func (t *Crypto) VerifyMulti(messages [][]byte, bbsSignature []byte, signerPubKH interface{}) error {
keyHandle, ok := signerPubKH.(*keyset.Handle)
if !ok {
return errBadKeyHandleFormat
}

verifier, err := bbs.NewVerifier(keyHandle)
if err != nil {
return fmt.Errorf("create new BBS+ verifier: %w", err)
}

err = verifier.Verify(messages, bbsSignature)
if err != nil {
err = fmt.Errorf("BBS+ verify msg: %w", err)
}

return err
}

// VerifyProof will verify a BBS+ signature proof (generated e.g. by Verifier's DeriveProof() call) for revealedMessages
// with the signer's public key in signerPubKH handle.
// returns:
// error in case of errors or nil if signature proof verification was successful
func (t *Crypto) VerifyProof(revealedMessages [][]byte, proof, nonce []byte, signerPubKH interface{}) error {
keyHandle, ok := signerPubKH.(*keyset.Handle)
if !ok {
return errBadKeyHandleFormat
}

verifier, err := bbs.NewVerifier(keyHandle)
if err != nil {
return fmt.Errorf("create new BBS+ verifier: %w", err)
}

err = verifier.VerifyProof(revealedMessages, proof, nonce)
if err != nil {
err = fmt.Errorf("verify proof msg: %w", err)
}

return err
}

// DeriveProof will create a BBS+ signature proof for a list of revealed messages using BBS signature
// (can be built using a Signer's SignMulti() call) and the signer's public key in signerPubKH handle.
// returns:
// signature proof in []byte
// error in case of errors
func (t *Crypto) DeriveProof(messages [][]byte, bbsSignature, nonce []byte, revealedIndexes []int,
signerPubKH interface{}) ([]byte, error) {
keyHandle, ok := signerPubKH.(*keyset.Handle)
if !ok {
return nil, errBadKeyHandleFormat
}

verifier, err := bbs.NewVerifier(keyHandle)
if err != nil {
return nil, fmt.Errorf("create new BBS+ verifier: %w", err)
}

proof, err := verifier.DeriveProof(messages, bbsSignature, nonce, revealedIndexes)
if err != nil {
return nil, fmt.Errorf("verify proof msg: %w", err)
}

return proof, nil
}
102 changes: 102 additions & 0 deletions pkg/crypto/tinkcrypto/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package tinkcrypto
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"math/big"
"testing"

Expand All @@ -24,6 +25,7 @@ import (
chacha "golang.org/x/crypto/chacha20poly1305"

"github.com/hyperledger/aries-framework-go/pkg/crypto"
"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/bbs"
"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh"
"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/keyio"
ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto"
Expand Down Expand Up @@ -625,3 +627,103 @@ func TestCrypto_ECDH1PU_Wrap_Unwrap_Key_Using_CryptoPubKey_as_SenderKey(t *testi
require.NoError(t, err)
require.EqualValues(t, cek, uCEK)
}

func TestBBSCrypto_SignVerify_DeriveProofVerifyProof(t *testing.T) {
c := Crypto{}
msg := [][]byte{
[]byte(testMessage + "0"), []byte(testMessage + "1"), []byte(testMessage + "2"),
[]byte(testMessage + "3"), []byte(testMessage + "4"), []byte(testMessage + "5"),
}

var (
s []byte
pubKH *keyset.Handle
badKH *keyset.Handle
)

t.Run("test with BBS+ signature", func(t *testing.T) {
kh, err := keyset.NewHandle(bbs.BLS12381G2KeyTemplate())
require.NoError(t, err)

badKH, err = keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate("babdUrl", nil))
require.NoError(t, err)

s, err = c.SignMulti(msg, kh)
require.NoError(t, err)

// sign with nil key handle - should fail
_, err = c.SignMulti(msg, nil)
require.EqualError(t, err, errBadKeyHandleFormat.Error())

// sign with bad key type - should fail
_, err = c.SignMulti(msg, "bad key type")
require.EqualError(t, err, errBadKeyHandleFormat.Error())

// sign with empty messages - should fail
_, err = c.SignMulti([][]byte{}, kh)
require.EqualError(t, err, "BBS+ sign msg: messages are not defined")

// sign with bad key handle - should fail
_, err = c.SignMulti(msg, badKH)
require.Error(t, err)

// get corresponding public key handle to verify
pubKH, err = kh.Public()
require.NoError(t, err)

err = c.VerifyMulti(msg, s, nil)
require.EqualError(t, err, errBadKeyHandleFormat.Error())

err = c.VerifyMulti(msg, s, "bad key type")
require.EqualError(t, err, errBadKeyHandleFormat.Error())

err = c.VerifyMulti(msg, s, badKH)
require.Error(t, err)

err = c.VerifyMulti([][]byte{}, s, pubKH)
require.EqualError(t, err, "BBS+ verify msg: bbs_verifier_factory: invalid signature")

err = c.VerifyMulti(msg, s, pubKH)
require.NoError(t, err)
})

require.NotEmpty(t, s)

t.Run("test with BBS+ proof", func(t *testing.T) {
revealedIndexes := []int{0, 2}
nonce := make([]byte, 32)

_, err := rand.Read(nonce)
require.NoError(t, err)

_, err = c.DeriveProof(msg, s, nonce, revealedIndexes, nil)
require.EqualError(t, err, errBadKeyHandleFormat.Error())

_, err = c.DeriveProof(msg, s, nonce, revealedIndexes, "bad key type")
require.EqualError(t, err, errBadKeyHandleFormat.Error())

_, err = c.DeriveProof(msg, s, nonce, revealedIndexes, badKH)
require.Error(t, err)

_, err = c.DeriveProof([][]byte{}, s, nonce, revealedIndexes, pubKH)
require.EqualError(t, err, "verify proof msg: bbs_verifier_factory: invalid signature proof")

proof, err := c.DeriveProof(msg, s, nonce, revealedIndexes, pubKH)
require.NoError(t, err)

err = c.VerifyProof([][]byte{msg[0], msg[2]}, proof, nonce, nil)
require.EqualError(t, err, errBadKeyHandleFormat.Error())

err = c.VerifyProof([][]byte{msg[0], msg[2]}, proof, nonce, "bad key type")
require.EqualError(t, err, errBadKeyHandleFormat.Error())

err = c.VerifyProof([][]byte{msg[0], msg[2]}, proof, nonce, badKH)
require.Error(t, err)

err = c.VerifyProof([][]byte{msg[3], msg[4]}, proof, nonce, pubKH)
require.EqualError(t, err, "verify proof msg: bbs_verifier_factory: invalid signature proof")

err = c.VerifyProof([][]byte{msg[0], msg[2]}, proof, nonce, pubKH)
require.NoError(t, err)
})
}
2 changes: 1 addition & 1 deletion pkg/crypto/tinkcrypto/primitive/bbs/bbs.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ SPDX-License-Identifier: Apache-2.0
// v := bbs.NewVerifier(verKH)
//
// // and verify signature
// pt, err := v.Verify(messages, sig)
// err = v.Verify(messages, sig)
// if err != nil {
// // handle error
// }
Expand Down
Loading

0 comments on commit 93c9922

Please sign in to comment.