Skip to content

Post-Quantum Transaction Protocol for Blocknet #16

Description

@donuts-are-good

Post-Quantum Transaction Protocol for Blocknet

@donuts-are-good, Blocknet Team
June 2026

Abstract

This document specifies a work-in-progress for a post-quantum transaction protocol for Blocknet. The protocol replaces all elliptic-curve-based primitives (Ed25519, Schnorr, CLSAG, Pedersen commitments, Bulletproofs) with a hash-based zero-knowledge proof system and lattice-based key encapsulation. Spend authorization, membership proofs, key images, range checks, and balance verification are consolidated into a single STARK proof per transaction. Recipient detection uses Kyber-512 (ML-KEM). The protocol's fund security depends only on hash function preimage and collision resistance.


1. Notation

Symbol Definition
p A prime suitable for the STARK field
H_ext SHA3-512 (external hash)
H_int Poseidon2 over F_p (internal/circuit hash)
KEM.KeyGen() ML-KEM-512 key generation → (pk, sk), pk = 800 B, sk = 1632 B
KEM.Encaps(pk) ML-KEM-512 encapsulation → (ct, ss), ct = 768 B, ss = 32 B
KEM.Decaps(sk, ct) Kyber-512 decapsulation → ss ∈ {0,1}^256
Enc(key, nonce, plaintext) AES-256-GCM authenticated encryption
Dec(key, nonce, ciphertext) AES-256-GCM authenticated decryption
R Merkle root of the UTXO tree
depth Merkle tree depth (parameter; 30 supports ~10^9 UTXOs)
Failure / no match

Byte lengths: ML-KEM-512 public key = 800 bytes, secret key = 1632 bytes, ciphertext = 768 bytes, shared secret = 32 bytes. SHA3-512 output = 64 bytes, truncated to 32 bytes where noted. Poseidon2 output = field element(s), serialized to 32 bytes. "Kyber-512" and "ML-KEM-512" denote the same FIPS 203 parameter set throughout.

2. Key Generation

All keys are derived deterministically from a single seed.

KeyGen(seed):
  // Spend key (hash-based)
  k_spend    = H_ext("blocknet_spend_key" || seed)[0:32]
  K_spend    = H_ext("blocknet_pubkey" || k_spend)[0:32]

  // KEM key (Kyber-512, for recipient detection)
  kem_seed   = H_ext("blocknet_kem_seed" || seed)[0:64]
  (pk_kem, sk_kem) = KEM.KeyGen(kem_seed)

  // Key image base (deterministic per spend key)
  I          = H_ext("blocknet_image" || k_spend)[0:32]

  return (k_spend, K_spend, pk_kem, sk_kem, I)

The spend key k_spend is a 256-bit secret. The public key K_spend is its SHA3-512 hash, truncated to 256 bits. The key image I is a deterministic function of k_spend alone.

The Kyber keypair (pk_kem, sk_kem) is derived from a domain-separated hash of the seed to ensure independence from the spend key material.

2.1 Address

A Blocknet address is the 800-byte Kyber-512 public key pk_kem, encoded in a transport format (base58, base64, or binary QR code). The spend public key K_spend is not published separately; it is embedded in output commitments.

For human-readable addressing, the blocknet.id key server maps names to pk_kem values. This mapping is off-chain and non-authoritative; the raw pk_kem is canonical.

3. UTXO Structure

3.1 Output Commitment

An output is a triple (commitment, ciphertext, encrypted_data) stored on-chain.

