diff --git a/Cargo.toml b/Cargo.toml
index ad6180db..a6f93ed4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,7 +20,7 @@ bitcoin = { version = "0.29.2", optional = true }
bitcoin_hashes = "0.11"
byteorder = "1.3"
elements = { version = "0.21.1", optional = true }
-elements-miniscript = { git = "https://github.com/ElementsProject/elements-miniscript", rev = "955f380" }
+elements-miniscript = { git = "https://github.com/apoelstra/elements-miniscript", tag = "2023-07--rust-simplicity-patch" }
simplicity-sys = { version = "0.1.0", path = "./simplicity-sys" }
actual-serde = { package = "serde", version = "1.0.103", features = ["derive"], optional = true }
diff --git a/jets-bench/benches/elements/main.rs b/jets-bench/benches/elements/main.rs
index 3cb8dfd6..a79dca1d 100644
--- a/jets-bench/benches/elements/main.rs
+++ b/jets-bench/benches/elements/main.rs
@@ -471,7 +471,7 @@ fn bench(c: &mut Criterion) {
let (src_ty, tgt_ty) = jet_arrow(jet);
let env = env_sampler.env();
- let mut group = c.benchmark_group(&format!("{}", jet.to_string()));
+ let mut group = c.benchmark_group(&jet.to_string());
for i in 0..NUM_RANDOM_SAMPLES {
let params = JetParams::with_rand_aligns(InputSampling::Random);
let name = format!("{}", i);
@@ -531,7 +531,7 @@ fn bench(c: &mut Criterion) {
let (src_ty, tgt_ty) = jet_arrow(jet);
let env = EnvSampling::Null.env();
- let mut group = c.benchmark_group(&format!("{}", jet.to_string()));
+ let mut group = c.benchmark_group(&jet.to_string());
for i in 0..NUM_RANDOM_SAMPLES {
let params = JetParams::with_rand_aligns(InputSampling::Custom(inp_fn.clone()));
let name = format!("{}", i);
@@ -612,7 +612,7 @@ fn bench(c: &mut Criterion) {
for (jet, index, env_type) in arr {
let (src_ty, tgt_ty) = jet_arrow(jet);
let env = env_type.env();
- let mut group = c.benchmark_group(&format!("{}", jet.to_string()));
+ let mut group = c.benchmark_group(&jet.to_string());
for i in 0..NUM_RANDOM_SAMPLES {
// We always select the current input because this is where we
diff --git a/src/analysis.rs b/src/analysis.rs
index 039ec8ad..6af29690 100644
--- a/src/analysis.rs
+++ b/src/analysis.rs
@@ -14,7 +14,10 @@
use crate::jet::Jet;
use crate::Value;
-use std::{cmp, fmt, io};
+use std::{cmp, fmt};
+
+#[cfg(feature = "elements")]
+use std::io;
#[cfg(feature = "elements")]
use elements::encode::Encodable;
diff --git a/src/bit_encoding/decode.rs b/src/bit_encoding/decode.rs
index 014fd171..c9e18257 100644
--- a/src/bit_encoding/decode.rs
+++ b/src/bit_encoding/decode.rs
@@ -410,7 +410,7 @@ mod tests {
#[test]
fn root_unit_to_unit() {
// main = jet_eq_32 :: 2^64 -> 2 # 7387d279
- let justjet = vec![0x6d, 0xb8, 0x80];
+ let justjet = [0x6d, 0xb8, 0x80];
// Should be able to decode this as an expression...
let mut iter = BitIter::from(&justjet[..]);
decode_expression::<_, Core>(&mut iter).unwrap();
diff --git a/src/bit_machine/mod.rs b/src/bit_machine/mod.rs
index b3f16cd2..007cb9a8 100644
--- a/src/bit_machine/mod.rs
+++ b/src/bit_machine/mod.rs
@@ -528,7 +528,7 @@ mod tests {
prog.cmr().to_string(),
cmr_str,
"CMR mismatch (got {} expected {}) for program {}",
- prog.cmr().to_string(),
+ prog.cmr(),
cmr_str,
prog_hex,
);
@@ -536,7 +536,7 @@ mod tests {
prog.imr().to_string(),
imr_str,
"IMR mismatch (got {} expected {}) for program {}",
- prog.imr().to_string(),
+ prog.imr(),
imr_str,
prog_hex,
);
@@ -544,7 +544,7 @@ mod tests {
prog.amr().to_string(),
amr_str,
"AMR mismatch (got {} expected {}) for program {}",
- prog.amr().to_string(),
+ prog.amr(),
amr_str,
prog_hex,
);
diff --git a/src/human_encoding/README.md b/src/human_encoding/README.md
index e3a8db8f..6bfe21e9 100644
--- a/src/human_encoding/README.md
+++ b/src/human_encoding/README.md
@@ -52,8 +52,8 @@ and EXPRESSION is
* `unit`, `iden`, or `witness`;
* `injl`, `injr`, `take`, or `drop` followed by another EXPRESSION;
* `case`, `comp`, or `pair` followed by two EXPRESSIONs;
-* `assertl` followed by an EXPRESSION, a literal `#`, and another EXPRESSION;
-* `assertr` followed by a literal `#` and two EXPRESSIONs;
+* `assertl` followed by an EXPRESSION and a CMR (defined below);
+* `assertr` followed by CMR and an EXPRESSION;
* a jet, which begins with `jet_` and must belong to the list of jets (FIXME define this list);
* `const` followed by a VALUE (defined below);
* `fail` followed by an ENTROPY (defined below); or
@@ -63,6 +63,14 @@ Note that while we allow parenthesis to help group parts of expressions for huma
understanding, they are never needed for disambiguation and are essentially
ignored by the parser.
+A CMR is
+
+* `#{` followed by an expression followed by `}`; or
+* `#` followed by 64 hex bytes.
+
+The first case indicates that an expression should be replaced by its commitment
+Merkle root; the second case just directly encodes the Merkle root.
+
A HOLE is the literal `?` followed by a NAME. It indicates an expression that has
yet to be defined. Holes have a different namespace than other names.
@@ -151,7 +159,7 @@ Expressions may be
* one of the core combinators `unit`, `iden`, `comp`, `injl`, `injr`, `case`, `take`, `drop`, `pair`, followed by subexpression(s) as needed;
* the `disconnect` combinator followed by an expression and a hole;
* the `witness` combinator which currently allows no subexpressions;
-* the assertions, `assertl` or `assertr`, which take two subexpressions, one of which will be hidden in the decoded program. The hidden subexpression should be prefixed by `#` which indicates to the parser to take the CMR of that expression, not the expression itself.
+* the assertions, `assertl` or `assertr`, which take a subexpressions and a CMR. The CMR is encoded as a full expression prefixed by `#{` and suffixed by `}`; but in the bit-encoding the expression does not appear, only its CMR;
* `fail` followed by a 128-to-512-bit entropy value, which should occur only in the pruned branch of an assertion, though this is not enforced;
* `const` followed by a value, which is a "constant-word jet" and is equivalent to constructing the given value by a tree of `pair`s whose leaves are `injl unit` (0) or `injr unit` (1);
diff --git a/src/human_encoding/error.rs b/src/human_encoding/error.rs
new file mode 100644
index 00000000..3cbcbef3
--- /dev/null
+++ b/src/human_encoding/error.rs
@@ -0,0 +1,217 @@
+// Simplicity "Human-Readable" Language
+//
+// To the extent possible under law, the author(s) have dedicated all
+// copyright and related and neighboring rights to this software to
+// the public domain worldwide. This software is distributed without
+// any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication
+// along with this software.
+// If not, see .
+//
+
+//! Parsing Errors
+
+use std::collections::BTreeMap;
+use std::sync::{Arc, Mutex};
+use std::{error, fmt, iter};
+
+use crate::types;
+
+use super::Position;
+
+/// A set of errors found in a human-readable encoding of a Simplicity program.
+#[derive(Clone, Debug, Default)]
+pub struct ErrorSet {
+ context: Option>,
+ line_map: Arc>>,
+ errors: BTreeMap