simplicity/human_encoding/
mod.rs1mod error;
10mod named_node;
11mod parse;
12
13use crate::dag::{DagLike, MaxSharing};
14use crate::jet::Jet;
15use crate::node::{self, CommitNode, NoWitness};
16use crate::{Cmr, ConstructNode, Ihr, Value};
17
18use std::collections::HashMap;
19use std::str;
20use std::sync::Arc;
21
22pub use self::error::{Error, ErrorSet};
23pub use self::named_node::NamedCommitNode;
24
25#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
31pub struct Position {
32 line: usize,
33 column: usize,
34}
35
36impl<'a> From<&'a santiago::lexer::Position> for Position {
37 fn from(position: &'a santiago::lexer::Position) -> Position {
38 Position {
39 line: position.line,
40 column: position.column,
41 }
42 }
43}
44
45impl From<santiago::lexer::Position> for Position {
46 fn from(position: santiago::lexer::Position) -> Position {
47 Position {
48 line: position.line,
49 column: position.column,
50 }
51 }
52}
53
54#[derive(Debug, PartialEq, Eq, Clone, Hash)]
61pub enum WitnessOrHole {
62 Witness,
65 TypedHole(Arc<str>),
67}
68
69impl WitnessOrHole {
70 pub fn shallow_clone(&self) -> Self {
71 match self {
72 WitnessOrHole::Witness => WitnessOrHole::Witness,
73 WitnessOrHole::TypedHole(name) => WitnessOrHole::TypedHole(Arc::clone(name)),
74 }
75 }
76}
77
78impl From<&'_ NoWitness> for WitnessOrHole {
79 fn from(_: &NoWitness) -> Self {
80 WitnessOrHole::Witness
81 }
82}
83
84#[derive(Clone, Debug, PartialEq, Eq)]
85pub struct Forest<J: Jet> {
86 roots: HashMap<Arc<str>, Arc<NamedCommitNode<J>>>,
87}
88
89impl<J: Jet> Forest<J> {
90 pub fn parse(s: &str) -> Result<Self, ErrorSet> {
92 parse::parse(s).map(|roots| Forest { roots })
93 }
94
95 pub fn from_program(root: Arc<CommitNode<J>>) -> Self {
97 let root = NamedCommitNode::from_node(&root);
98 let mut roots = HashMap::new();
99 roots.insert("main".into(), root);
100 Forest { roots }
101 }
102
103 pub fn roots(&self) -> &HashMap<Arc<str>, Arc<NamedCommitNode<J>>> {
105 &self.roots
106 }
107
108 pub fn string_serialize(&self) -> String {
110 struct Print {
111 cmr: Cmr,
112 ihr: Option<Ihr>,
113 expr_str: String, arrow_str: String, }
116 fn print_lines(lines: &[Print], skip_before_end: bool) -> String {
117 let mut ret = String::new();
118 let expr_width = lines.iter().map(|line| line.expr_str.len()).max().unwrap();
119 let arrow_width = lines.iter().map(|line| line.arrow_str.len()).max().unwrap();
120 let last_line = lines.len();
121 for (n, line) in lines.iter().enumerate() {
122 ret += "\n";
123 if skip_before_end && n == last_line - 1 {
124 ret += "\n";
125 }
126 ret += &format!("-- CMR: {}\n", line.cmr);
127 if let Some(ihr) = line.ihr {
128 ret += &format!("-- IHR: {}\n", ihr);
129 } else {
130 ret += "-- IHR: [undetermined]\n";
131 }
132 ret += &format!(
133 "{0:1$} {2:3$}\n",
134 line.expr_str, expr_width, line.arrow_str, arrow_width,
135 );
136 }
137 ret
138 }
139
140 let mut witness_lines = vec![];
141 let mut const_lines = vec![];
142 let mut program_lines = vec![];
143 for root in self.roots.values() {
145 for data in root.as_ref().post_order_iter::<MaxSharing<_>>() {
146 let node = data.node;
147 let name = node.name();
148 let mut expr_str = match node.inner() {
149 node::Inner::AssertR(cmr, _) => format!("{} := assertr #{}", name, cmr),
150 node::Inner::Fail(entropy) => format!("{} := fail {}", name, entropy),
151 node::Inner::Jet(ref j) => format!("{} := jet_{}", name, j),
152 node::Inner::Word(ref word) => {
153 format!("{} := const {}", name, word)
154 }
155 inner => format!("{} := {}", name, inner),
156 };
157 if let Some(child) = node.left_child() {
158 expr_str.push(' ');
159 expr_str.push_str(child.name());
160 }
161 if let Some(child) = node.right_child() {
162 expr_str.push(' ');
163 expr_str.push_str(child.name());
164 } else if let node::Inner::AssertL(_, cmr) = node.inner() {
165 expr_str.push_str(" #");
166 expr_str.push_str(&cmr.to_string());
167 } else if let node::Inner::Disconnect(_, hole_name) = node.inner() {
168 expr_str.push_str(&format!(" ?{}", hole_name));
169 }
170
171 let arrow = node.arrow();
172 let arrow_str = format!(": {} -> {}", arrow.source, arrow.target).replace('×', "*"); let print = Print {
175 cmr: node.cmr(),
176 ihr: node.ihr(),
177 expr_str,
178 arrow_str,
179 };
180 if let node::Inner::Witness(..) = node.inner() {
181 witness_lines.push(print);
182 } else if let node::Inner::Word(..) = node.inner() {
183 const_lines.push(print);
184 } else {
185 program_lines.push(print);
186 }
187 }
188 }
189
190 let mut ret = String::new();
192 if !witness_lines.is_empty() {
193 ret += "--------------\n-- Witnesses\n--------------\n";
194 ret += &print_lines(&witness_lines, false);
195 ret += "\n";
196 }
197 if !const_lines.is_empty() {
198 ret += "--------------\n-- Constants\n--------------\n";
200 ret += &print_lines(&const_lines, false);
201 ret += "\n";
202 }
203 if !program_lines.is_empty() {
204 ret += "--------------\n-- Program code\n--------------\n";
205 ret += &print_lines(&program_lines, true );
206 }
207 ret
208 }
209
210 pub fn to_witness_node(
214 &self,
215 witness: &HashMap<Arc<str>, Value>,
216 ) -> Option<Arc<ConstructNode<J>>> {
217 let main = self.roots.get("main")?;
218 Some(main.to_construct_node(witness, self.roots()))
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use crate::human_encoding::Forest;
225 use crate::jet::{Core, Jet};
226 use crate::{BitMachine, Value};
227 use std::collections::HashMap;
228 use std::sync::Arc;
229
230 fn assert_finalize_ok<J: Jet>(
231 s: &str,
232 witness: &HashMap<Arc<str>, Value>,
233 env: &J::Environment,
234 ) {
235 let program = Forest::<J>::parse(s)
236 .expect("Failed to parse human encoding")
237 .to_witness_node(witness)
238 .expect("Forest is missing expected root")
239 .finalize_pruned(env)
240 .expect("Failed to finalize");
241 let mut mac = BitMachine::for_program(&program).expect("program has reasonable bounds");
242 mac.exec(&program, env).expect("Failed to run program");
243 }
244
245 fn assert_finalize_err<J: Jet>(
246 s: &str,
247 witness: &HashMap<Arc<str>, Value>,
248 env: &J::Environment,
249 err_msg: &'static str,
250 ) {
251 let program = match Forest::<J>::parse(s)
252 .expect("Failed to parse human encoding")
253 .to_witness_node(witness)
254 .expect("Forest is missing expected root")
255 .finalize_pruned(env)
256 {
257 Ok(program) => program,
258 Err(error) => {
259 assert_eq!(&error.to_string(), err_msg);
260 return;
261 }
262 };
263 let mut mac = BitMachine::for_program(&program).expect("program has reasonable bounds");
264 match mac.exec(&program, env) {
265 Ok(_) => panic!("Execution is expected to fail"),
266 Err(error) => assert_eq!(&error.to_string(), err_msg),
267 }
268 }
269
270 #[test]
271 fn executed_witness_with_value() {
272 let s = "
273 a := witness
274 b := witness
275 main := comp
276 comp
277 pair a b
278 jet_lt_8
279 jet_verify
280 ";
281
282 let a_less_than_b = HashMap::from([
283 (Arc::from("a"), Value::u8(0x00)),
284 (Arc::from("b"), Value::u8(0x01)),
285 ]);
286 assert_finalize_ok::<Core>(s, &a_less_than_b, &());
287
288 let b_greater_equal_a = HashMap::from([
289 (Arc::from("a"), Value::u8(0x01)),
290 (Arc::from("b"), Value::u8(0x01)),
291 ]);
292 assert_finalize_err::<Core>(s, &b_greater_equal_a, &(), "Jet failed during execution");
293 }
294
295 #[test]
296 fn executed_witness_without_value() {
297 let witness = HashMap::from([(Arc::from("wit1"), Value::u32(1337))]);
298 assert_finalize_err::<Core>(
299 "
300 wit1 := witness : 1 -> 2^32
301 wit2 := witness : 1 -> 2^32
302
303 wits_are_equal := comp (pair wit1 wit2) jet_eq_32 : 1 -> 2
304 main := comp wits_are_equal jet_verify : 1 -> 1
305 ",
306 &witness,
307 &(),
308 "Jet failed during execution",
309 );
310 }
311
312 #[test]
313 fn pruned_witness_without_value() {
314 let s = "
315 wit1 := witness : 1 -> 2
316 wit2 := witness : 1 -> 2^64
317 input := pair wit1 unit : 1 -> 2 * 1
318 process := case (drop injr unit) (drop comp wit2 jet_all_64) : 2 * 1 -> 2
319 main := comp input comp process jet_verify : 1 -> 1
320 ";
321 let wit2_is_pruned = HashMap::from([(Arc::from("wit1"), Value::u1(0))]);
322 assert_finalize_ok::<Core>(s, &wit2_is_pruned, &());
323
324 let wit2_is_missing = HashMap::from([(Arc::from("wit1"), Value::u1(1))]);
325 assert_finalize_err::<Core>(s, &wit2_is_missing, &(), "Jet failed during execution");
326
327 let wit2_is_present = HashMap::from([
328 (Arc::from("wit1"), Value::u1(1)),
329 (Arc::from("wit2"), Value::u64(u64::MAX)),
330 ]);
331 assert_finalize_ok::<Core>(s, &wit2_is_present, &());
332 }
333
334 #[test]
335 fn executed_hole_with_value() {
336 let empty = HashMap::new();
337 assert_finalize_ok::<Core>(
338 "
339 id1 := iden : 2^256 * 1 -> 2^256 * 1
340 main := comp (disconnect id1 ?hole) unit
341 hole := unit
342 ",
343 &empty,
344 &(),
345 );
346 }
347
348 #[test]
349 fn executed_hole_without_value() {
350 let empty = HashMap::new();
351 assert_finalize_err::<Core>(
352 "
353 wit1 := witness
354 main := comp wit1 comp disconnect iden ?dis2 unit
355 ",
356 &empty,
357 &(),
358 "disconnect node had one child (redeem time); must have two",
359 );
360 }
361
362 #[test]
363 fn witness_name_override() {
364 let s = "
365 wit1 := witness : 1 -> 2
366 wit2 := wit1 : 1 -> 2
367 main := comp wit2 jet_verify : 1 -> 1
368 ";
369 let wit1_populated = HashMap::from([(Arc::from("wit1"), Value::u1(1))]);
370 assert_finalize_err::<Core>(s, &wit1_populated, &(), "Jet failed during execution");
371
372 let wit2_populated = HashMap::from([(Arc::from("wit2"), Value::u1(1))]);
373 assert_finalize_ok::<Core>(s, &wit2_populated, &());
374 }
375}