Crypto Primitives
This page documents the cryptographic operations that the C++ bridge (crypto/ package) provides to the Go codebase. Each primitive is described at a conceptual level: what it does, why the chain needs it, and which hardfork introduces or changes it.
Curve Operations
Ed25519 / Curve25519
What it does: Elliptic curve arithmetic on the Ed25519 curve (Twisted Edwards form of Curve25519). Point addition, scalar multiplication, point-scalar operations.
Why it is needed: All public keys, key images, commitments, and ring signature operations are built on Ed25519 group elements. The curve provides 128-bit security.
Key types:
PublicKey(32 bytes) -- compressed Ed25519 pointSecretKey(32 bytes) -- scalar modulo the group order lKeyDerivation(32 bytes) -- Diffie-Hellman shared secret point
Available from: Genesis (HF0).
Hash Functions
Keccak-256 (cn_fast_hash)
What it does: Computes Keccak-256 (the original Keccak, not SHA-3) of arbitrary data, producing a 32-byte hash.
Why it is needed: The primary hash function throughout the protocol. Used for transaction hashes, block hashes, key derivations, address checksums, and proof construction.
Available from: Genesis (HF0).
Tree Hash (tree_hash)
What it does: Computes a Merkle tree hash over a set of transaction hashes within a block. Uses Keccak-256 as the leaf/node hash.
Why it is needed: The block header commits to all transactions via a single 32-byte root hash. This allows SPV-style proofs of transaction inclusion.
Available from: Genesis (HF0).
BLAKE2
What it does: BLAKE2b hash function, used in specific proof constructions (Bulletproofs+, Zarcanum).
Why it is needed: Provides domain-separated hashing in zero-knowledge proof systems where Keccak is not used.
Available from: HF4 (Zarcanum).
Stealth Addresses
Key Derivation
What it does: Given a transaction public key R and the recipient's secret view key a, computes a shared secret D = a * R. This derivation is then hashed with an output index to produce per-output keys.
Why it is needed: Enables unlinkable one-time addresses. Each output appears at a unique stealth address that only the recipient can identify and spend.
One-Time Key Generation
What it does: For output index i, derives the one-time public key P = Hs(D, i) * G + B where B is the recipient's spend public key. The recipient can compute the corresponding secret key.
Why it is needed: Ensures that outputs sent to the same address are indistinguishable from each other on the blockchain.
Available from: Genesis (HF0).
Key Images
What it does: For a one-time key pair (p, P), computes the key image I = p * Hp(P) where Hp is a hash-to-point function.
Why it is needed: Double-spend prevention. Each output can only be spent once. When spent, its key image is revealed and recorded; any subsequent attempt to spend the same output would produce an identical key image, which the network rejects.
Properties: Key images are deterministic (same output always produces the same image) and unlinkable (the image cannot be traced back to the output without the secret key).
Available from: Genesis (HF0).
Ring Signatures
Ring signatures allow a spender to prove ownership of one output within a set (the "ring") without revealing which specific output they own. The set of other outputs (decoys) provides anonymity.
Classic CryptoNote Ring Signatures (NLSAG)
What it does: A Spontaneous Anonymous Group signature (SAG) scheme as described in the original CryptoNote whitepaper. For each input, the spender constructs a ring of public keys and signs a message such that any ring member could have been the signer.
Ring size: 10 decoys + 1 real (pre-HF4).
Why it is needed: Transaction input privacy. Observers cannot determine which output in the ring is being spent.
Available from: Genesis (HF0). Used for transaction versions 0 and 1.
CLSAG-GG
What it does: Compact Linkable Spontaneous Anonymous Group signature with two base points (G, G). A more efficient ring signature that produces smaller signatures and faster verification compared to the classic scheme.
Why it is needed: Reduces transaction size and verification time while maintaining the same security guarantees.
Available from: HF4 (Zarcanum).
CLSAG-GGX
What it does: CLSAG variant with three base points (G, G, X). Used for Zarcanum confidential transactions where the signer must prove knowledge of the secret key and the amount commitment blinding factor simultaneously.
Why it is needed: Enables confidential (hidden amount) transactions. The ring signature simultaneously proves spend authority and that the amount commitment is well-formed.
Available from: HF4 (Zarcanum). Used in ZC_sig structures.
CLSAG-GGXXG
What it does: CLSAG variant with five base points (G, G, X, X, G). The most complex variant, used in Zarcanum Proof-of-Stake block signing where the staker must prove knowledge of multiple secrets simultaneously.
Why it is needed: Combines spend authority proof, amount commitment proof, and staking eligibility proof into a single compact ring signature for PoS blocks.
Available from: HF4 (Zarcanum). Used in zarcanum_sig structures.
Range Proofs
Bulletproofs+ (BP+)
What it does: Zero-knowledge range proofs that demonstrate a committed value lies within [0, 2^64) without revealing the value. Bulletproofs+ are an improved version of Bulletproofs with smaller proof size and faster verification.
Why it is needed: When amounts are hidden in Pedersen commitments, the network must verify that no output has a negative amount (which would allow inflation). BP+ provides this guarantee.
Proof format: bpp_signature_serialized with an associated vector_UG_aggregation_proof for commitment aggregation.
Available from: HF4 (Zarcanum). Stored in zc_outs_range_proof attachments.
Bulletproofs++ (BP++) for Stake Proofs
What it does: An extended Bulletproofs variant used specifically in Zarcanum PoS proofs. Proves that the stake amount meets the minimum threshold without revealing the exact amount.
Why it is needed: PoS stakers must prove they hold sufficient stake without revealing their balance.
Proof format: bppe_signature_serialized within zarcanum_sig.
Available from: HF4 (Zarcanum).
Zarcanum PoS Proofs
What it does: A composite proof structure for Proof-of-Stake block production under Zarcanum. Combines:
- A stake commitment proof (scalar
d, pointsC,C',E) - Schnorr-like response scalars (
c,y0-y4) - A BP++ range proof for the stake amount (
E_range_proof) - A CLSAG-GGXXG ring signature (
clsag_ggxxg) - A pseudo-output amount commitment
Why it is needed: Allows PoS validators to prove they own a valid stake (with sufficient amount and coinage) and produce a valid block, all without revealing which specific output they are staking or how much it contains.
Available from: HF4 (Zarcanum).
Asset Surjection Proofs
BGE Proofs (Bootle-Groth-Esgin)
What it does: Proves that each output's blinded asset ID corresponds to one of the input asset IDs, without revealing which. One proof per output (non-aggregated).
Why it is needed: When confidential assets are introduced (HF5), transactions can move multiple asset types. The surjection proof ensures that assets are not created or transmuted -- only the legitimate asset types present in the inputs can appear in the outputs.
Available from: HF5 (confidential assets). Stored in zc_asset_surjection_proof attachments.
Balance Proofs
Double Schnorr Signature
What it does: Proves that the transaction balances (sum of inputs = sum of outputs + fee) without revealing individual amounts. Implemented as a generic double Schnorr signature (generic_double_schnorr_sig_s).
For transactions without Zarcanum inputs: proves the balance point is a linear combination of G. For transactions with Zarcanum inputs: proves the balance point is a linear combination of X (the asset point), ensuring blinded asset tags cancel correctly.
Also proves knowledge of the transaction secret key.
Why it is needed: Conservation of value. Without this proof, a transaction could create or destroy coins.
Available from: HF4 (Zarcanum). Stored in zc_balance_proof attachments.
Pedersen Commitments
What it does: Commits to a value v with blinding factor r as C = v * H + r * G (or C = v * U + r * G in some Zarcanum contexts), where H and G are independent generator points.
Why it is needed: Pedersen commitments are additively homomorphic: C(a) + C(b) = C(a+b). This allows verification that inputs and outputs balance without revealing amounts. The blinding factor prevents observers from determining the committed value.
Available from: HF4 (Zarcanum). The native coin asset ID H is a fixed curve point.
Wallet Encryption
ChaCha8
What it does: ChaCha stream cipher with 8 rounds, used to encrypt wallet files and sensitive in-memory data.
Why it is needed: Protects wallet keys at rest. The wallet key file is encrypted with a key derived from the user's password via a KDF.
File signatures: 0x1111011201101011 (wallet v2 format).
Available from: Genesis (HF0).
Summary Table
| Primitive | Purpose | Hardfork | Package constant |
|---|---|---|---|
| Keccak-256 | Primary hash | HF0 | -- |
| Tree hash | Tx merkle root | HF0 | -- |
| BLAKE2 | Proof hashing | HF4 | -- |
| Ed25519 ops | Key arithmetic | HF0 | -- |
| Key derivation | Stealth addresses | HF0 | -- |
| Key images | Double-spend prevention | HF0 | -- |
| NLSAG ring sigs | Input privacy (classic) | HF0 | CURRENCY_DEFAULT_DECOY_SET_SIZE = 10 |
| CLSAG-GG | Efficient ring sigs | HF4 | CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE = 15 |
| CLSAG-GGX | Confidential tx sigs | HF4 | -- |
| CLSAG-GGXXG | PoS stake sigs | HF4 | -- |
| Bulletproofs+ | Amount range proofs | HF4 | -- |
| Bulletproofs++ | Stake range proofs | HF4 | -- |
| Zarcanum proofs | PoS composite proofs | HF4 | -- |
| BGE surjection | Asset type proofs | HF5 | -- |
| Double Schnorr | Balance proofs | HF4 | -- |
| Pedersen commitments | Hidden amounts | HF4 | -- |
| ChaCha8 | Wallet encryption | HF0 | -- |