Dual-Mode Remint: An EIP-7503 Birthday-Attack Mitigation That Preserves Token Composability

1. Problem Statement

1.1 Background

EIP-7503 (Zero-Knowledge Wormholes) proposes an on-chain privacy design built around burn addresses. ERC-8065 (Zero Knowledge Token Wrapper) defines a wrapper that adds EIP-7503-style privacy to existing tokens. ZWToken is a full implementation of ERC-8065, supporting ERC-20, native ETH, ERC-721, and ERC-1155.

As an ERC-8065 implementation, ZWToken inherits the core security issue raised but not resolved in EIP-7503—the 160-bit birthday attack. This document states that problem and ZWToken’s mitigation.

1.2 Burn address privacy flow

The core flow of EIP-7503 is:

  1. The user derives a burn address (privacy address) from a secret
  2. Tokens are sent to that address (deposit into a commitment)
  3. Via a ZK proof that they know secret, the user remints an equal amount of tokens at another address

Privacy in this flow relies on: no one can link the burn address to the recipient address.

1.3 Attack vectors

Ethereum addresses are 160 bits. The burn address can be derived as:

addrScalar = Poseidon(8065, tokenId, secret)    // ~254 bits
addr20 = addrScalar mod 2^160                   // truncated to 160 bits

A birthday attack can find a collision in 2^80 operations. The attacker searches two spaces in parallel; by the birthday paradox, ~2^80 trials suffice to find a matching pair:

Vector 1: Double-mint (two secrets collide to the same address)

Poseidon(8065, 0, secret_A) mod 2^160 == Poseidon(8065, 0, secret_B) mod 2^160

The attacker uses secret_A and secret_B to produce different nullifiers and remints twice against the same commitment.

Vector 2: CREATE2 collision

Poseidon(8065, 0, secret) mod 2^160 == CREATE2(deployer, salt, codehash)

The attacker uses CREATE2 to control the burn address: they can drain tokens directly and also remint via ZK proof.

Vector 3: EOA private-key collision

Poseidon(8065, 0, secret) mod 2^160 == keccak256(publicKey)[12:32]

The attacker searches over both secret and ECDSA keys; on collision they hold the private key for the burn address and can sign transfers out.

1.4 Severity

Metric Value
Attack complexity 2^80 hash operations
128-bit security 2^128 operations
Gap Does not meet 128-bit security
Rough cost estimate Tens of billions of USD in hardware (today)
Impact Protocol inflation; pool may be drained

Though economically infeasible today, risk grows with hardware and ASIC optimization.

2. Prior Art

2.1 EIP-7503 Proof-of-Work

Add a PoW constraint in the ZK circuit:

Poseidon(MAGIC_POW, secret) mod 2^POW_BITS == 0

secret must satisfy the PoW condition, raising the cost of finding valid secrets.

Pros:

  • No change to the user-facing flow
  • Fits naturally into the ZK circuit

Cons:

  • Only improves the constant factor, not asymptotic complexity—the attacker pays a 2^POW_BITS multiplier
  • Proof generation time increases significantly (users run PoW client-side)
  • Worse experience on mobile
  • POW_BITS is hard to tune: too low is ineffective, too high is unacceptable for users

2.2 Deposit Cap

Cap the maximum amount per deposit/transfer/remint.

Pros:

  • Simple to implement
  • Caps per-attack profit below the cost of a 2^80 birthday attack

Cons:

  • Breaks token compatibility and composability—deposit, transfer, etc. cannot exceed the cap, so ZWToken (e.g. Wrapped ERC-20 with privacy) cannot behave as a standard ERC-20 with DeFi (Uniswap, Aave, etc.)
  • Constrains legitimate large transfers

3. ZWToken Solution: Dual-Mode Remint

3.1 Core Idea

Set an anonymousCap below the economic cost of a 2^80 birthday attack:

  • Amount ≤ anonymousCap: fully anonymous mode; behavior unchanged from before
  • Amount > anonymousCap: reveal mode; the user must publish the burn address; the contract burns from that address then mints

In the worst case, after ~2^80 work the attacker can only steal up to anonymousCap. If anonymousCap is set below the estimated cost of a 2^80 attack (tens of billions of USD today), there is no rational economic motive. Large transfers are forced through burn-from-address, so inflation from this vector is impossible.

Unlike a global deposit cap, the limit applies only at remint; standard ERC-20 deposit, transfer, and withdraw are unrestricted, preserving full compatibility and DeFi composability. The UI caps transfers to burn addresses at anonymousCap; transfers between ordinary addresses are unlimited.

3.2 Circuit Design

Add one public input revealedAddr and one quadratic constraint:

signal input revealedAddr;  // 0 = anonymous, addr20 = revealed

// If revealedAddr != 0, it must equal addr20
revealedAddr * (revealedAddr - addr20) === 0;
  • revealedAddr = 0: anonymous mode; constraint holds trivially
  • revealedAddr = addr20: reveal mode; proves revealedAddr matches the in-circuit addr20
  • revealedAddr = anything else: constraint fails; proof cannot be produced

Cost: one extra constraint (13084 → 13085); negligible impact on proving time.

3.3 Contract Design

// BaseZWToken.sol
uint256 public immutable anonymousCap;  // 0 = no cap

function _requireRevealIfNeeded(uint256 amount, address revealedAddr) internal view {
    // Amount above cap requires reveal
    if (anonymousCap > 0 && amount > anonymousCap && revealedAddr == address(0)) {
        revert RevealRequired();
    }
    // Revealed address with code = CREATE2 collision attack
    if (revealedAddr != address(0) && revealedAddr.code.length != 0) {
        revert BurnAddressHasCode();
    }
}

Reveal-mode remint flow (ZWERC20 example):

// 1. Burn from burn address first
if (revealedAddr != address(0)) {
    _burn(revealedAddr, amount);
}
// 2. Then normal remint (mint to recipient)
_executeRemint(to, id, amount, redeem, relayerFee);

Effect: burn amount → mint amount (split across recipient + relayer + protocol); net totalSupply change is 0.

3.4 EXTCODESIZE Guard

A valid burn address is a random address from Poseidon; it is always an EOA (no bytecode). If a revealedAddr has code, someone deployed a contract there via CREATE2 collision—direct evidence of attack.

if (revealedAddr.code.length != 0) revert BurnAddressHasCode();

Cost: EXTCODESIZE opcode, ~100 gas.

4. References