CreateOutput(K_recipient, v, pk_kem_recipient):
  // Derive shared secret via KEM
  (ct, ss)    = KEM.Encaps(pk_kem_recipient)

  // Derive one-time spend key
  k_one_time  = H_ext("blocknet_onetime" || K_recipient || ss)[0:32]
  K_one_time  = H_ext("blocknet_pubkey" || k_one_time)[0:32]

  // Derive blinding factor
  b           = H_ext("blocknet_blind" || ss)[0:32]

  // Compute commitment (stored in Merkle tree)
  commitment  = H_int(K_one_time || v || b)

  // Encrypt amount and blinding for recipient.
  // Nonce is derived deterministically from ss so it need not be stored;
  // ss is unique per output (fresh KEM encapsulation), so nonce reuse cannot
  // occur across outputs under the same key.
  enc_key     = H_ext("blocknet_enc" || ss)[0:32]
  nonce       = H_ext("blocknet_nonce" || ss)[0:12]
  encrypted   = Enc(enc_key, nonce, v || b)

  // View tag (skips post-decapsulation work for non-matches; see §6.1)
  view_tag    = H_ext("blocknet_vtag" || ss)[0]    // 1 byte

  // Field order matches the on-chain output tuple used in §4.1, §6.1, §7.1.
  return (commitment, ct, view_tag, encrypted)

3.2 On-Chain Representation

Each output occupies:

Field Size Description
commitment 32 bytes H_int(K_one_time ‖ v ‖ b), leaf in Merkle tree
ciphertext 768 bytes Kyber-512 ciphertext
view_tag 1 byte First byte of H_ext("blocknet_vtag" ‖ ss)
encrypted_data 56 bytes AES-256-GCM(enc_key, v ‖ b), 40B payload + 16B tag

Total per output: 857 bytes.

3.3 UTXO Merkle Tree

All output commitments are inserted into a Poseidon2 Merkle tree of fixed depth. The tree is append-only; spent outputs are not removed (their key images prevent double-spending).

Tree parameters:

Parameter Value
Hash function Poseidon2 (t=3, α=5) over F_p
Depth 30
Capacity 2^30 ≈ 10^9 outputs
Leaf H_int(K_one_time ‖ v ‖ b)
Internal node H_int(left ‖ right)
Empty leaf 0

The root R is a consensus-critical value, recomputed with each block.

4. Transaction Structure

A transaction tx consumes m ≥ 1 inputs and produces n ≥ 1 outputs.

4.1 Public Data

Transaction {
  // Inputs (public)
  key_images:      [I_1, ..., I_m]              // 32 bytes each
  tree_root:       R                            // 32 bytes

  // Outputs (public)
  outputs:         [(commitment_1, ct_1, vtag_1, enc_1),
                    ...,
                    (commitment_n, ct_n, vtag_n, enc_n)]

  // Fee
  fee:             u64                          // 8 bytes, plaintext

  // Proof
  proof:           π                            // STARK proof
}

4.2 Transaction Hash

tx_hash = H_ext(
  key_images[1] || ... || key_images[m] ||
  R ||
  commitment_1 || ... || commitment_n ||
  fee
)

The transaction hash binds all public inputs to prevent proof transplant attacks.

5. Proof Circuit

The STARK proof π establishes the following statement. All operations below occur inside the arithmetic circuit.

5.1 Private Witness

For each input i ∈ {1, ..., m}:
  k_i       : 32 bytes    — one-time spend secret key
  v_i       : u64         — input amount
  b_i       : 32 bytes    — input blinding factor
  path_i    : [32 bytes × depth]  — Merkle sibling hashes
  pos_i     : [bit × depth]      — path position indicators

For each output j ∈ {1, ..., n}:
  v_j       : u64         — output amount
  b_j       : 32 bytes    — output blinding factor
  K_j       : 32 bytes    — recipient one-time public key

5.2 Constraints

The circuit enforces the following constraints:

Input membership (for each input i):

// Derive public key from secret
K_i = H_ext("blocknet_pubkey" || k_i)[0:32]

// Reconstruct leaf
leaf_i = H_int(K_i || v_i || b_i)

// Verify Merkle path
node = leaf_i
for d in 0..depth-1:
  if pos_i[d] == 0:
    node = H_int(node || path_i[d])
  else:
    node = H_int(path_i[d] || node)
assert node == R

Hash count per input: 1 H_ext + 1 H_int (leaf) + depth × H_int (path) = 1 H_ext + 31 H_int.

