Transaction Bundles
Transaction Bundles - Technical Specification
This document describes the transaction bundle format, which packages all components of a Roru transaction into a single, verifiable unit.
Bundle Structure
Bundle Format
Transaction Bundle:
pub struct TransactionBundle {
pub header: BundleHeader,
pub inputs: Vec<Input>,
pub outputs: Vec<Output>,
pub proof: Proof,
pub nullifiers: Vec<Nullifier>,
pub public_data: PublicData,
pub signature: Signature,
pub metadata: BundleMetadata,
}Bundle Header
Header Format:
pub struct BundleHeader {
pub version: u8, // Bundle version
pub network_id: u32, // Network identifier
pub timestamp: u64, // Creation timestamp
pub expiry: Option<u64>, // Expiry timestamp (if any)
pub bundle_hash: Hash, // Hash of bundle
}Input Structure
Input Format
Input Definition:
pub struct Input {
pub note_commitment: Commitment, // Commitment to note
pub merkle_proof: MerkleProof, // Proof of inclusion
pub nullifier: Nullifier, // Nullifier for note
pub authorization: Authorization, // Spending authorization
}Input Components
Note Commitment:
Pedersen commitment to note
Proves note exists
Hides note value
Binding commitment
Merkle Proof:
Proof note exists in tree
Path from leaf to root
Verifies inclusion
Logarithmic size
Nullifier:
Prevents double-spending
Unique per note
Unlinkable
Verifiable
Authorization:
Proves spending right
Signature or proof
Device attestation (if used)
Validates ownership
Output Structure
Output Format
Output Definition:
pub struct Output {
pub commitment: Commitment, // Commitment to new note
pub encrypted_note: EncryptedNote, // Encrypted note data
pub recipient: ShieldedAddress, // Recipient address
}Output Components
Commitment:
Pedersen commitment
Added to state tree
Hides value
Binding
Encrypted Note:
Encrypted note data
Only recipient can decrypt
End-to-end encryption
Privacy-preserving
Recipient Address:
Shielded address format
Cannot be linked
Privacy-preserving
Verifiable
Proof Structure
Proof Format
Proof Definition:
pub struct Proof {
pub input_proof: InputProof, // Proof for inputs
pub output_proof: OutputProof, // Proof for outputs
pub balance_proof: BalanceProof, // Balance proof
pub authorization_proof: AuthProof, // Authorization proof
}Proof Components
Input Proof:
Proves input notes exist
Validates nullifiers
Verifies authorization
Ensures notes not spent
Output Proof:
Proves output notes valid
Validates commitments
Checks recipient format
Ensures value ranges
Balance Proof:
Proves value conservation
Hides individual values
Verifies no overflow
Ensures correctness
Authorization Proof:
Proves spending right
Validates signature
Checks device (if used)
Ensures ownership
Nullifier Set
Nullifier Format
Nullifier Structure:
pub struct Nullifier {
pub hash: Hash, // Nullifier hash
}Nullifier Verification
Verification Process:
Check nullifier not in set
Verify nullifier format
Validate nullifier generation
Add to nullifier set
Verification Code:
fn verify_nullifiers(nullifiers: &[Nullifier], nullifier_set: &NullifierSet) -> bool {
for nullifier in nullifiers {
if nullifier_set.contains(nullifier) {
return false; // Double-spend detected
}
}
true
}Public Data
Public Data Format
Public Data Structure:
pub struct PublicData {
pub fee: Option<u64>, // Public fee (if any)
pub refund: Option<u64>, // Public refund (if any)
pub memo: Option<Vec<u8>>, // Public memo (if any)
pub metadata: Option<Metadata>, // Additional metadata
}Public Data Usage
Use Cases:
Public fees
Compliance requirements
Transparent operations
Optional metadata
Signature
Signature Format
Signature Structure:
pub struct Signature {
pub signature: [u8; 64], // Signature bytes
pub public_key: Point, // Public key
}Signature Verification
Verification Process:
Recover public key
Verify signature
Check authorization
Validate format
Verification Code:
fn verify_signature(bundle: &TransactionBundle, signature: &Signature) -> bool {
let message = bundle.hash();
verify_signature(&message, &signature.signature, &signature.public_key)
}Bundle Metadata
Metadata Format
Metadata Structure:
pub struct BundleMetadata {
pub version: u8, // Metadata version
pub chain_id: u32, // Target chain
pub gas_limit: Option<u64>, // Gas limit (if applicable)
pub priority: Option<u8>, // Priority level
pub tags: Vec<String>, // Optional tags
}Bundle Serialization
Serialization Format
Binary Format:
[Header][Inputs][Outputs][Proof][Nullifiers][PublicData][Signature][Metadata]Serialization Code:
fn serialize_bundle(bundle: &TransactionBundle) -> Vec<u8> {
let mut data = Vec::new();
data.extend_from_slice(&bundle.header.serialize());
data.extend_from_slice(&serialize_inputs(&bundle.inputs));
data.extend_from_slice(&serialize_outputs(&bundle.outputs));
data.extend_from_slice(&bundle.proof.serialize());
data.extend_from_slice(&serialize_nullifiers(&bundle.nullifiers));
data.extend_from_slice(&bundle.public_data.serialize());
data.extend_from_slice(&bundle.signature.serialize());
data.extend_from_slice(&bundle.metadata.serialize());
data
}Deserialization
Deserialization Code:
fn deserialize_bundle(data: &[u8]) -> Result<TransactionBundle> {
let mut offset = 0;
let header = BundleHeader::deserialize(&data[offset..])?;
offset += header.size();
// ... continue deserializing other components
Ok(TransactionBundle { /* ... */ })
}Bundle Validation
Validation Process
Validation Steps:
Verify bundle format
Verify signatures
Verify proofs
Verify nullifiers
Verify balance
Verify constraints
Validation Code:
fn validate_bundle(bundle: &TransactionBundle, state: &State) -> Result<()> {
// Verify format
verify_format(bundle)?;
// Verify signatures
verify_signature(bundle)?;
// Verify proofs
verify_proofs(bundle, state)?;
// Verify nullifiers
verify_nullifiers(&bundle.nullifiers, &state.nullifier_set)?;
// Verify balance
verify_balance(bundle)?;
// Verify constraints
verify_constraints(bundle)?;
Ok(())
}Bundle Hashing
Hash Calculation
Hash Formula:
bundle_hash = Hash(header || inputs || outputs || proof || nullifiers || public_data)Hash Implementation:
fn hash_bundle(bundle: &TransactionBundle) -> Hash {
let mut hasher = Hasher::new();
hasher.update(&bundle.header.serialize());
hasher.update(&serialize_inputs(&bundle.inputs));
hasher.update(&serialize_outputs(&bundle.outputs));
hasher.update(&bundle.proof.serialize());
hasher.update(&serialize_nullifiers(&bundle.nullifiers));
hasher.update(&bundle.public_data.serialize());
hasher.finalize()
}Performance
Bundle Sizes
Typical Sizes:
Header: ~64 bytes
Input (per): ~500 bytes
Output (per): ~300 bytes
Proof: ~1-2 KB
Nullifiers: 32 bytes each
Signature: ~96 bytes
Total: ~2-5 KB (typical)
Optimization
Optimization Techniques:
Compress proofs
Batch operations
Efficient serialization
Reduce redundancy
Security
Security Properties
Integrity:
Bundle hash prevents tampering
Signatures ensure authenticity
Proofs ensure correctness
Nullifiers prevent double-spending
Privacy:
Values hidden in commitments
Addresses encrypted
Proofs hide information
No linkability
Conclusion
Transaction bundles provide:
Completeness: All transaction data
Verifiability: Cryptographic proofs
Privacy: Hidden information
Efficiency: Compact format
Security: Cryptographic guarantees
Understanding bundles is essential for transaction processing.
Last updated
