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