CHIP-0057: Silent Payments - #198
Conversation
Create Silent Payments CHIP
Create chip-kdc2000-silent_payments
|
This CHIP has been assigned as CHIP-57 and is a Please leave your reviews here, and feel free to comment in the #chips channel of our Discord. |
|
The recording of the discussion of this CHIP is now available on Youtube. |
|
This CHIP is now in |
… fixes Reconcile the spec to the simplified single-Pass-2 scanning model (v1.5): - Collapse Pass 2a (puzzle-hash grouping) + Pass 2b into a single Pass 2 (opcode-64 ASSERT_CONCURRENT_SPEND directed-SCC); drop puzzle-hash grouping. - Reword the stale "Spend group" glossary definition to concurrent-spend linkage. - Correct Appendix A bandwidth for Chia's ~1-in-3 transaction-block frequency (~1,536 tx blocks/day; ~7.5-9 MB/day total). - Remove Appendix C (ECDH scalar multiplication). - Genericize evolving reference-implementation file references. Status unchanged (Review). Test Vector 4 cryptographic values unchanged.
|
Update on the multi-input grouping, plus a few editorial corrections. Grouping: strongly connected components over While implementing silent payments in the chia-wallet-sdk, I adopted strongly-connected-component (SCC) grouping over explicit opcode-64 This replaces the earlier approach, which combined two heuristics: grouping coins that share a puzzle hash, and linking coins via coin announcements (opcode 60/61, Test Vector 4's cryptographic values are unchanged. Editorial corrections
Status unchanged ( |
Absent any new reviews, do you foresee yourself needing to make additional changes to your CHIP? If not, then I could move it to Last Call soon. |
I've just reviewed this again, and I have a few small changes I would like to make. They should be done by the end of this week. |
…ent model The appendix predated multi-input scanning: it served per-spend (PK, coin ID) entries with client-side ECDH, which cannot reproduce Pass-2 spend-group formation (grouping requires executing puzzles/solutions for opcode-64 conditions). Rewritten to server-side grouping serving one precomputed 48-byte tweak point (input_hash * A_sum) per spend group, group-level transaction cut-through, and bandwidth estimates recomputed at 48 B/group.
The address data part now carries a leading 5-bit version character. v0 = the 96-byte scan||spend payload (exact length enforced); v1-30 are forward-compatible (senders use the first 96 payload bytes and ignore trailing data); v31 is reserved as a must-reject sentinel for backward-incompatible upgrades. Also specifies the 1,023-character length allowance (SP addresses exceed bech32's 90-char limit).
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4be6090. Configure here.
| **Verification:** | ||
| - Scanner using *b*<sub>scan</sub> + *A* produces the same puzzle hash: YES | ||
| - Recipient derives one-time SK = (*b*<sub>spend</sub> + *t*<sub>0</sub>) mod *r* = `3c399c61ae130724903b3b650e936ff042b7646764289a33519e17100a89db37` | ||
| - One-time SK * G matches P_0: YES |
There was a problem hiding this comment.
Test vector spend key mismatch
Medium Severity
Test Vector 1 lists a one-time spend key that is not equal to (b_spend + t_0) mod r from the same vector. The stated verification that this key’s public point matches P_0 cannot hold, so implementations that check or use this hex will fail spend tests.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 4be6090. Configure here.
There was a problem hiding this comment.
False positive — the arithmetic checks out, including the mod-r reduction:
b_spend + t_0 = 0x53d140b3…b087 + 0x5c560301…2ab1
= 0xb02743b4d7b0846cc375136d183547f59675086a6426f632519e170f0a89db38
The raw sum exceeds the group order r, and reducing mod r (one subtraction of r) gives exactly the value printed in the vector:
(b_spend + t_0) mod r = 0x3c399c61ae130724903b3b650e936ff042b7646764289a33519e17100a89db37
This is also verified end-to-end by the automated suites that generate these vectors: b_spend is derived from the TV1 mnemonic, and multiplying the resulting one-time SK by G (BLS12-381 scalar multiplication via chia_rs/blst) reproduces the printed P_0 = b671487c…e964d byte-for-byte, in both the Python and Rust reference test suites. No change needed.
| * Let *group*: `list[CoinSpend]` = *removals* whose coin_id is in *scc* | ||
| * For each *removal* in *group*: let *pk*<sub>i</sub> = extract_synthetic_pk(*removal*.puzzle_reveal); skip if None | ||
| * Let *A*<sub>sum</sub>: `G1` = *pk*<sub>1</sub> + *pk*<sub>2</sub> + ... + *pk*<sub>n</sub> | ||
| * Let *group_coin_ids*: `list[bytes32]` = coin IDs of all *removals* in *group* |
There was a problem hiding this comment.
Pass 2 coin set mismatch
High Severity
Pass 2 builds A_sum only from extractable synthetic keys (skip if None) but sets group_coin_ids to every coin in the SCC. Security also requires cycling every input coin. If a non-standard coin joins that cycle, coin_id_L can diverge from the sender’s eligible set and multi-input payments are silently missed.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 4be6090. Configure here.
There was a problem hiding this comment.
The premise requires a non-standard coin inside the opcode-64 binding cycle, which can't arise for a conforming sender and has no recipient-side impact:
- No third party can inject a coin into a group. That's precisely what directed-SCC selection provides: an outside spend asserting a victim's coin ID creates a one-way edge and lands in its own trivial SCC (see Scanner Grouping Strategies). Only the sender constructs the cycle.
- A conforming sender's cycle contains only standard coins. The Sending procedure takes one synthetic secret key per spent coin — every coin participating in the derivation is a standard-puzzle coin by construction, so within a conforming group
skip if Nonenever fires and the scanner's key set and coin-ID set coincide exactly with the sender's. Theskip if Nonebranch is defensive handling for nonconforming input, per the Non-Standard Puzzles section. - A nonconforming sender only harms itself. If a sender cycles in a coin it didn't include in its own derivation, the resulting mismatch means that sender's payment isn't detected — a self-inflicted correctness failure with no security or privacy impact on recipients, and no risk to funds (the coin still exists; it's simply not detected as a silent payment).
Given the practical severity is "a sender deviating from the spec breaks its own payment," we don't think a spec change is warranted; the reference implementation additionally rejects mixed-asset bundles outright, so it cannot produce such a group.
|
Humans, please leave your further reviews here before the spec is finalized. Discussions can also happen in the #chips channel of our Discord. |


Note
Low Risk
This PR only adds a specification document to the CHIPs repo; it does not change consensus, puzzles, or wallet code. Future implementation mistakes in ECDH, grouping, or key handling would be security-sensitive, but that risk is outside this diff.
Overview
Adds CHIP-0057 (
CHIPs/chip-0057.md), a new Review-status process/tooling CHIP that specifies silent payments on Chia—unlinkable one-time outputs from a staticspxch1/tspxch1address, adapted from Bitcoin BIP-352.The document defines BLS12-381 ECDH using the sender’s synthetic public key from standard
p2_delegated_puzzle_or_hidden_puzzlereveals, EIP-2333 scan/spend paths (m/12381/8444/12/0and13/0), tagged hashes, input hashing from smallest coin ID plus aggregated sender key, output indexing, labeling via forward puzzle-hash checks, and multi-input spend grouping via cyclicASSERT_CONCURRENT_SPEND(opcode 64) SCCs. It includes send/scan/spend pseudocode,K_max, security and compatibility notes (no consensus changes), four full test vectors, a reference implementation link, and appendices on light clients and ECDH vs pairings.Reviewed by Cursor Bugbot for commit 4be6090. Bugbot is set up for automated code reviews on this repo. Configure here.