Repository navigation
policy: reject fake 1-of-N multisig data carriers (bpub/bitfiles) - #435
MarcanoFilms wants to merge 1 commit into
Conversation
2f0290a to
ae19d19
Compare
|
The shape test rejects live wallets, and the encoder gets past it with one more signature, so I would fold this into #422 rather than take it as a rule of its own. I ran ae19d19 over every transaction since the fork, 961640 to 974573 (3,103,397 transactions). It rejects all 19 bpub reveals: the 14 through 974259 and five more today at 974541 to 974573, 1,793 inputs and 1.13 MB between them. It also rejects 105 other transactions: 64 spend a 1-of-3, 33 a 1-of-4, 4 a 1-of-5, 3 a 1-of-6 and 1 a 1-of-8. Those are wallets, not data. One P2WSH 1-of-3 script has been spent in 12 transactions from 961852 (4d11a45481bb35be47b39d44ce5000fb5f4c2687e4f8145efe32e6c063b2d969) to 974315 (9ca0432bcca0bac3feed8f72b8bca10c462a12340def9bb144d44e228407fcb9), and two 1-of-4 scripts in 6 and 5 transactions across the same span, one or two inputs at a time. bpub never reuses a script. For comparison, #422 as posted rejects 507 of the same set, and 3 with a per-script allowance of 8 spare keys. The rule is a subset of #422. An encoder that moves to 2-of-15 gives up one data key per input and adds one signature, and this check no longer sees it, while #422 still counts the 13 unproven keys. Could the m == 1 shape be the floor under #422's allowance instead of a separate check? Two smaller things:
|
Spends that reveal a 1-of-N CHECKMULTISIG (N >= MULTISIG_DATACARRIER_MIN_KEYS) wrapped in P2SH/P2WSH are a common on-chain shape for file-embedding overlays (bitfiles/bpub): 14 of 15 'pubkeys' are payload, only one signs. AreInputsStandard solves the executed script of every P2SH/P2WSH/P2SH-P2WSH input and rejects this shape as datacarrier-fakemultisig, in PreChecks, so it covers relay and block templates. Gated by its own -rejectfakemultisig option (default on, reset by -corepolicy), independent of -permitbaremultisig. Threshold multisig (m >= 2) and 1-of-2 are untouched. The m == 1 shape is a strong but not exclusive signal: a survey of the fork chain rejects all known bpub reveals plus a small number of genuine 1-of-N wallet spends, and an embedder could migrate to m >= 2. Documented as relay/mempool policy (not consensus), complementary to the funding-side dust filter, and reconcilable with a general unproven-key allowance.
ae19d19 to
7d176d0
Compare
|
Thanks for running it over the whole chain — that data is exactly what this needed, and it changes my framing. You're right that it's not false-positive-free. The 105 genuine 1-of-3…1-of-8 spends (some scripts reused across many txs, which bpub never does) disprove the claim in my description. I've dropped that wording; the On folding into #422: yes — I agree the Meanwhile I've addressed the smaller points so this branch stands on its own if useful:
Rebuilt and the functional test passes. Let me know if you'd prefer the floor to live in #422 and I'll close this. |
Problem
File-storage overlays such as bitfiles (via the
bpublibrary) embed arbitrary files on chain by hiding payload bytes inside the "public keys" of a 1-of-NCHECKMULTISIGscript, wrapped in P2SH/P2WSH:OP_1 <pk1> ... <pk15> OP_15 OP_CHECKMULTISIG, where 14 of the 15 "public keys" are ~31 bytes of file data each and only one is a real signer.Why existing filters miss the reveal
-permitbaremultisig=0only inspects output scripts; here the multisig is a P2WSH witnessScript revealed on spend.CScript::DatacarrierBytes()recognizes OP_RETURN, inscription envelopes,<data> OP_DROP, OLGA and OPNet — but not the bare-multisig data pattern.Fix
AreInputsStandardnow solves the executed script of every P2SH / P2WSH / P2SH-P2WSH input (viaGetScriptForTransactionInput) and, when-rejectfakemultisigis set, rejects the tx as non-standard if it is a 1-of-N multisig with N ≥MULTISIG_DATACARRIER_MIN_KEYS(3) — reasondatacarrier-fakemultisig.The check has its own option (
-rejectfakemultisig, default on, reset by-corepolicy, like-rejectparasites) so it is independent of-permitbaremultisig. It runs inPreChecks(before signature validation), so it applies to relay and block-template construction. Threshold multisig (2-of-3, 3-of-5, …) and 1-of-2 scripts are untouched.Accuracy — not a clean separator
A 1-of-N multisig lets any single one of its N keys spend, which is strictly weaker than a plain single-key output, so N ≥ 3 is a strong hint of data carriage — but not exclusive to it. Running this over the fork chain (961640–974573) rejects all known bpub reveals and ~105 spends of genuine 1-of-3…1-of-8 wallet scripts (some reused across many txs, which bpub never does). An embedder could also migrate to
m ≥ 2to dodge them == 1test. This is therefore best seen as the floor of a general unproven-key allowance (cf. #422), and it is complementary to the funding-side dust filter (#389). Operators who need those spends can set-rejectfakemultisig=0.Testing
Functional test
feature_datacarrier_fakemultisig.py:datacarrier-fakemultisigAlso verified against the real witnessScript of an observed reveal tx (
be667d76425d48df0ea891176fd8ef0a3a4329775cecc5afaf4558500c9e84e9).Docs
doc/policy/datacarrier-fakemultisig.md— full write-up incl. limitations (relay/mining policy not consensus; false positives on genuine 1-of-N wallets;m ≥ 2migration; relationship to policy: count pubkeys no signature can prove as datacarrier bytes #422/policy: Count data in output hashes and keys #389). Threshold constant kept inpolicy.h.-rejectfakemultisighelp; reverted the-permitbaremultisighelp to its original wording.