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′=mnull⋅Hnull+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=04mi⋅Hi∈G1
    • Generate 1st signature σ′=(A1,e) where:
    e←$Zp,A=1x+e⋅C1
    • Use same e to generate 2nd signature σ′=(A2′,e) where:
    A′=1x+e⋅C2
    • 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=mnull⋅Hnull+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,⋯}ml⋅Hl+mnull⋅Hnull+mγ⋅Hγ

    where:

    • A―=r⋅A (randomized signature point)
    • B―=r⋅C−r⋅e⋅A
    • CJ=G1+∑j∈Jmj⋅Hj
    • U=α⋅CJ+β⋅A―+δγ⋅Hγ
    • c=H(ctx||m→J||A―||B―||U)(FS transform)
    • s=α+r⋅c, t=β−e⋅c (responses for r,e)
    • uγ=δγ+r⋅mγ⋅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+∑j∈Jmj⋅Hj

    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 m→J as it's revealed):
      c′=H(ctx||m→J||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+c′⋅B―=?s⋅CJ+t⋅A―+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―=r⋅A 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.