Enhanced Mandala Token Protocol
Jake Jones ([email protected])
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_DROPOutputs:
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 ✓
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
Last updated
Was this helpful?

