hal_simplicity/
hal_simplicity.rs1use std::sync::Arc;
5
6use simplicity::bitcoin::secp256k1;
7use simplicity::jet::Jet;
8use simplicity::{BitIter, CommitNode, DecodeError, ParseError, RedeemNode};
9
10pub struct Program<J: Jet> {
13 commit_prog: Arc<CommitNode<J>>,
22 redeem_prog: Option<Arc<RedeemNode<J>>>,
25}
26
27impl<J: Jet> Program<J> {
28 pub fn from_str(prog_b64: &str, wit_hex: Option<&str>) -> Result<Self, ParseError> {
34 Ok(Self {
35 commit_prog: CommitNode::from_str(prog_b64)?,
36 redeem_prog: wit_hex.map(|hex| RedeemNode::from_str(prog_b64, hex)).transpose()?,
37 })
38 }
39
40 pub fn from_bytes(prog_bytes: &[u8], wit_bytes: Option<&[u8]>) -> Result<Self, DecodeError> {
42 let prog_iter = BitIter::from(prog_bytes);
43 let wit_iter = wit_bytes.map(BitIter::from);
44 Ok(Self {
45 commit_prog: CommitNode::decode(prog_iter.clone())?,
46 redeem_prog: wit_iter.map(|iter| RedeemNode::decode(prog_iter, iter)).transpose()?,
47 })
48 }
49
50 pub fn cmr(&self) -> simplicity::Cmr {
52 self.commit_prog.cmr()
53 }
54
55 pub fn amr(&self) -> Option<simplicity::Amr> {
57 self.redeem_prog.as_ref().map(Arc::as_ref).map(RedeemNode::amr)
58 }
59
60 pub fn ihr(&self) -> Option<simplicity::Ihr> {
62 self.redeem_prog.as_ref().map(Arc::as_ref).map(RedeemNode::ihr)
63 }
64
65 pub fn commit_prog(&self) -> &CommitNode<J> {
67 &self.commit_prog
68 }
69
70 pub fn redeem_node(&self) -> Option<&RedeemNode<J>> {
72 self.redeem_prog.as_ref().map(Arc::as_ref)
73 }
74}
75
76fn unspendable_internal_key() -> secp256k1::XOnlyPublicKey {
78 secp256k1::XOnlyPublicKey::from_slice(&[
79 0xf5, 0x91, 0x9f, 0xa6, 0x4c, 0xe4, 0x5f, 0x83, 0x06, 0x84, 0x90, 0x72, 0xb2, 0x6c, 0x1b,
80 0xfd, 0xd2, 0x93, 0x7e, 0x6b, 0x81, 0x77, 0x47, 0x96, 0xff, 0x37, 0x2b, 0xd1, 0xeb, 0x53,
81 0x62, 0xd2,
82 ])
83 .expect("key should be valid")
84}
85
86fn script_ver(cmr: simplicity::Cmr) -> (elements::Script, elements::taproot::LeafVersion) {
87 let script = elements::script::Script::from(cmr.as_ref().to_vec());
88 (script, simplicity::leaf_version())
89}
90
91fn taproot_spend_info(cmr: simplicity::Cmr) -> elements::taproot::TaprootSpendInfo {
92 let builder = elements::taproot::TaprootBuilder::new();
93 let (script, version) = script_ver(cmr);
94 let builder = builder.add_leaf_with_ver(0, script, version).expect("tap tree should be valid");
95 builder
96 .finalize(secp256k1::SECP256K1, unspendable_internal_key())
97 .expect("tap tree should be valid")
98}
99
100pub fn elements_address(
101 cmr: simplicity::Cmr,
102 params: &'static elements::AddressParams,
103) -> elements::Address {
104 let info = taproot_spend_info(cmr);
105 let blinder = None;
106 elements::Address::p2tr(
107 secp256k1::SECP256K1,
108 info.internal_key(),
109 info.merkle_root(),
110 blinder,
111 params,
112 )
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn fixed_hex_vector_1() {
121 let b64 = "zSQIS29W33fvVt9371bfd+9W33fvVt9371bfd+9W33fvVt93hgGA";
123 let prog = Program::<simplicity::jet::Core>::from_str(b64, Some("")).unwrap();
124
125 assert_eq!(
126 prog.cmr(),
127 "abdd773fc7a503908739b4a63198416fdd470948830cb5a6516b98fe0a3bfa85".parse().unwrap()
128 );
129 assert_eq!(
130 prog.amr(),
131 Some(
132 "1362ee53ae75218ed51dc4bd46cdbfa585f934ac6c6c3ff787e27dce91ccd80b".parse().unwrap()
133 )
134 );
135 assert_eq!(
136 prog.ihr(),
137 Some(
138 "251c6778129e0f12da3f2388ab30184e815e9d9456b5931e54802a6715d9ca42".parse().unwrap()
139 ),
140 );
141
142 let b64 = "zSQIS29W33fvVt9371bfd+9W33fvVt9371bfd+9W33fvVt93hgGA";
147 let prog = Program::<simplicity::jet::Core>::from_str(b64, None).unwrap();
148
149 assert_eq!(
150 prog.cmr(),
151 "abdd773fc7a503908739b4a63198416fdd470948830cb5a6516b98fe0a3bfa85".parse().unwrap()
152 );
153 assert_eq!(prog.amr(), None);
154 assert_eq!(prog.ihr(), None);
155 }
156}