Key image correctness (for each input i):

assert I_i == H_ext("blocknet_image" || k_i)[0:32]

Hash count per input: 1 H_ext.

Output well-formedness (for each output j):

assert commitment_j == H_int(K_j || v_j || b_j)

Hash count per output: 1 H_int.

Range checks (for each output j):

// Decompose v_j into 64 bits
bits = bit_decompose(v_j, 64)
assert v_j == Σ bits[k] × 2^k for k in 0..63
assert each bits[k] ∈ {0, 1}

Constraint count per output: 64 bit constraints + 1 recomposition check.

Field-size caveat. Both candidate STARK fields are smaller than 2^64 (M31 = 2^31 − 1; Goldilocks = 2^64 − 2^32 + 1). A 64-bit amount therefore does not fit in a single field element with room to spare, and the recomposition Σ bits[k]·2^k and the balance sum below can wrap modulo p, which would permit inflation if not handled. The implementation must either (a) cap amounts to a width that leaves headroom for the largest possible balance sum (e.g. ≤ 2^63 for Goldilocks, with a bounded input count), or (b) represent amounts as multiple limbs and perform multi-limb range and balance arithmetic. The parameter choice (amount width, maximum input count, limb layout) is deferred to the field selection (Section 12, item 1) and item 8.

Balance:

assert Σ v_i (i=1..m) == Σ v_j (j=1..n) + fee   // computed without field wraparound

Constraint count: 1 arithmetic constraint (plus carry handling if limbed).

Transaction binding:

assert tx_hash == H_ext(I_1 || ... || I_m || R || commitment_1 || ...
                        || commitment_n || fee)

Hash count: 1 H_ext.

5.3 Total Circuit Cost

For a transaction with m inputs and n outputs:

Operation Count Hash Type
Key derivation m H_ext
Key image verification m H_ext
Leaf reconstruction m H_int
Merkle path verification m × depth H_int
Output commitment n H_int
Range decomposition n × 64 bits Arithmetic
Balance check 1 Arithmetic
Transaction binding 1 H_ext

Total H_ext: 2m + 1
Total H_int: m × (depth + 1) + n
Total bit constraints: 64n

For the typical case (m=2, n=2, depth=30):

  • H_ext evaluations: 5
  • H_int evaluations: 64
  • Bit constraints: 128
  • Arithmetic constraints: 1

5.4 Proof System Parameters

Parameter Value
Proof system STARK with FRI
Field Goldilocks (p = 2^64 − 2^32 + 1) or M31 (p = 2^31 − 1)
Security level 128-bit (conjecture, post-quantum)
FRI blowup factor 8 (configurable)
Number of FRI queries ~30–90 (depends on blowup and conjectured vs. proven soundness)

Estimated proof size for a 2-in-2-out transaction: on the order of 40–150 KB. This estimate is not settled. FRI-based STARK proofs carry a large constant overhead (Merkle authentication paths across all query rounds) that dominates small circuits; published systems (Plonky2, Stwo, Boojum) produce proofs in the tens-to-low-hundreds of KB range even for modest computations. The low end of the estimate assumes aggressive optimization (small field such as M31, tuned FRI parameters, and possibly a recursive wrapping step to compress the final proof). The actual figure must be established by benchmarking the chosen proof system on the target circuit (Section 12, item 3). The proof dominates transaction size (metadata is under 2 KB by comparison) and is the primary engineering risk for the protocol.

Estimated proving time: implementation-dependent; a target of a few seconds on consumer hardware is aspirational and unverified.

6. Recipient Detection (Scanning)

6.1 Routine Scan

