Skip to content

fix(mix): reject duplicate nullifiers and deposit amount overflow - #1340

Open
vipwzw wants to merge 1 commit into
masterfrom
fix-mix-nullifier-overflow
Open

vipwzw wants to merge 1 commit into
masterfrom
fix-mix-nullifier-overflow

Conversation

@vipwzw

@vipwzw vipwzw commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

问题

本次 v1.76.3 审计发现 mix 执行器两处可直接盗取资金池的问题:

  1. Withdraw 同交易重复 nullifier 双花:withdrawVerify/spendVerify 只读状态检查 nullifier 是否存在,nullifier KV 在整笔 action 付款完成后才写入,且循环内不写库。同一 MixWithdrawAction 里重复放同一个 proof,把 Amount 写成 N*value 即可通过 sumValue == Amount 校验,同一张票据被支付 N 次。
  2. Deposit 金额 uint64 累加溢出:sum += v.Uint64() 无溢出检查,付款使用 int64(sum)。构造多张单张可正常取出的票据,使总和超过 2^64,实际只支付回绕后的零头,票据仍按原面额逐张进入 Merkle 树后取出。

修复

  • ForkMixDupNullifier:Withdraw 在单笔 action 内维护 nullifier 集合,重复直接返回 ErrNulliferHashExist。
  • ForkMixAmountOverflow:Deposit 累加前校验 v.Uint64() > math.MaxInt64 - sum,溢出返回 ErrAmountOverflow。

两个分叉默认注册为高度 0;老链如需保持旧共识行为,在 [fork.sub.mix] 中配置为未来高度即可。

验证

  • go build ./plugin/dapp/mix/... 通过
  • go test ./plugin/dapp/mix/executor/ -count=1 通过(既有执行器套件)
  • 修复前行为:同一 proof 重复 N 次可取 N 份;185 张票据总面额 2^64+1e8 的存款只扣 1e8

Withdraw only reads the nullifier state during proof verification and writes
it after the payout, so the same proof repeated in one MixWithdrawAction was
paid N times. Deposit accumulates note amounts in a uint64 without an overflow
check, so several notes whose values sum past 2^64 could be recorded in the
Merkle tree after paying only the wrapped remainder.

- ForkMixDupNullifier: deduplicate nullifiers inside one action.
- ForkMixAmountOverflow: reject v.Uint64() that would overflow MaxInt64-sum
  before accumulating.

Both forks are registered defaulting to height 0; set a future height in the
fork config to keep the legacy behavior for an existing chain.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant