Skip to content

Latest commit

 

History

History
136 lines (96 loc) · 4.78 KB

README.md

File metadata and controls

136 lines (96 loc) · 4.78 KB

go-bbs

Go Report Card GitHub release License dependency - github.com/suutaku/bls12381

A BBS++ signature pure go implementation refer to hyperledger/ursa (Rust) and heyperledger/aries-framework-go (Without Blind sign).

Keygen

BBS+ supports two types of public keys. One that is created as described in the paper where the message specific generators are randomly generated and a deterministic version that looks like a BLS public key and whose message specific generators are computed using IETF's Hash to Curve algorithm which is also constant time combined with known inputs.

  pub, priv, err := bbs.GenerateKeyPair(sha256.New, nil)
  if err != nil {
    panic(err)
  }

Signing

Signing can be done where the signer knows all the messages or where the signature recipient commits to some messages beforehand and the signer completes the signature with the remaining messages.

To create a signature:

_, priv, _ := bbs.GenerateKeyPair(sha256.New, nil)
bbsInstance := bbs.NewBbs()

signature, err := bbsInstance.SignWithKey([][]byte{message}, priv)
require.NoError(t, err)

Blinding Signing

Blinding signing needs Issuer and Holder exchange Nonce and BlindSignatureContext.

Step 1. Issuer create a Nonce and send to Holder

Step 2. Holder recived Nonce, use it to create a BlindSignatureContext and a BlindingFactory. Keep BlindingFactory and send BlindSignatureContext to Issuer.

// holder pre blind secret
secretMsgs := make(map[int][]byte, 0)
secretMsgs[0] = []byte("identity")
secretMsgs[2] = []byte("password")
secretMsgs[4] = []byte("phone number")

ctx, blinding, err := NewBlindSignatureContext(secretMsgs, generators, nonce)
require.NoError(t, err)

Note: generator can generated from Holder's PublicKey, the messageCount is sum of all messages (secret message number + revealed message number):

generators, err := pub.ToPublicKeyWithGenerators(messageCount)
require.NoError(t, err)

Step 3. Issuer recived BlindSignatureContext and revealed messages, verify secret commitment in BlindSignatureContext and create a Blind Signature.

// signer use known message with index to create blinding signature
revealedMsg := make(map[int][]byte, 0)
revealedMsg[1] = []byte("firstname")
revealedMsg[3] = []byte("age")

blindSig, err := ctx.ToBlindSignature(revealedMsg, priv, generators, nonce)
require.NoError(t, err)
require.NotNil(t, blindSig)

Step 4. Holder recived blind signature, convert it to signature with blindingFactory:

// holder convert blinding signature to signature
sig := blindSig.ToUnblinded((*SignatureBliding)(blinding))
require.NotNil(t, sig)

Step 5. Finally, Holder can verify signature with all Messages:

// verifier verify signature
allMsg := make([]*SignatureMessage, 5)
allMsg[0] = ParseSignatureMessage([]byte("identity"))
allMsg[1] = ParseSignatureMessage([]byte("firstname"))
allMsg[2] = ParseSignatureMessage([]byte("password"))
allMsg[3] = ParseSignatureMessage([]byte("age"))
allMsg[4] = ParseSignatureMessage([]byte("phone number"))

err = sig.Verify(allMsg, generators)
require.NoError(t, err)

At this time, blinding signature is end and some secret message was not known to Issuer. Now you can use signature to create SelectiveDisclosure with DeriveProof.

DeriveProof

DeriveProof derives a proof of BBS+ signature with some messages disclosed.

allMsg := make([]*SignatureMessage, 5)
allMsg[0] = ParseSignatureMessage([]byte("identity"))
allMsg[1] = ParseSignatureMessage([]byte("firstname"))
allMsg[2] = ParseSignatureMessage([]byte("password"))
allMsg[3] = ParseSignatureMessage([]byte("age"))
allMsg[4] = ParseSignatureMessage([]byte("phone number"))

revealedIndexes := []int{
  1,3,4,
}

proof,err := bbsInstance.DeriveProof(allMsg, signature, nonce, pubkey, revealedIndexes)

Verify Proof

VerifyProof verifies BBS+ signature proof for one or more revealed messages.

 err := bbsInstance.VerifyProof(messagesBytes, proof, nonce, pubKeyBytes) 

License

Released under MIT by @suutaku.