ScanOutput(sk_kem, K_spend, output):
  (commitment, ct, view_tag, encrypted) = output

  // Decapsulation is mandatory and is the dominant per-output cost.
  ss = KEM.Decaps(sk_kem, ct)

  // View tag rejects non-matching outputs before the (cheaper) remaining work.
  expected_vtag = H_ext("blocknet_vtag" || ss)[0]
  if view_tag ≠ expected_vtag:
    return ⊥

  // Derive keys and check commitment
  k_one_time = H_ext("blocknet_onetime" || K_spend || ss)[0:32]
  K_one_time = H_ext("blocknet_pubkey" || k_one_time)[0:32]
  enc_key    = H_ext("blocknet_enc" || ss)[0:32]
  nonce      = H_ext("blocknet_nonce" || ss)[0:12]
  (v, b)     = Dec(enc_key, nonce, encrypted)
  if commitment == H_int(K_one_time || v || b):
    return (k_one_time, v, b)
  else:
    return ⊥

Scan cost is one ML-KEM-512 decapsulation per output. This is unavoidable: the shared secret ss does not exist until decapsulation completes, so the view tag cannot be computed before paying the decapsulation cost. The view tag therefore does not reduce the dominant cost. Its only benefit is to skip the subsequent key derivations and AES decryption (a few SHA3-512 evaluations and one AEAD operation) for the ~255/256 of outputs that are not the recipient's. Relative to a decapsulation, this saving is small.

This differs from the view tag's role in ECDH-based stealth schemes (e.g., Monero), where the post-shared-secret work includes a second scalar multiplication and the view tag avoids it. Here there is no comparably expensive step after decapsulation, so the view tag is of marginal value. It is retained because the 1-byte cost is negligible, but it must not be relied upon for scan performance. Scan throughput is fundamentally bounded by decapsulation rate.

6.2 Wallet Recovery

RecoverWallet(seed):
  (k_spend, K_spend, pk_kem, sk_kem, I) = KeyGen(seed)
  owned_outputs = []

  for each output in chain_history:
    result = ScanOutput(sk_kem, K_spend, output)
    if result ≠ ⊥:
      owned_outputs.append(result)

  return owned_outputs

Recovery scans every output ever recorded on-chain. For a chain with N outputs, the cost is N ML-KEM-512 decapsulations plus ~N/256 full derivations for view-tag matches. Decapsulation dominates.

