Enhanced Mandala Token Protocol
A minimal token protocol leaves amounts as plain numbers, which anyone in the chain could quietly alter. This adds a cryptographic commitment so tampering is detectable, without abandoning the minimal design.
Summary
- Why
- Lightweight wallets have no way to independently confirm that a token transfer preserves the correct total amount without trusting an overlay network.
- What
- BRC-107 is an extension to the Mandala Token Protocol (BRC-92) that adds a cryptographic commitment hash to each token output so its amount and history can be verified without a full node or overlay.
- How
- A wallet computes a SHA-256 hash of the asset ID, amount, previous transaction ID, and an optional nonce, embeds it in the output alongside the existing BRC-92 fields, and sends it with a Simplified Payment Verification (SPV) proof so the recipient can recompute the hash and check that input and output totals match.
What this lets you do
- Verify a token amount hasn't been tampered with using only transaction data
- Check that input and output token amounts still balance without an overlay network
- Accept token payments in an SPV wallet with a sub-100ms local check
- Add privacy to token transfers with an optional nonce to prevent amount linking
- Keep old BRC-92 tokens working unchanged alongside commitment-enabled ones
Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.
Reference for an AI
Everything an assistant needs to answer questions about BRC-107 accurately, including what it depends on.
The specification
Abstract
This proposal extends BRC-92 (Mandala Token Protocol) with cryptographic commitments to provide tamper-evident token amounts and SPV-friendly verification while maintaining the minimalist design philosophy. The enhancement adds a commitment hash to each token output that cryptographically binds the token amount to its transaction history, enabling lightweight clients to verify token integrity without accessing the full blockchain or trusting overlay networks.
Motivation
The original BRC-92 Mandala Token Protocol provides a minimalist approach to tokenization on BSV, but relies entirely on overlay networks to validate token conservation rules. In real-world usage scenarios, particularly SPV wallets and point-of-sale transactions, users need cryptographic assurance that token amounts haven't been tampered with. This enhancement addresses these limitations while preserving the simplicity that makes BRC-92 attractive.
Key problems this solves:
- SPV wallets cannot verify token conservation without trusting overlays
- No cryptographic proof linking token amounts to their history
- Potential for amount tampering between transaction creation and overlay submission
- Lack of standardized verification protocol for lightweight clients
Specification
Enhanced Token Output Format
Building upon BRC-92's structure, we add a cryptographic commitment field:
Fungible Token Output
21 <assetId> <amount> <commitment> OP_2DROP OP_2DROP OP_DROP ...
Where:
21(0x21): UTF-8 exclamation mark prefix (unchanged from BRC-92)assetId: Genesis transaction outpoint (txid:vout) (unchanged)amount: Token amount in Bitcoin number format (unchanged)commitment: NEW - Cryptographic commitment hash...: Functional locking script (e.g., P2PKH) (unchanged)
Commitment Construction
The commitment is calculated as:
commitment = H(assetId || amount || prevTxid || nonce)
Where:
H: SHA-256 hash function||: Concatenation operatorprevTxid: Transaction ID of the input being spentnonce: Optional 32-byte random value for privacy
NFT Token Output
21 <assetId> <commitment> OP_2DROP OP_DROP ...
For NFTs, the commitment is:
commitment = H(assetId || prevTxid || metadata_hash)
SPV Verification Protocol
When transferring tokens in an SPV context, the sender provides:
{
"transaction": "hex_encoded_transaction",
"tokenProofs": {
"inputs": [
{
"index": 0,
"amount": 100,
"commitment": "abc123...",
"prevTx": "def456...",
"merkleProof": "..."
}
],
"outputs": [
{
"index": 0,
"amount": 60,
"commitment": "ghi789..."
},
{
"index": 1,
"amount": 40,
"commitment": "jkl012..."
}
],
"conservationProof": {
"totalIn": 100,
"totalOut": 100
}
}
}
Verification Steps
Recipients MUST perform the following verification:
-
Commitment Verification: For each input and output, verify:
commitment == H(assetId || amount || prevTxid || nonce) -
Conservation Check: Verify that:
sum(input_amounts) == sum(output_amounts) -
Merkle Proof Validation: Verify SPV proofs for recent transactions
-
Accept/Reject: Transaction is valid if all checks pass
Backward Compatibility
This enhancement maintains full backward compatibility with BRC-92:
- Existing BRC-92 tokens continue to function
- Overlays that don't recognize commitments can ignore them (treated as extra data)
- The drop pattern ensures scripts execute identically
- Migration path: New tokens use commitments, old tokens grandfathered
Privacy Considerations
The commitment includes an optional nonce field to prevent amount analysis:
- Without nonce: Same amounts produce same commitments (linkable)
- With nonce: Same amounts produce different commitments (unlinkable)
Design Justification
Why Commitments Instead of Script Enforcement?
Bitcoin Script's execution model prevents cross-input/output verification within scripts. Cryptographic commitments provide the next best solution:
- Tamper-evident: Can't change amounts without breaking commitments
- SPV-compatible: Verifiable with just transaction data
- Minimalist: Adds only one hash field
- Overlay-independent: Cryptographic proof doesn't require trust
Why Include prevTxid?
Including the previous transaction ID in the commitment:
- Creates an unforgeable chain of custody
- Prevents replay attacks with old commitments
- Links each token to its complete history
- Enables proof of lineage back to genesis
Why Optional Nonce?
The nonce field balances transparency and privacy:
- Public tokens (securities): No nonce for full transparency
- Private tokens (cash-like): Nonce prevents amount correlation
- User choice: Applications decide based on use case
Example Transactions
Token Transfer with Commitments
Input (100 tokens from previous tx):
Previous output:
21 <assetId> <100> <H(assetId||100||prev_prev_txid||nonce)> OP_2DROP OP_2DROP OP_DROP
Outputs:
Output 0 (60 tokens to Bob):
21 <assetId> <60> <H(assetId||60||current_input_txid||nonce1)> OP_2DROP OP_2DROP OP_DROP P2PKH(Bob)
Output 1 (40 tokens change to Alice):
21 <assetId> <40> <H(assetId||40||current_input_txid||nonce2)> OP_2DROP OP_2DROP OP_DROP P2PKH(Alice)
SPV Verification Example
Bob receives a payment at a coffee shop:
- Alice sends: Transaction + commitment proofs + merkle proof
- Bob's wallet verifies (< 100ms):
- Commitment:
H(assetId||30||prevTxid||nonce) == provided_commitment✓ - Conservation:
50 in == 30 + 20 out✓ - Merkle proof: Transaction exists in blockchain ✓
- Commitment:
- Bob accepts: Payment verified without blockchain access
Implementation Considerations
Wallet Integration
Wallets implementing this standard should:
- Generate commitments when creating token transactions
- Store nonces for privacy-enabled tokens
- Verify commitments before accepting tokens
- Provide SPV proof packages to recipients
Overlay Network Integration
Overlay networks can:
- Reject transactions with invalid commitments
- Use commitments for faster validation
- Provide commitment verification as a service
- Index tokens by commitment for quick lookups
Performance Impact
- Additional data: 32 bytes per output (commitment)
- Computation: One SHA-256 hash per input/output
- Verification time: < 1ms per token on modern devices
- Storage: Negligible increase (< 5% for typical token transactions)
Security Considerations
Commitment Forgery
Forging a commitment requires finding a hash collision:
- SHA-256 preimage resistance: 2^256 operations
- Collision resistance: 2^128 operations
- Practically impossible with current technology
Replay Attacks
Including prevTxid prevents replay:
- Old commitments won't match new transactions
- Each commitment is unique to its transaction chain
Amount Tampering
Changing amounts breaks commitments:
- Detectable by any verifier
- Rejected by overlays and recipients
Migration Path
- Phase 1: Wallets add commitment generation (optional)
- Phase 2: Overlays prefer commitment-enabled tokens
- Phase 3: Recipients require commitments for new tokens
- Phase 4: Full ecosystem adoption
References
- BRC-92: Mandala Token Protocol
- BRC-62: Background Evaluation Extended Format (BEEF) Transactions
- BRC-67: Simplified Payment Verification
Test Vectors
Commitment Calculation
Input:
assetId = "abc...def:0"
amount = 100
prevTxid = "123...456"
nonce = "000...000"
Output:
commitment = SHA256("abc...def:0" || 100 || "123...456" || "000...000")
= "a7b8c9d0e1f2..."
Conservation Verification
Valid (conserves tokens):
Inputs: [50, 30, 20] (sum = 100)
Outputs: [60, 40] (sum = 100)
Result: VALID ✓
Invalid (creates tokens):
Inputs: [50, 30] (sum = 80)
Outputs: [60, 40] (sum = 100)
Result: INVALID ✗
Implementations
Reference implementations available at:
- TypeScript: Coming Soon
- Go: Coming Soon
- Python: Coming Soon