Skip to content

Instantly share code, notes, and snippets.

@melvincarvalho
Created September 10, 2025 10:36
Show Gist options
  • Select an option

  • Save melvincarvalho/d5c2450268493e5ea7a804c047a20c28 to your computer and use it in GitHub Desktop.

Select an option

Save melvincarvalho/d5c2450268493e5ea7a804c047a20c28 to your computer and use it in GitHub Desktop.
RGBNIA1.md

RGB Contract Encoding and Commitment Analysis

Executive Summary

This document provides a detailed analysis of how RGB Non-Inflatable Assets (NIA) are encoded, hashed, and committed to Bitcoin using the RGB protocol. The analysis is based on the issue_nia::case_1 test executi on.


Test Parameters

  • Test Case: issue_nia::case_1
  • Wallet Descriptor: Wpkh (Witness Public Key Hash)
  • Close Method: OpretFirst (OP_RETURN commitment)
  • Asset Type: NIA (Non-Inflatable Asset) - RGB20 standard
  • Issued Supply: 999 tokens
  • Precision: 2 decimals (0.01 minimum unit)

1. Genesis Contract Structure

Core Genesis Fields (Strict Encoded)

pub struct Genesis {
    pub ffv: Ffv,                        // Format flag version: 0x00
    pub schema_id: SchemaId,             // RGB20 schema ID (32 bytes)
    pub flags: ReservedBytes<1, 0>,      // Reserved: [0x00]
    pub timestamp: i64,                  // Unix timestamp: 1736430XXX
    pub issuer: Identity,                // "ssi:anonymous" (13 bytes)
    pub testnet: bool,                   // true (regtest)
    pub alt_layers1: AltLayer1Set,       // Empty set: []
    pub asset_tags: AssetTags,           // Empty tags: []
    pub metadata: Metadata,              // Asset metadata (see below)
    pub globals: GlobalState,            // Contract terms (see below)
    pub assignments: Assignments,         // Token allocations (see below)
    pub valencies: Valencies,            // Interface definitions
    pub validator: ReservedBytes<1, 0>,  // Reserved: [0x00]
}

Asset Metadata Structure

pub struct Metadata {
    // Field 0: Ticker
    ticker: "TCKR",                    // 4 bytes ASCII
    
    // Field 1: Name  
    name: "asset name",                // 10 bytes ASCII
    
    // Field 2: Details
    details: Some("some details"),     // 12 bytes ASCII
    
    // Field 3: Precision
    precision: 2u8,                    // 1 byte (2 decimal places)
}

Global State (Contract Terms)

pub struct GlobalState {
    // Field 0: Terms text
    terms_text: "Ricardian contract",  // 17 bytes ASCII
    
    // Field 1: Terms media
    terms_media: Some(Media {
        ty: MediaType("image/jpeg"),   // MIME type
        digest: "02d2cc5d7883885bb7472e4fe96a07344b1d7cf794cb06943e1cdb5c57754d8a"
    }),
}

Assignment Structure

pub struct Assignments {
    // Assignment Type 0: Fungible tokens
    fungible: {
        seal: GenesisSeal {
            method: OpretFirst,        // Close method
            outpoint: Outpoint {       // UTXO reference
                txid: "a1b2c3d4e5f6...", // 32-byte transaction ID
                vout: 1u32,            // Output index
            },
            blinding: [u8; 32],        // Random blinding factor
        },
        state: Amount(999),            // Token amount (u64)
    }
}

2. Strict Encoding Process

Encoding Rules

  1. Field Ordering: Fixed canonical order
  2. Length Prefixes: Variable-length fields prefixed with length
  3. Type Encoding: Each type has specific encoding rules
  4. Endianness: Big-endian for multi-byte integers
  5. Padding: No padding, compact representation

Example Field Encodings

# FFV (1 byte)
00

# Schema ID (32 bytes)
a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890

# Timestamp (8 bytes, big-endian i64)
000000017a2b3c4d

# Issuer Identity (1 byte length + 13 bytes data)
0d7373693a616e6f6e796d6f7573  # "ssi:anonymous"

# Testnet flag (1 byte)
01

# Ticker (1 byte length + 4 bytes data)
0454434b52  # "TCKR"

# Name (1 byte length + 10 bytes data)
0a6173736574206e616d65  # "asset name"

# Amount (8 bytes, big-endian u64)
00000000000003e7  # 999

Complete Strict Encoded Genesis (Simplified)

00                                    # FFV
a1b2c3d4...567890                    # Schema ID (32 bytes)
00                                    # Flags
000000017a2b3c4d                     # Timestamp
0d7373693a616e6f6e796d6f7573         # Issuer
01                                    # Testnet
00                                    # Alt layers (empty)
00                                    # Asset tags (empty)
04                                    # Metadata field count
  00 04 54434b52                     # Field 0: Ticker
  01 0a 6173736574206e616d65         # Field 1: Name
  02 0c 736f6d652064657461696c73     # Field 2: Details
  03 01 02                           # Field 3: Precision
02                                    # Global state field count
  00 11 526963617264696e20636f6e...  # Field 0: Terms text
  01 22 696d6167652f6a70656702d2...  # Field 1: Terms media
01                                    # Assignment type count
  00                                  # Assignment type 0
    01                               # Assignment count
      00                             # Close method (OpretFirst)
      a1b2c3d4...4567890 00000001    # Outpoint (txid + vout)
      1234567890abcdef...            # Blinding (32 bytes)
      00000000000003e7               # Amount (999)
00                                    # Valencies (empty)
00                                    # Validator

3. Hash Generation

Contract ID Calculation

// 1. Strict encode the Genesis struct
let encoded_genesis: Vec<u8> = genesis.strict_encode();

// 2. Calculate SHA256 hash
let genesis_hash: [u8; 32] = sha256(&encoded_genesis);

// 3. Contract ID = Genesis Operation ID
let contract_id = ContractId::from(genesis_hash);

Example Hash Calculation

Input (Strict Encoded Genesis):
00a1b2c3d4e5f67890abcdef...

SHA256 Hash:
b4f2e8a3d7c1b9e5f8a2c6d4e1f7b8c3a5d9e2f6b7c8a4d1e5f8b2c7a3d6e9f1

Contract ID (BAID64):
rgb:b4f2e8a3d7c1b9e5f8a2c6d4e1f7b8c3a5d9e2f6b7c8a4d1e5f8b2c7a3d6e9f1

4. BAID64 Encoding

BAID64 Configuration for Contract ID

impl DisplayBaid64<32> for ContractId {
    const HRI: &'static str = "rgb";     // Human-readable identifier
    const CHUNKING: bool = true;         // Add dashes every 5 chars
    const PREFIX: bool = true;           // Include "rgb:" prefix
    const EMBED_CHECKSUM: bool = false;  // No embedded checksum
    const MNEMONIC: bool = false;        // No mnemonic support
}

BAID64 Character Set

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!$

Example BAID64 Encoding

Raw Hash (32 bytes):
b4f2e8a3d7c1b9e5f8a2c6d4e1f7b8c3a5d9e2f6b7c8a4d1e5f8b2c7a3d6e9f1

Base64-like Encoding:
tPLoP9fBueX4osXU4fe4w6XZ4va3yKTR5fiyxzo9bp8R

BAID64 with Chunking:
tPLoP-9fBue-X4osX-U4fe4-w6XZ4-va3yK-TR5fi-yxzo9-bp8R

Final BAID64:
rgb:tPLoP-9fBue-X4osX-U4fe4-w6XZ4-va3yK-TR5fi-yxzo9-bp8R#example-contract

5. OP_RETURN Commitment

Transaction Structure

Transaction {
    version: 2,
    inputs: [
        TxIn {
            previous_output: OutPoint { /* funding UTXO */ },
            script_sig: Script::new(),
            sequence: 0xffffffff,
            witness: Witness { /* witness data */ }
        }
    ],
    outputs: [
        TxOut {
            value: 0,  // No value in OP_RETURN output
            script_pubkey: Script::op_return(&commitment)  // RGB commitment
        },
        TxOut {
            value: 546,  // Dust limit
            script_pubkey: /* recipient address */
        },
        TxOut {
            value: /* change amount */,
            script_pubkey: /* change address */
        }
    ],
    lock_time: 0
}

OP_RETURN Script Construction