At an indicative software decapsulation rate of order 10^4–10^5 operations per second per core, recovery scales as roughly N/10^5 core-seconds. A chain with 10^6 outputs recovers in tens of seconds; a chain with 10^8 outputs (a mature privacy chain's scale) requires tens of minutes to hours on a single core, and is parallelizable across cores. Unlike the current ECDH scan, there is no cheaper pre-filter than decapsulation itself, so scan/recovery cost is a standing concern for the design and a motivation for incremental scanning (checkpoint the last-scanned height and only scan new outputs).

7. Spending

7.1 Spend Procedure

Spend(seed, owned_inputs, recipients, fee):
  (k_spend, K_spend, pk_kem, sk_kem, I) = KeyGen(seed)

  // Build outputs
  outputs = []
  for each (K_recipient, pk_kem_recipient, v) in recipients:
    output = CreateOutput(K_recipient, v, pk_kem_recipient)
    outputs.append(output)

  // Collect witness for each input
  witness_inputs = []
  for each (k_one_time, v, b, merkle_path, pos) in owned_inputs:
    witness_inputs.append({
      k: k_one_time,
      v: v,
      b: b,
      path: merkle_path,
      pos: pos,
      I: H_ext("blocknet_image" || k_one_time)[0:32]
    })

  // Collect witness for each output
  witness_outputs = []
  for each output in outputs:
    witness_outputs.append({v: output.v, b: output.b, K: output.K_one_time})

  // Generate STARK proof
  public_inputs = {
    R:           current_tree_root,
    key_images:  [w.I for w in witness_inputs],
    commitments: [o.commitment for o in outputs],
    fee:         fee,
    tx_hash:     H_ext(... as defined in §4.2 ...)
  }

  π = STARK.Prove(circuit, witness_inputs, witness_outputs, public_inputs)

  // Assemble transaction
  return Transaction {
    key_images:  public_inputs.key_images,
    tree_root:   R,
    outputs:     [(o.commitment, o.ct, o.vtag, o.encrypted) for o in outputs],
    fee:         fee,
    proof:       π
  }

7.2 Verification

VerifyTransaction(tx, R_current):
  // Check tree root is recent (within accepted window)
  assert tx.tree_root ∈ recent_roots

  // Check key images are not already spent
  for I in tx.key_images:
    assert I ∉ spent_key_images

  // Verify STARK proof
  public_inputs = {
    R:           tx.tree_root,
    key_images:  tx.key_images,
    commitments: [o.commitment for o in tx.outputs],
    fee:         tx.fee,
    tx_hash:     H_ext(tx.key_images || tx.tree_root ||
                       tx.commitments || tx.fee)
  }

  assert STARK.Verify(circuit, public_inputs, tx.proof)

  // Record key images as spent
  for I in tx.key_images:
    spent_key_images.insert(I)

  // Insert new outputs into Merkle tree
  for o in tx.outputs:
    utxo_tree.append(o.commitment)

  return VALID

8. Transaction Size

8.1 Per-Transaction Breakdown

For a transaction with m inputs and n outputs:

Component Size
Key images 32m bytes
Tree root 32 bytes
Output commitments 32n bytes
Output ciphertexts 768n bytes
Output view tags n bytes
Output encrypted data 56n bytes
Fee 8 bytes
STARK proof ~40,000–150,000 bytes (see §5.4; unverified)

Total per output: 857 bytes (commitment + ciphertext + view tag + encrypted).

8.2 Typical Transactions

The proof size is approximately constant in the number of inputs/outputs for the small circuits considered here (it grows logarithmically with circuit size, and these transactions differ by only a handful of hash evaluations). A single representative proof-size band is therefore used rather than per-row estimates. Metadata figures are exact.

Type m n Metadata Proof (est., unverified) Total (est.)
Simple send 1 2 1,786 B ~40–150 KB ~42–152 KB
Two-input send 2 2 1,818 B ~40–150 KB ~42–152 KB
Consolidation 4 1 1,025 B ~40–150 KB ~41–151 KB
Multi-output 1 4 3,500 B ~40–150 KB ~43–154 KB

Proof size dominates total transaction size by one to two orders of magnitude over metadata. Per-output metadata is exactly 857 bytes. The proof band is an unverified estimate (§5.4) and is the key quantity to establish by benchmarking. For comparison, the current RingCT transaction for the two-input send case is approximately 3.9 KB; the proposed protocol is expected to be roughly 10–40× larger, in exchange for full-chain anonymity and post-quantum security.

9. Double-Spend Prevention

The key image I = H_ext("blocknet_image" || k_one_time)[0:32] is deterministic: the same one-time key always produces the same image. Consensus nodes maintain a set of all spent key images. A transaction is rejected if any of its key images already appear in this set.

The STARK proof ensures that each key image was correctly derived from the secret key used to prove Merkle membership. A prover cannot fabricate a key image that passes verification without knowing the corresponding secret.

Collision resistance of SHA3-512 (truncated to 256 bits) ensures that distinct keys produce distinct images with overwhelming probability.

10. Security Analysis

10.1 Spend Authorization

An attacker attempting to spend an output must produce a valid STARK proof containing:

  • A secret key k such that H_ext("blocknet_pubkey" || k) matches the public key committed in a UTXO leaf.
  • A valid Merkle path from that leaf to the current root.

The first condition requires inverting the public key. Public keys and key images are SHA3-512 outputs truncated to 256 bits (32 bytes) for on-chain storage efficiency. Preimage resistance of a 256-bit output is 2^256 classically and 2^128 under Grover. Spend authorization therefore has 128-bit post-quantum security — consistent with the protocol's 128-bit floor (Kyber-512 Level 1, AES-256 under Grover, STARK soundness), not higher. Keeping the full 512-bit output would raise this to 2^256 post-quantum but provides no benefit while the floor is 128 bits elsewhere; the truncation is a deliberate storage/security tradeoff. The second condition requires the Merkle path to be consistent with the Poseidon2 tree, which is enforced by the STARK verifier.

10.2 Double-Spend

The relevant threat is not hash collision. A collision (two distinct keys mapping to the same image) only lets an attacker render one of their own outputs unspendable, which is not an attack. The actual requirements to double-spend a given output are:

  • Reusing the output: spending the same output twice produces the same deterministic key image and is rejected by the spent-image set.
  • Forging a distinct valid image for the same output: each output commits to exactly one public key K_one_time, so a second spending key would require a second preimage of that 256-bit public key (2^128 under Grover), and the STARK proof binds the published key image to the key used in the membership proof. Producing an inconsistent image additionally requires breaking STARK soundness (128-bit).

Double-spend resistance thus rests on 256-bit-output second-preimage resistance (2^128 post-quantum) and STARK soundness, both at the 128-bit level. Collision resistance of the truncated image (2^128 classical, ~2^85 under BHT) is not load-bearing for this property.

10.3 Inflation

Creating value requires either:

  • A STARK proof where the balance constraint (Σ inputs = Σ outputs + fee) is violated — requires breaking STARK soundness (hash-based, 128-bit security). - An amount that is out of range or that wraps modulo p — prevented by the range decomposition, but only if the amount width and balance arithmetic are chosen so that no value or sum exceeds p. This is the field-size caveat of Section 5.2 and is a correctness precondition for inflation resistance, not an automatic property: with a field smaller than 2^64, a naive single-element 64-bit amount can itself wrap. The amount width, input/output bounds, and limb layout (Section 12, items 1 and 8) must be set to close this path.

10.4 Privacy

Sender privacy: The STARK proof reveals nothing about which UTXO was spent. The Merkle root is a commitment to the entire tree; the path is part of the private witness.

Recipient privacy: Output commitments are opaque hashes. The Kyber ciphertext is IND-CCA2 secure under the Module-LWE assumption: an attacker without the recipient's Kyber private key cannot determine which recipient an output is addressed to. Note that Kyber ciphertexts are structured, not uniform random strings — they are not indistinguishable from random bytes, only indistinguishable with respect to the encapsulated key. Any protocol property that would require ciphertext-pseudorandomness (e.g., full traffic indistinguishability from noise) is not provided by Kyber alone.

Amount privacy: Amounts are encrypted with AES-256-GCM under a key derived from the Kyber shared secret. They appear only inside the STARK proof's private witness.

Linkability: Key images are deterministic and visible, linking all spends of the same output. They do not link different outputs belonging to the same wallet (each output has a distinct one-time key, producing a distinct image).

10.5 Quantum Security Summary

Property Assumption Post-Quantum Security
Spend authorization 256-bit-truncated SHA3-512 preimage 128 bits (Grover)
Double-spend resistance 256-bit second preimage + STARK soundness 128 bits
Inflation resistance STARK soundness (FRI/Poseidon2) 128 bits
Sender privacy STARK zero-knowledge Information-theoretic
Recipient privacy Module-LWE (Kyber-512, IND-CCA2) ~128 bits (believed)
Amount privacy AES-256-GCM 128 bits (Grover)

Every property targets a uniform 128-bit post-quantum security level. This is a deliberate design choice: the floor is set by Kyber-512 (NIST Level 1) and AES/STARK at 128 bits, so the hash outputs on the fund-critical path are truncated to 256 bits (128-bit post-quantum preimage under Grover) rather than kept at 512 bits, since additional hash-path margin would not raise the system-wide floor. If a higher floor is desired, it must be raised simultaneously across the KEM (Kyber-768/1024), the symmetric layer, the STARK parameters, and the hash output lengths.

11. Parameters Summary

Parameter Value Justification
External hash SHA3-512 Conservative; 40+ years of analysis
Internal hash Poseidon2 (t=3, α=5) Circuit efficiency; most scrutinized ZK hash
KEM Kyber-512 (ML-KEM-512) NIST standard; smallest parameters
Symmetric encryption AES-256-GCM Standard; AEAD
Merkle tree depth 30 Supports ~10^9 outputs
Key image length 32 bytes Truncated SHA3-512
Commitment length 32 bytes Poseidon2 output
STARK field Goldilocks or M31 Implementation-dependent
STARK security 128 bits Standard target
View tag 1 byte Skips post-decapsulation work only (marginal; see §6.1)

12. Open Questions

  1. STARK field selection. Goldilocks (2^64 − 2^32 + 1) and M31 (2^31 − 1) are both viable. Field choice affects proof size, proving time, and Poseidon2 parameterization. Benchmarking on target hardware is required.

  2. Poseidon2 parameterization. The number of rounds, state width, and S-box exponent depend on the chosen field and the target security level. Published parameters exist for common fields but must be validated against current cryptanalysis.

  3. Proof size and proving time. This is the central open problem. The 40–150 KB proof-size estimate (§5.4) and any proving-time target are unverified and must be established by benchmarking a concrete proof system (Stwo, Plonky3, custom) on the actual circuit and target hardware (CPU, GPU). Proof size is the dominant contributor to transaction size and the protocol is not viable for a bandwidth-constrained chain until it is shown to be acceptable. Reduction strategies to evaluate: small-field STARKs (M31), recursive proof wrapping to compress the final proof, and a purpose-built proof system specialized to the fixed spend circuit rather than a general-purpose zkVM.

  4. Multi-asset support. This specification covers a single native asset. Extension to multiple asset types requires additional commitments and balance constraints.

  5. Coinbase transactions. Mining rewards (new issuance) require a transaction format without inputs. The proof for a coinbase transaction covers only output well-formedness and range checks; no membership or key image constraints apply.

  6. View key delegation. This specification does not support delegated scanning (watch-only wallets). If this capability is required, options include a second Kyber keypair per wallet or encrypted transaction export.

  7. Kyber migration. If Module-LWE is compromised, recipients must rotate to a replacement KEM. The spend-layer security (hash-based) is unaffected, but recipient privacy for historical transactions would be retroactively lost.

  8. Amount representation vs. field size. Both candidate fields are smaller than 2^64, so amounts and balance sums cannot be carried in a single field element without risking modular wraparound (Section 5.2). The amount width, maximum input/output counts, and limb layout must be fixed jointly with the field choice to guarantee no overflow path enables inflation.

  9. Recursive block-level aggregation. Each transaction carries its own proof so that relaying nodes can verify it independently before inclusion (Sections 5, 7.2). A separate recursive step can fold the proofs of all transactions in a block into a single block proof attesting that every contained transaction verified, so that syncing and long-term storage cost one proof per block rather than one per transaction. This is a sync/storage optimization layered on top of the per-transaction proofs, not a replacement for them, and it does not affect mempool validation. The proving cost of the aggregation step, the recursion-friendliness of the chosen proof system, and the resulting block-proof size are to be determined alongside item 3.

References

[1] NIST. "Module-Lattice-Based Key-Encapsulation Mechanism Standard." FIPS 203, August 2024.

[2] Grassi, Khovratovich, Rechberger, Roy, Schofnegger. "Poseidon2: A Faster Version of the Poseidon Hash Function." AFRICACRYPT 2023.

[3] NIST. "SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions." FIPS 202, August 2015.

[4] B. Lehmann, @donuts-are-good. "Ran and Shaw: A High-Security Curve Cycle over the Curve25519 Field." 2026.

[5] A. Schrottenloher. "Optimized Point Addition Circuits for Elliptic Curve Discrete Logarithms." arXiv:2606.02235v1, June 2026.

[6] R. Babbush et al. "Securing elliptic curve cryptocurrencies against quantum vulnerabilities." arXiv:2603.28846, 2026.

[7] Ben-Sasson, Bentov, Horesh, Riabzev. "Scalable, transparent, and post-quantum secure computational integrity." IACR ePrint 2018/046.

[8] "Post-Quantum Stealth Address Protocols." arXiv:2501.13733, January 2025.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions