BIP352 defines A = A₁ + … + Aₙ on the receiving side and a = a₁ + … + aₙ on the sending side, and it says what to do when the total is the identity (receiver: skip; sender: fail). It does not say what happens when an intermediate partial sum equals the point at infinity during accumulation. This pins the intended behavior normatively:
- accumulation MUST tolerate intermediate infinity (it is the group identity — it does not affect the total);
- accumulation MUST be order-invariant;
- EC backends that error on point-at-infinity addition MUST catch the condition and continue accumulating.
This is a clarification, not a behavior change: the reference implementation (secp256k1lab GE.sum) already tolerates intermediate infinity, and the official send_and_receive_test_vectors.json already contains the intermediate-cancellation (zero-sum) case. It also matches the text's existing claim — the sum is a group operation, whose identity element is the point at infinity.
Why reachable, not theoretical
For any private key a with P = a·G, the negated public key −P = (n − a)·G is also spendable by the same holder. Consequently a transaction whose input-key list contains an intermediate cancellation (e.g. [P, −P, Q] summing to Q, non-infinite total) is ordinary, consensus-valid, and cheap — reachable by construction, with ordering as the knob. An implementation that errors on intermediate cancellation becomes input-order-dependent, dropping or mis-deriving payments that conformant implementations accept, and receiver software scans arbitrary on-chain transactions containing any of the eligible input types (P2TR, P2WPKH, P2SH-P2WPKH, P2PKH).
Evidence (backend contracts differ at today’s public pins)
- The BIP352 reference implementation tolerates intermediate cancellation (
secp256k1labGE.sum); the official vectors already contain that case. go-libsecp256k1.PubKeyAdderrors withinvalid public key: [0,0] not on secp256k1 curveon an intermediate infinity — the index then silently drops the transaction depending on input ordering.- rust-secp256k1 reports
InvalidPublicKeySum/InvalidTweakon the same case in the Rust silent-payments crates (rust-silentpayments / spdk) — send aborts, receive errors, both diverging from the reference verdict. - libsecp256k1 (C core) handles infinity correctly at the group-element level (
secp256k1_ge/gejops), while serialized-pubkey helpers (secp256k1_ec_pubkey_combine) reject it — so wrappers inherit either behavior depending on which API layer they call.
Cross-implementation divergence on this clause was found during a public differential of open implementations against the BIP's own official vectors; the fix is to pin the reference semantics in prose, and no vector changes are needed.