Skip to content

K0 privacy package: eliminate ringsize-2 (fixes #120) - #121

Open
liqdmetal wants to merge 4 commits into
DEROFDN:community-devfrom
liqdmetal:fix/k0-privacy-package
Open

K0 privacy package: eliminate ringsize-2 (fixes #120)#121
liqdmetal wants to merge 4 commits into
DEROFDN:community-devfrom
liqdmetal:fix/k0-privacy-package

Conversation

@liqdmetal

Copy link
Copy Markdown

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% of
mainnet 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
PrivacyWarning surfaced 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:

  • fork-boundary dodge — the floor keys off the chain tip, not the
    attacker-settable tx.Height (a tx can reference a block 11 back)
  • SC_TX type-lie — a ringsize-2 NORMAL transfer stamped SC_TX (a no-op
    execution 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_DATA Type byte — 33-byte wire format unchanged) marks
contracts that never call SIGNER(), auto-detected at install via AST scan
(ContractUsesSigner). Existing contracts default to uses_signer=true
(behavior preserved). Then:

  • SC_TX + ringsize 2 + NoSigner → rejected
  • SC_INSTALL at ringsize < 4 → rejected

After 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.mod is 3 lines with no
vendor/modules.txt, so fresh clones don't build).

Tests (22, all green)

  • blockchain: k0_ringsize (floor reject / not-active / pre-fork), wargame
    bypass + 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 field

Sequencing note

The fourth stage — Fix C, owner auth via verify_sig so gated contracts can
run at ringsize ≥ 4 — depends on the DVM v9 verify_sig intrinsic and remains
a 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 on community-dev.

…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).
@liqdmetal

Copy link
Copy Markdown
Author

@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 (Extract_signer). Over half of mainnet txs currently use ringsize 2.

The fix is three stages, in one reviewable PR (17 files, no vendor noise):

  1. Fix A (wallet, no hard fork) — warn when a transfer resolves to ringsize 2, surface PrivacyWarning over RPC. Ships immediately.
  2. Fix B1 (consensus, hard fork) — from K0_MIN_RING4_HEIGHT, NORMAL/BURN txs with ringsize < 4 are rejected. Hardened against fork-boundary and SC_TX type-lie bypasses.
  3. Fix B2 (consensus, hard fork) — NoSigner bit in SC_META_DATA (33-byte wire format unchanged) auto-detected at install; ringsize-2 SC calls + SC_INSTALL at ring < 4 rejected. Existing contracts default to uses_signer=true, so behavior is preserved.

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 verify_sig so gated contracts run at ringsize >= 4) is a separate PR (#98) because it depends on the DVM v9 intrinsics.

Happy to rebase, split, or adjust the hard-fork height — just let me know what you'd like to see.

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