Jake Jones (jake.jones@bsvassociation.org)
This proposal extends the Enhanced Mandala Token Protocol (BRC-107) with identity certificate integration based on BRC-52/53. It enables tokens to enforce real-world compliance requirements, KYC/AML regulations, and identity-based access controls while preserving privacy through selective field revelation. The protocol supports regulated security tokens, accredited investor requirements, geographic restrictions, and identity-based recovery mechanisms, all validated through SPV-friendly cryptographic proofs.
Current token systems on BSV lack native integration with identity verification, making regulatory compliance difficult and limiting adoption for security tokens and regulated assets. While BRC-52/53 provides a robust identity certificate system, there's no standard for linking these certificates to token ownership and transfers.
This proposal addresses:
- Regulatory compliance for security tokens requiring KYC/AML
- Accredited investor verification for restricted offerings
- Geographic restrictions for regulatory jurisdictions
- Identity-based recovery for lost keys
- Privacy-preserving compliance through selective revelation
- Fraud prevention through identity linkage
We define three levels of identity requirements for tokens:
- Open Tokens: No identity requirements (backward compatible with BRC-92/BRC-107)
- Verified Tokens: Require valid BRC-52 certificate
- Restricted Tokens: Require specific certificate fields or types
The genesis transaction establishes identity requirements:
21 <assetId>
<issuerCertificateHash>
<complianceRules>
<identityCommitment>
OP_2DROP OP_2DROP OP_2DROP OP_DROP ...Where:
issuerCertificateHash: SHA-256 hash of issuer's BRC-52 certificatecomplianceRules: Encoded rules for token transfersidentityCommitment:H(assetId || issuerCertificate || complianceRules || maxSupply)
{
"version": 1,
"requireIdentity": true,
"allowedCertificateTypes": [
"8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE="
],
"requiredFields": ["country", "accreditedStatus"],
"restrictions": {
"allowedCountries": ["US", "CA", "GB"],
"minCertificateLevel": "enhanced_kyc",
"maxAmountPerIdentity": 10000,
"cooldownPeriod": 86400
}
}21 <assetId> <amount>
<recipientCertificateHash>
<identityCommitment>
OP_2DROP OP_2DROP OP_2DROP OP_DROP P2PKHWhere:
recipientCertificateHash: SHA-256 hash of recipient's BRC-52 certificateidentityCommitment:H(assetId || amount || certificateHash || prevTxid)
When transferring identity-linked tokens, the sender provides:
{
"transaction": "hex_encoded_transaction",
"tokenProofs": {
"inputs": [...],
"outputs": [...],
"conservationProof": {...}
},
"identityProofs": {
"sender": {
"certificate": {
"type": "8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE=",
"subject": "0376d67c86b45be3c36c328c2aa5c5dd79c546d2...",
"serialNumber": "kUahacBHmYL2nkzemkatFg==",
"certifier": "035ce8cc44dbcf4c991d666d381d67263aed9123...",
"revocationOutpoint": "48645047cd66f7b48b24efb080ec7e27...1",
"signature": "3045022100c0686907...",
"keyring": {
"country": "encrypted_for_recipient",
"accreditedStatus": "encrypted_for_recipient"
}
},
"certificateProof": {
"merkleProof": "...",
"blockHeight": 850000
}
},
"recipient": {
"certificateHash": "sha256_hash_of_recipient_certificate",
"certificateType": "8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE="
}
},
"complianceAttestation": {
"rulesVersion": 1,
"checksPassed": [
"country_allowed",
"accredited_investor",
"amount_within_limit"
],
"timestamp": 1234567890,
"attestorSignature": "..."
}
}Recipients and overlays MUST verify:
- Commitment verification
- Conservation check
- Merkle proof validation
function verifyIdentityCompliance(transfer) {
// Verify sender's certificate
if (!verifyCertificate(transfer.identityProofs.sender.certificate)) {
return false;
}
// Check certificate not revoked
if (isSpent(transfer.identityProofs.sender.certificate.revocationOutpoint)) {
return false;
}
// Verify certificate matches output
senderCertHash = H(transfer.identityProofs.sender.certificate);
if (senderCertHash != transfer.transaction.inputs[0].certificateHash) {
return false;
}
// Decrypt and verify required fields
fields = decryptFields(transfer.identityProofs.sender.certificate.keyring);
if (!meetsComplianceRules(fields, token.complianceRules)) {
return false;
}
// Verify recipient certificate type
if (!token.complianceRules.allowedCertificateTypes.includes(
transfer.identityProofs.recipient.certificateType)) {
return false;
}
return true;
}Certificate holders reveal only required fields:
- Determine Required Fields: Based on token's compliance rules
- Encrypt for Recipient: Using BRC-52/53 key derivation
- Include in Transfer: Add encrypted keys to certificate keyring
- Recipient Decrypts: Using their identity key
Example revealing only country for geographic restriction:
{
"certificate": {
"fields": {
"firstName": "encrypted_not_revealed",
"lastName": "encrypted_not_revealed",
"country": "encrypted_value",
"city": "encrypted_not_revealed"
},
"keyring": {
"country": "encrypted_revelation_key_for_recipient"
}
}
}Tokens can include recovery conditions:
21 <assetId> <amount>
<primaryCertificateHash>
<recoveryCommitment>
OP_IF
<recoveryDelay> OP_CHECKSEQUENCEVERIFY OP_DROP
<recoveryCertificateHash> OP_EQUAL
OP_ELSE
<primaryCertificateHash> OP_EQUAL
OP_ENDIFWhere:
recoveryCommitment:H(certificateType || recoveryFields || recoveryPubkey)recoveryDelay: Time lock before recovery (e.g., 30 days)
{
"certificateLevels": {
"basic_kyc": {
"maxTransferAmount": 1000,
"dailyLimit": 5000,
"allowedOperations": ["transfer", "receive"]
},
"enhanced_kyc": {
"maxTransferAmount": 10000,
"dailyLimit": 50000,
"allowedOperations": ["transfer", "receive", "stake"]
},
"institutional": {
"maxTransferAmount": null,
"dailyLimit": null,
"allowedOperations": ["transfer", "receive", "stake", "mint", "burn"]
}
}
}// Genesis specifies accredited investor requirement
complianceRules = {
requiredFields: ["accreditedStatus", "country"],
allowedCountries: ["US"],
restrictions: {
mustBeAccredited: true,
minInvestment: 10000
}
}// Token only transferable within specific regions
complianceRules = {
requiredFields: ["country"],
allowedCountries: ["EU", "UK", "CH"],
restrictions: {
blockRestrictedCountries: ["US", "CN", "RU"]
}
}// Gaming tokens requiring age verification
complianceRules = {
requiredFields: ["ageRange"],
restrictions: {
minimumAge: 18,
requireAgeAttestation: true
}
}// Different limits based on certificate type
if (certificate.type == "retail") {
maxDailyVolume = 10000;
} else if (certificate.type == "qualified") {
maxDailyVolume = 100000;
} else if (certificate.type == "institutional") {
maxDailyVolume = unlimited;
}For sensitive compliance checks, support ZK proofs:
- Prove age > 18 without revealing exact age
- Prove accredited status without revealing net worth
- Prove country membership without revealing specific country
All certificate fields remain encrypted until revelation:
- Only revealed fields are decrypted
- Revelation is counterparty-specific
- No permanent plaintext exposure
Users can maintain pseudonymity while proving compliance:
- Certificate links to pubkey, not real name
- Only certifier knows real identity
- Selective revelation preserves privacy
- Always verify certificate signatures
- Check revocation status via UTXO
- Validate certifier is trusted
- Ensure certificate hasn't expired
- Include prevTxid in commitments
- Timestamp compliance attestations
- Use nonces for uniqueness
- Certificate revocation via UTXO spending
- Recovery mechanisms for token access
- Time-locked recovery periods
- Open tokens work without identity
- Existing BRC-92/106 tokens unaffected
- Optional identity for gradual adoption
- Phase 1: Deploy identity-aware wallets
- Phase 2: Certifiers issue BRC-52 certificates
- Phase 3: Token issuers adopt compliance rules
- Phase 4: Overlays enforce identity requirements
- Phase 5: Full ecosystem adoption
async function createIdentityToken(params) {
// Get issuer's certificate
const issuerCert = await wallet.getCertificate();
// Define compliance rules
const rules = {
requireIdentity: true,
allowedCertificateTypes: [params.certificateTypeId],
requiredFields: params.requiredFields,
restrictions: params.restrictions
};
// Create genesis with identity binding
const genesis = {
assetId: generateAssetId(),
issuerCertificateHash: hash(issuerCert),
complianceRules: rules,
identityCommitment: hash(
assetId + issuerCert + rules + params.maxSupply
)
};
return createGenesisTransaction(genesis);
}async function transferWithCompliance(amount, recipient) {
// Get certificates
const senderCert = await wallet.getCertificate();
const recipientCert = await requestCertificate(recipient);
// Check compliance
const compliance = await checkCompliance(
senderCert,
recipientCert,
token.complianceRules
);
if (!compliance.passed) {
throw new Error(`Compliance failed: ${compliance.reason}`);
}
// Reveal required fields
const keyring = await revealFields(
senderCert,
token.complianceRules.requiredFields,
recipient
);
// Create transfer
return {
transaction: createTokenTransfer(amount, recipient),
identityProofs: {
sender: {
certificate: senderCert,
keyring: keyring
},
recipient: {
certificateHash: hash(recipientCert)
}
},
complianceAttestation: compliance.attestation
};
}Input:
assetId: "abc...def:0"
certificateHash: "123...789"
amount: 100
prevTxid: "def...456"
Output:
commitment = SHA256(assetId || amount || certificateHash || prevTxid)
= "xyz...123"
Certificate Fields:
country: "US"
accreditedStatus: "true"
Compliance Rules:
allowedCountries: ["US", "CA"]
mustBeAccredited: true
Result: PASS ✓
- BRC-52: Identity Certificates
- BRC-53: Certificate Creation and Revelation
- BRC-92: Mandala Token Protocol
- BRC-107: Enhanced Mandala Token Protocol
- BRC-43: Security Levels, Protocol IDs, Key IDs and Counterparties
- BRC-2: Data Encryption and Decryption
- BRC-3: Digital Signature Creation and Verification
Reference implementations:
- TypeScript: Coming Soon
- Go: Coming Soon
- Python: Coming Soon