// Original script: OP_RETURN (1 byte)
let mut script = ScriptPubkey::from_unsafe(vec![OP_RETURN]);

// Commitment: SHA256 of bundle (32 bytes)
let commitment: [u8; 32] = bundle.commitment_id().into_inner();

// Final script: OP_RETURN <push_32> <commitment>
script = ScriptPubkey::op_return(&commitment);

OP_RETURN Script Bytes

6a20b4f2e8a3d7c1b9e5f8a2c6d4e1f7b8c3a5d9e2f6b7c8a4d1e5f8b2c7a3d6e9f1
│ │ │
│ │ └── RGB commitment (32 bytes)
│ └── Push 32 bytes (0x20)
└── OP_RETURN opcode (0x6a)

6. Bundle Commitment Process

Multi-Protocol Commitment (MPC)

RGB uses MPC to commit multiple protocols in a single OP_RETURN:

pub struct Bundle {
    pub known_transitions: Vec<Transition>,  // RGB state transitions
    pub anchor: Anchor,                      // Bitcoin anchor point
}

// Bundle commitment calculation
let bundle_hash = sha256(&bundle.strict_encode());
let mpc_commitment = MpcCommitment::new(bundle_hash);

Commitment Verification

  1. Extract OP_RETURN data from Bitcoin transaction
  2. Parse MPC commitment structure
  3. Verify RGB bundle hash matches commitment
  4. Validate all state transitions in bundle
  5. Check single-use seals are properly closed

7. Single-Use Seals

Seal Structure

pub struct GenesisSeal {
    pub method: Method,        // OpretFirst or TapretFirst
    pub outpoint: Outpoint,    // UTXO reference
    pub blinding: u64,         // Blinding factor for privacy
}

Seal Verification

  1. UTXO Existence: Verify outpoint exists on Bitcoin
  2. Spending Check: Ensure UTXO is spent in commitment transaction
  3. Commitment Link: Verify OP_RETURN contains proper commitment
  4. State Validity: Validate assigned state is correctly formed

8. Privacy Features

Confidential Amounts

  • On-chain: Only commitment hash visible
  • Off-chain: Full amount stored in RGB consignment
  • Verification: Receiver validates amount against commitment

Blinded UTXOs

  • Genesis: Initial allocation to blinded UTXO
  • Transfers: New assignments use fresh blinding
  • Revelation: Only relevant parties know UTXO mapping

Selective Disclosure

  • Full Consignment: Complete contract history
  • Partial Consignment: Only relevant state transitions
  • Proof Consignment: Minimal data for specific validation

9. Client-Side Validation

Validation Steps

  1. Schema Compliance: Verify operations follow RGB20 schema
  2. State Transitions: Check all transitions are valid
  3. Seal Verification: Ensure single-use seals properly closed
  4. Commitment Verification: Match off-chain data to on-chain commitments
  5. Script Validation: Execute contract validation scripts

Validation Result

pub enum ValidationStatus {
    Valid,                    // All checks passed
    Invalid(ValidationError), // Validation failed
    Unknown,                 // Insufficient data
}

10. Storage and Distribution

On-Chain Data (Bitcoin)

  • OP_RETURN: 32-byte commitment only
  • Transaction: Standard Bitcoin transaction
  • Size Overhead: ~34 bytes per RGB transaction

Off-Chain Data (RGB Consignment)

  • Genesis Contract: Complete contract definition
  • State Transitions: All historical transfers
  • Validation Scripts: Contract logic code
  • Attachments: Media files, documents

Distribution Methods

  • Direct Transfer: P2P consignment exchange
  • Consignment Servers: Centralized storage
  • IPFS/BitTorrent: Distributed storage
  • Lightning Network: Encrypted channel distribution

Conclusion

The RGB protocol achieves scalable, private smart contracts on Bitcoin through:

  1. Deterministic Encoding: Strict encoding ensures consistent hashing
  2. Compact Commitments: Only 32-byte hash committed on-chain
  3. Client-Side Validation: Full validation without blockchain bloat
  4. Privacy by Design: Confidential amounts and blinded UTXOs
  5. Single-Use Seals: Prevent double-spending without global state

This architecture enables unlimited RGB contracts with minimal Bitcoin blockchain impact while maintaining full decentralization and censorship resistance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment