K0 privacy package: eliminate ringsize-2 (fixes #120) - #121
Conversation
…mod, no vendor/modules.txt)
…PC field (no HF) RingSize-2 txs expose the signer on-chain by design (Extract_signer). The wallet/API half of K0: warn when a transfer resolves to ringsize 2, surface PrivacyWarning to programmatic callers. Ships immediately, no consensus.
…r registry (hard fork) The consensus half of eliminating ringsize-2 on-chain: B1 — from K0_MIN_RING4_HEIGHT, NORMAL/BURN txs with ringsize < 4 are rejected (privacy floor of 4 = sender + receiver + 2 decoys). Hardened against fork-boundary and SC_TX type-lie bypasses. B2 — ringsize-2 SC_TX exposes the signer by design; the NoSigner bit (high bit of SC_META_DATA Type byte, 33-byte wire format unchanged) marks contracts that never call SIGNER(), auto-detected at install via AST scan. SC_TX + ringsize 2 + NoSigner is rejected; SC_INSTALL at ringsize < 4 is rejected. Existing contracts default to uses_signer=true (behavior preserved). Tests: k0_ringsize, wargame bypass, k0_b2 consensus, uses-signer detection.
…plements it Upstream community-dev vendors a readline without KickReader, so the wallet-cli does not build from a fresh clone. Replace the two call sites with a no-op (UI shim only, not consensus-relevant).
|
@CaptainDero @Slixe @8lecramm — flagging for review. This is a security fix, not a feature. The issue: ringsize-2 transactions expose the signer on-chain by design — the ring is sender+receiver, and parity selects the sender ( The fix is three stages, in one reviewable PR (17 files, no vendor noise):
22 tests green across blockchain/dvm/walletapi. Full tree builds from a fresh clone (the branch also carries the minimal go.mod/go.sum fix — upstream's go.mod is 3 lines with no vendor/modules.txt). The fourth stage (owner auth via Happy to rebase, split, or adjust the hard-fork height — just let me know what you'd like to see. |
Summary
The complete K0 privacy package, consolidated into one reviewable PR.
RingSize-2 transactions expose the signer on-chain by design — the ring is
sender + receiver, and parity selects the sender (
Extract_signer). 56.8% ofmainnet txs use ringsize 2. This package eliminates the loophole in three
stages, sequenced so each is independently reviewable and the non-consensus
half ships immediately.
The fixes
Fix A — wallet warning (no hard fork, ships now)
The wallet/API half. When a transfer resolves to ringsize 2, the wallet sets a
PrivacyWarningsurfaced through the RPC result. No consensus change.Fix B1 — consensus min-ring-4 floor (hard fork)
From
K0_MIN_RING4_HEIGHT, NORMAL/BURN txs with ringsize < 4 are rejected.The floor of 4 = sender + receiver + 2 decoys is the smallest meaningful
anonymity set. Hardened against two bypasses found during wargaming:
attacker-settable
tx.Height(a tx can reference a block 11 back)SC_TX(a no-opexecution path) no longer dodges the gate
Fix B2 — uses_signer registry (hard fork)
RingSize-2 SC calls expose the signer the same way. The NoSigner bit (high
bit of the
SC_META_DATAType byte — 33-byte wire format unchanged) markscontracts that never call
SIGNER(), auto-detected at install via AST scan(
ContractUsesSigner). Existing contracts default touses_signer=true(behavior preserved). Then:
SC_TX+ ringsize 2 + NoSigner → rejectedSC_INSTALLat ringsize < 4 → rejectedAfter B1+B2, ringsize 2 has no legitimate remaining use.
Why this is one PR now
Previously split across four PRs (#80, #82, #91, #98), each carrying a
4,400-file vendored-dependency diff that made review impractical. This is the
same code consolidated into 16 files / ~1,000 lines, with no vendor noise,
plus the build-manifest fix (upstream's
go.modis 3 lines with novendor/modules.txt, so fresh clones don't build).Tests (22, all green)
blockchain: k0_ringsize (floor reject / not-active / pre-fork), wargamebypass + SC_TX type-lie, k0_b2 consensus
dvm: ContractUsesSigner (detect / no-false-positive / case-insensitive),SC_META NoSigner bit, Private+NoSigner coexist
walletapi: ringsize-2 warning set, ring-4 no-warning, Transfer result fieldSequencing note
The fourth stage — Fix C, owner auth via
verify_sigso gated contracts canrun at ringsize ≥ 4 — depends on the DVM v9
verify_sigintrinsic and remainsa separate PR (submitted separately against the intrinsics).
Supersedes
Closes the fragmented #80 (Fix A), #82 (Fix B1), #91 (Fix B2) in favour of
this single package. (#98 / Fix C stays open as it targets a different base.)
Branch
fix/k0-privacy-package, based oncommunity-dev.