Repository: ergoplatform/sigma-rust (language: rust)

Issue:
Use BoundedVec for children (2+) in sigma protocol trees and SigmaAnd, SigmaOr(1+)
Look into const generics as well as existing crates like vec1.
~`TupleItems` also has the same issue of minimal length.~ (done in #253)


Discussion / hints:

Fix patch:
diff --git a/ergotree-interpreter/src/eval/block.rs b/ergotree-interpreter/src/eval/block.rs
index 8fa73e31e..14a17db16 100644
--- a/ergotree-interpreter/src/eval/block.rs
+++ b/ergotree-interpreter/src/eval/block.rs
@@ -11,7 +11,7 @@ use crate::eval::Evaluable;
 impl Evaluable for BlockValue {
     fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result<Value, EvalError> {
         let mut cur_env = env.clone();
-        for i in self.items.iter() {
+        for i in &self.items {
             let val_def = i.clone().try_extract_into::<ValDef>()?;
             let v: Value = val_def.rhs.eval(&cur_env, ctx)?;
             cur_env.insert(val_def.id, v);
diff --git a/ergotree-interpreter/src/eval/coll_exists.rs b/ergotree-interpreter/src/eval/coll_exists.rs
index 1072813a3..4819d0b5a 100644
--- a/ergotree-interpreter/src/eval/coll_exists.rs
+++ b/ergotree-interpreter/src/eval/coll_exists.rs
@@ -44,7 +44,7 @@ impl Evaluable for Exists {
             ))),
         }?;
 
-        for item in normalized_input_vals.into_iter() {
+        for item in normalized_input_vals {
             let res = condition_call(item)?.try_extract_into::<bool>()?;
             if res {
                 return Ok(true.into());
diff --git a/ergotree-interpreter/src/eval/coll_forall.rs b/ergotree-interpreter/src/eval/coll_forall.rs
index 732f0f2e8..186ec5f45 100644
--- a/ergotree-interpreter/src/eval/coll_forall.rs
+++ b/ergotree-interpreter/src/eval/coll_forall.rs
@@ -44,7 +44,7 @@ impl Evaluable for ForAll {
             ))),
         }?;
 
-        for item in normalized_input_vals.into_iter() {
+        for item in normalized_input_vals {
             let res = condition_call(item)?.try_extract_into::<bool>()?;
             if !res {
                 return Ok(false.into());
diff --git a/ergotree-interpreter/src/eval/sigma_and.rs b/ergotree-interpreter/src/eval/sigma_and.rs
index e918c3028..dcb59f643 100644
--- a/ergotree-interpreter/src/eval/sigma_and.rs
+++ b/ergotree-interpreter/src/eval/sigma_and.rs
@@ -11,13 +11,10 @@ use crate::eval::Evaluable;
 
 impl Evaluable for SigmaAnd {
     fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result<Value, EvalError> {
-        let items_v_res: Result<Vec<Value>, EvalError> =
-            self.items.iter().map(|arg| arg.eval(env, ctx)).collect();
+        let items_v_res = self.items.try_mapped_ref(|it| it.eval(env, ctx));
         let items_sigmabool = items_v_res?
-            .try_extract_into::<Vec<SigmaProp>>()?
-            .into_iter()
-            .map(|sp| sp.into())
-            .collect();
+            .try_mapped(|it| it.try_extract_into::<SigmaProp>())?
+            .mapped(|it| it.value().clone());
         Ok(Value::SigmaProp(Box::new(SigmaProp::new(
             Cand::normalized(items_sigmabool),
         ))))
@@ -29,6 +26,7 @@ impl Evaluable for SigmaAnd {
 mod tests {
     use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
     use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjecture;
+    use std::convert::TryInto;
     use std::rc::Rc;
 
     use crate::eval::context::Context;
@@ -54,7 +52,7 @@ mod tests {
             let expected_sb: Vec<SigmaBoolean> = sigmaprops.into_iter().map(|sp| sp.into()).collect();
             prop_assert!(matches!(res.clone().into(), SigmaBoolean::SigmaConjecture(SigmaConjecture::Cand(_))));
             if let SigmaBoolean::SigmaConjecture(SigmaConjecture::Cand(Cand {items: actual_sb})) = res.into() {
-                prop_assert_eq!(actual_sb, expected_sb);
+                prop_assert_eq!(actual_sb, expected_sb.try_into().unwrap());
             }
         }
     }
diff --git a/ergotree-interpreter/src/eval/sigma_or.rs b/ergotree-interpreter/src/eval/sigma_or.rs
index dfc62c34d..3c3acc97e 100644
--- a/ergotree-interpreter/src/eval/sigma_or.rs
+++ b/ergotree-interpreter/src/eval/sigma_or.rs
@@ -11,13 +11,10 @@ use crate::eval::Evaluable;
 
 impl Evaluable for SigmaOr {
     fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result<Value, EvalError> {
-        let items_v_res: Result<Vec<Value>, EvalError> =
-            self.items.iter().map(|arg| arg.eval(env, ctx)).collect();
+        let items_v_res = self.items.try_mapped_ref(|it| it.eval(env, ctx));
         let items_sigmabool = items_v_res?
-            .try_extract_into::<Vec<SigmaProp>>()?
-            .into_iter()
-            .map(|sp| sp.into())
-            .collect();
+            .try_mapped(|it| it.try_extract_into::<SigmaProp>())?
+            .mapped(|it| it.value().clone());
         Ok(Value::SigmaProp(Box::new(SigmaProp::new(Cor::normalized(
             items_sigmabool,
         )))))
@@ -29,6 +26,7 @@ impl Evaluable for SigmaOr {
 mod tests {
     use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
     use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjecture;
+    use std::convert::TryInto;
     use std::rc::Rc;
 
     use crate::eval::context::Context;
@@ -54,7 +52,7 @@ mod tests {
             let expected_sb: Vec<SigmaBoolean> = sigmaprops.into_iter().map(|sp| sp.into()).collect();
             prop_assert!(matches!(res.clone().into(), SigmaBoolean::SigmaConjecture(SigmaConjecture::Cor(_))));
             if let SigmaBoolean::SigmaConjecture(SigmaConjecture::Cor(Cor {items: actual_sb})) = res.into() {
-                prop_assert_eq!(actual_sb, expected_sb);
+                prop_assert_eq!(actual_sb, expected_sb.try_into().unwrap());
             }
         }
     }
diff --git a/ergotree-interpreter/src/sigma_protocol/fiat_shamir.rs b/ergotree-interpreter/src/sigma_protocol/fiat_shamir.rs
index 24b610c53..145c1edde 100644
--- a/ergotree-interpreter/src/sigma_protocol/fiat_shamir.rs
+++ b/ergotree-interpreter/src/sigma_protocol/fiat_shamir.rs
@@ -129,8 +129,8 @@ fn fiat_shamir_write_bytes<W: SigmaByteWrite>(
             w.put_u8(INTERNAL_NODE_PREFIX)?;
             w.put_u8(c.conjecture_type() as u8)?;
             w.put_i16_be_bytes(c.children().len() as i16)?;
-            for child in c.children() {
-                fiat_shamir_write_bytes(&child, w)?;
+            for child in &c.children() {
+                fiat_shamir_write_bytes(child, w)?;
             }
         }
     })
diff --git a/ergotree-interpreter/src/sigma_protocol/proof_tree.rs b/ergotree-interpreter/src/sigma_protocol/proof_tree.rs
index c9871c5ae..c6446e4cb 100644
--- a/ergotree-interpreter/src/sigma_protocol/proof_tree.rs
+++ b/ergotree-interpreter/src/sigma_protocol/proof_tree.rs
@@ -5,6 +5,7 @@ use std::fmt::Debug;
 use derive_more::From;
 use derive_more::TryInto;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
+use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjectureItems;
 
 use crate::sigma_protocol::unproven_tree::CandUnproven;
 use crate::sigma_protocol::unproven_tree::UnprovenConjecture;
@@ -135,7 +136,7 @@ pub(crate) enum ConjectureType {
 
 pub(crate) trait ProofTreeConjecture {
     fn conjecture_type(&self) -> ConjectureType;
-    fn children(&self) -> Vec<ProofTree>;
+    fn children(&self) -> SigmaConjectureItems<ProofTree>;
 }
 
 pub(crate) enum ProofTreeKind<'a> {
@@ -149,20 +150,17 @@ pub(crate) fn rewrite<F>(tree: ProofTree, f: &F) -> Result<ProofTree, ProverErro
 where
     F: Fn(&ProofTree) -> Result<Option<ProofTree>, ProverError>,
 {
-    let cast_to_ust = |children: Vec<ProofTree>| {
-        children
-            .into_iter()
-            .map(|c| {
-                if let ProofTree::UncheckedTree(UncheckedTree::UncheckedSigmaTree(ust)) = c {
-                    Ok(ust)
-                } else {
-                    Err(ProverError::Unexpected(format!(
-                        "rewrite: expected UncheckedSigmaTree got: {:?}",
-                        c
-                    )))
-                }
-            })
-            .collect::<Result<Vec<UncheckedSigmaTree>, _>>()
+    let cast_to_ust = |children: SigmaConjectureItems<ProofTree>| {
+        children.try_mapped(|c| {
+            if let ProofTree::UncheckedTree(UncheckedTree::UncheckedSigmaTree(ust)) = c {
+                Ok(ust)
+            } else {
+                Err(ProverError::Unexpected(format!(
+                    "rewrite: expected UncheckedSigmaTree got: {:?}",
+                    c
+                )))
+            }
+        })
     };
 
     let rewritten_tree = f(&tree)?.unwrap_or(tree);
@@ -172,24 +170,14 @@ where
             UnprovenTree::UnprovenConjecture(conj) => match conj {
                 UnprovenConjecture::CandUnproven(cand) => UnprovenTree::UnprovenConjecture(
                     UnprovenConjecture::CandUnproven(CandUnproven {
-                        children: cand
-                            .children
-                            .clone()
-                            .into_iter()
-                            .map(|c| rewrite(c, f))
-                            .collect::<Result<Vec<ProofTree>, _>>()?,
+                        children: cand.children.clone().try_mapped(|c| rewrite(c, f))?,
                         ..cand.clone()
                     }),
                 )
                 .into(),
                 UnprovenConjecture::CorUnproven(cor) => {
                     UnprovenTree::UnprovenConjecture(UnprovenConjecture::CorUnproven(CorUnproven {
-                        children: cor
-                            .children
-                            .clone()
-                            .into_iter()
-                            .map(|c| rewrite(c, f))
-                            .collect::<Result<Vec<ProofTree>, _>>()?,
+                        children: cor.children.clone().try_mapped(|c| rewrite(c, f))?,
                         ..cor.clone()
                     }))
                     .into()
@@ -205,11 +193,8 @@ where
                         challenge,
                         children,
                     } => {
-                        let rewritten_children = children
-                            .clone()
-                            .into_iter()
-                            .map(|c| rewrite(c.into(), f))
-                            .collect::<Result<Vec<ProofTree>, _>>()?;
+                        let rewritten_children =
+                            children.clone().try_mapped(|c| rewrite(c.into(), f))?;
                         let casted_children = cast_to_ust(rewritten_children)?;
                         UncheckedConjecture::CandUnchecked {
                             children: casted_children,
@@ -221,11 +206,8 @@ where
                         challenge,
                         children,
                     } => {
-                        let rewritten_children = children
-                            .clone()
-                            .into_iter()
-                            .map(|c| rewrite(c.into(), f))
-                            .collect::<Result<Vec<ProofTree>, _>>()?;
+                        let rewritten_children =
+                            children.clone().try_mapped(|c| rewrite(c.into(), f))?;
                         let casted_children = cast_to_ust(rewritten_children)?;
                         UncheckedConjecture::CorUnchecked {
                             children: casted_children,
diff --git a/ergotree-interpreter/src/sigma_protocol/prover.rs b/ergotree-interpreter/src/sigma_protocol/prover.rs
index 23acc1148..21be13687 100644
--- a/ergotree-interpreter/src/sigma_protocol/prover.rs
+++ b/ergotree-interpreter/src/sigma_protocol/prover.rs
@@ -16,6 +16,7 @@ use crate::sigma_protocol::Challenge;
 use crate::sigma_protocol::UncheckedSigmaTree;
 use crate::sigma_protocol::UnprovenLeaf;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
+use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjectureItems;
 use std::convert::TryInto;
 use std::rc::Rc;
 
@@ -217,7 +218,7 @@ fn mark_real<P: Prover + ?Sized>(
                     UnprovenConjecture::CandUnproven(cand) => {
                         // If the node is AND, mark it "real" if all of its children are marked real; else mark it "simulated"
                         let simulated = cast_to_unp(cand.children.clone())?
-                            .into_iter()
+                            .iter()
                             .any(|c| c.simulated());
                         Some(
                             CandUnproven {
@@ -230,7 +231,7 @@ fn mark_real<P: Prover + ?Sized>(
                     UnprovenConjecture::CorUnproven(cor) => {
                         // If the node is OR, mark it "real" if at least one child is marked real; else mark it "simulated"
                         let simulated = cast_to_unp(cor.children.clone())?
-                            .into_iter()
+                            .iter()
                             .all(|c| c.simulated());
                         Some(
                             CorUnproven {
@@ -251,12 +252,10 @@ fn mark_real<P: Prover + ?Sized>(
 
 /// Set positions for children of a unproven inner node (conjecture, so AND/OR/THRESHOLD)
 fn set_positions(uc: UnprovenConjecture) -> UnprovenConjecture {
-    let upd_children: Vec<ProofTree> = uc
+    let upd_children = uc
         .children()
-        .into_iter()
-        .enumerate()
-        .map(|(idx, utree)| utree.with_position(uc.position().child(idx)))
-        .collect();
+        .enumerated()
+        .mapped(|(idx, utree)| utree.with_position(uc.position().child(idx)));
     match uc {
         UnprovenConjecture::CandUnproven(cand) => cand.with_children(upd_children).into(),
         UnprovenConjecture::CorUnproven(cor) => cor.with_children(upd_children).into(),
@@ -280,33 +279,30 @@ fn make_cor_children_simulated(cor: CorUnproven) -> Result<CorUnproven, ProverEr
         })?;
     let children = casted_children
         .clone()
-        .into_iter()
-        .map(|c| {
+        .mapped(|c| {
             if &c == first_real_child || c.simulated() {
                 c
             } else {
                 c.with_simulated(true)
             }
         })
-        .map(|c| c.into())
-        .collect();
+        .mapped(|c| c.into());
     Ok(CorUnproven { children, ..cor })
 }
 
-fn cast_to_unp(children: Vec<ProofTree>) -> Result<Vec<UnprovenTree>, ProverError> {
-    children
-        .into_iter()
-        .map(|c| {
-            if let ProofTree::UnprovenTree(ut) = c {
-                Ok(ut)
-            } else {
-                Err(ProverError::Unexpected(format!(
-                    "make_cor_children_simulated: expected UnprovenTree got: {:?}",
-                    c
-                )))
-            }
-        })
-        .collect()
+fn cast_to_unp(
+    children: SigmaConjectureItems<ProofTree>,
+) -> Result<SigmaConjectureItems<UnprovenTree>, ProverError> {
+    children.try_mapped(|c| {
+        if let ProofTree::UnprovenTree(ut) = c {
+            Ok(ut)
+        } else {
+            Err(ProverError::Unexpected(format!(
+                "make_cor_children_simulated: expected UnprovenTree got: {:?}",
+                c
+            )))
+        }
+    })
 }
 
 /// Prover Step 3: This step will change some "real" nodes to "simulated" to make sure each node has
@@ -325,9 +321,7 @@ fn polish_simulated<P: Prover + ?Sized>(
                     let a: CandUnproven = if cand.simulated {
                         cand.clone().with_children(
                             cast_to_unp(cand.children.clone())?
-                                .into_iter()
-                                .map(|c| c.with_simulated(true).into())
-                                .collect(),
+                                .mapped(|c| c.with_simulated(true).into()),
                         )
                     } else {
                         cand.clone()
@@ -339,9 +333,7 @@ fn polish_simulated<P: Prover + ?Sized>(
                     let o: CorUnproven = if cor.simulated {
                         CorUnproven {
                             children: cast_to_unp(cor.children.clone())?
-                                .into_iter()
-                                .map(|c| c.with_simulated(true).into())
-                                .collect::<Vec<ProofTree>>(),
+                                .mapped(|c| c.with_simulated(true).into()),
                             ..cor.clone()
                         }
                     } else {
@@ -384,8 +376,7 @@ fn simulate_and_commit(
                 UnprovenConjecture::CorUnproven(cor),
             )) if cor.is_real() => {
                 let new_children = cast_to_unp(cor.children.clone())?
-                    .into_iter()
-                    .map(|c| {
+                    .mapped(|c| {
                         if c.is_real() {
                             c
                         } else {
@@ -400,8 +391,7 @@ fn simulate_and_commit(
                             c.with_challenge(new_challenge)
                         }
                     })
-                    .map(|c| c.into())
-                    .collect();
+                    .mapped(|c| c.into());
                 Ok(Some(
                     CorUnproven {
                         children: new_children,
@@ -422,9 +412,7 @@ fn simulate_and_commit(
                     let new_children = cand
                         .children
                         .clone()
-                        .into_iter()
-                        .map(|it| it.with_challenge(challenge.clone()))
-                        .collect();
+                        .mapped(|it| it.with_challenge(challenge.clone()));
                     Ok(Some(
                         CandUnproven {
                             children: new_children,
@@ -460,19 +448,21 @@ fn simulate_and_commit(
                             ProverError::Unexpected(format!("no challenge in {:?}", it))
                         })?);
                     }
-                    let head = if let Some(first) = unproven_children.first() {
-                        first.clone().with_challenge(xored_challenge)
-                    } else {
-                        return Err(ProverError::Unexpected(format!(
-                            "empty children in {:?}",
-                            cor
-                        )));
-                    };
+                    let head = unproven_children
+                        .first()
+                        .clone()
+                        .with_challenge(xored_challenge);
                     let mut new_children = vec![head];
                     new_children.append(&mut tail);
+                    #[allow(clippy::unwrap_used)] // since quantity is preserved unwrap is safe here
                     Ok(Some(
                         CorUnproven {
-                            children: new_children.into_iter().map(|c| c.into()).collect(),
+                            children: new_children
+                                .into_iter()
+                                .map(|c| c.into())
+                                .collect::<Vec<ProofTree>>()
+                                .try_into()
+                                .unwrap(),
                             ..cor.clone()
                         }
                         .into(),
@@ -586,9 +576,7 @@ fn proving<P: Prover + ?Sized>(
                                 let updated = cand
                                     .clone()
                                     .children
-                                    .into_iter()
-                                    .map(|child| child.with_challenge(challenge.clone()))
-                                    .collect();
+                                    .mapped(|child| child.with_challenge(challenge.clone()));
                                 Ok(Some(cand.clone().with_children(updated).into()))
                             } else {
                                 Err(ProverError::Unexpected(
@@ -608,20 +596,15 @@ fn proving<P: Prover + ?Sized>(
                                 let challenge: Challenge = cor
                                     .children
                                     .clone()
-                                    .into_iter()
+                                    .iter()
                                     .flat_map(|c| c.challenge())
                                     .fold(root_challenge.clone(), |acc, c| acc.xor(c));
-                                let children = cor
-                                    .children
-                                    .clone()
-                                    .into_iter()
-                                    .map(|c| match c {
-                                        ProofTree::UnprovenTree(ref ut) if ut.is_real() => {
-                                            c.with_challenge(challenge.clone())
-                                        }
-                                        _ => c,
-                                    })
-                                    .collect();
+                                let children = cor.children.clone().mapped(|c| match c {
+                                    ProofTree::UnprovenTree(ref ut) if ut.is_real() => {
+                                        c.with_challenge(challenge.clone())
+                                    }
+                                    _ => c,
+                                });
                                 Ok(Some(
                                     CorUnproven {
                                         children,
@@ -714,11 +697,7 @@ fn convert_to_unproven(sb: SigmaBoolean) -> UnprovenTree {
             proposition: cand.clone(),
             challenge_opt: None,
             simulated: false,
-            children: cand
-                .items
-                .into_iter()
-                .map(|it| convert_to_unproven(it).into())
-                .collect(),
+            children: cand.items.mapped(|it| convert_to_unproven(it).into()),
             position: NodePosition::crypto_tree_prefix(),
         }
         .into(),
@@ -726,11 +705,7 @@ fn convert_to_unproven(sb: SigmaBoolean) -> UnprovenTree {
             proposition: cor.clone(),
             challenge_opt: None,
             simulated: false,
-            children: cor
-                .items
-                .into_iter()
-                .map(|it| convert_to_unproven(it).into())
-                .collect(),
+            children: cor.items.mapped(|it| convert_to_unproven(it).into()),
             position: NodePosition::crypto_tree_prefix(),
         }
         .into(),
@@ -763,24 +738,14 @@ fn convert_to_unchecked(tree: ProofTree) -> Result<UncheckedSigmaTree, ProverErr
                     challenge: cand.challenge_opt.clone().ok_or_else(|| {
                         ProverError::Unexpected(format!("no challenge in {:?}", cand))
                     })?,
-                    children: cand
-                        .children
-                        .clone()
-                        .into_iter()
-                        .map(convert_to_unchecked)
-                        .collect::<Result<Vec<UncheckedSigmaTree>, _>>()?,
+                    children: cand.children.clone().try_mapped(convert_to_unchecked)?,
                 }
                 .into()),
                 UnprovenConjecture::CorUnproven(cor) => Ok(UncheckedConjecture::CorUnchecked {
                     challenge: cor.challenge_opt.clone().ok_or_else(|| {
                         ProverError::Unexpected(format!("no challenge in {:?}", cor))
                     })?,
-                    children: cor
-                        .children
-                        .clone()
-                        .into_iter()
-                        .map(convert_to_unchecked)
-                        .collect::<Result<Vec<UncheckedSigmaTree>, _>>()?,
+                    children: cor.children.clone().try_mapped(convert_to_unchecked)?,
                 }
                 .into()),
             },
diff --git a/ergotree-interpreter/src/sigma_protocol/sig_serializer.rs b/ergotree-interpreter/src/sigma_protocol/sig_serializer.rs
index ec3db1aad..bf567f2bd 100644
--- a/ergotree-interpreter/src/sigma_protocol/sig_serializer.rs
+++ b/ergotree-interpreter/src/sigma_protocol/sig_serializer.rs
@@ -1,5 +1,7 @@
 //! Serialization of proof tree signatures
 
+use std::convert::TryInto;
+
 use super::prover::ProofBytes;
 use super::unchecked_tree::UncheckedConjecture;
 use super::unchecked_tree::UncheckedLeaf;
@@ -74,12 +76,11 @@ fn sig_write_bytes<W: SigmaByteWrite>(
                 children,
             } => {
                 // don't write last child's challenge -- it's computed by the verifier via XOR
-                if let Some((last, elements)) = children.split_last() {
-                    for child in elements {
-                        sig_write_bytes(child, w, true)?;
-                    }
-                    sig_write_bytes(last, w, false)?;
+                let (last, elements) = children.split_last();
+                for child in elements {
+                    sig_write_bytes(child, w, true)?;
                 }
+                sig_write_bytes(last, w, false)?;
                 Ok(())
             }
         },
@@ -144,14 +145,9 @@ fn parse_sig_compute_challnges_reader<R: SigmaByteRead>(
             SigmaConjecture::Cand(cand) => {
                 // Verifier Step 2: If the node is AND, then all of its children get e_0 as
                 // the challenge
-                let mut children: Vec<UncheckedSigmaTree> = Vec::new();
-                for it in cand.items.clone() {
-                    children.push(parse_sig_compute_challnges_reader(
-                        &it,
-                        r,
-                        Some(challenge.clone()),
-                    )?);
-                }
+                let children = cand.items.try_mapped_ref(|it| {
+                    parse_sig_compute_challnges_reader(it, r, Some(challenge.clone()))
+                })?;
                 Ok(UncheckedConjecture::CandUnchecked {
                     challenge,
                     children,
@@ -166,23 +162,23 @@ fn parse_sig_compute_challnges_reader<R: SigmaByteRead>(
                 // Read all the children but the last and compute the XOR of all the challenges including e_0
                 let mut children: Vec<UncheckedSigmaTree> = Vec::new();
 
-                if let Some((last, rest)) = cor.items.split_last() {
-                    for it in rest {
-                        children.push(parse_sig_compute_challnges_reader(&it, r, None)?);
-                    }
-                    let xored_challenge = children
-                        .clone()
-                        .into_iter()
-                        .map(|c| c.challenge())
-                        .fold(challenge.clone(), |acc, c| acc.xor(c));
-                    let last_child =
-                        parse_sig_compute_challnges_reader(last, r, Some(xored_challenge))?;
-                    children.push(last_child);
+                let (last, rest) = cor.items.split_last();
+                for it in rest {
+                    children.push(parse_sig_compute_challnges_reader(&it, r, None)?);
                 }
+                let xored_challenge = children
+                    .clone()
+                    .into_iter()
+                    .map(|c| c.challenge())
+                    .fold(challenge.clone(), |acc, c| acc.xor(c));
+                let last_child =
+                    parse_sig_compute_challnges_reader(last, r, Some(xored_challenge))?;
+                children.push(last_child);
 
+                #[allow(clippy::unwrap_used)] // since quantity is preserved unwrap is safe here
                 Ok(UncheckedConjecture::CorUnchecked {
                     challenge,
-                    children,
+                    children: children.try_into().unwrap(),
                 }
                 .into())
             }
diff --git a/ergotree-interpreter/src/sigma_protocol/unchecked_tree.rs b/ergotree-interpreter/src/sigma_protocol/unchecked_tree.rs
index aa73a2ed4..04dea8926 100644
--- a/ergotree-interpreter/src/sigma_protocol/unchecked_tree.rs
+++ b/ergotree-interpreter/src/sigma_protocol/unchecked_tree.rs
@@ -2,6 +2,7 @@
 
 use ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
+use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjectureItems;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
 
 use super::proof_tree::ConjectureType;
@@ -121,16 +122,16 @@ impl From<UncheckedSchnorr> for UncheckedTree {
 pub enum UncheckedConjecture {
     CandUnchecked {
         challenge: Challenge,
-        children: Vec<UncheckedSigmaTree>,
+        children: SigmaConjectureItems<UncheckedSigmaTree>,
     },
     CorUnchecked {
         challenge: Challenge,
-        children: Vec<UncheckedSigmaTree>,
+        children: SigmaConjectureItems<UncheckedSigmaTree>,
     },
 }
 
 impl UncheckedConjecture {
-    pub fn with_children(self, new_children: Vec<UncheckedSigmaTree>) -> Self {
+    pub fn with_children(self, new_children: SigmaConjectureItems<UncheckedSigmaTree>) -> Self {
         match self {
             UncheckedConjecture::CandUnchecked {
                 challenge,
@@ -149,7 +150,7 @@ impl UncheckedConjecture {
         }
     }
 
-    pub fn children_ust(&self) -> &[UncheckedSigmaTree] {
+    pub fn children_ust(self) -> SigmaConjectureItems<UncheckedSigmaTree> {
         match self {
             UncheckedConjecture::CandUnchecked {
                 challenge: _,
@@ -184,22 +185,16 @@ impl ProofTreeConjecture for UncheckedConjecture {
         }
     }
 
-    fn children(&self) -> Vec<ProofTree> {
+    fn children(&self) -> SigmaConjectureItems<ProofTree> {
         match self {
             UncheckedConjecture::CandUnchecked {
                 challenge: _,
                 children,
-            } => children
-                .iter()
-                .map(|ust| ust.clone().into())
-                .collect::<Vec<ProofTree>>(),
+            } => children.mapped_ref(|ust| ust.clone().into()),
             UncheckedConjecture::CorUnchecked {
                 challenge: _,
                 children,
-            } => children
-                .iter()
-                .map(|ust| ust.clone().into())
-                .collect::<Vec<ProofTree>>(),
+            } => children.mapped_ref(|ust| ust.clone().into()),
         }
     }
 }
diff --git a/ergotree-interpreter/src/sigma_protocol/unproven_tree.rs b/ergotree-interpreter/src/sigma_protocol/unproven_tree.rs
index 10bebdbd7..5fd8cc020 100644
--- a/ergotree-interpreter/src/sigma_protocol/unproven_tree.rs
+++ b/ergotree-interpreter/src/sigma_protocol/unproven_tree.rs
@@ -10,6 +10,7 @@ use ergotree_ir::sigma_protocol::sigma_boolean::cand::Cand;
 use ergotree_ir::sigma_protocol::sigma_boolean::cor::Cor;
 use ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
+use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjectureItems;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
 use k256::Scalar;
 
@@ -168,7 +169,7 @@ pub(crate) enum UnprovenConjecture {
 }
 
 impl UnprovenConjecture {
-    pub(crate) fn children(&self) -> Vec<ProofTree> {
+    pub(crate) fn children(&self) -> SigmaConjectureItems<ProofTree> {
         match self {
             UnprovenConjecture::CandUnproven(cand) => cand.children.clone(),
             UnprovenConjecture::CorUnproven(cor) => cor.children.clone(),
@@ -219,7 +220,7 @@ impl ProofTreeConjecture for UnprovenConjecture {
         }
     }
 
-    fn children(&self) -> Vec<ProofTree> {
+    fn children(&self) -> SigmaConjectureItems<ProofTree> {
         match self {
             UnprovenConjecture::CandUnproven(cand) => cand.children.clone(),
             UnprovenConjecture::CorUnproven(cor) => cor.children.clone(),
@@ -304,7 +305,7 @@ pub(crate) struct CandUnproven {
     pub(crate) proposition: Cand,
     pub(crate) challenge_opt: Option<Challenge>,
     pub(crate) simulated: bool,
-    pub(crate) children: Vec<ProofTree>,
+    pub(crate) children: SigmaConjectureItems<ProofTree>,
     pub(crate) position: NodePosition,
 }
 
@@ -331,7 +332,7 @@ impl CandUnproven {
         Self { simulated, ..self }
     }
 
-    pub(crate) fn with_children(self, children: Vec<ProofTree>) -> Self {
+    pub(crate) fn with_children(self, children: SigmaConjectureItems<ProofTree>) -> Self {
         CandUnproven { children, ..self }
     }
 }
@@ -341,7 +342,7 @@ pub(crate) struct CorUnproven {
     pub(crate) proposition: Cor,
     pub(crate) challenge_opt: Option<Challenge>,
     pub(crate) simulated: bool,
-    pub(crate) children: Vec<ProofTree>,
+    pub(crate) children: SigmaConjectureItems<ProofTree>,
     pub(crate) position: NodePosition,
 }
 
@@ -368,7 +369,7 @@ impl CorUnproven {
         Self { simulated, ..self }
     }
 
-    pub(crate) fn with_children(self, children: Vec<ProofTree>) -> Self {
+    pub(crate) fn with_children(self, children: SigmaConjectureItems<ProofTree>) -> Self {
         Self { children, ..self }
     }
 }
diff --git a/ergotree-interpreter/src/sigma_protocol/verifier.rs b/ergotree-interpreter/src/sigma_protocol/verifier.rs
index 38f1e54ca..72d382450 100644
--- a/ergotree-interpreter/src/sigma_protocol/verifier.rs
+++ b/ergotree-interpreter/src/sigma_protocol/verifier.rs
@@ -121,12 +121,7 @@ fn compute_commitments(sp: UncheckedSigmaTree) -> UncheckedSigmaTree {
         },
         UncheckedSigmaTree::UncheckedConjecture(conj) => conj
             .clone()
-            .with_children(
-                conj.children_ust()
-                    .iter()
-                    .map(|c| compute_commitments(c.clone()))
-                    .collect(),
-            )
+            .with_children(conj.children_ust().mapped(compute_commitments))
             .into(),
     }
 }
@@ -299,7 +294,7 @@ mod tests {
                     Rc::new(force_any_val::<Context>()),
                     message.as_slice(),
                     &HintsBag::empty());
-                let proof = res.unwrap().proof;
+                let proof = res.unwrap_or_else(|_| panic!("proof failed for secret: {:?}", secret)).proof;
                 let verifier = TestVerifier;
                 let ver_res = verifier.verify(&tree,
                                               &Env::empty(),
@@ -340,7 +335,7 @@ mod tests {
                     Rc::new(force_any_val::<Context>()),
                     message.as_slice(),
                     &HintsBag::empty());
-                let proof = res.unwrap().proof;
+                let proof = res.unwrap_or_else(|_| panic!("proof failed for secret: {:?}", secret)).proof;
                 let verifier = TestVerifier;
                 let ver_res = verifier.verify(&tree,
                                               &Env::empty(),
diff --git a/ergotree-ir/Cargo.toml b/ergotree-ir/Cargo.toml
index 1e03df34b..139788be4 100644
--- a/ergotree-ir/Cargo.toml
+++ b/ergotree-ir/Cargo.toml
@@ -28,8 +28,8 @@ proptest-derive = {version = "0.3.0", optional = true }
 bs58 = "0.4.0"
 base16 = "0.2.1"
 num-bigint = "0.4.0"
-# bounded-vec = { git = "https://github.com/ergoplatform/bounded-vec", rev="6726ac0" }
-bounded-vec = { version = "^0.2.0" }
+# bounded-vec = { git = "https://github.com/ergoplatform/bounded-vec", rev="78f1c83" }
+bounded-vec = { version = "^0.3.0" }
 
 [features]
 default = []
diff --git a/ergotree-ir/src/mir/sigma_and.rs b/ergotree-ir/src/mir/sigma_and.rs
index 9503d7fd0..0186b4a2e 100644
--- a/ergotree-ir/src/mir/sigma_and.rs
+++ b/ergotree-ir/src/mir/sigma_and.rs
@@ -1,10 +1,13 @@
 //! AND conjunction for sigma propositions
 
+use std::convert::TryInto;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
 use crate::serialization::SerializationError;
 use crate::serialization::SigmaSerializable;
+use crate::sigma_protocol::sigma_boolean::SigmaConjectureItems;
 use crate::types::stype::SType;
 
 use super::expr::Expr;
@@ -15,7 +18,7 @@ use crate::has_opcode::HasStaticOpCode;
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct SigmaAnd {
     /// Collection of SSigmaProp
-    pub items: Vec<Expr>,
+    pub items: SigmaConjectureItems<Expr>,
 }
 
 impl SigmaAnd {
@@ -30,7 +33,9 @@ impl SigmaAnd {
             .iter()
             .all(|tpe| matches!(tpe, SType::SSigmaProp))
         {
-            Ok(Self { items })
+            Ok(Self {
+                items: items.try_into()?,
+            })
         } else {
             Err(InvalidArgumentError(format!(
                 "Sigma conjecture: expected all items be of type SSigmaProp, got {:?},\n items: {:?}",
@@ -71,10 +76,16 @@ mod arbitrary {
         type Strategy = BoxedStrategy<Self>;
         type Parameters = ();
 
+        #[allow(clippy::unwrap_used)]
         fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
             vec(any_with::<Constant>(SType::SSigmaProp.into()), 2..5)
                 .prop_map(|constants| Self {
-                    items: constants.into_iter().map(|c| c.into()).collect(),
+                    items: constants
+                        .into_iter()
+                        .map(|c| c.into())
+                        .collect::<Vec<Expr>>()
+                        .try_into()
+                        .unwrap(),
                 })
                 .boxed()
         }
diff --git a/ergotree-ir/src/mir/sigma_or.rs b/ergotree-ir/src/mir/sigma_or.rs
index 22cb572df..2542e10ab 100644
--- a/ergotree-ir/src/mir/sigma_or.rs
+++ b/ergotree-ir/src/mir/sigma_or.rs
@@ -1,10 +1,13 @@
 //! OR conjunction for sigma propositions
 
+use std::convert::TryInto;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
 use crate::serialization::SerializationError;
 use crate::serialization::SigmaSerializable;
+use crate::sigma_protocol::sigma_boolean::SigmaConjectureItems;
 use crate::types::stype::SType;
 
 use super::expr::Expr;
@@ -15,7 +18,7 @@ use crate::has_opcode::HasStaticOpCode;
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct SigmaOr {
     /// Collection of SSigmaProp
-    pub items: Vec<Expr>,
+    pub items: SigmaConjectureItems<Expr>,
 }
 
 impl SigmaOr {
@@ -30,7 +33,9 @@ impl SigmaOr {
             .iter()
             .all(|tpe| matches!(tpe, SType::SSigmaProp))
         {
-            Ok(Self { items })
+            Ok(Self {
+                items: items.try_into()?,
+            })
         } else {
             Err(InvalidArgumentError(format!(
                 "Sigma conjecture: expected all items be of type SSigmaProp, got {:?},\n items: {:?}",
@@ -71,10 +76,16 @@ mod arbitrary {
         type Strategy = BoxedStrategy<Self>;
         type Parameters = ();
 
+        #[allow(clippy::unwrap_used)]
         fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
             vec(any_with::<Constant>(SType::SSigmaProp.into()), 2..5)
                 .prop_map(|constants| Self {
-                    items: constants.into_iter().map(|c| c.into()).collect(),
+                    items: constants
+                        .into_iter()
+                        .map(|c| c.into())
+                        .collect::<Vec<Expr>>()
+                        .try_into()
+                        .unwrap(),
                 })
                 .boxed()
         }
diff --git a/ergotree-ir/src/serialization/serializable.rs b/ergotree-ir/src/serialization/serializable.rs
index 7b339cbb3..459d6ee19 100644
--- a/ergotree-ir/src/serialization/serializable.rs
+++ b/ergotree-ir/src/serialization/serializable.rs
@@ -10,9 +10,11 @@ use super::{
 };
 use crate::serialization::types::TypeCode;
 use crate::types::smethod::MethodId;
+use bounded_vec::BoundedVec;
 use bounded_vec::BoundedVecOutOfBounds;
 use io::Cursor;
 use sigma_ser::vlq_encode;
+use std::convert::TryInto;
 use std::io;
 use thiserror::Error;
 
@@ -141,6 +143,18 @@ impl<T: SigmaSerializable> SigmaSerializable for Vec<T> {
     }
 }
 
+impl<T: SigmaSerializable, const L: usize, const U: usize> SigmaSerializable
+    for BoundedVec<T, L, U>
+{
+    fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> Result<(), io::Error> {
+        self.as_vec().sigma_serialize(w)
+    }
+
+    fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SerializationError> {
+        Ok(Vec::<T>::sigma_parse(r)?.try_into()?)
+    }
+}
+
 impl<T: SigmaSerializable> SigmaSerializable for Option<Box<T>> {
     fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> Result<(), io::Error> {
         match self {
diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean.rs
index d4e58c2af..d0118b7e3 100644
--- a/ergotree-ir/src/sigma_protocol/sigma_boolean.rs
+++ b/ergotree-ir/src/sigma_protocol/sigma_boolean.rs
@@ -14,6 +14,7 @@ use std::convert::TryFrom;
 use std::convert::TryInto;
 
 extern crate derive_more;
+use bounded_vec::BoundedVec;
 use derive_more::From;
 use derive_more::Into;
 use derive_more::TryInto;
@@ -21,6 +22,9 @@ use derive_more::TryInto;
 pub mod cand;
 pub mod cor;
 
+/// Sigma conjecture items type with bounds check (2..=1000)
+pub type SigmaConjectureItems<T> = BoundedVec<T, 2, 1000>;
+
 /// Construct a new SigmaBoolean value representing public key of discrete logarithm signature protocol.
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct ProveDlog {
diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs
index ff93275ab..604542ae4 100644
--- a/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs
+++ b/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs
@@ -1,20 +1,22 @@
 //! AND conjunction for sigma proposition
+use std::convert::TryInto;
+
 use super::SigmaBoolean;
+use super::SigmaConjectureItems;
 use crate::sigma_protocol::sigma_boolean::SigmaConjecture;
 
 /// AND conjunction for sigma proposition
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct Cand {
     /// Items of the conjunctions
-    pub items: Vec<SigmaBoolean>,
+    pub items: SigmaConjectureItems<SigmaBoolean>,
 }
 
 impl Cand {
     /// Connects the given sigma propositions into CAND proposition performing
     /// partial evaluation when some of them are trivial propositioins.
-    pub fn normalized(items: Vec<SigmaBoolean>) -> SigmaBoolean {
-        assert!(!items.is_empty());
-        let mut res = Vec::new();
+    pub fn normalized(items: SigmaConjectureItems<SigmaBoolean>) -> SigmaBoolean {
+        let mut res: Vec<SigmaBoolean> = Vec::new();
         for it in items {
             match it {
                 SigmaBoolean::TrivialProp(false) => return it,
@@ -28,7 +30,11 @@ impl Cand {
             #[allow(clippy::unwrap_used)]
             res.first().unwrap().clone()
         } else {
-            SigmaBoolean::SigmaConjecture(SigmaConjecture::Cand(Cand { items: res }))
+            #[allow(clippy::unwrap_used)]
+            SigmaBoolean::SigmaConjecture(SigmaConjecture::Cand(Cand {
+                // should be 2 or more so unwrap is safe here
+                items: res.try_into().unwrap(),
+            }))
         }
     }
 }
@@ -43,28 +49,20 @@ mod tests {
 
     #[test]
     fn trivial_true() {
-        let cand = Cand::normalized(vec![true.into()]);
+        let cand = Cand::normalized(vec![true.into(), true.into()].try_into().unwrap());
         assert!(matches!(cand, SigmaBoolean::TrivialProp(true)));
     }
 
     #[test]
     fn trivial_false() {
-        let cand = Cand::normalized(vec![false.into()]);
+        let cand = Cand::normalized(vec![false.into(), true.into()].try_into().unwrap());
         assert!(matches!(cand, SigmaBoolean::TrivialProp(false)));
     }
 
-    #[test]
-    fn pk() {
-        let pk = force_any_val::<ProveDlog>();
-        let cand = Cand::normalized(vec![pk.clone().into()]);
-        let res: ProveDlog = cand.try_into().unwrap();
-        assert_eq!(res, pk);
-    }
-
     #[test]
     fn pk_triv_true() {
         let pk = force_any_val::<ProveDlog>();
-        let cand = Cand::normalized(vec![pk.clone().into(), true.into()]);
+        let cand = Cand::normalized(vec![pk.clone().into(), true.into()].try_into().unwrap());
         let res: ProveDlog = cand.try_into().unwrap();
         assert_eq!(res, pk);
     }
@@ -72,7 +70,7 @@ mod tests {
     #[test]
     fn pk_triv_false() {
         let pk = force_any_val::<ProveDlog>();
-        let cand = Cand::normalized(vec![pk.into(), false.into()]);
+        let cand = Cand::normalized(vec![pk.into(), false.into()].try_into().unwrap());
         assert!(matches!(cand, SigmaBoolean::TrivialProp(false)));
     }
 
@@ -80,7 +78,8 @@ mod tests {
     fn pk_pk() {
         let pk1 = force_any_val::<ProveDlog>();
         let pk2 = force_any_val::<ProveDlog>();
-        let pks = vec![pk1.into(), pk2.into()];
+        let pks: SigmaConjectureItems<SigmaBoolean> =
+            vec![pk1.into(), pk2.into()].try_into().unwrap();
         let cand = Cand::normalized(pks.clone());
         assert!(matches!(
             cand,
diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs
index 5206b8187..0f69928eb 100644
--- a/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs
+++ b/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs
@@ -1,18 +1,21 @@
 //! OR conjunction for sigma proposition
+use std::convert::TryInto;
+
 use super::SigmaBoolean;
+use super::SigmaConjectureItems;
 use crate::sigma_protocol::sigma_boolean::SigmaConjecture;
 
 /// OR conjunction for sigma proposition
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct Cor {
     /// Items of the conjunctions
-    pub items: Vec<SigmaBoolean>,
+    pub items: SigmaConjectureItems<SigmaBoolean>,
 }
 
 impl Cor {
     /// Connects the given sigma propositions into COR proposition performing
     /// partial evaluation when some of them are trivial propositioins.
-    pub fn normalized(items: Vec<SigmaBoolean>) -> SigmaBoolean {
+    pub fn normalized(items: SigmaConjectureItems<SigmaBoolean>) -> SigmaBoolean {
         assert!(!items.is_empty());
         let mut res = Vec::new();
         for it in items {
@@ -28,7 +31,11 @@ impl Cor {
             #[allow(clippy::unwrap_used)]
             res.first().unwrap().clone()
         } else {
-            SigmaBoolean::SigmaConjecture(SigmaConjecture::Cor(Cor { items: res }))
+            #[allow(clippy::unwrap_used)]
+            SigmaBoolean::SigmaConjecture(SigmaConjecture::Cor(Cor {
+                // should be 2 or more so unwrap is safe here
+                items: res.try_into().unwrap(),
+            }))
         }
     }
 }
@@ -43,35 +50,27 @@ mod tests {
 
     #[test]
     fn trivial_true() {
-        let cor = Cor::normalized(vec![true.into()]);
+        let cor = Cor::normalized(vec![true.into(), false.into()].try_into().unwrap());
         assert!(matches!(cor, SigmaBoolean::TrivialProp(true)));
     }
 
     #[test]
     fn trivial_false() {
-        let cor = Cor::normalized(vec![false.into()]);
+        let cor = Cor::normalized(vec![false.into(), false.into()].try_into().unwrap());
         assert!(matches!(cor, SigmaBoolean::TrivialProp(false)));
     }
 
-    #[test]
-    fn pk() {
-        let pk = force_any_val::<ProveDlog>();
-        let cor = Cor::normalized(vec![pk.clone().into()]);
-        let res: ProveDlog = cor.try_into().unwrap();
-        assert_eq!(res, pk);
-    }
-
     #[test]
     fn pk_triv_true() {
         let pk = force_any_val::<ProveDlog>();
-        let cor = Cor::normalized(vec![pk.into(), true.into()]);
+        let cor = Cor::normalized(vec![pk.into(), true.into()].try_into().unwrap());
         assert!(matches!(cor, SigmaBoolean::TrivialProp(true)));
     }
 
     #[test]
     fn pk_triv_false() {
         let pk = force_any_val::<ProveDlog>();
-        let cor = Cor::normalized(vec![pk.clone().into(), false.into()]);
+        let cor = Cor::normalized(vec![pk.clone().into(), false.into()].try_into().unwrap());
         let res: ProveDlog = cor.try_into().unwrap();
         assert_eq!(res, pk);
     }
@@ -80,7 +79,8 @@ mod tests {
     fn pk_pk() {
         let pk1 = force_any_val::<ProveDlog>();
         let pk2 = force_any_val::<ProveDlog>();
-        let pks = vec![pk1.into(), pk2.into()];
+        let pks: SigmaConjectureItems<SigmaBoolean> =
+            vec![pk1.into(), pk2.into()].try_into().unwrap();
         let cor = Cor::normalized(pks.clone());
         assert!(matches!(
             cor,
diff --git a/ergotree-ir/src/types/type_unify.rs b/ergotree-ir/src/types/type_unify.rs
index 401e81ded..451d6ca0e 100644
--- a/ergotree-ir/src/types/type_unify.rs
+++ b/ergotree-ir/src/types/type_unify.rs
@@ -28,9 +28,9 @@ pub fn unify_many(
         .collect();
     let mut res = HashMap::new();
     for substitutions in list_of_substitutions? {
-        for (type_var, tpe) in substitutions.iter() {
+        for (type_var, tpe) in substitutions {
             match res.insert(type_var.clone(), tpe.clone()) {
-                Some(previous_val) if previous_val != *tpe => {
+                Some(previous_val) if previous_val != tpe => {
                     return Err(TypeUnificationError(format!(
                         "cannot merge new substitution {:?} for {:?} already exist substitution {:?}",
                         tpe, type_var, previous_val


Test patch: