Skip to content

BIP-379: add test vectors from rust-miniscript - #2240

Open
guggero wants to merge 3 commits into
bitcoin:masterfrom
guggero:bip379-test-vectors
Open

BIP-379: add test vectors from rust-miniscript#2240
guggero wants to merge 3 commits into
bitcoin:masterfrom
guggero:bip379-test-vectors

Conversation

@guggero

@guggero guggero commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

The BIP-379 currently has a TBD in the test vector section.
I have extracted a bunch of test vectors from the rust-miniscript project, either directly or by slightly modifying test code to dump them into text/TSV files.
They have been very helpful for re-implementation in another language, so I think they should be made easily available here.

@jonatack jonatack added Proposed BIP modification PR by non-owner to update BIP content Pending acceptance This BIP modification requires sign-off by the champion of the BIP being modified labels Aug 6, 2026
@jonatack

jonatack commented Aug 7, 2026

Copy link
Copy Markdown
Member

Concept ACK. It may be handy to provide a file here that runs/verifies the test vectors.

@guggero
guggero force-pushed the bip379-test-vectors branch from 3ef799a to 9334aa2 Compare August 7, 2026 08:56
@guggero

guggero commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Concept ACK. It may be handy to provide a file here that runs/verifies the test vectors.

That's a great idea. I've added that in the latest push.
Output looks like this:

$ cd bip-0379; go run main.go
Checking the BIP379 test vectors in . against
github.com/btcsuite/btcd/descriptors/miniscript.

Testing vectors in valid_from_alloy.txt       [positive]: 5896/5896 done (type column not compared)
Testing vectors in valid_8f1e8_from_alloy.txt [positive]: 3492/3492 done (type column not compared)
Testing vectors in malleable_from_alloy.txt   [positive/negative]: 7024/7024 + 7024/7024 done
Testing vectors in conflict_from_alloy.txt    [positive]: 1773/1773 done (1586 of them are rejected by the sanity checks)
Testing vectors in edge_cases.txt             [positive]: 42/42 done
Testing vectors in opcodes.txt                [positive]: 18185/18185 done (type and op count columns not compared)
Testing vectors in invalid.txt                [negative]: 5574/5574 done
Testing vectors in props_from_rust.tsv        [positive]: 8198/8198 done (op_count and exec_stack columns not compared)
Testing vectors in props_from_rust_tap.tsv    [positive/negative]: 6728/6728 + 1470/1470 done (op_count and exec_stack columns not compared)
Testing vectors in scripts_from_rust.tsv      [positive]: 8198/8198 done
Testing vectors in scripts_from_rust_tap.tsv  [positive/negative]: 6728/6728 + 1470/1470 done
Testing vectors in redeem.json                [positive/negative]: 12/12 + 34/34 done (each spend is executed in the script engine)

All 81848 vectors passed (0 skipped).

@murchandamus

Copy link
Copy Markdown
Member

cc Authors: @sipa, @apoelstra, @sanket1729, @darosior, @achow101

@sipa

sipa commented Aug 19, 2026

Copy link
Copy Markdown
Member

I tried to run these tests through the Bitcoin Core miniscript implementation, but quickly hit the problem that the typing rules are inplemented inconsistently. This isn't a problem in production, because the differences are all within expressions that are invalid (for the correctness-related typing rules) or malleable (for the malleability-related typing rules) anyway, but it does mean that exact type tests like the ones in malleable_from_alloy.txt enforce than strictly needed.

In fact, rust-miniscript, Bitcoin Core, and the BIP text are all inconsistent with each other, in minor irrelevant ways. If we want to go the direction of having strict test vectors (which I support), I think we also need to first align all implementations and specifications. My suggestion would be to make everything match the BIP text. I have an (LLM written) patch for Bitcoin Core to make it do that (which passes all its unit & fuzz tests) which I'm happy to PR, but someone else will need to do the same for rust-bitcoin. It differs from the BIP in one rule: the thresh rule for the "unique dissatisfiable" e rule in the BIP is that all children are s, while rust-miniscript (and Bitcoin Core, so far) additionally (and superfluously) require that all children are e.

@jonatack

Copy link
Copy Markdown
Member

My suggestion would be to make everything match the BIP text.

(non-author) approach ACK

@guggero

guggero commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Thanks a lot for testing the test vectors with Bitcoin Core, @sipa.

I'm also in favor of attempting to align everything with the BIP text.

but someone else will need to do the same for rust-bitcoin

Will attempt that soon-ish.

EDIT: Here's the BIP amendment PR and the rust-miniscript PR.

@guggero
guggero force-pushed the bip379-test-vectors branch from ade6aa3 to 3526e43 Compare August 22, 2026 12:44
@guggero

guggero commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

I I've pushed up a fixup commit (3526e43) that addresses #2240 (comment) (and also fixes the Golang import issues I didn't realize were there).

@apoelstra

Copy link
Copy Markdown
Contributor

concept ACK. Great effort. I'm sure a LLM can fill in the documented gaps in a followup PR.

I didn't look at the test vectors or the Go code, but the markdown updates look good to me.

Will review rust-bitcoin/rust-miniscript#1032 more carefully.

guggero added a commit to guggero/bips that referenced this pull request Aug 26, 2026
Both tables give the properties of a fragment in function of those of its
subexpressions, and both are written assuming that the conditions in the
"Requires" column of that fragment hold. Where they do not, the tables
still assign values, but the values carry none of the meaning the
descriptions of the properties give them, and implementations are free to
differ on them.

thresh is the case that surfaced this. Its rule is "e=all are s", so
thresh(2,or_i(pk(A),pk(B)),a:or_i(pk(C),pk(D))) is "e" even though each
or_i child has two unconditional dissatisfactions, giving the threshold
four, which is the opposite of the "unique unconditional dissatisfaction"
that the description of "e" promises. The threshold fails the "e"
requirement the same table imposes, though, so it is malleable and the
value is a don't-care.

Say so below both tables, so that implementations which disagree on the
type of an invalid or malleable expression are not read as contradicting
this document. Bitcoin Core (bitcoin/bitcoin#36028) and rust-miniscript
are aligning on the values the tables give, and the test vectors proposed
in bitcoin#2240 leave out the properties that are not meaningful: z/o/n/d/u for
invalid expressions and s/f/e for malleable ones.
@guggero

guggero commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

I've updated the test vectors in a fixup commit to match the discussion in #2267 and the proposed changes in rust-bitcoin/rust-miniscript#1037.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Pending acceptance This BIP modification requires sign-off by the champion of the BIP being modified Proposed BIP modification PR by non-owner to update BIP content

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants