Summary
bitcoinerlab/miniscript accepts a bare Miniscript multi(k, ...) expression with more than 20 pubkeys and compiles it successfully instead of rejecting it.
Current reference implementations reject this family because CHECKMULTISIG supports at most 20 pubkeys. However, the exposed bare-Miniscript surface here currently treats the same input as both valid and sane.
Minimal repro
const { analyzeMiniscript, compileMiniscript } = require("@bitcoinerlab/miniscript");
const source =
"multi(2,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5,02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a,03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8,03499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4,02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e,03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a,03defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34,025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc,022b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c,024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97,02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5)";
console.log(analyzeMiniscript(source, { tapscript: false }));
console.log(compileMiniscript(source, { tapscript: false }).asm);
Observed locally
The payload contains 21 unique pubkeys.
Observed behavior:
-
analyzeMiniscript(source, { tapscript: false }) reports:
-
compileMiniscript(source, { tapscript: false }) succeeds
-
the compiler emits script for the same invalid policy
Expected behavior
The input should be rejected because bare multi(k, ...) maps to CHECKMULTISIG, which supports at most 20 pubkeys.
For this payload, the expected behavior is a parse / validation / compilation failure for:
Cross-check against maintained peers
The same payload is rejected by maintained implementations:
rust-miniscript: invalid threshold 2-of-21; maximum size is 20
bitcoin/bitcoin: parse failed
elements-miniscript: CHECKMULTISIG ('multi()' descriptor) only supports up to 20 pubkeys
Summary
bitcoinerlab/miniscriptaccepts a bare Miniscriptmulti(k, ...)expression with more than 20 pubkeys and compiles it successfully instead of rejecting it.Current reference implementations reject this family because
CHECKMULTISIGsupports at most 20 pubkeys. However, the exposed bare-Miniscript surface here currently treats the same input as both valid and sane.Minimal repro
Observed locally
The payload contains 21 unique pubkeys.
Observed behavior:
analyzeMiniscript(source, { tapscript: false })reports:valid: trueissane: truecompileMiniscript(source, { tapscript: false })succeedsthe compiler emits script for the same invalid policy
Expected behavior
The input should be rejected because bare
multi(k, ...)maps toCHECKMULTISIG, which supports at most 20 pubkeys.For this payload, the expected behavior is a parse / validation / compilation failure for:
Cross-check against maintained peers
The same payload is rejected by maintained implementations:
rust-miniscript:invalid threshold 2-of-21; maximum size is 20bitcoin/bitcoin: parse failedelements-miniscript:CHECKMULTISIG ('multi()' descriptor) only supports up to 20 pubkeys