Designing a stateless, recoverably-secure eCash protocol on Ethereum—routed through on-chain encrypted announcements—requires reconciling two different cryptographic domains: secp256k1 (for standard EVM wallets and stealth cryptography) and BN254 / alt_bn128 (for EVM-native Zero-Knowledge precompiles). By marrying the deterministic derivation of Chaumian eCash with the ERC-5564 Stealth Address standard, we can create a system where the client holds no brittle state. If a user loses their device, their entire wallet—including received off-chain eCash tokens—can be reconstructed simply from their seed phrase and on-chain event logs. Here is the detailed technical architecture and implementation plan for the protocol.
- Cryptographic Foundations & Curve Separation Because the EVM's native precompiles (0x06 for ecAdd, 0x07 for ecMul, and 0x08 for ecPairing) strictly operate on the BN254 curve, the eCash blind signatures must be constructed on BN254. However, the encrypted messaging and stealth address routing will utilize secp256k1 to remain compatible with standard Ethereum keypairs and SDKs like KEthereum or Trust Wallet Core.
- eCash Domain (BN254): Used for token secrets, blind signatures, and smart contract verification.
- Stealth Domain (secp256k1): Used for Diffie-Hellman key exchange, generating ephemeral keys, and encrypting the token payloads for transfer.
- The Stateless Derivation Engine (Deterministic Secrets) To achieve statelessness, every piece of eCash data must be deterministically generated from the user's BIP-39 Master Seed. We utilize a Hierarchical Deterministic (HD) path or an HKDF (HMAC-based Extract-and-Expand Key Derivation Function). For every token index i, the client derives:
- Token Secret (x_i): A 32-byte scalar.
- Blinding Factor (r_i): A 32-byte scalar.
- Nullifier Key (nk_i): An ECDSA private key used as the "Smart Nullifier" to mathematically bind the token to a specific withdrawal transaction, preventing MEV front-running. Recovery Mechanism: If the user resets their app, the client simply re-runs the derivation loop from i = 0 to n, regenerating the exact same secrets, and checking the smart contract to see which nullifiers are already marked as spent.
- Minting: The Blind Diffie-Hellman Flow When Alice locks USDC in the Smart Contract Vault to mint a token, she interacts with the off-chain Mint (TEE Enclave).
- Hash to Curve: Alice takes her deterministic secret x_i and maps it to a point on the BN254 curve: Y = \text{hash_to_curve}(x_i).
- Blinding: Alice masks the point using her deterministic blinding factor r_i and the curve generator G: B' = Y + r_iG
- Signing: The Mint verifies Alice's on-chain deposit, and blindly signs the point with its private key sk: C' = sk \times B'
- Unblinding: Alice receives C' and unblinds it locally to retrieve the valid token signature C: C = C' - r_i(sk \times G) Alice now holds a valid eCash token represented by the tuple: (Secret: x_i, Signature: C, Denomination_ID).
- Transfer: Encrypted On-Chain Announcements (ERC-5564) To send the token to Bob statelessly, Alice must transfer the (x_i, C) tuple to him over a public channel without anyone else intercepting it. She will utilize an ERC-5564-style announcement registry. Step A: Ephemeral Key Exchange Alice obtains Bob's Stealth Meta-Address, which contains his public Viewing Key (V_{pub}) and Spending Key (S_{pub}) on secp256k1.
- Alice generates a random ephemeral private key (ek) and its corresponding public key (EK_{pub}).
- Alice performs an Elliptic Curve Diffie-Hellman (ECDH) exchange: SharedSecret = ECDH(ek, V_{pub}). Step B: Payload Encryption Alice derives a symmetric encryption key from the SharedSecret (e.g., via HKDF). She then encrypts the eCash token tuple using AES-256-GCM or ChaCha20-Poly1305.
- Ciphertext Payload: Encrypt(SymmetricKey, {x_i, C, Denomination_ID}) Step C: On-Chain Publishing Alice submits a transaction to the Ethereum network calling the Announce function on the standard Singleton Registry contract. function announce( uint256 schemeId, address stealthAddress, bytes memory ephemeralPubKey, bytes memory ciphertext ) external;
Note: The transaction fee for this announcement can be subsidized by a relayer or paid by Alice's standard EVM wallet. 5. Discovery & State Recovery (The Receiver) Bob's mobile client remains completely stateless. To find his funds, it passively scans the Announce events emitted by the registry contract.
- Event Parsing: For every event, Bob's client reads the ephemeralPubKey (EK_{pub}).
- ECDH Trial: Bob combines EK_{pub} with his private Viewing Key (v_{priv}) to compute the SharedSecret.
- Trial Decryption: Bob attempts to decrypt the ciphertext. If the MAC check passes, the decryption succeeds.
- Token Extraction: Bob has successfully recovered the eCash token (x_i, C). He can verify its validity locally by checking e(C, G_2) == e(\text{hash_to_curve}(x_i), PK_{mint}). If Bob drops his phone in a lake, he simply imports his seed phrase into a new device. The app re-derives his Viewing Key, parses the chain history, and instantly decrypts all of his historical inbound tokens.
- On-Chain Redemption & MEV Protection When Bob is ready to cash out his tokens back into USDC on his public Ethereum address, he constructs a withdrawal proof.
- BLS Aggregation: If Bob has 5 tokens, he adds the 5 BN254 signature points together off-chain: \sigma_{agg} = \sum C_i.
- MEV Lock: To prevent mempool snipers from replacing his destination address, Bob uses the ECDSA "Smart Nullifier" key associated with each token (derived deterministically from x_i) to sign the payload: "Pay to: <Bob's_Public_Address>".
- Submission: Bob submits the nullifiers (the public keys of the Smart Nullifiers), the ECDSA signatures, and the aggregated BLS signature \sigma_{agg} to the Vault contract. The Vault Contract Execution:
- Verifies that the nullifiers have not been spent.
- Recovers the ECDSA signatures (ecrecover) to prove the transaction intent wasn't hijacked.
- Hashes the nullifiers to the BN254 curve and sums them: M_{agg} = \sum \text{hash_to_curve}(nullifier_i).
- Executes the native ecPairing precompile: e(\sigma_{agg}, G_2) == e(M_{agg}, PK_{mint}).
- If mathematically sound, dispenses the USDC to Bob's address. Technical Stack & Library Mapping To build this on Android/Kotlin per the referenced ecosystem:
- BIP-39 & Key Derivation: kotlin-bip39 (Electric Coin Company) and kotlin-bip for HD path generation.
- secp256k1 (Stealth & ECDSA): secp256k1-kmp (ACINQ) or Trust Wallet Core via JNI for highly optimized ECDH shared secret generation and standard signing.
- BN254 (Blind Signatures): A Kotlin multiplatform wrapper around mcl-wasm (or a direct JNI C++ bridge to an optimized pairings library) will be required to handle the hash_to_curve, point addition, and unblinding logic locally before submitting to the EVM.