2026.02.28
Guides
Disclose Only What AI Needs
The Selective Disclosure Problem
A signed document contains many fields. A KYC record might include name, date of birth, address, nationality, ID number, and verification status. But a lending protocol only needs to know "is this person verified and not sanctioned?" — not their home address.
Without selective disclosure, you face a binary choice: share everything or share nothing. Lemma introduces a third option: share exactly the fields that matter, with cryptographic proof that they belong to the original signed document.
How BBS+ Selective Disclosure Works
Lemma uses BBS+ signatures as the default selective disclosure mechanism. The SDK's disclose module provides a complete BBS+ implementation:
Key generation and message preparation:
import { disclose } from "@lemmaoracle/sdk";
// Generate BBS+ key pair
const kp = await disclose.generateKeyPair();
// Convert payload to sorted "key:value" messages
const messages = disclose.payloadToMessages({
age: 25,
name: "Alice",
country: "JP",
});
// → ["age:25", "country:JP", "name:Alice"]Issuer signs the full document:
const signed = await disclose.sign(client, {
messages,
secretKey: kp.secretKey,
header: new TextEncoder().encode("my-app-header"),
issuerId: "issuer-1",
});
// signed.signature → BBS+ signatureHolder reveals only selected attributes:
const revealed = await disclose.reveal(client, {
signature: signed.signature,
messages,
publicKey: signed.publicKey,
disclosedIndexes: [0], // index of "age:25" in messages array
header: signed.header,
});
// revealed.disclosed → { age: "25" }
// revealed.proof → BBS+ selective disclosure proof
// Wrap for spec compliance
const sd = disclose.toSelectiveDisclosure(revealed);
// sd.format → "bbs+", sd.disclosedAttributes → { age: "25" }, sd.proof → hex-encodedThe proof mathematically guarantees that { age: 25 } is part of the document the issuer signed, without revealing any other field. The verifier never sees the full document.
Provenance Survives Partial Views
A common concern with selective disclosure is loss of context. If you only see one field, how do you know it is trustworthy?
In Lemma, disclosed attributes carry full provenance:
- The issuer who signed the original document.
- The schema that defines the attribute's type and normalization.
- The proof that links the disclosed value to the original BBS+ signature.
- The on-chain registry entry that anchors the document's existence.
Even a single disclosed field traces back to its origin through an unbroken chain of cryptographic evidence.
Role-Based and Party-Specific Views
Different consumers need different views of the same document:
- A lending protocol sees
{ verified: true, not_sanctioned: true }. - An age-gated service sees
{ age_bucket: "adult" }. - An internal auditor sees
{ country: "JP", verification_date: "2026-01-15" }.
Each view is generated from the same signed document with a different attributes array passed to disclose.reveal. No separate copies of the data are created. No additional signing steps are needed.
Future-Proof Design
The SDK's disclose namespace is named for the function it performs, not the cryptographic scheme it uses. The initial implementation uses BBS+, but the API is designed to support SD-JWT and other mechanisms without changing the developer-facing interface. When you call disclose.reveal, you are expressing intent ("show only these fields") rather than choosing a specific algorithm.
Complete BBS+ API
The disclose module includes all necessary BBS+ operations:
generateKeyPair(): Create BBS+ key pair (32-byte secret, 96-byte public)payloadToMessages(): Convert attribute object to sorted "key:value" arraysign(): BBS+ signing with issuer secret key and headerverify(): Verify BBS+ signature against issuer public keyreveal(): Generate selective disclosure proof for specific message indexesverifyProof(): Verify selective disclosure prooftoSelectiveDisclosure(): WrapRevealOutputinto spec-compliantSelectiveDisclosuretype