System Architecture
Anubis adopts an innovative three-layer architectural design, establishing a tight synergy among the underlying consensus, execution environment, and application layer. At its core lies a unique Hybrid State Model, enabling seamless interoperability between the UTXO and Account models.
3.1 Overall Architecture Layering
Layers
Components
Function Description
Layer 3: Application layer
DApps &
Wallets
It includes DeFi protocols, NFT marketplaces, and privacy wallets. It interacts with the underlying infrastructure via the Anubis SDK, handling off-chain transaction construction and zero-knowledge proof generation (Client-side Proving).
Layer 2: Privacy Execution Layer
Anubis EVM
Extensions
It includes a note system, a stealth address registry, and ZK-verified pre-compiled contracts. This serves as a bridge connecting privacy computing and EVM logic.
Layer 1: Core protocol layer
Consensus &
Ledger
Responsible for achieving consensus (PoS), block proposals, and maintaining and synchronizing the State Trie & Note Tree.
Table 3-1 Anubis Three-layer Architecture Components and Functions

Figure 3-1 Anubis Three-Layer Architecture Diagram
3.2 Detailed Explanation of Core Components
3.2.1 Anubis EVM (Modified Geth)
Anubis is built upon deep customization of the mature Go-Ethereum (Geth) client. Beyond standard EVM functionality, Anubis introduces a suite of privacy-focused precompiled contracts. Instead of existing as EVM bytecode, these contracts are implemented directly in Go and compiled into the node client, ensuring exceptionally high execution efficiency.
List of key pre-compiled contracts:
Address
Name
Function
Gas Mechanism
0x0100
VERIFY_PROOF
Verification of PLONK zero-knowledge proof
Fixed base cost + variable cost (approximately 50k gas)3
0x0101
PEDERSEN_COMMIT
Calculate Pedersen commitments C = g^v * h^r
Extremely low, optimized based on ECC addition.
0x0102
STEALTH_ADDRESS
Stealth address and shared key derived from EIP-5564
Medium difficulty, involving elliptic curve multiplication.
0x0103
NULLIFIER_CHECK
Check and mark null characters (to prevent double-spending).
High, including Bloom filter lookup and state writing.
0x0104
ENCRYPT_NOTE
Encrypt note data using the ECIES algorithm.
The length increases linearly with the data length.
0x0105
VIEW_KEY_DERIVE
Derive view keys at each level from the private key.
Based on curve scalar multiplication
Table 3-2 List of Key Anubis EVM Pre-compiled Contracts
These pre-compiled contracts allow Solidity developers to easily implement logic in smart contracts that "Verify that someone owns an asset without revealing who it is."
3.2.2 Note-taking system
To achieve privacy, Anubis introduces a UTXO-like "Note" model alongside the traditional account-based balance model.
Note structure:
Solidity
struct Note { bytes32 commitment; // Pedersen commitment: C = g^amount * h^blinding bytes32 nullifier; // Null symbol, used to prevent double-spending during consumption address assetType; // Asset type (e.g., USDC address), publicly visible uint256 amount; // Amount, hidden in the promise, or revealed in selective privacy mode bytes encryptedData; // Encrypted metadata (recipient, Memo, etc.), visible only to those holding the View Key. }
Note lifecycle:
Create (Minting/Shielding) When a user transfers funds from a public account to a private pool, a new Note is generated. Its Commitment is added to the Note Commitment Tree.
Holding Notes exist statically within the Merkle tree. Since only the Commitment is public, the owner and value of a Note are unknown to outsiders.
Spending When a user constructs a transaction, they need to generate a ZK proof to demonstrate that they possess the private key of a specific Note in the tree and disclose the corresponding Note of the Nullifier。
Nullification The nullifier is recorded in the nullifier set. Any transaction attempting to reuse the nullifier will be rejected, thus preventing double-spending.
State explosion and optimization mechanism
As transaction volume increases, the Merkle Tree and Nullifier Set can grow indefinitely. Anubis employs several optimization measures:
Sparse Merkle Tree Using a tree structure with a depth of 32, the theoretical capacity reaches...
(Approximately 4.3 billion) notes, supporting efficient non-containment proofs. To address long-term state growth:
Paid Notes Pruning Nullifier Set using a hybrid approach of Bloom Filter + full storage.
Historical state archiving Historical data exceeding a certain block height can be archived to cold storage via the Merkle path.
Stateless clients Lightweight clients only require the latest Tree Root; the Merkle Path is provided on demand by full nodes.
Bloom filter optimization To accelerate nullifier deduplication, a Bloom filter is maintained in memory. This is a probabilistic data structure that can quickly determine whether a nullifier "absolutely does not exist" or "may exist" with minimal memory usage. If Bloom FilterReturning to "potentially exists" before performing a disk database query, significantly reduces disk I/O and improves TPS.4。
JoinSplit mechanism To prevent "Dust Attacks" from exceeding circuit input limits (currently capped at 4 input Notes for PLONK circuits), the SDK automatically performs background JoinSplit operations. By merging multiple small-amount Notes into a single large-amount Note, it ensures that interactions with major DeFi protocols do not fail due to input overflow.

Figure 3-2 Schematic Diagram of Anubis JoinSplit Merging Mechanism
3.2.3 Stealth address registry
Anubis includes a built-in stealth address registry contract compliant with the EIP-5564 standard.
Solidity
contract StealthAddressRegistry { // User's meta address mapping (User -> MetaAddress) mapping(address => StealthMetaAddress) public metaAddresses; struct StealthMetaAddress { bytes32 spendingPubKey; // Public key for spending: used to generate a stealth address bytes32 viewingPubKey; // View public key: Used to generate the shared key (ECDH) } // Registration meta address function register(bytes32 spendPubKey, bytes32 viewPubKey) external; // On-chain helper function: Calculates the stealth address (usually calculated by the off-chain SDK to save gas). function generateStealthAddress(address recipient, bytes32 ephemeralPubKey) external view returns (address); }
This registry acts as the "phonebook" of the privacy ecosystem. It enables any user to look up a recipient's meta-address via their public identity (such as an ENS domain) and generate a unique stealth address for transfers—eliminating the need for real-time peer-to-peer negotiation.
3.3 Mixed-State Model
The most significant architectural breakthrough of Anubis lies in its state synchronization.
Account state Based on Patricia Merkle Trie, it stores contract code, public balances (such as ETH balance), and contract storage.
Private State (Note State) Store Note Commitments based on an Append-only Merkle Tree.
Synchronization mechanism:
When executing a block, the EVM updates both trees simultaneously. For example, a Type 103 (privacy contract call) transaction might:
Mark old notes as spent in the Note Tree (insert nullifier).
Temporarily increase the contract's token balance in the Account State.
Execute the contract logic and change the Storage Variable in the Account State.
Insert the newly generated Note Commitment into the Note Tree.
All state changes are atomically committed, either all succeed or all are rolled back.
This design allows Anubis to possess both the concurrent processing capabilities and privacy of the UTXO model and the Turing completeness of the account model.

Last updated
