md_codec/test_vectors.rs
1//! Canonical `md` test-vector corpus.
2//!
3//! Used by `md-codec`'s own integration tests, by `md-cli`'s `vectors`
4//! subcommand, and by `md-cli`'s `tests/json_snapshots.rs` /
5//! `tests/template_roundtrip.rs`. Single source of truth: any vector
6//! addition / removal / rename happens here.
7//!
8//! `Vector` is `#[non_exhaustive]` so future fields can be added without a
9//! breaking-change bump: external consumers construct nothing — they only
10//! read `MANIFEST` entries.
11
12/// One entry of the canonical test-vector corpus.
13#[non_exhaustive]
14pub struct Vector {
15 /// Vector identifier — used in test failure messages and as a stable
16 /// handle for cross-suite filtering. Convention: snake_case mirroring
17 /// the wallet-policy template's distinguishing structure.
18 pub name: &'static str,
19 /// BIP-388 wallet-policy template string the vector encodes. Parsed
20 /// by `parse::template`; round-tripped through `encode` and `decode`.
21 pub template: &'static str,
22 /// `(@N, xpub)` pairs binding each `@N` placeholder in `template`. Empty
23 /// when the vector exercises template-only paths (no key binding).
24 pub keys: &'static [(u8, &'static str)],
25 /// `(@N, 4-byte master fingerprint)` pairs aligned with `keys`. Empty
26 /// when the vector does not exercise fingerprint round-tripping.
27 pub fingerprints: &'static [(u8, [u8; 4])],
28 /// When true, force the encoder onto the chunked wire path even if the
29 /// payload would fit in a single chunk. Exercises chunk-boundary logic
30 /// without padding the template artificially.
31 pub force_chunked: bool,
32}
33
34/// The canonical 10-entry corpus.
35///
36/// `tr_with_leaf` and `sh_wpkh` are intentionally omitted: their round-trip
37/// via the v0.14+ codec is asymmetric (encode requires explicit origin;
38/// decode strips canonical 86'/0'/0' resp. 49'/0'/0'). Coverage for those
39/// wrappers is preserved by `parse::template` unit tests
40/// (`tr_with_one_leaf`, `sh_wpkh_nested`).
41#[rustfmt::skip]
42pub const MANIFEST: &[Vector] = &[
43 Vector { name: "wpkh_basic", template: "wpkh(@0/<0;1>/*)", keys: &[], fingerprints: &[], force_chunked: false },
44 Vector { name: "pkh_basic", template: "pkh(@0/<0;1>/*)", keys: &[], fingerprints: &[], force_chunked: false },
45 Vector { name: "wsh_multi_2of2", template: "wsh(multi(2,@0/<0;1>/*,@1/<0;1>/*))", keys: &[], fingerprints: &[], force_chunked: false },
46 Vector { name: "wsh_multi_2of3", template: "wsh(multi(2,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*))", keys: &[], fingerprints: &[], force_chunked: false },
47 Vector { name: "wsh_sortedmulti", template: "wsh(sortedmulti(2,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*))", keys: &[], fingerprints: &[], force_chunked: false },
48 Vector { name: "tr_keyonly", template: "tr(@0/<0;1>/*)", keys: &[], fingerprints: &[], force_chunked: false },
49 Vector { name: "sh_wsh_multi", template: "sh(wsh(multi(2,@0/<0;1>/*,@1/<0;1>/*)))", keys: &[], fingerprints: &[], force_chunked: false },
50 Vector { name: "wsh_divergent_paths", template: "wsh(multi(2,@0/<0;1>/*,@1/<2;3>/*))", keys: &[], fingerprints: &[], force_chunked: false },
51 Vector { name: "wsh_with_fingerprints", template: "wsh(multi(2,@0/<0;1>/*,@1/<0;1>/*))",
52 keys: &[],
53 fingerprints: &[(0, [0xDE,0xAD,0xBE,0xEF]), (1, [0xCA,0xFE,0xBA,0xBE])],
54 force_chunked: false },
55 Vector { name: "wsh_multi_chunked", template: "wsh(multi(3,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*))", keys: &[], fingerprints: &[], force_chunked: true },
56];