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

Issue:
Transacrion in block 400188 fails to roundtrip
Namely [this one](https://explorer.ergoplatform.com/en/transactions/9da0ea07e4f859b6a71817d9ccb67f43ddfa1f8a59f7cf2af18a544bcd799706). Offending ergo tree is: `1000d1ed8503` which deserialized as
```
BoolToSigmaProp(
    BoolToSigmaProp {
        input: BinOp(
            BinOp {
                kind: Relation(
                    And,
                ),
                left: Const(
                    Constant {
                        tpe: SBoolean,
                        v: Boolean(false,),
                    },
                ),
                right: Const(
                    Constant {
                        tpe: SBoolean,
                        v: Boolean(false,),
                    },
                ),
            },
        ),
    },
)
```

I suspect problem is in `ReadSigmaVlqExt::get_bits`. I it decodes bit vector in MST while it should use LSB instead. 


Discussion / hints:
Yep, looks like the case. We're using `bit-vec` crate which seems to be only offering MSB. There is `bitvec` crate that might have LSB.

Fix patch:
diff --git a/ergotree-ir/src/mir/bin_op.rs b/ergotree-ir/src/mir/bin_op.rs
index 819bacfd9..5b2ae3fb0 100644
--- a/ergotree-ir/src/mir/bin_op.rs
+++ b/ergotree-ir/src/mir/bin_op.rs
@@ -201,7 +201,11 @@ mod arbitrary {
 mod tests {
 
     use super::*;
+    use crate::mir::constant::Constant;
+    use crate::mir::expr::Expr;
+    use crate::mir::value::Value::Boolean;
     use crate::serialization::sigma_serialize_roundtrip;
+    use crate::serialization::SigmaSerializable;
     use proptest::prelude::*;
 
     proptest! {
@@ -213,4 +217,26 @@ mod tests {
         }
 
     }
+
+    // Test that binop with boolean literals serialized correctly
+    #[test]
+    fn regression_249() {
+        let e = Expr::sigma_parse_bytes(vec![0xed, 0x85, 0x03]);
+        assert_eq!(
+            e,
+            Ok(Expr::BinOp(BinOp {
+                kind: BinOpKind::Relation(RelationOp::And,),
+                left: Expr::Const(Constant {
+                    tpe: SType::SBoolean,
+                    v: Boolean(true),
+                })
+                .into(),
+                right: Expr::Const(Constant {
+                    tpe: SType::SBoolean,
+                    v: Boolean(true),
+                })
+                .into(),
+            }))
+        );
+    }
 }
diff --git a/sigma-ser/Cargo.toml b/sigma-ser/Cargo.toml
index a009c6a70..0ba87691d 100644
--- a/sigma-ser/Cargo.toml
+++ b/sigma-ser/Cargo.toml
@@ -16,7 +16,7 @@ crate-type = ["cdylib", "rlib"]
 [dependencies]
 # wasm-bindgen = "0.2"
 thiserror = "1"
-bit-vec = "0.6.3"
+bitvec = "0.22.3"
 
 # The `console_error_panic_hook` crate provides better debugging of panics by
 # logging them with `console.error`. This is great for development, but requires
diff --git a/sigma-ser/src/vlq_encode.rs b/sigma-ser/src/vlq_encode.rs
index b22a1010a..a8fa6fdb4 100644
--- a/sigma-ser/src/vlq_encode.rs
+++ b/sigma-ser/src/vlq_encode.rs
@@ -3,7 +3,8 @@ use std::convert::TryFrom;
 use std::io;
 
 use crate::peekable_reader;
-use bit_vec::BitVec;
+use bitvec::order::Lsb0;
+use bitvec::prelude::BitVec;
 use peekable_reader::Peekable;
 #[cfg(test)]
 use proptest::{num::u64, prelude::*};
@@ -100,12 +101,14 @@ pub trait WriteSigmaVlqExt: io::Write {
 
     /// Encode bool array as bit vector, filling trailing bits with `false`
     fn put_bits(&mut self, bools: &[bool]) -> io::Result<()> {
-        let mut bits = BitVec::from_elem(bools.len(), true);
-        bools
-            .iter()
-            .enumerate()
-            .for_each(|(idx, i)| bits.set(idx, *i));
-        self.write_all(bits.to_bytes().as_slice())
+        let mut bits = BitVec::<Lsb0, u8>::new();
+        for b in bools {
+            bits.push(*b);
+        }
+        for c in bits.as_bitslice().domain() {
+            self.put_u8(c)?;
+        }
+        Ok(())
     }
 }
 
@@ -181,9 +184,13 @@ pub trait ReadSigmaVlqExt: peekable_reader::Peekable {
         let byte_num = (size + 7) / 8;
         let mut buf = vec![0u8; byte_num];
         self.read_exact(&mut buf)?;
-        let mut bits = BitVec::from_bytes(buf.as_slice());
+        // May fail if number of bits in buf is larger that maximum value of usize
+        let mut bits = match BitVec::<Lsb0, u8>::from_slice(&buf) {
+            Ok(v) => v,
+            Err(_) => return Err(VlqEncodingError::VlqDecodingFailed),
+        };
         bits.truncate(size);
-        Ok(bits.iter().collect::<Vec<bool>>())
+        Ok(bits.iter().map(|x| *x).collect::<Vec<bool>>())
     }
 }
 


Test patch: