Skip to main content

md_codec/
tree.rs

1//! Tree (operator AST) per spec §3.6 + §6.
2
3use crate::bitstream::{BitReader, BitWriter};
4use crate::error::Error;
5use crate::tag::Tag;
6
7/// A node in the operator AST: a tag plus its body.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Node {
10    /// Operator tag identifying this node's kind.
11    pub tag: Tag,
12    /// Body fields and/or children, shape determined by `tag`.
13    pub body: Body,
14}
15
16/// Body shape for a [`Node`], determined by its [`Tag`].
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum Body {
19    /// No body fields beyond N child nodes (Class 1 fixed-arity).
20    Children(Vec<Node>),
21    /// Variable-arity body for `Tag::Thresh` only (post-v0.30 Phase C).
22    /// Encodes `k` + N child Nodes. Multi-family tags use [`Body::MultiKeys`]
23    /// per SPEC v0.30 §4.
24    Variable {
25        /// Threshold `k`.
26        k: u8,
27        /// Child nodes; `n = children.len()`.
28        children: Vec<Node>,
29    },
30    /// Multi-family body (`Tag::Multi`, `SortedMulti`, `MultiA`,
31    /// `SortedMultiA`): k-of-n with raw `kiw`-width key indices, NOT full
32    /// child Nodes. Per SPEC v0.30 §4: wire layout is
33    /// `tag | (k-1)(5) | (n-1)(5) | n × index(kiw)`.
34    MultiKeys {
35        /// Threshold `k`.
36        k: u8,
37        /// Placeholder indices `@i`; `n = indices.len()`. Each entry is
38        /// emitted as `kiw` bits.
39        indices: Vec<u8>,
40    },
41    /// Tr's body: NUMS flag, key index, optional tap-script-tree root.
42    /// Per SPEC v0.30 §7: wire shape is
43    /// `Tag::Tr | is_nums(1) | [key_index(kiw) iff !is_nums] | has_tree(1) | [tree iff has_tree]`.
44    /// When `is_nums = true`, the internal key is the BIP-341 NUMS H-point
45    /// `50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0`
46    /// and `key_index` is unused on the wire (encoder writes 0 by convention;
47    /// decoder ignores). When `is_nums = false`, `key_index` is a `0..n`
48    /// placeholder index encoded at `kiw` bits.
49    Tr {
50        /// `true` iff the internal key is the BIP-341 NUMS H-point.
51        is_nums: bool,
52        /// Internal-key index into the descriptor's key table. Unused when
53        /// `is_nums = true` (no wire representation).
54        key_index: u8,
55        /// Optional tap-script-tree root.
56        tree: Option<Box<Node>>,
57    },
58    /// Single key-arg (Pkh, Wpkh, PkK, PkH, multi-family children).
59    /// Wire bit-width for `index` is determined by the parent Descriptor's
60    /// key_index_width(); not carried in the AST.
61    KeyArg {
62        /// Key index into the descriptor's key table.
63        index: u8,
64    },
65    /// 256-bit hash literal (Sha256, Hash256).
66    Hash256Body([u8; 32]),
67    /// 160-bit hash literal (Hash160, Ripemd160, RawPkH).
68    Hash160Body([u8; 20]),
69    /// 32-bit Bitcoin-native u32 (After, Older).
70    Timelock(u32),
71    /// No body (False, True).
72    Empty,
73}
74
75/// Encode a [`Node`] to the bit stream.
76///
77/// `key_index_width` is the bit width used for key-index fields, derived from
78/// the descriptor's path-decl head. Filled in across phases 7-11.
79pub fn write_node(w: &mut BitWriter, node: &Node, key_index_width: u8) -> Result<(), Error> {
80    node.tag.write(w);
81    match &node.body {
82        Body::KeyArg { index } => {
83            w.write_bits(u64::from(*index), key_index_width as usize);
84        }
85        Body::Children(children) => {
86            for c in children {
87                write_node(w, c, key_index_width)?;
88            }
89        }
90        Body::Variable { k, children } => {
91            // Thresh-only post-v0.30 Phase C. Encode k-1 in 5 bits per spec §4.2.
92            if !(1..=32).contains(&(*k as u32)) {
93                return Err(Error::ThresholdOutOfRange { k: *k });
94            }
95            if !(1..=32).contains(&(children.len() as u32)) {
96                return Err(Error::ChildCountOutOfRange {
97                    count: children.len(),
98                });
99            }
100            w.write_bits((*k - 1) as u64, 5);
101            w.write_bits((children.len() - 1) as u64, 5);
102            for c in children {
103                write_node(w, c, key_index_width)?;
104            }
105        }
106        Body::MultiKeys { k, indices } => {
107            // Multi-family per SPEC v0.30 §4: k-of-n + raw kiw-width indices.
108            if !(1..=32).contains(&(*k as u32)) {
109                return Err(Error::ThresholdOutOfRange { k: *k });
110            }
111            if !(1..=32).contains(&(indices.len() as u32)) {
112                return Err(Error::ChildCountOutOfRange {
113                    count: indices.len(),
114                });
115            }
116            w.write_bits((*k - 1) as u64, 5);
117            w.write_bits((indices.len() - 1) as u64, 5);
118            for idx in indices {
119                w.write_bits(u64::from(*idx), key_index_width as usize);
120            }
121        }
122        Body::Tr {
123            is_nums,
124            key_index,
125            tree,
126        } => {
127            // SPEC v0.30 §7: is_nums(1) | [key_index(kiw) iff !is_nums] |
128            // has_tree(1) | [tree iff has_tree].
129            debug_assert!(
130                !(*is_nums && *key_index != 0),
131                "is_nums=true implies key_index=0 (no wire representation otherwise)"
132            );
133            w.write_bits(u64::from(*is_nums), 1);
134            if !*is_nums {
135                w.write_bits(u64::from(*key_index), key_index_width as usize);
136            }
137            w.write_bits(u64::from(tree.is_some()), 1);
138            if let Some(t) = tree {
139                write_node(w, t, key_index_width)?;
140            }
141        }
142        Body::Timelock(v) => {
143            w.write_bits(u64::from(*v), 32);
144        }
145        Body::Hash256Body(h) => {
146            for byte in h {
147                w.write_bits(u64::from(*byte), 8);
148            }
149        }
150        Body::Hash160Body(h) => {
151            for byte in h {
152                w.write_bits(u64::from(*byte), 8);
153            }
154        }
155        Body::Empty => {}
156    }
157    Ok(())
158}
159
160/// Hard cap on `read_node` recursion depth. Shared across all recursive tags
161/// (`Sh`, `AndV`, `AndOr`, `TapTree`, `Multi`, `Tr`, …) as a generic anti-DOS
162/// hardening bound — not a spec-mandated value for non-taproot sites. The
163/// value 128 happens to coincide with BIP-341 `TAPROOT_CONTROL_MAX_NODE_COUNT`,
164/// but its role here is just "any depth a real miniscript expression could
165/// plausibly reach + headroom"; P2WSH script-size limits cap practical
166/// miniscript depth at well under 50.
167pub const MAX_DECODE_DEPTH: u8 = 128;
168
169/// Decode a [`Node`] from the bit stream.
170///
171/// `key_index_width` is the bit width used for key-index fields, derived from
172/// the descriptor's path-decl head. Filled in across phases 7-11.
173///
174/// Top-level entry point. Internally threads a recursion-depth counter that
175/// errors out at [`MAX_DECODE_DEPTH`] before parsing the next node, so a
176/// hostile wire payload nesting recursive tags (`Tag::Sh`, `Tag::AndV`,
177/// `Tag::TapTree`, etc.) arbitrarily deep cannot blow the Rust stack.
178pub fn read_node(r: &mut BitReader, key_index_width: u8) -> Result<Node, Error> {
179    read_node_with_depth(r, key_index_width, 0)
180}
181
182/// Inner recursive form of `read_node` that threads `depth`. Public callers
183/// should use `read_node` instead, which starts at depth 0. Increments
184/// `depth` once per call and errors if it reaches [`MAX_DECODE_DEPTH`].
185fn read_node_with_depth(r: &mut BitReader, key_index_width: u8, depth: u8) -> Result<Node, Error> {
186    if depth >= MAX_DECODE_DEPTH {
187        return Err(Error::DecodeRecursionDepthExceeded {
188            depth,
189            max: MAX_DECODE_DEPTH,
190        });
191    }
192    let tag = Tag::read(r)?;
193    let body = match tag {
194        Tag::PkK | Tag::PkH | Tag::Wpkh | Tag::Pkh => {
195            let index = r.read_bits(key_index_width as usize)? as u8;
196            Body::KeyArg { index }
197        }
198        Tag::Sh
199        | Tag::Wsh
200        | Tag::Check
201        | Tag::Verify
202        | Tag::Swap
203        | Tag::Alt
204        | Tag::DupIf
205        | Tag::NonZero
206        | Tag::ZeroNotEqual => {
207            let child = read_node_with_depth(r, key_index_width, depth + 1)?;
208            Body::Children(vec![child])
209        }
210        Tag::AndV | Tag::AndB | Tag::OrB | Tag::OrC | Tag::OrD | Tag::OrI => {
211            let l = read_node_with_depth(r, key_index_width, depth + 1)?;
212            let r2 = read_node_with_depth(r, key_index_width, depth + 1)?;
213            Body::Children(vec![l, r2])
214        }
215        Tag::AndOr => {
216            let a = read_node_with_depth(r, key_index_width, depth + 1)?;
217            let b = read_node_with_depth(r, key_index_width, depth + 1)?;
218            let c = read_node_with_depth(r, key_index_width, depth + 1)?;
219            Body::Children(vec![a, b, c])
220        }
221        Tag::TapTree => {
222            let l = read_node_with_depth(r, key_index_width, depth + 1)?;
223            let r2 = read_node_with_depth(r, key_index_width, depth + 1)?;
224            Body::Children(vec![l, r2])
225        }
226        Tag::Multi | Tag::SortedMulti | Tag::MultiA | Tag::SortedMultiA => {
227            let k = (r.read_bits(5)? + 1) as u8;
228            let count = (r.read_bits(5)? + 1) as usize;
229            if k as usize > count {
230                return Err(Error::KGreaterThanN { k, n: count });
231            }
232            let mut indices = Vec::with_capacity(count);
233            for _ in 0..count {
234                indices.push(r.read_bits(key_index_width as usize)? as u8);
235            }
236            Body::MultiKeys { k, indices }
237        }
238        Tag::Thresh => {
239            let k = (r.read_bits(5)? + 1) as u8;
240            let count = (r.read_bits(5)? + 1) as usize;
241            if k as usize > count {
242                return Err(Error::KGreaterThanN { k, n: count });
243            }
244            let mut children = Vec::with_capacity(count);
245            for _ in 0..count {
246                children.push(read_node_with_depth(r, key_index_width, depth + 1)?);
247            }
248            Body::Variable { k, children }
249        }
250        Tag::Tr => {
251            // SPEC v0.30 §7: is_nums(1) | [key_index(kiw) iff !is_nums] |
252            // has_tree(1) | [tree iff has_tree].
253            let is_nums = r.read_bits(1)? != 0;
254            let key_index = if is_nums {
255                0
256            } else {
257                r.read_bits(key_index_width as usize)? as u8
258            };
259            let has_tree = r.read_bits(1)? != 0;
260            let tree = if has_tree {
261                Some(Box::new(read_node_with_depth(
262                    r,
263                    key_index_width,
264                    depth + 1,
265                )?))
266            } else {
267                None
268            };
269            Body::Tr {
270                is_nums,
271                key_index,
272                tree,
273            }
274        }
275        Tag::After | Tag::Older => {
276            let v = r.read_bits(32)? as u32;
277            Body::Timelock(v)
278        }
279        Tag::Sha256 => {
280            let mut h = [0u8; 32];
281            for byte in &mut h {
282                *byte = r.read_bits(8)? as u8;
283            }
284            Body::Hash256Body(h)
285        }
286        Tag::Hash160 => {
287            let mut h = [0u8; 20];
288            for byte in &mut h {
289                *byte = r.read_bits(8)? as u8;
290            }
291            Body::Hash160Body(h)
292        }
293        Tag::Hash256 => {
294            let mut h = [0u8; 32];
295            for byte in &mut h {
296                *byte = r.read_bits(8)? as u8;
297            }
298            Body::Hash256Body(h)
299        }
300        Tag::Ripemd160 | Tag::RawPkH => {
301            let mut h = [0u8; 20];
302            for byte in &mut h {
303                *byte = r.read_bits(8)? as u8;
304            }
305            Body::Hash160Body(h)
306        }
307        Tag::False | Tag::True => Body::Empty,
308    };
309    Ok(Node { tag, body })
310}
311
312#[cfg(test)]
313mod tests {
314    use super::*;
315    use crate::bitstream::{BitReader, BitWriter};
316
317    #[test]
318    fn key_arg_n1_zero_bits() {
319        // v0.30: at n=1, kiw = ⌈log₂(1)⌉ = 0; key-arg emits zero bits.
320        let n = Node {
321            tag: Tag::PkK,
322            body: Body::KeyArg { index: 0 },
323        };
324        let mut w = BitWriter::new();
325        write_node(&mut w, &n, 0).unwrap();
326        // Tag::PkK (6 bits) + key-arg (0 bits) = 6 bits total.
327        assert_eq!(w.bit_len(), 6);
328    }
329
330    #[test]
331    fn key_arg_n3_two_bits() {
332        // v0.30: at n=3, kiw = ⌈log₂(3)⌉ = 2.
333        let n = Node {
334            tag: Tag::PkK,
335            body: Body::KeyArg { index: 2 },
336        };
337        let mut w = BitWriter::new();
338        write_node(&mut w, &n, 2).unwrap();
339        // Tag::PkK (6 bits) + key-arg (2 bits) = 8 bits total.
340        assert_eq!(w.bit_len(), 8);
341    }
342
343    #[test]
344    fn key_arg_round_trip() {
345        let n = Node {
346            tag: Tag::PkK,
347            body: Body::KeyArg { index: 1 },
348        };
349        let mut w = BitWriter::new();
350        write_node(&mut w, &n, 2).unwrap();
351        let bytes = w.into_bytes();
352        let mut r = BitReader::new(&bytes);
353        assert_eq!(read_node(&mut r, 2).unwrap(), n);
354    }
355
356    #[test]
357    fn wrapper_chain_v_c_pk_round_trip() {
358        // v:c:pk_k(@0) — three nested wrappers around PkK
359        let n = Node {
360            tag: Tag::Verify,
361            body: Body::Children(vec![Node {
362                tag: Tag::Check,
363                body: Body::Children(vec![Node {
364                    tag: Tag::PkK,
365                    body: Body::KeyArg { index: 0 },
366                }]),
367            }]),
368        };
369        let mut w = BitWriter::new();
370        write_node(&mut w, &n, 2).unwrap();
371        let bytes = w.into_bytes();
372        let mut r = BitReader::new(&bytes);
373        assert_eq!(read_node(&mut r, 2).unwrap(), n);
374    }
375
376    #[test]
377    fn sortedmulti_2of3_round_trip() {
378        let n = Node {
379            tag: Tag::SortedMulti,
380            body: Body::MultiKeys {
381                k: 2,
382                indices: vec![0, 1, 2],
383            },
384        };
385        let mut w = BitWriter::new();
386        write_node(&mut w, &n, 2).unwrap();
387        let bytes = w.into_bytes();
388        let mut r = BitReader::new(&bytes);
389        assert_eq!(read_node(&mut r, 2).unwrap(), n);
390    }
391
392    /// v0.30 Phase C — multi packing bit-cost pin.
393    /// `Tag(6-bit) | k-1(5) | n-1(5) | 3×kiw(2 at n=3) = 22 bits` (SPEC §4.2).
394    /// Saves 14 bits over v0.x's per-child encoding (which was 36 bits).
395    #[test]
396    fn sortedmulti_2of3_bit_cost() {
397        let n = Node {
398            tag: Tag::SortedMulti,
399            body: Body::MultiKeys {
400                k: 2,
401                indices: vec![0, 1, 2],
402            },
403        };
404        let mut w = BitWriter::new();
405        write_node(&mut w, &n, 2).unwrap();
406        assert_eq!(w.bit_len(), 22);
407    }
408
409    /// v0.30 Phase C — `Body::MultiKeys` round-trips under `Tag::Multi`.
410    #[test]
411    fn multi_keys_body_round_trip() {
412        let n = Node {
413            tag: Tag::Multi,
414            body: Body::MultiKeys {
415                k: 2,
416                indices: vec![0, 1, 2],
417            },
418        };
419        let mut w = BitWriter::new();
420        write_node(&mut w, &n, 2).unwrap();
421        let bytes = w.into_bytes();
422        let mut r = BitReader::new(&bytes);
423        assert_eq!(read_node(&mut r, 2).unwrap(), n);
424    }
425
426    /// v0.30 Phase C — `Body::MultiKeys` round-trips under `Tag::SortedMultiA`.
427    #[test]
428    fn sortedmulti_a_indices_round_trip() {
429        let n = Node {
430            tag: Tag::SortedMultiA,
431            body: Body::MultiKeys {
432                k: 2,
433                indices: vec![0, 1, 2],
434            },
435        };
436        let mut w = BitWriter::new();
437        write_node(&mut w, &n, 2).unwrap();
438        let bytes = w.into_bytes();
439        let mut r = BitReader::new(&bytes);
440        assert_eq!(read_node(&mut r, 2).unwrap(), n);
441    }
442
443    #[test]
444    fn tr_bip86_no_tree() {
445        // v0.30: tr(@0) keypath-only at synthetic width=0 (n=1 in Descriptor
446        // would yield kiw=0). Exercises the zero-width edge of write_node /
447        // read_node directly.
448        let n = Node {
449            tag: Tag::Tr,
450            body: Body::Tr {
451                is_nums: false,
452                key_index: 0,
453                tree: None,
454            },
455        };
456        let mut w = BitWriter::new();
457        write_node(&mut w, &n, 0).unwrap();
458        // Tag::Tr (6) + is_nums (1) + key_index (0, kiw=0) + has_tree (1) = 8 bits.
459        assert_eq!(w.bit_len(), 8);
460        let bytes = w.into_bytes();
461        let mut r = BitReader::new(&bytes);
462        assert_eq!(read_node(&mut r, 0).unwrap(), n);
463    }
464
465    #[test]
466    fn thresh_2of3_with_pk_children() {
467        // thresh(2, pk_k(@0), pk_k(@1), pk_k(@2))
468        let n = Node {
469            tag: Tag::Thresh,
470            body: Body::Variable {
471                k: 2,
472                children: vec![
473                    Node {
474                        tag: Tag::PkK,
475                        body: Body::KeyArg { index: 0 },
476                    },
477                    Node {
478                        tag: Tag::PkK,
479                        body: Body::KeyArg { index: 1 },
480                    },
481                    Node {
482                        tag: Tag::PkK,
483                        body: Body::KeyArg { index: 2 },
484                    },
485                ],
486            },
487        };
488        let mut w = BitWriter::new();
489        write_node(&mut w, &n, 2).unwrap();
490        let bytes = w.into_bytes();
491        let mut r = BitReader::new(&bytes);
492        assert_eq!(read_node(&mut r, 2).unwrap(), n);
493    }
494
495    #[test]
496    fn tr_with_single_leaf() {
497        // tr(@0, multi_a(2, @1, @2))
498        let n = Node {
499            tag: Tag::Tr,
500            body: Body::Tr {
501                is_nums: false,
502                key_index: 0,
503                tree: Some(Box::new(Node {
504                    tag: Tag::MultiA,
505                    body: Body::MultiKeys {
506                        k: 2,
507                        indices: vec![1, 2],
508                    },
509                })),
510            },
511        };
512        let mut w = BitWriter::new();
513        write_node(&mut w, &n, 2).unwrap();
514        let bytes = w.into_bytes();
515        let mut r = BitReader::new(&bytes);
516        assert_eq!(read_node(&mut r, 2).unwrap(), n);
517    }
518
519    /// v0.30 Phase F — `Body::Tr { is_nums: true, .. }` round-trips. NUMS
520    /// suppresses the kiw field on the wire entirely.
521    #[test]
522    fn tr_nums_flag_round_trip() {
523        let n = Node {
524            tag: Tag::Tr,
525            body: Body::Tr {
526                is_nums: true,
527                key_index: 0,
528                tree: None,
529            },
530        };
531        let mut w = BitWriter::new();
532        write_node(&mut w, &n, 2).unwrap();
533        let bytes = w.into_bytes();
534        let mut r = BitReader::new(&bytes);
535        assert_eq!(read_node(&mut r, 2).unwrap(), n);
536    }
537
538    /// v0.30 Phase F — `Body::Tr { is_nums: false, key_index, .. }` round-
539    /// trips with explicit key_index written at kiw width.
540    #[test]
541    fn tr_is_nums_false_round_trip() {
542        let n = Node {
543            tag: Tag::Tr,
544            body: Body::Tr {
545                is_nums: false,
546                key_index: 2,
547                tree: None,
548            },
549        };
550        let mut w = BitWriter::new();
551        write_node(&mut w, &n, 2).unwrap();
552        let bytes = w.into_bytes();
553        let mut r = BitReader::new(&bytes);
554        assert_eq!(read_node(&mut r, 2).unwrap(), n);
555    }
556
557    #[test]
558    fn after_700_000_round_trip() {
559        let n = Node {
560            tag: Tag::After,
561            body: Body::Timelock(700_000),
562        };
563        let mut w = BitWriter::new();
564        write_node(&mut w, &n, 0).unwrap();
565        // Tag(6) + u32(32) = 38 bits
566        assert_eq!(w.bit_len(), 38);
567        let bytes = w.into_bytes();
568        let mut r = BitReader::new(&bytes);
569        assert_eq!(read_node(&mut r, 0).unwrap(), n);
570    }
571
572    #[test]
573    fn sha256_round_trip() {
574        let h = [0xab; 32];
575        let n = Node {
576            tag: Tag::Sha256,
577            body: Body::Hash256Body(h),
578        };
579        let mut w = BitWriter::new();
580        write_node(&mut w, &n, 0).unwrap();
581        // Tag(6) + 256 = 262 bits
582        assert_eq!(w.bit_len(), 262);
583        let bytes = w.into_bytes();
584        let mut r = BitReader::new(&bytes);
585        assert_eq!(read_node(&mut r, 0).unwrap(), n);
586    }
587
588    #[test]
589    fn hash160_round_trip() {
590        let h = [0xcd; 20];
591        let n = Node {
592            tag: Tag::Hash160,
593            body: Body::Hash160Body(h),
594        };
595        let mut w = BitWriter::new();
596        write_node(&mut w, &n, 0).unwrap();
597        // Tag(6) + 160 = 166 bits
598        assert_eq!(w.bit_len(), 166);
599        let bytes = w.into_bytes();
600        let mut r = BitReader::new(&bytes);
601        assert_eq!(read_node(&mut r, 0).unwrap(), n);
602    }
603
604    #[test]
605    fn hash256_round_trip() {
606        let h = [0xef; 32];
607        let n = Node {
608            tag: Tag::Hash256,
609            body: Body::Hash256Body(h),
610        };
611        let mut w = BitWriter::new();
612        write_node(&mut w, &n, 0).unwrap();
613        // Tag(6) + 256 = 262 bits (Hash256 primary 0x1F in v0.30).
614        assert_eq!(w.bit_len(), 262);
615        let bytes = w.into_bytes();
616        let mut r = BitReader::new(&bytes);
617        assert_eq!(read_node(&mut r, 0).unwrap(), n);
618    }
619
620    #[test]
621    fn ripemd160_round_trip() {
622        let h = [0x42; 20];
623        let n = Node {
624            tag: Tag::Ripemd160,
625            body: Body::Hash160Body(h),
626        };
627        let mut w = BitWriter::new();
628        write_node(&mut w, &n, 0).unwrap();
629        let bytes = w.into_bytes();
630        let mut r = BitReader::new(&bytes);
631        assert_eq!(read_node(&mut r, 0).unwrap(), n);
632    }
633
634    #[test]
635    fn false_round_trip() {
636        let n = Node {
637            tag: Tag::False,
638            body: Body::Empty,
639        };
640        let mut w = BitWriter::new();
641        write_node(&mut w, &n, 0).unwrap();
642        assert_eq!(w.bit_len(), 6); // Tag(6), no body (False primary 0x22 in v0.30)
643        let bytes = w.into_bytes();
644        let mut r = BitReader::new(&bytes);
645        assert_eq!(read_node(&mut r, 0).unwrap(), n);
646    }
647
648    #[test]
649    fn true_round_trip() {
650        let n = Node {
651            tag: Tag::True,
652            body: Body::Empty,
653        };
654        let mut w = BitWriter::new();
655        write_node(&mut w, &n, 0).unwrap();
656        let bytes = w.into_bytes();
657        let mut r = BitReader::new(&bytes);
658        assert_eq!(read_node(&mut r, 0).unwrap(), n);
659    }
660
661    #[test]
662    fn older_144_round_trip() {
663        let n = Node {
664            tag: Tag::Older,
665            body: Body::Timelock(144),
666        };
667        let mut w = BitWriter::new();
668        write_node(&mut w, &n, 0).unwrap();
669        let bytes = w.into_bytes();
670        let mut r = BitReader::new(&bytes);
671        assert_eq!(read_node(&mut r, 0).unwrap(), n);
672    }
673
674    #[test]
675    fn tr_nums_n_1_bare_round_trip() {
676        // v0.30: tr(<NUMS>) with no script tree at n=1. NUMS is now signalled
677        // via the `is_nums` flag, not a reserved sentinel `key_index`. At n=1
678        // the v0.30 kiw is 0 — but `is_nums=true` suppresses the kiw write
679        // entirely, so the kiw width is irrelevant here.
680        let n = Node {
681            tag: Tag::Tr,
682            body: Body::Tr {
683                is_nums: true,
684                key_index: 0,
685                tree: None,
686            },
687        };
688        let mut w = BitWriter::new();
689        // kiw=0 at n=1 (irrelevant — is_nums=true suppresses the kiw field).
690        write_node(&mut w, &n, 0).unwrap();
691        // Tag::Tr (6) + is_nums (1) + has_tree (1) = 8 bits.
692        assert_eq!(w.bit_len(), 8);
693        let bytes = w.into_bytes();
694        let mut r = BitReader::new(&bytes);
695        assert_eq!(read_node(&mut r, 0).unwrap(), n);
696    }
697
698    #[test]
699    fn tr_nums_n_2_and_v_inheritance_round_trip() {
700        // v0.30: tr(<NUMS>, and_v(v:pk(@0), pk(@1))) — inheritance pattern via
701        // NUMS internal key, signalled by `is_nums = true`. Exercises and_v +
702        // verify wrapper inside the script-path branch.
703        let n = Node {
704            tag: Tag::Tr,
705            body: Body::Tr {
706                is_nums: true,
707                key_index: 0,
708                tree: Some(Box::new(Node {
709                    tag: Tag::AndV,
710                    body: Body::Children(vec![
711                        Node {
712                            tag: Tag::Verify,
713                            body: Body::Children(vec![Node {
714                                tag: Tag::PkK,
715                                body: Body::KeyArg { index: 0 },
716                            }]),
717                        },
718                        Node {
719                            tag: Tag::PkK,
720                            body: Body::KeyArg { index: 1 },
721                        },
722                    ]),
723                })),
724            },
725        };
726        let mut w = BitWriter::new();
727        // v0.30 width at n=2: ⌈log₂(2)⌉ = 1.
728        write_node(&mut w, &n, 1).unwrap();
729        let bytes = w.into_bytes();
730        let mut r = BitReader::new(&bytes);
731        assert_eq!(read_node(&mut r, 1).unwrap(), n);
732    }
733
734    #[test]
735    fn tr_nums_n_3_multi_a_2_of_3_round_trip() {
736        // v0.30: tr(<NUMS>, multi_a(2, @0, @1, @2)) — the canonical 2-of-3
737        // hardware-wallet multisig encoding (the headline use case). NUMS
738        // signalled by `is_nums = true`. At n=3 the v0.30 kiw is 2.
739        let n = Node {
740            tag: Tag::Tr,
741            body: Body::Tr {
742                is_nums: true,
743                key_index: 0,
744                tree: Some(Box::new(Node {
745                    tag: Tag::MultiA,
746                    body: Body::MultiKeys {
747                        k: 2,
748                        indices: vec![0, 1, 2],
749                    },
750                })),
751            },
752        };
753        let mut w = BitWriter::new();
754        write_node(&mut w, &n, 2).unwrap();
755        let bytes = w.into_bytes();
756        let mut r = BitReader::new(&bytes);
757        assert_eq!(read_node(&mut r, 2).unwrap(), n);
758    }
759
760    #[test]
761    fn tr_nums_n_4_bare_round_trip() {
762        // v0.30: tr(<NUMS>) at n=4. NUMS signalled by `is_nums = true`. At
763        // n=4 the v0.30 kiw is ⌈log₂(4)⌉ = 2; is_nums=true suppresses the
764        // kiw field, so it's irrelevant here.
765        let n = Node {
766            tag: Tag::Tr,
767            body: Body::Tr {
768                is_nums: true,
769                key_index: 0,
770                tree: None,
771            },
772        };
773        let mut w = BitWriter::new();
774        // kiw=2 at n=4 (irrelevant — is_nums=true suppresses the kiw field).
775        write_node(&mut w, &n, 2).unwrap();
776        // Tag::Tr (6) + is_nums (1) + has_tree (1) = 8 bits.
777        assert_eq!(w.bit_len(), 8);
778        let bytes = w.into_bytes();
779        let mut r = BitReader::new(&bytes);
780        assert_eq!(read_node(&mut r, 2).unwrap(), n);
781    }
782
783    /// v0.19 — multi-branch tap tree wire-format round-trip. Closes audit
784    /// Concern B (no codec-level tests for `Tag::TapTree` with branching
785    /// existed before v0.19; multi-branch was previously walker-rejected
786    /// so there was no real input that exercised this wire shape).
787    /// `tr(@0, {pk(@1), pk(@2)})` with key_index_width=2.
788    /// Bit-length pin (v0.30): Tag::Tr (6) + is_nums (1) + kiw (2) + has_tree (1)
789    ///                 + Tag::TapTree (6) + 2×(Tag::PkK (6) + kiw (2)) = 32 bits.
790    #[test]
791    fn tap_tree_two_leaf_round_trip() {
792        let n = Node {
793            tag: Tag::Tr,
794            body: Body::Tr {
795                is_nums: false,
796                key_index: 0,
797                tree: Some(Box::new(Node {
798                    tag: Tag::TapTree,
799                    body: Body::Children(vec![
800                        Node {
801                            tag: Tag::PkK,
802                            body: Body::KeyArg { index: 1 },
803                        },
804                        Node {
805                            tag: Tag::PkK,
806                            body: Body::KeyArg { index: 2 },
807                        },
808                    ]),
809                })),
810            },
811        };
812        let mut w = BitWriter::new();
813        write_node(&mut w, &n, 2).unwrap();
814        assert_eq!(w.bit_len(), 32, "2-leaf TapTree wire layout pin");
815        let bytes = w.into_bytes();
816        let mut r = BitReader::new(&bytes);
817        assert_eq!(read_node(&mut r, 2).unwrap(), n);
818    }
819
820    /// v0.19 — 4-leaf nested multi-branch tap tree:
821    /// `tr(@0, {{pk(@1),pk(@2)}, {pk(@3),pk(@4)}})`. Verifies recursion
822    /// through `read_node`/`write_node` on nested Tag::TapTree.
823    #[test]
824    fn tap_tree_nested_four_leaf_round_trip() {
825        let mk_branch = |a: u8, b: u8| Node {
826            tag: Tag::TapTree,
827            body: Body::Children(vec![
828                Node {
829                    tag: Tag::PkK,
830                    body: Body::KeyArg { index: a },
831                },
832                Node {
833                    tag: Tag::PkK,
834                    body: Body::KeyArg { index: b },
835                },
836            ]),
837        };
838        let n = Node {
839            tag: Tag::Tr,
840            body: Body::Tr {
841                is_nums: false,
842                key_index: 0,
843                tree: Some(Box::new(Node {
844                    tag: Tag::TapTree,
845                    body: Body::Children(vec![mk_branch(1, 2), mk_branch(3, 4)]),
846                })),
847            },
848        };
849        let mut w = BitWriter::new();
850        // 5 distinct indices (0..=4) → v0.30 kiw = ⌈log₂(5)⌉ = 3.
851        write_node(&mut w, &n, 3).unwrap();
852        let bytes = w.into_bytes();
853        let mut r = BitReader::new(&bytes);
854        assert_eq!(read_node(&mut r, 3).unwrap(), n);
855    }
856
857    /// v0.19 — 3-leaf unbalanced: `tr(@0, {pk(@1), {pk(@2),pk(@3)}})`.
858    /// Asymmetric shape — the right child is a TapTree, the left is a
859    /// bare PkK leaf. Verifies the wire format doesn't require balanced
860    /// trees.
861    #[test]
862    fn tap_tree_unbalanced_round_trip() {
863        let n = Node {
864            tag: Tag::Tr,
865            body: Body::Tr {
866                is_nums: false,
867                key_index: 0,
868                tree: Some(Box::new(Node {
869                    tag: Tag::TapTree,
870                    body: Body::Children(vec![
871                        Node {
872                            tag: Tag::PkK,
873                            body: Body::KeyArg { index: 1 },
874                        },
875                        Node {
876                            tag: Tag::TapTree,
877                            body: Body::Children(vec![
878                                Node {
879                                    tag: Tag::PkK,
880                                    body: Body::KeyArg { index: 2 },
881                                },
882                                Node {
883                                    tag: Tag::PkK,
884                                    body: Body::KeyArg { index: 3 },
885                                },
886                            ]),
887                        },
888                    ]),
889                })),
890            },
891        };
892        let mut w = BitWriter::new();
893        // v0.30 kiw at n=3: ⌈log₂(3)⌉ = 2.
894        write_node(&mut w, &n, 2).unwrap();
895        let bytes = w.into_bytes();
896        let mut r = BitReader::new(&bytes);
897        assert_eq!(read_node(&mut r, 2).unwrap(), n);
898    }
899
900    /// v0.19 hardening — reject deeply-nested TapTree on the decode side.
901    /// Encode-side has no cap (input here is a programmatically-constructed
902    /// Node tree, not from the walker), but the decode-side cap fires
903    /// when the deepest left-child read attempts at depth MAX_DECODE_DEPTH.
904    #[test]
905    fn read_node_rejects_excessive_taptree_nesting() {
906        let mut left = Node {
907            tag: Tag::PkK,
908            body: Body::KeyArg { index: 0 },
909        };
910        // 128 TapTree wrappers: deepest leaf ends up at depth 128 on the
911        // left chain; cap fires when reading that leaf.
912        for _ in 0..128 {
913            left = Node {
914                tag: Tag::TapTree,
915                body: Body::Children(vec![
916                    left,
917                    Node {
918                        tag: Tag::PkK,
919                        body: Body::KeyArg { index: 0 },
920                    },
921                ]),
922            };
923        }
924        let mut w = BitWriter::new();
925        write_node(&mut w, &left, 0).unwrap();
926        let bytes = w.into_bytes();
927        let mut r = BitReader::new(&bytes);
928        let err = read_node(&mut r, 0).unwrap_err();
929        assert_eq!(
930            err,
931            Error::DecodeRecursionDepthExceeded {
932                depth: 128,
933                max: MAX_DECODE_DEPTH,
934            }
935        );
936    }
937
938    /// v0.19 hardening — cap is tag-agnostic; fires for non-taproot
939    /// recursive tags (AndV chain) the same way it fires for TapTree.
940    #[test]
941    fn read_node_rejects_excessive_andv_chain_nesting() {
942        let mut left = Node {
943            tag: Tag::PkK,
944            body: Body::KeyArg { index: 0 },
945        };
946        // 128 AndV wrappers on the left, with PkK leaves on the right at
947        // each level. Deepest left-leaf at depth 128 triggers the cap.
948        for _ in 0..128 {
949            left = Node {
950                tag: Tag::AndV,
951                body: Body::Children(vec![
952                    left,
953                    Node {
954                        tag: Tag::PkK,
955                        body: Body::KeyArg { index: 0 },
956                    },
957                ]),
958            };
959        }
960        let mut w = BitWriter::new();
961        write_node(&mut w, &left, 0).unwrap();
962        let bytes = w.into_bytes();
963        let mut r = BitReader::new(&bytes);
964        let err = read_node(&mut r, 0).unwrap_err();
965        assert_eq!(
966            err,
967            Error::DecodeRecursionDepthExceeded {
968                depth: 128,
969                max: MAX_DECODE_DEPTH,
970            }
971        );
972    }
973
974    /// v0.19 hardening — depth exactly at the limit (deepest leaf at
975    /// depth 127, one shy of MAX_DECODE_DEPTH) round-trips successfully.
976    #[test]
977    fn read_node_accepts_max_depth_minus_one() {
978        let mut left = Node {
979            tag: Tag::PkK,
980            body: Body::KeyArg { index: 0 },
981        };
982        // 127 TapTree wrappers: deepest leaf at depth 127, just under cap.
983        for _ in 0..127 {
984            left = Node {
985                tag: Tag::TapTree,
986                body: Body::Children(vec![
987                    left,
988                    Node {
989                        tag: Tag::PkK,
990                        body: Body::KeyArg { index: 0 },
991                    },
992                ]),
993            };
994        }
995        let mut w = BitWriter::new();
996        write_node(&mut w, &left, 0).unwrap();
997        let bytes = w.into_bytes();
998        let mut r = BitReader::new(&bytes);
999        let decoded = read_node(&mut r, 0).unwrap();
1000        assert_eq!(decoded, left);
1001    }
1002}