Verify It Works
Run this demo to prove the stealth address cryptography works without any blockchain connection.
No Blockchain Required
This example runs entirely offline. It demonstrates that the cryptographic primitives work correctly: address generation, payment creation, detection, and key derivation.
Run the Demo
Clone the repository and run the demo example:
git clone https://github.com/onyx-labs/onyx-sdk
cd onyx-sdk
cargo run --example demoWhat It Proves
Stealth addresses are unique
Each payment generates a different one-time address, even for the same recipient.
Recipients can detect their payments
Using their viewing key, recipients successfully identify incoming payments.
Recipients can spend received funds
The derived keypair matches the stealth address, proving spend capability.
Others cannot detect your payments
Different users scanning the same announcements find nothing intended for them.
Demo Source Code
Here is the complete demo that runs through the full stealth payment flow:
use onyx_sdk::{Scanner, StealthMetaAddress, StealthPayment, StealthKeypair};
fn main() {
// Step 1: Alice generates her stealth meta-address
let alice_meta = StealthMetaAddress::generate();
let alice_public = alice_meta.public_meta_address();
println!("Alice's public meta-address (shareable):");
println!("{}", alice_public.to_string());
// Step 2: Bob creates a stealth payment to Alice
let amount = 1_000_000_000; // 1 SOL in lamports
let payment = StealthPayment::create(&alice_public, amount).unwrap();
println!("Payment created:");
println!(" Stealth address: {}", payment.stealth_address);
println!(" Ephemeral pubkey: {}", hex::encode(&payment.ephemeral_pubkey[..8]));
println!(" Amount: {} lamports (1 SOL)", amount);
// Step 3: Alice scans and detects the payment
// Simulate an announcement (what would be on-chain)
let announcement = onyx_sdk::Announcement {
ephemeral_pubkey: payment.ephemeral_pubkey,
stealth_address: payment.stealth_address,
timestamp: 1234567890,
};
let scanner = Scanner::new(&alice_meta);
let detected = scanner.scan_announcements_list(&[announcement.clone()]).unwrap();
println!("Scanning 1 announcement(s)...");
println!("Found {} payment(s) for Alice!", detected.len());
// Step 4: Alice derives the spending keypair
let stealth_keypair = StealthKeypair::derive(&alice_meta, &payment.ephemeral_pubkey).unwrap();
let derived_address = stealth_keypair.address();
println!("Derived keypair address: {}", derived_address);
println!("Original stealth address: {}", payment.stealth_address);
// Step 5: Verify the addresses match
let addresses_match = derived_address == payment.stealth_address;
if addresses_match {
println!("SUCCESS: Derived address matches stealth address!");
println!("Alice can spend funds from this address.");
}
// Step 6: Verify Bob cannot detect Alice's payment
let bob_meta = StealthMetaAddress::generate();
let bob_scanner = Scanner::new(&bob_meta);
let bob_detected = bob_scanner.scan_announcements_list(&[announcement]).unwrap();
println!("Bob tries to scan the same announcement...");
println!("Payments detected by Bob: {}", bob_detected.len());
if bob_detected.is_empty() {
println!("SUCCESS: Bob cannot detect Alice's payment!");
println!("Privacy preserved.");
}
println!("All verifications passed! Stealth payments work.");
}Expected Output
╔════════════════════════════════════════════════════════════╗
║ Onyx SDK - Stealth Payment Demo ║
╚════════════════════════════════════════════════════════════╝
┌─────────────────────────────────────────────────────────────┐
│ Step 1: Alice generates her stealth meta-address │
└─────────────────────────────────────────────────────────────┘
Alice's public meta-address (shareable):
stealth1...
┌─────────────────────────────────────────────────────────────┐
│ Step 2: Bob creates a stealth payment to Alice │
└─────────────────────────────────────────────────────────────┘
Payment created:
• Stealth address: <unique one-time address>
• Amount: 1000000000 lamports (1 SOL)
┌─────────────────────────────────────────────────────────────┐
│ Step 3: Alice scans and detects the payment │
└─────────────────────────────────────────────────────────────┘
Scanning 1 announcement(s)...
Found 1 payment(s) for Alice!
┌─────────────────────────────────────────────────────────────┐
│ Step 4: Alice derives the spending keypair │
└─────────────────────────────────────────────────────────────┘
Derived keypair address: <matches stealth address>
Original stealth address: <same as derived>
┌─────────────────────────────────────────────────────────────┐
│ Step 5: Verification │
└─────────────────────────────────────────────────────────────┘
✓ SUCCESS: Derived address matches stealth address!
✓ Alice can spend funds from this address.
┌─────────────────────────────────────────────────────────────┐
│ Step 6: Privacy verification │
└─────────────────────────────────────────────────────────────┘
Bob tries to scan the same announcement...
Payments detected by Bob: 0
✓ SUCCESS: Bob cannot detect Alice's payment!
✓ Privacy preserved.
╔════════════════════════════════════════════════════════════╗
║ All verifications passed! Stealth payments work. ║
╚════════════════════════════════════════════════════════════╝Run the Test Suite
For comprehensive verification, run the full test suite with 14+ tests covering all cryptographic operations:
cargo test
# Expected output:
# running 14 tests
# test keys::tests::test_generate_meta_address ... ok
# test keys::tests::test_public_meta_address_encoding ... ok
# test address::tests::test_create_stealth_payment ... ok
# test address::tests::test_stealth_address_detection ... ok
# test scanner::tests::test_scan_detects_payment ... ok
# test address::tests::test_each_payment_unique_address ... ok
# test spend::tests::test_derive_spend_key ... ok
# ...
# test result: ok. 14 passed; 0 failed