Skip to content

baseid-bbs

BBS+ signatures enable privacy-preserving credential presentation — a holder can selectively reveal specific claims from a credential while keeping others hidden, and different presentations of the same credential cannot be correlated by colluding verifiers.

  • Unlinkable selective disclosure — reveal only the claims needed, keep the rest hidden
  • Zero-knowledge predicates — prove “age > 18” without revealing the actual age
  • Constant-size signatures — one 80-byte BBS+ signature covers any number of claims
  • Derived proofs — each presentation produces unique proof bytes (unlinkable)
  • IETF-aligned — implements draft-irtf-cfrg-bbs-signatures using BLS12-381
use baseid_bbs::{BbsKeyPair, BbsLifecycle};
use baseid_core::claims::{ClaimSet, DisclosureSelection, PredicateType};
use baseid_core::lifecycle::*;
use serde_json::json;
// Generate BBS+ key pair (BLS12-381 G2)
let key_pair = BbsKeyPair::generate()?;
let lifecycle = BbsLifecycle::new(key_pair);
// Issue a credential with multiple claims
let mut claims = ClaimSet::new();
claims.insert("", "given_name", json!("Alice"));
claims.insert("", "family_name", json!("Smith"));
claims.insert("", "age", json!(25));
claims.insert("", "nationality", json!("Canadian"));
let issued = lifecycle.issue(
"did:key:issuer",
Some("did:key:holder"),
&claims,
&IssuanceOptions::default(),
)?;
// Present with selective disclosure
let disclosure = DisclosureSelection::new()
.reveal("given_name") // Verifier sees: "Alice"
.reveal("family_name") // Verifier sees: "Smith"
.predicate("age", PredicateType::GreaterThan(json!(18))) // Proves age > 18
.hide("nationality"); // Hidden from verifier
let presented = lifecycle.present(
&issued.data,
&disclosure,
&PresentationOptions::default(),
)?;
assert!(presented.unlinkable); // Presentations cannot be correlated
// Verify the derived proof
let outcome = baseid_bbs::verify_derived_proof(&presented.data)?;
assert!(outcome.valid);
assert!(outcome.unlinkable);

Each claim in the credential becomes a separate BBS+ “message”. The issuer signs all messages together with a single constant-size signature. The holder receives the signed credential.

When presenting, the holder creates a derived proof that:

  1. Proves they possess a valid signature over all messages
  2. Reveals only the messages (claims) they choose
  3. Produces unique proof bytes each time (unlinkable)

The verifier learns only the disclosed claims — they cannot determine the values of hidden claims, and cannot correlate presentations from the same credential.

For claims marked with ClaimDisclosure::Predicate, the holder can prove properties about hidden values:

PredicateExampleWhat Verifier Learns
GreaterThan(18)age > 18The age is over 18 (not the actual age)
LessThan("2008-03-01")born before dateUnder a certain age
InSet(["CA", "US"])nationality ∈ setNationality is one of CA or US
NonRevokednot revokedCredential hasn’t been revoked
TypeDescription
BbsKeyPairBLS12-381 G2 key pair for BBS+ signing
BbsCredentialSigned credential with ordered claim messages
BbsDerivedProofZero-knowledge proof with disclosed claims
BbsLifecycleImplements CredentialIssuer, CredentialVerifier, CredentialPresenter
BbsClaimIndividual claim (namespace, name, value)

BBS+ credentials use CredentialFormat::Bbs and SignatureAlgorithm::BbsPlus with KeyType::Bls12381G2.

  • baseid-revocation — Privacy-preserving revocation (accumulators)
  • baseid-core — Lifecycle traits, claim types, predicates
  • baseid-crypto — ZK proof traits (MultiMessageSigner, ProofDeriver, ProofVerifier)