Skip to content

BBS DID Scheme - Holographic Overview

BBS Signature Scheme (Chinese)

System Architecture

  • User: The user who wants to obtain a credential (passport) to access a DApp.
  • Issuer: An on-chain contract deployed by the DApp on the origin chain, which can mint a soulbound token (ERC-5114 / ERC-5484, revocable by the Issuer) to the User on the destination chain.
  • Signer: An off-chain Trusted Third Party (TTP) service provider that verifies user information and issues BBS signatures.
  • Verifier: A contract deployed by the DApp/Signer that verifies the NIZK proof and triggers a callback to the Issuer contract to mint the token. Can be deployed on different chains to minimize verification costs.(Reactive Network)

Prelude

Message coding definition:

Message IDMessage contents
m0,H0Constrain1, e.g., "Is_Adult=1"
m1,H1Constrain2, e.g., "keccak(nationality)=keccak("CN")"
m2,H2Constrain3, ...
m3,H3Constrain4, ...
m4,H4Expiration Height
mnull,HnullNullifier commitment
mγ,HγBlind factor

1. Init

  • Issuer generates unique Hnull and encodes it in the contract.

  • Signer runs KeyGen to get private key x and publishes the public key X.

  • Signer or Issuer deploys the Verifier contract and embeds Hnull and X into the contract.

NOTE

Current status

  • Public: Hnull,X,m
    • Signer: x

2. User apply

  • User

    • Use view function to read Hnull and the requirements (m) of DApp on chain.

    • Sample mnull,mγ,λZp, compute:

      • Nullifier hash: N=Hash(0xUserAddress||mnull)
      • Nullifier commitment: N=mnullHnull+mγHγ
      • Bind the commit: C2=λ(mnullHnull+mγHγ)
    • Send N to Verifier Contract to stash it on chain (KeyExist[mapping(uint=>bool)][N]] = true) by using a new address 0xRelayerAddr.

    • Aggregate the constraints m={m0,m1,m2,}.

    • Send (m,C2) to Signer.

    NOTE

    Current status

    • Public: Hnull,X,m
      • Verifier: N,0xRelayerAddr
    • Signer: x, UserID,m,C2
    • User: 0xUserAddr,mnull,mγ,λ

3. Signer gen signature

  • Signer

    • Check whether the user's info corresponds to the constraints in m. If not, refuse to sign.
    • Compute 1st commitment:
    C1=G1+i=04miHiG1
    • Generate 1st signature σ=(A1,e) where:
    e$Zp,A=1x+eC1
    • Use same e to generate 2nd signature σ=(A2,e) where:
    A=1x+eC2
    • Send signature σ=(A1,A2,e) back to User.

NOTE

Current status

  • Public: Hnull,X,m
    • Verifier: N,0xRelayerAddr
  • Signer: x, UserID,N,σ
  • User: 0xUserAddr,mnull,mγ, σ

4. User gen NIZK proof

  • User

    • Unnlind the A2:
    A2=A2λ1=mnullHnull+mγHγx+e
    • Reconstruct the signature σ=(A,e):
    σ=(A,e)=(A1+A2,e)
    • Generate NIZK proof π to prove knowledge of a valid signature σ for messages (m,mγ,mnull) while hiding (mγ,A,e).
    π=(A, B, U, s, t, uγ)

    Let J={0,1,2,3,4,null} (public message indices), while I={γ} is the hidden message.

    C=CJ+CI=G1+l{1,2,3,4,}mlHl+mnullHnull+mγHγ

    where:

    • A=rA (randomized signature point)
    • B=rCreA
    • CJ=G1+jJmjHj
    • U=αCJ+βA+δγHγ
    • c=H(ctx||mJ||A||B||U)(FS transform)
    • s=α+rc, t=βec (responses for r,e)
    • uγ=δγ+rmγc
    • Send (π,mnull,0xUserAddr) to Verifier.

NOTE

Current status

  • Public: Hnull,X,m
    • Verifier: N,0xRelayerAddr,0xUserAddr,mnull,π
  • Signer: x, UserID,N,σ
  • User: 0xUserAddr,mnull,σ,π

5. Verify the Signature and mint the token

  • Verifier

    • Compute public part commitment (pre-computed since constraints are hard-coded):
    CJ=G1+jJmjHj

    where J={0,1,2,3,4,null} (public message indices).

    • Verify nullifier pre-commitment:

      • Compute N=Hash(0xUserAddr||mnull)
      • Require KeyExist[N] == true (check pre-committed in Step 2)
      • Require Used[N] == false (prevent double-spending)
    • Verify the NIZK proof π=(A,B,U,s,t,uγ):

      1. Recompute the Fiat-Shamir challenge (note: mnull is included in mJ as it's revealed):
      c=H(ctx||mJ||A||B||U)
      1. Pairing check (verify randomized signature is valid):
      e(A,X)=?e(B,G2)
      1. Homomorphic check (verify correct representation of B with hidden mγ):
      U+cB=?sCJ+tA+uγHγ

      If any check fails, revert.

    • Mark nullifier as used:

      • Set Used[N] = true
    • Call the Issuer's function mint(timestamp, 0xUserAddr) to issue the soulbound token to 0xUserAddr.

6. Summary

Features

  • [x] Unforgeability: Only the Signer with secret key x can generate valid signatures.
  • [x] Unlinkability: The Signer cannot track where the User uses the signature because:
    • The NIZK proof is randomized (A=rA with fresh r each time)
    • The Signer only sees N=mnullHnull+mγHγ, even though mnull,0xUserAddr is revealed at spend time and holds the realtion of (mnull,Hnull,Hγ) simutanuesly, the Signer should iterate every possible mγ and λ to track the User.
  • [x] Single-use: The User cannot use the same signature multiple times because:
    • N=Hash(0xUserAddr||mnull) is pre-committed before signing
    • Verifier checks and marks N as used atomically
  • [x] Privacy:
    • mγ (blind factor) is hidden via zero-knowledge in the proof
    • Signature (A,e) is hidden via randomization
  • [x] Domain separation: The ctx parameter in Fiat-Shamir transform prevents proof replay across different DApps.
  • [x] Expiration: The token could be burn after a specified block height (encoded in m4, e.g.) to limit the validity period of the credential, or a real-world time by aquiring the current time from a external oracle.

Extensions

  • [x] Multiple signatures: ...
  • [x] The length of the Messages: the could be freely extended by adding more Hi in the public parameters and encoding more constraints in the signature.
  • [x] Support Timed Encryption?: When the User gen mγ, the User could use RSW to encrypt mγ to feature and gen a zk-proof, so the Verifier could aquire mγ after some time delay and eventually link the VC to the exact User.
  • [x] Support zkvm?: The User could utilize the zkvm network to compress the proof into only one groth16 proof and minimize the on-chain verification cost.

Remaining Issues

  • [ ] Signature malleability: The basic BBS signature σ=(A,e) is susceptible to forgery σ=(A2,e) for commitment C2. To solve this, we should consider using BBS+.
  • [ ] Nullifier waste: User commits N before receiving signature. If Signer refuses, the nullifier is wasted.