simplicity/merkle/
ihr.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use crate::impl_midstate_wrapper;
4use crate::jet::Jet;
5use crate::types::arrow::FinalArrow;
6use crate::value::Word;
7use crate::{Cmr, Tmr, Value};
8use hashes::sha256::Midstate;
9
10use super::{bip340_iv, compact_value, FailEntropy};
11
12/// Identity Merkle Root
13///
14/// A Merkle root that commits to a node's combinator, its witness data (if present),
15/// and recursively its children. Used as input to the [`Ihr`] type which is probably
16/// actually what you want.
17#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
18pub struct Imr(Midstate);
19
20impl_midstate_wrapper!(Imr);
21
22/// Identity Hash Root
23///
24/// A Merkle root that commits to a node's [`Imr`] (which recursively commits to its
25/// childrens' [`Imr`]s) as well as its source and target types.
26///
27/// Uniquely identifies a program's structure in terms of combinators at redemption time.
28#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
29pub struct Ihr(Midstate);
30
31impl_midstate_wrapper!(Ihr);
32
33impl From<Cmr> for Imr {
34    fn from(cmr: Cmr) -> Self {
35        Imr::from_byte_array(cmr.to_byte_array())
36    }
37}
38
39impl From<Cmr> for Ihr {
40    fn from(cmr: Cmr) -> Self {
41        Ihr::from_byte_array(cmr.to_byte_array())
42    }
43}
44
45impl From<Tmr> for Ihr {
46    fn from(tmr: Tmr) -> Self {
47        Ihr::from_byte_array(tmr.to_byte_array())
48    }
49}
50
51impl Imr {
52    /// Produce a CMR for an iden combinator
53    pub const fn iden() -> Self {
54        Self::IDEN_IV
55    }
56
57    /// Produce a CMR for a unit combinator
58    pub const fn unit() -> Self {
59        Self::UNIT_IV
60    }
61
62    /// Produce a CMR for an injl combinator
63    pub fn injl(child: Self) -> Self {
64        Self::INJL_IV.update_1(child)
65    }
66
67    /// Produce a CMR for an injr combinator
68    pub fn injr(child: Self) -> Self {
69        Self::INJR_IV.update_1(child)
70    }
71
72    /// Produce a CMR for a take combinator
73    pub fn take(child: Self) -> Self {
74        Self::TAKE_IV.update_1(child)
75    }
76
77    /// Produce a CMR for a drop combinator
78    pub fn drop(child: Self) -> Self {
79        Self::DROP_IV.update_1(child)
80    }
81
82    /// Produce a CMR for a comp combinator
83    pub fn comp(left: Self, right: Self) -> Self {
84        Self::COMP_IV.update(left, right)
85    }
86
87    /// Produce a CMR for a case combinator
88    pub fn case(left: Self, right: Self) -> Self {
89        Self::CASE_IV.update(left, right)
90    }
91
92    /// Produce a CMR for a pair combinator
93    pub fn pair(left: Self, right: Self) -> Self {
94        Self::PAIR_IV.update(left, right)
95    }
96
97    /// Produce a CMR for a disconnect combinator
98    pub fn disconnect(left: Self, right: Self) -> Self {
99        Self::DISCONNECT_IV.update(left, right)
100    }
101
102    /// Produce a CMR for a witness combinator
103    pub fn witness(ty: &FinalArrow, value: &Value) -> Self {
104        use hashes::{sha256, HashEngine};
105
106        // 1 Bit-wise hash of `value`
107        let value_hash = compact_value(value);
108        // 2 Hash of hash of `value` and TMR of `value_type`
109        let mut engine = sha256::HashEngine::from_midstate(Self::WITNESS_IV.0, 0);
110        engine.input(&value_hash[..]);
111        engine.input(ty.target.tmr().as_ref());
112        Self(engine.midstate())
113    }
114
115    /// Produce an IHR for a fail combinator
116    pub fn fail(entropy: FailEntropy) -> Self {
117        Self::FAIL_IV.update_fail_entropy(entropy)
118    }
119
120    /// Produce a CMR for a jet
121    pub fn jet<J: Jet>(jet: J) -> Self {
122        Cmr::jet(jet).into()
123    }
124
125    /// Compute the CMR of a constant word jet
126    ///
127    /// This is equal to the IHR of the equivalent scribe, converted to a CMR in
128    /// the usual way for jets.
129    pub fn const_word(word: &Word) -> Self {
130        Cmr::const_word(word).into()
131    }
132
133    #[rustfmt::skip]
134    const IDEN_IV: Self = Self(Midstate([
135        0x54, 0x1a, 0x1a, 0x69, 0xbd, 0x4b, 0xcb, 0xda,
136        0x7f, 0x34, 0x31, 0x0e, 0x30, 0x78, 0xf7, 0x26,
137        0x44, 0x31, 0x22, 0xfb, 0xcc, 0x1c, 0xb5, 0x36,
138        0x0c, 0x78, 0x64, 0xec, 0x0d, 0x32, 0x3a, 0xc0,
139    ]));
140
141    #[rustfmt::skip]
142    const UNIT_IV: Self = Self(Midstate([
143        0xc4, 0x0a, 0x10, 0x26, 0x3f, 0x74, 0x36, 0xb4,
144        0x16, 0x0a, 0xcb, 0xef, 0x1c, 0x36, 0xfb, 0xa4,
145        0xbe, 0x4d, 0x95, 0xdf, 0x18, 0x1a, 0x96, 0x8a,
146        0xfe, 0xab, 0x5e, 0xac, 0x24, 0x7a, 0xdf, 0xf7,
147    ]));
148
149    #[rustfmt::skip]
150    const INJL_IV: Self = Self(Midstate([
151        0x54, 0xe9, 0x1d, 0x18, 0xd8, 0xf8, 0x1f, 0x6d,
152        0x29, 0x86, 0xbb, 0x58, 0x47, 0x9a, 0x54, 0xeb,
153        0x63, 0x0e, 0x95, 0x23, 0xb6, 0x9e, 0xe8, 0x53,
154        0x29, 0x80, 0xd0, 0x55, 0x58, 0x19, 0x4f, 0x15,
155    ]));
156
157    #[rustfmt::skip]
158    const INJR_IV: Self = Self(Midstate([
159        0xd7, 0x0f, 0xfd, 0xce, 0x97, 0x77, 0x7b, 0x4d,
160        0xfe, 0x31, 0xfd, 0x9f, 0xf5, 0xd0, 0x17, 0xa6,
161        0x30, 0x5d, 0x7e, 0xc6, 0x0d, 0xf3, 0xb1, 0xbf,
162        0x6d, 0x25, 0xe8, 0x16, 0x33, 0xde, 0xd4, 0xbf,
163    ]));
164
165    #[rustfmt::skip]
166    const TAKE_IV: Self = Self(Midstate([
167        0x50, 0x5f, 0xc0, 0x81, 0xb5, 0xba, 0x2a, 0xcd,
168        0x09, 0x50, 0x67, 0xc3, 0xdf, 0xb8, 0xea, 0x12,
169        0x6f, 0xa1, 0x5d, 0x55, 0xcb, 0x21, 0x1e, 0x6a,
170        0xed, 0x34, 0xe8, 0xd1, 0xe3, 0x7a, 0xf0, 0xfa,
171    ]));
172
173    #[rustfmt::skip]
174    const DROP_IV: Self = Self(Midstate([
175        0x8a, 0x30, 0x8d, 0x38, 0xa1, 0x13, 0xa2, 0x60,
176        0xb4, 0xc7, 0x14, 0x5a, 0xbd, 0xc5, 0x22, 0x4d,
177        0xeb, 0x70, 0x13, 0x79, 0x59, 0x0e, 0x0c, 0x8c,
178        0x38, 0x86, 0x0b, 0xab, 0x12, 0x71, 0xa8, 0xa8,
179    ]));
180
181    #[rustfmt::skip]
182    const COMP_IV: Self = Self(Midstate([
183        0x57, 0xec, 0x23, 0xa2, 0xa4, 0x77, 0x8e, 0x01,
184        0x58, 0xa6, 0x21, 0x7a, 0xea, 0x3e, 0xf7, 0x42,
185        0x8b, 0xa0, 0x90, 0x92, 0x73, 0xb9, 0x73, 0xfa,
186        0x14, 0x32, 0xa9, 0x27, 0x84, 0x3e, 0x92, 0x7a,
187    ]));
188
189    #[rustfmt::skip]
190    const CASE_IV: Self = Self(Midstate([
191        0x29, 0x5e, 0x2a, 0x6d, 0xc8, 0xc5, 0xce, 0x59,
192        0xe4, 0xed, 0xcf, 0xe9, 0xb4, 0xd8, 0xf7, 0x64,
193        0x13, 0x3a, 0xa5, 0x51, 0x4b, 0xd3, 0xee, 0x8b,
194        0x4b, 0x75, 0xec, 0x8f, 0x4d, 0xeb, 0x08, 0xbe,
195    ]));
196
197    #[rustfmt::skip]
198    const PAIR_IV: Self = Self(Midstate([
199        0x7d, 0x5e, 0x6d, 0xac, 0x15, 0xb1, 0x42, 0x8a,
200        0x0d, 0x26, 0x0c, 0x94, 0x29, 0xdb, 0xe8, 0x89,
201        0x65, 0x93, 0xf3, 0x1f, 0x70, 0x86, 0x27, 0xee,
202        0x75, 0xb2, 0x7e, 0xee, 0xfd, 0xd0, 0x50, 0x05,
203    ]));
204
205    #[rustfmt::skip]
206    const DISCONNECT_IV: Self = Self(Midstate([
207        0x4e, 0xb7, 0x99, 0x5f, 0xb5, 0xdd, 0xe5, 0xd0,
208        0x85, 0xf4, 0x70, 0x85, 0xcd, 0x95, 0x3d, 0x16,
209        0x84, 0x54, 0x11, 0xed, 0xc6, 0x89, 0xe2, 0x7a,
210        0xf9, 0xc3, 0xde, 0xa2, 0xfb, 0x12, 0x25, 0xd5,
211    ]));
212
213    #[rustfmt::skip]
214    const WITNESS_IV: Self = Self(Midstate([
215        0xcb, 0x37, 0xff, 0x70, 0x01, 0xc6, 0x2d, 0x94,
216        0x42, 0x4f, 0x98, 0x7f, 0x30, 0x23, 0xb3, 0x5e,
217        0x30, 0xd2, 0x17, 0x23, 0x96, 0x27, 0x6f, 0x89,
218        0xd0, 0x9f, 0x07, 0xaa, 0x67, 0xb6, 0x21, 0x96,
219    ]));
220
221    #[rustfmt::skip]
222    const FAIL_IV: Self = Self(Midstate([
223        0x22, 0x83, 0xc1, 0x81, 0x9e, 0x69, 0x2f, 0x96,
224        0x85, 0xfe, 0x95, 0x40, 0x76, 0xc5, 0x16, 0x7c,
225        0x03, 0xbd, 0xe7, 0xcc, 0xda, 0xab, 0x00, 0x5e,
226        0x55, 0x36, 0x12, 0x2e, 0x18, 0xf7, 0x23, 0x7a,
227    ]));
228}
229
230impl Ihr {
231    /// Construct an IHR from its components: an IMR and the source and target types.
232    pub fn from_imr(imr: Imr, ty: &FinalArrow) -> Ihr {
233        let iv = Ihr(bip340_iv(b"Simplicity\x1fIdentity"));
234        iv.update_1(Ihr(imr.0))
235            .update(ty.source.tmr().into(), ty.target.tmr().into())
236    }
237}
238
239#[cfg(test)]
240mod tests {
241    use super::*;
242
243    #[test]
244    #[rustfmt::skip] // wants to split up the check_iv lines below
245    fn ivs() {
246        fn check_iv(target: Imr, s: &'static str) {
247            let name = s
248                .trim_start_matches("Simplicity\x1f")
249                .trim_start_matches("Commitment\x1f")
250                .trim_start_matches("Identity\x1f");
251            // Uncomment this if the IVs ever change
252            /*
253            let target = Imr(bip340_iv(s.as_bytes()));
254            println!("    #[rustfmt::skip]");
255            println!("    const {}_IV: Imr = Imr(Midstate([", name.to_ascii_uppercase());
256            print!("       "); for ch in &target.0[0..8] { print!(" 0x{:02x},", ch); }; println!();
257            print!("       "); for ch in &target.0[8..16] { print!(" 0x{:02x},", ch); }; println!();
258            print!("       "); for ch in &target.0[16..24] { print!(" 0x{:02x},", ch); }; println!();
259            print!("       "); for ch in &target.0[24..32] { print!(" 0x{:02x},", ch); }; println!();
260            println!("    ]));");
261            println!();
262            */
263            assert_eq!(target, Imr(bip340_iv(s.as_bytes())), "mismatch on IV for {}", name);
264        }
265
266        // Note that these are the same as those for CMRs **except** for disconnect and witness.
267        check_iv(Imr::IDEN_IV, "Simplicity\x1fCommitment\x1fiden");
268        check_iv(Imr::UNIT_IV, "Simplicity\x1fCommitment\x1funit");
269        check_iv(Imr::INJL_IV, "Simplicity\x1fCommitment\x1finjl");
270        check_iv(Imr::INJR_IV, "Simplicity\x1fCommitment\x1finjr");
271        check_iv(Imr::TAKE_IV, "Simplicity\x1fCommitment\x1ftake");
272        check_iv(Imr::DROP_IV, "Simplicity\x1fCommitment\x1fdrop");
273        check_iv(Imr::COMP_IV, "Simplicity\x1fCommitment\x1fcomp");
274        check_iv(Imr::CASE_IV, "Simplicity\x1fCommitment\x1fcase");
275        check_iv(Imr::PAIR_IV, "Simplicity\x1fCommitment\x1fpair");
276        check_iv(Imr::DISCONNECT_IV, "Simplicity\x1fIdentity\x1fdisconnect");
277        check_iv(Imr::WITNESS_IV, "Simplicity\x1fIdentity\x1fwitness");
278        check_iv(Imr::FAIL_IV, "Simplicity\x1fCommitment\x1ffail");
279    }
280}