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

Issue:
no_std support
Add no_std support for embedded environments where std is not available:

- Replace collection imports from std with imports from alloc::
- Replace instances of io::Write with core2::Write only if no_std is enabled
- For usages of HashMap consider replacing them with BTreeMap, or [hashbrown](https://crates.io/crates/hashbrown)'s hashmap. sigma-rust already uses hashbrown::HashMap internally in some places
- Make p2p crate an optional feature in ergo-lib. This would also be useful for normal library users since ergo-p2p brings in tokio as a dependency


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0414ff330..918ba2d32 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,8 +27,8 @@ jobs:
       - name: Build ergo-lib
         uses: actions-rs/cargo@v1
         with:
-          command: build
-          args: --no-default-features --manifest-path ergo-lib/Cargo.toml
+          command: rustc
+          args: --no-default-features --manifest-path ergo-lib/Cargo.toml --crate-type rlib
 
   test:
     name: Tests on ${{ matrix.os }}
diff --git a/Cargo.toml b/Cargo.toml
index acc5db38a..7c20d043f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,4 +1,5 @@
 [workspace]
+resolver = "2"
 members = [
     "sigma-test-util",
     "sigma-ser",
@@ -26,21 +27,21 @@ edition = "2021"
 
 [workspace.dependencies]
 sigma-util = { version = "^0.18.0", path = "./sigma-util" }
-sigma-ser = { version = "^0.19.0", path = "./sigma-ser" }
-ergotree-ir = { version = "^0.28.0", path = "./ergotree-ir" }
-ergo-chain-types = { version = "^0.15.0", path = "./ergo-chain-types" }
+sigma-ser = { version = "^0.19.0", path = "./sigma-ser", default-features = false }
+ergotree-ir = { version = "^0.28.0", path = "./ergotree-ir", default-features = false }
+ergo-chain-types = { version = "^0.15.0", path = "./ergo-chain-types", default-features = false }
 sigma-test-util = { version = "^0.3.0", path = "./sigma-test-util" }
 ergoscript-compiler = { version = "^0.24.0", path = "./ergoscript-compiler" }
-ergotree-interpreter = { version = "^0.28.0", path = "./ergotree-interpreter" }
+ergotree-interpreter = { version = "^0.28.0", path = "./ergotree-interpreter", default-features = false }
 ergo-nipopow = { version = "^0.15", path = "./ergo-nipopow" }
-ergo-merkle-tree = { version = "^0.15.0", path = "./ergo-merkle-tree" }
+ergo-merkle-tree = { version = "^0.15.0", path = "./ergo-merkle-tree", default-features = false }
 ergo-rest = { version = "^0.13.0", path = "./ergo-rest" }
 ergo-lib = { version = "^0.28.0", path = "./ergo-lib" }
-k256 = { version = "0.13.1", features = ["arithmetic", "ecdsa"] }
+k256 = { version = "0.13.1", default-features = false, features = [
+    "arithmetic",
+    "ecdsa",
+] }
 elliptic-curve = { version = "0.13", features = ["ff"] }
-thiserror = "1"
-bounded-vec = { version = "^0.7.0" }
-bitvec = { version = "1.0.1" }
 derive_more = { version = "0.99", features = [
     "add",
     "add_assign",
@@ -52,25 +53,30 @@ derive_more = { version = "0.99", features = [
     "from_str",
     "display",
 ] }
-blake2 = "0.10"
-sha2 = "0.10"
 num-derive = "0.4.2"
-num-traits = "0.2.14"
-num-integer = "0.1.44"
-num-bigint = "0.4.0"
-lazy_static = "1.4"
-bs58 = "0.4.0"
-base16 = "0.2.1"
-base64 = "0.13.0"
-indexmap = { version = "1.3.2", features = ["serde"] }
-serde = { version = "1.0", features = ["derive"] }
-serde_json = { version = "1.0", features = [
+thiserror = { version = "2.0.1", default-features = false }
+bounded-vec = { version = "0.8.0", default-features = false }
+bitvec = { version = "1.0.1", default-features = false, features = ["alloc"] }
+blake2 = { version = "0.10.6", default-features = false }
+sha2 = { version = "0.10", default-features = false }
+num-traits = { version = "0.2.14", default-features = false }
+num-integer = { version = "0.1.44", default-features = false }
+num-bigint = { version = "0.4.0", default-features = false }
+lazy_static = { version = "1.4", features = ["spin_no_std"] }
+bs58 = { version = "0.4.0", default-features = false, features = ["alloc"] }
+base16 = { version = "0.2.1", default-features = false, features = ["alloc"] }
+base64 = { version = "0.13.0", default-features = false, features = ["alloc"] }
+indexmap = { version = "2.6.0", default-features = false }
+serde = { version = "1.0", default-features = false, features = ["derive"] }
+serde_json = { version = "1.0", default-features = false, features = [
     "arbitrary_precision",
-    "preserve_order",
 ] }
-serde_with = { version = "1.9.1", features = ["json"] }
+serde_with = { version = "3.11.0", default-features = false, features = [
+    "json",
+    "macros",
+] }
 rand = "0.8.5"
-bytes = "1.1"
+bytes = { version = "1.1", default-features = false }
 byteorder = "1"
 futures = "0.3"
 tokio = { version = "1.15.0", features = ["full"] }
@@ -79,16 +85,19 @@ tokio-util = { version = "0.6.9", features = ["codec"] }
 bounded-integer = { version = "^0.5", features = ["types"] }
 url = "~2.2"
 getrandom = { version = "0.2.7" }
-itertools = "0.10.3"
+itertools = { version = "0.10.3", default-features = false }
 miette = { version = "5", features = ["fancy"] }
-
+hashbrown = { version = "0.14.3", features = ["serde"] }
+core2 = { version = "0.4.0", default-features = false, features = ["alloc"] }
 # dev-dependencies
-proptest = { version = "=1.0", default-features = false, features = ["std"] }
+proptest = { version = "1.5.0", default-features = false, features = [
+    "alloc",
+    "std",
+] }
 proptest-derive = "0.3"
 pretty_assertions = "1.3"
 wasm-bindgen-test = "0.3.37"
 expect-test = "1.4.1"
-
 [profile.release]
 # Tell `rustc` to optimize for small code size.
 opt-level = "z"
diff --git a/bindings/ergo-lib-c-core/Cargo.toml b/bindings/ergo-lib-c-core/Cargo.toml
index 44d31d155..30394b1f2 100644
--- a/bindings/ergo-lib-c-core/Cargo.toml
+++ b/bindings/ergo-lib-c-core/Cargo.toml
@@ -22,9 +22,10 @@ futures-util = "0.3"
 url = { workspace = true }
 bounded-integer = { workspace = true }
 serde_with = { workspace = true }
-bounded-vec = { workspace = true, features=["serde"] }
+bounded-vec = { workspace = true, features = ["serde"] }
 
 [features]
-default = ["mnemonic_gen", "ergo-lib/compiler"]
+default = ["mnemonic_gen", "ergo-lib/compiler", "json"]
+json = []
 rest = ["tokio", "ergo-lib/rest"]
 mnemonic_gen = ["ergo-lib/mnemonic_gen"]
diff --git a/bindings/ergo-lib-c-core/src/rest/api/node/abortable.rs b/bindings/ergo-lib-c-core/src/rest/api/node/abortable.rs
index fc165e4ed..5383486a1 100644
--- a/bindings/ergo-lib-c-core/src/rest/api/node/abortable.rs
+++ b/bindings/ergo-lib-c-core/src/rest/api/node/abortable.rs
@@ -5,12 +5,9 @@ use crate::rest::api::runtime::RestApiRuntime;
 use crate::Error;
 
 /// Wraps a task with future::Abortable, spawns it on the provided runtime and returns task's abort handle
-pub(crate) fn spawn_abortable<T: 'static>(
-    runtime: &RestApiRuntime,
-    task: T,
-) -> Result<AbortHandle, Error>
+pub(crate) fn spawn_abortable<T>(runtime: &RestApiRuntime, task: T) -> Result<AbortHandle, Error>
 where
-    T: futures_util::Future<Output = ()> + Send,
+    T: futures_util::Future<Output = ()> + Send + 'static,
 {
     let (abort_handle, abort_registration) = AbortHandle::new_pair();
     let future = Abortable::new(task, abort_registration);
diff --git a/bindings/ergo-lib-c-core/src/transaction.rs b/bindings/ergo-lib-c-core/src/transaction.rs
index ebebca3cc..31102de1b 100644
--- a/bindings/ergo-lib-c-core/src/transaction.rs
+++ b/bindings/ergo-lib-c-core/src/transaction.rs
@@ -79,7 +79,7 @@ pub unsafe fn hints_bag_get(
 }
 
 /// TransactionHintsBag
-pub struct TransactionHintsBag(pub(crate) ergo_lib::wallet::multi_sig::TransactionHintsBag);
+pub struct TransactionHintsBag(pub(crate) ergo_lib::wallet::TransactionHintsBag);
 pub type TransactionHintsBagPtr = *mut TransactionHintsBag;
 pub type ConstTransactionHintsBagPtr = *const TransactionHintsBag;
 
@@ -90,7 +90,7 @@ pub unsafe fn transaction_hints_bag_empty(
     let transaction_hints_bag_out =
         mut_ptr_as_mut(transaction_hints_bag_out, "transaction_hints_bag_out")?;
     *transaction_hints_bag_out = Box::into_raw(Box::new(TransactionHintsBag(
-        ergo_lib::wallet::multi_sig::TransactionHintsBag::empty(),
+        ergo_lib::wallet::TransactionHintsBag::empty(),
     )));
     Ok(())
 }
diff --git a/bindings/ergo-lib-wasm/src/transaction.rs b/bindings/ergo-lib-wasm/src/transaction.rs
index 62f44ae72..cdca918f1 100644
--- a/bindings/ergo-lib-wasm/src/transaction.rs
+++ b/bindings/ergo-lib-wasm/src/transaction.rs
@@ -76,13 +76,13 @@ impl From<ergo_lib::ergotree_interpreter::sigma_protocol::prover::hint::HintsBag
 
 /// TransactionHintsBag
 #[wasm_bindgen]
-pub struct TransactionHintsBag(pub(crate) ergo_lib::wallet::multi_sig::TransactionHintsBag);
+pub struct TransactionHintsBag(pub(crate) ergo_lib::wallet::TransactionHintsBag);
 
 #[wasm_bindgen]
 impl TransactionHintsBag {
     /// Empty TransactionHintsBag
     pub fn empty() -> TransactionHintsBag {
-        TransactionHintsBag(ergo_lib::wallet::multi_sig::TransactionHintsBag::empty())
+        TransactionHintsBag(ergo_lib::wallet::TransactionHintsBag::empty())
     }
 
     /// Adding hints for input
@@ -106,8 +106,8 @@ impl TransactionHintsBag {
     }
 }
 
-impl From<ergo_lib::wallet::multi_sig::TransactionHintsBag> for TransactionHintsBag {
-    fn from(t: ergo_lib::wallet::multi_sig::TransactionHintsBag) -> Self {
+impl From<ergo_lib::wallet::TransactionHintsBag> for TransactionHintsBag {
+    fn from(t: ergo_lib::wallet::TransactionHintsBag) -> Self {
         TransactionHintsBag(t)
     }
 }
diff --git a/ergo-chain-types/Cargo.toml b/ergo-chain-types/Cargo.toml
index f413c252b..e00b6f556 100644
--- a/ergo-chain-types/Cargo.toml
+++ b/ergo-chain-types/Cargo.toml
@@ -6,12 +6,7 @@ authors = ["Denys Zadorozhnyi <denys@zadorozhnyi.com>"]
 repository.workspace = true
 edition.workspace = true
 description = "Ergo blockchain types"
-exclude = [
-    "proptest-regressions/*"
-]
-
-[lib]
-crate-type = ["cdylib", "rlib"]
+exclude = ["proptest-regressions/*"]
 
 [dependencies]
 thiserror = { workspace = true }
@@ -22,19 +17,20 @@ base16 = { workspace = true }
 base64 = { workspace = true }
 serde = { workspace = true, optional = true }
 serde_json = { workspace = true, optional = true }
-url = { workspace = true }
+url = { workspace = true, optional = true }
 k256 = { workspace = true }
 elliptic-curve = { workspace = true }
 num-bigint = { workspace = true }
-byteorder = { workspace = true }
 serde_with = { workspace = true, optional = true }
-proptest = { workspace = true , optional = true }
-proptest-derive = {workspace = true, optional = true }
+proptest = { workspace = true, optional = true }
+proptest-derive = { workspace = true, optional = true }
 num-traits = { workspace = true }
+core2 = { workspace = true }
 
 [features]
-default = ["json"]
-arbitrary = ["proptest", "proptest-derive"]
+default = ["std", "json"]
+arbitrary = ["proptest", "proptest-derive", "std"]
 json = ["serde", "serde_json", "serde_with"]
+std = ["dep:url", "base16/std", "base64/std", "serde/std"]
 
 [dev-dependencies]
diff --git a/ergo-chain-types/src/base16_bytes.rs b/ergo-chain-types/src/base16_bytes.rs
index cf0532150..5e55942eb 100644
--- a/ergo-chain-types/src/base16_bytes.rs
+++ b/ergo-chain-types/src/base16_bytes.rs
@@ -1,9 +1,12 @@
 //! Transitioning type for Base16 encoded bytes in JSON serialization
 
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::convert::TryInto;
 #[cfg(feature = "json")]
 use serde::{Deserialize, Serialize};
-use std::convert::TryFrom;
-use std::convert::TryInto;
 extern crate derive_more;
 use derive_more::{From, Into};
 
diff --git a/ergo-chain-types/src/block_id.rs b/ergo-chain-types/src/block_id.rs
index 5e600c508..ad44f2f4b 100644
--- a/ergo-chain-types/src/block_id.rs
+++ b/ergo-chain-types/src/block_id.rs
@@ -1,5 +1,6 @@
 //! Main "remote" type for [BlockId]()
 
+use alloc::{string::String, vec::Vec};
 use derive_more::Display;
 
 use crate::DigestNError;
diff --git a/ergo-chain-types/src/digest32.rs b/ergo-chain-types/src/digest32.rs
index 54783856d..39eaa93eb 100644
--- a/ergo-chain-types/src/digest32.rs
+++ b/ergo-chain-types/src/digest32.rs
@@ -1,14 +1,17 @@
 //! Digest types for various sizes
 
+use alloc::boxed::Box;
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::convert::TryInto;
+use core::fmt::Formatter;
 use sigma_ser::vlq_encode::ReadSigmaVlqExt;
 use sigma_ser::vlq_encode::WriteSigmaVlqExt;
 use sigma_ser::ScorexParsingError;
 use sigma_ser::ScorexSerializable;
 use sigma_ser::ScorexSerializeResult;
 use sigma_util::AsVecI8;
-use std::convert::TryFrom;
-use std::convert::TryInto;
-use std::fmt::Formatter;
 use thiserror::Error;
 
 /// N-bytes array in a box. `Digest32` is most type synonym.
@@ -47,14 +50,14 @@ impl<const N: usize> Digest<N> {
     }
 }
 
-impl<const N: usize> std::fmt::Debug for Digest<N> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl<const N: usize> core::fmt::Debug for Digest<N> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         base16::encode_lower(&(self.0)).fmt(f)
     }
 }
 
-impl<const N: usize> std::fmt::Display for Digest<N> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl<const N: usize> core::fmt::Display for Digest<N> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         base16::encode_lower(&(self.0)).fmt(f)
     }
 }
@@ -149,14 +152,40 @@ impl AsRef<[u8]> for Digest32 {
 #[derive(Error, Debug)]
 pub enum DigestNError {
     /// error decoding from Base16
+    #[cfg(feature = "std")]
     #[error("error decoding from Base16: {0}")]
     Base16DecodingError(#[from] base16::DecodeError),
+    /// error decoding from Base16
+    #[cfg(not(feature = "std"))]
+    #[error("error decoding from Base16")]
+    Base16DecodingError,
     /// Invalid byte array size
     #[error("Invalid byte array size ({0})")]
-    InvalidSize(#[from] std::array::TryFromSliceError),
+    InvalidSize(#[from] core::array::TryFromSliceError),
     /// error decoding from Base64
+    #[cfg(feature = "std")]
     #[error("error decoding from Base64: {0}")]
     Base64DecodingError(#[from] base64::DecodeError),
+
+    /// error decoding from Base64
+    #[cfg(not(feature = "std"))]
+    #[error("error decoding from Base64")]
+    Base64DecodingError,
+}
+
+/// both base16 and base64 don't implement core::error::Error for their error types yet, so we can't use them in thiserror in no_std contexts
+#[cfg(not(feature = "std"))]
+impl From<base16::DecodeError> for DigestNError {
+    fn from(_: base16::DecodeError) -> Self {
+        Self::Base16DecodingError
+    }
+}
+
+#[cfg(not(feature = "std"))]
+impl From<base64::DecodeError> for DigestNError {
+    fn from(_: base64::DecodeError) -> Self {
+        Self::Base64DecodingError
+    }
 }
 
 /// Arbitrary
@@ -165,9 +194,9 @@ pub enum DigestNError {
 pub(crate) mod arbitrary {
 
     use super::Digest;
+    use core::convert::TryInto;
     use proptest::prelude::{Arbitrary, BoxedStrategy};
     use proptest::{collection::vec, prelude::*};
-    use std::convert::TryInto;
 
     impl<const N: usize> Arbitrary for Digest<N> {
         type Parameters = ();
diff --git a/ergo-chain-types/src/ec_point.rs b/ergo-chain-types/src/ec_point.rs
index df90938a5..ecc141474 100644
--- a/ergo-chain-types/src/ec_point.rs
+++ b/ergo-chain-types/src/ec_point.rs
@@ -1,13 +1,14 @@
 //! Elliptic curve point.
 
+use alloc::string::String;
+use core::convert::TryFrom;
+use core::ops::{Add, Mul, Neg};
 use derive_more::{From, Into};
 use k256::elliptic_curve::group::prime::PrimeCurveAffine;
 use k256::elliptic_curve::sec1::ToEncodedPoint;
 use k256::{ProjectivePoint, PublicKey, Scalar};
 use sigma_ser::vlq_encode::{ReadSigmaVlqExt, WriteSigmaVlqExt};
 use sigma_ser::{ScorexParsingError, ScorexSerializable, ScorexSerializeResult};
-use std::convert::TryFrom;
-use std::ops::{Add, Mul, Neg};
 
 /// Elliptic curve point
 #[derive(PartialEq, Clone, Default, From, Into)]
@@ -19,8 +20,8 @@ use std::ops::{Add, Mul, Neg};
 pub struct EcPoint(ProjectivePoint);
 
 #[allow(clippy::unwrap_used)]
-impl std::fmt::Debug for EcPoint {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+impl core::fmt::Debug for EcPoint {
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
         f.write_str("EC:")?;
         f.write_str(&base16::encode_lower(
             &self.scorex_serialize_bytes().unwrap(),
@@ -29,8 +30,8 @@ impl std::fmt::Debug for EcPoint {
 }
 
 #[allow(clippy::unwrap_used)]
-impl std::fmt::Display for EcPoint {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+impl core::fmt::Display for EcPoint {
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
         f.write_str(&base16::encode_lower(
             &self.scorex_serialize_bytes().unwrap(),
         ))
@@ -166,6 +167,7 @@ mod arbitrary {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
diff --git a/ergo-chain-types/src/extensioncandidate.rs b/ergo-chain-types/src/extensioncandidate.rs
index 853328c74..1218dda37 100644
--- a/ergo-chain-types/src/extensioncandidate.rs
+++ b/ergo-chain-types/src/extensioncandidate.rs
@@ -1,3 +1,5 @@
+use alloc::vec::Vec;
+
 /// Extension section of Ergo block. Contains key-value storage.
 #[derive(Clone, Debug, Default)]
 pub struct ExtensionCandidate {
diff --git a/ergo-chain-types/src/header.rs b/ergo-chain-types/src/header.rs
index 98cea4097..32befab68 100644
--- a/ergo-chain-types/src/header.rs
+++ b/ergo-chain-types/src/header.rs
@@ -1,12 +1,14 @@
 //! Block header
 use crate::{ADDigest, BlockId, Digest32, EcPoint};
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core2::io::Write;
 use num_bigint::BigInt;
 use sigma_ser::vlq_encode::{ReadSigmaVlqExt, WriteSigmaVlqExt};
 use sigma_ser::{
     ScorexParsingError, ScorexSerializable, ScorexSerializationError, ScorexSerializeResult,
 };
 use sigma_util::hash::blake2b256_hash;
-use std::io::Write;
 
 use crate::votes::Votes;
 
@@ -56,7 +58,6 @@ pub struct Header {
 impl Header {
     /// Used in nipowpow
     pub fn serialize_without_pow(&self) -> Result<Vec<u8>, ScorexSerializationError> {
-        use byteorder::{BigEndian, WriteBytesExt};
         let mut data = Vec::new();
         let mut w = &mut data;
         w.put_u8(self.version)?;
@@ -69,12 +70,8 @@ impl Header {
 
         // n_bits needs to be serialized in big-endian format. Note that it actually fits in a
         // `u32`.
-        let mut n_bits_writer = vec![];
-        #[allow(clippy::unwrap_used)]
-        n_bits_writer
-            .write_u32::<BigEndian>(self.n_bits as u32)
-            .unwrap();
-        w.write_all(&n_bits_writer)?;
+        let n_bits_be = (self.n_bits as u32).to_be_bytes();
+        w.write_all(&n_bits_be)?;
 
         w.put_u32(self.height)?;
         w.write_all(&self.votes.0)?;
@@ -108,14 +105,7 @@ impl ScorexSerializable for Header {
         let extension_root = Digest32::scorex_parse(r)?;
         let mut n_bits_buf = [0u8, 0, 0, 0];
         r.read_exact(&mut n_bits_buf)?;
-        let n_bits = {
-            use byteorder::{BigEndian, ReadBytesExt};
-            let mut reader = std::io::Cursor::new(n_bits_buf);
-            #[allow(clippy::unwrap_used)]
-            {
-                reader.read_u32::<BigEndian>().unwrap() as u64
-            }
-        };
+        let n_bits = u32::from_be_bytes(n_bits_buf) as u64;
         let height = r.get_u32()?;
         let mut votes_bytes = [0u8, 0, 0];
         r.read_exact(&mut votes_bytes)?;
@@ -126,8 +116,9 @@ impl ScorexSerializable for Header {
         if version > 1 {
             let new_field_size = r.get_u8()?;
             if new_field_size > 0 {
-                let mut field_bytes: Vec<u8> =
-                    std::iter::repeat(0).take(new_field_size as usize).collect();
+                let mut field_bytes: Vec<u8> = core::iter::repeat(0)
+                    .take(new_field_size as usize)
+                    .collect();
                 r.read_exact(&mut field_bytes)?;
             }
         }
@@ -136,10 +127,10 @@ impl ScorexSerializable for Header {
         let autolykos_solution = if version == 1 {
             let miner_pk = EcPoint::scorex_parse(r)?.into();
             let pow_onetime_pk = Some(EcPoint::scorex_parse(r)?.into());
-            let mut nonce: Vec<u8> = std::iter::repeat(0).take(8).collect();
+            let mut nonce: Vec<u8> = core::iter::repeat(0).take(8).collect();
             r.read_exact(&mut nonce)?;
             let d_bytes_len = r.get_u8()?;
-            let mut d_bytes: Vec<u8> = std::iter::repeat(0).take(d_bytes_len as usize).collect();
+            let mut d_bytes: Vec<u8> = core::iter::repeat(0).take(d_bytes_len as usize).collect();
             r.read_exact(&mut d_bytes)?;
             let pow_distance = Some(BigInt::from_signed_bytes_be(&d_bytes));
             AutolykosSolution {
@@ -153,7 +144,7 @@ impl ScorexSerializable for Header {
             let pow_onetime_pk = None;
             let pow_distance = None;
             let miner_pk = EcPoint::scorex_parse(r)?.into();
-            let mut nonce: Vec<u8> = std::iter::repeat(0).take(8).collect();
+            let mut nonce: Vec<u8> = core::iter::repeat(0).take(8).collect();
             r.read_exact(&mut nonce)?;
             AutolykosSolution {
                 miner_pk,
diff --git a/ergo-chain-types/src/json/autolykos_solution.rs b/ergo-chain-types/src/json/autolykos_solution.rs
index 4f6ed3308..d39241d3a 100644
--- a/ergo-chain-types/src/json/autolykos_solution.rs
+++ b/ergo-chain-types/src/json/autolykos_solution.rs
@@ -1,6 +1,9 @@
 //! Code to implement `AutolykosSolution` JSON encoding
 
-use std::str::FromStr;
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec::Vec;
+use core::str::FromStr;
 
 use num_bigint::BigInt;
 use num_traits::FromPrimitive;
diff --git a/ergo-chain-types/src/json/votes.rs b/ergo-chain-types/src/json/votes.rs
index 996cc4018..4cfa856e6 100644
--- a/ergo-chain-types/src/json/votes.rs
+++ b/ergo-chain-types/src/json/votes.rs
@@ -1,6 +1,7 @@
 //! Code to implement `Votes` JSON encoding
 
-use std::convert::{TryFrom, TryInto};
+use alloc::vec::Vec;
+use core::convert::{TryFrom, TryInto};
 
 use crate::votes::{Votes, VotesError};
 use crate::Base16DecodedBytes;
diff --git a/ergo-chain-types/src/lib.rs b/ergo-chain-types/src/lib.rs
index 79c7f5aea..f6fe60f5b 100644
--- a/ergo-chain-types/src/lib.rs
+++ b/ergo-chain-types/src/lib.rs
@@ -1,5 +1,6 @@
 //! Ergo blockchain types
 
+#![cfg_attr(not(feature = "std"), no_std)]
 // Coding conventions
 #![forbid(unsafe_code)]
 #![deny(non_upper_case_globals)]
@@ -18,13 +19,18 @@
 #![deny(clippy::unreachable)]
 #![deny(clippy::panic)]
 
+#[macro_use]
+extern crate alloc;
+
 mod base16_bytes;
 mod block_id;
 mod digest32;
 pub mod ec_point;
 mod extensioncandidate;
 mod header;
+#[cfg(feature = "json")]
 mod json;
+#[cfg(feature = "std")]
 mod peer_addr;
 mod peer_connection_dir;
 mod preheader;
@@ -41,6 +47,7 @@ pub use digest32::DigestNError;
 pub use ec_point::EcPoint;
 pub use extensioncandidate::ExtensionCandidate;
 pub use header::{AutolykosSolution, Header};
+#[cfg(feature = "std")]
 pub use peer_addr::PeerAddr;
 pub use peer_connection_dir::ConnectionDirection;
 pub use preheader::PreHeader;
diff --git a/ergo-chain-types/src/peer_addr.rs b/ergo-chain-types/src/peer_addr.rs
index 430a7e518..934602496 100644
--- a/ergo-chain-types/src/peer_addr.rs
+++ b/ergo-chain-types/src/peer_addr.rs
@@ -7,14 +7,12 @@ use std::{
 
 use derive_more::FromStr;
 use derive_more::{Display, From, Into};
-use serde::{Deserialize, Serialize};
 use sigma_ser::{ScorexSerializable, ScorexSerializationError};
 use url::Url;
 
 /// Peer address
-#[derive(
-    PartialEq, Eq, Debug, Copy, Clone, From, Into, Hash, Display, FromStr, Deserialize, Serialize,
-)]
+#[derive(PartialEq, Eq, Debug, Copy, Clone, From, Into, Hash, Display, FromStr)]
+#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
 pub struct PeerAddr(pub SocketAddr);
 
 impl PeerAddr {
diff --git a/ergo-chain-types/src/peer_connection_dir.rs b/ergo-chain-types/src/peer_connection_dir.rs
index 5ec2b23fe..89449de56 100644
--- a/ergo-chain-types/src/peer_connection_dir.rs
+++ b/ergo-chain-types/src/peer_connection_dir.rs
@@ -1,7 +1,6 @@
-use serde::{Deserialize, Serialize};
-
 /// Direction of the connection to a peer
-#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash, Deserialize, Serialize)]
+#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
+#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
 pub enum ConnectionDirection {
     /// A peer is connecting to us
     Incoming,
diff --git a/ergo-chain-types/src/preheader.rs b/ergo-chain-types/src/preheader.rs
index 2923c3599..25d68c412 100644
--- a/ergo-chain-types/src/preheader.rs
+++ b/ergo-chain-types/src/preheader.rs
@@ -1,4 +1,6 @@
 //! Block header with fields that can be predicted by miner
+use alloc::boxed::Box;
+
 use crate::{BlockId, EcPoint, Header, Votes};
 
 /// Block header with the current `spendingTransaction`, that can be predicted
diff --git a/ergo-chain-types/src/votes.rs b/ergo-chain-types/src/votes.rs
index 4a51c8dba..5824fb645 100644
--- a/ergo-chain-types/src/votes.rs
+++ b/ergo-chain-types/src/votes.rs
@@ -1,8 +1,9 @@
 //! Main "remote" type for [Vote]()
 use crate::{Base16DecodedBytes, Base16EncodedBytes};
+use alloc::vec::Vec;
 use thiserror::Error;
 
-use std::convert::{TryFrom, TryInto};
+use core::convert::{TryFrom, TryInto};
 
 /// Votes for changing system parameters
 #[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
@@ -36,7 +37,7 @@ impl TryFrom<Vec<u8>> for Votes {
 pub enum VotesError {
     /// Invalid byte array size
     #[error("Votes: Invalid byte array size ({0})")]
-    InvalidSize(#[from] std::array::TryFromSliceError),
+    InvalidSize(#[from] core::array::TryFromSliceError),
 }
 
 impl TryFrom<Base16DecodedBytes> for Votes {
diff --git a/ergo-lib/Cargo.toml b/ergo-lib/Cargo.toml
index 21efdbaaa..d21362e81 100644
--- a/ergo-lib/Cargo.toml
+++ b/ergo-lib/Cargo.toml
@@ -6,9 +6,7 @@ authors = ["Denys Zadorozhnyi <denys@zadorozhnyi.com>"]
 repository.workspace = true
 edition.workspace = true
 description = "ErgoTree interpreter and wallet-like features for Ergo"
-exclude = [
-    "proptest-regressions/*"
-]
+exclude = ["proptest-regressions/*"]
 
 [lib]
 crate-type = ["cdylib", "rlib"]
@@ -19,10 +17,10 @@ sigma-util = { workspace = true }
 ergo-chain-types = { workspace = true }
 ergotree-ir = { workspace = true }
 ergotree-interpreter = { workspace = true }
-ergo-nipopow = { workspace = true }
-ergoscript-compiler = { workspace = true, optional = true}
-ergo-merkle-tree = { workspace = true }
-ergo-rest = { workspace = true, optional = true}
+ergo-nipopow = { workspace = true, optional = true }
+ergoscript-compiler = { workspace = true, optional = true }
+ergo-merkle-tree = { workspace = true, optional = true }
+ergo-rest = { workspace = true, optional = true }
 indexmap = { workspace = true }
 base16 = { workspace = true }
 serde = { workspace = true, optional = true }
@@ -30,27 +28,44 @@ serde_json = { workspace = true, optional = true }
 thiserror = { workspace = true }
 derive_more = { workspace = true }
 bounded-vec = { workspace = true }
-num-bigint = { workspace = true, features = ["serde"] }
-proptest-derive = {workspace = true, optional = true }
+proptest-derive = { workspace = true, optional = true }
 k256 = { workspace = true }
 sha2 = { workspace = true }
 hmac = { version = "0.12" }
 pbkdf2 = "0.11"
-rand = { workspace = true }
+rand = { workspace = true, optional = true }
 bitvec = { workspace = true, optional = true }
-unicode-normalization = "0.1.19"
+unicode-normalization = { version = "0.1.19", default-features = false }
 lazy_static = { workspace = true }
-proptest = { workspace = true , optional = true }
+proptest = { workspace = true, optional = true }
 serde_with = { workspace = true, optional = true }
-itertools = { workspace = true }
+hashbrown = { workspace = true }
 
 
 [features]
-default = ["json"]
-json = ["serde", "serde_json", "serde_with", "bounded-vec/serde"]
+default = ["std", "json", "nipopow", "merkle"]
+std = ["rand", "ergotree-ir/std", "ergotree-interpreter/std"]
+json = [
+    "serde",
+    "serde_json",
+    "serde_with",
+    "bounded-vec/serde",
+    "ergotree-ir/json",
+    "ergotree-interpreter/json",
+    "ergo-merkle-tree?/json",
+]
 compiler = ["ergoscript-compiler"]
-arbitrary = ["proptest", "proptest-derive", "ergotree-ir/arbitrary", "ergo-chain-types/arbitrary", "ergotree-interpreter/arbitrary"]
-mnemonic_gen = ["bitvec"]
+arbitrary = [
+    "std",
+    "proptest",
+    "proptest-derive",
+    "ergotree-ir/arbitrary",
+    "ergo-chain-types/arbitrary",
+    "ergotree-interpreter/arbitrary",
+]
+merkle = ["ergo-merkle-tree"]
+nipopow = ["ergo-nipopow"]
+mnemonic_gen = ["bitvec", "rand"]
 rest = ["ergo-rest"]
 
 [dev-dependencies]
@@ -63,3 +78,11 @@ pretty_assertions = { workspace = true }
 bs58 = { workspace = true }
 byteorder = { workspace = true }
 expect-test = { workspace = true }
+
+
+# docs.rs-specific configuration
+[package.metadata.docs.rs]
+# document all features
+all-features = true
+# enable docsrs flag, which lets us enable doc_auto_cfg to mark feature-gated functionality in documentation
+rustdoc-args = ["--cfg", "docsrs"]
diff --git a/ergo-lib/src/chain/contract.rs b/ergo-lib/src/chain/contract.rs
index 53c1df5aa..4a56f8a39 100644
--- a/ergo-lib/src/chain/contract.rs
+++ b/ergo-lib/src/chain/contract.rs
@@ -37,16 +37,13 @@ impl Contract {
     }
 }
 
-#[cfg(test)]
+#[cfg(all(test, feature = "compiler"))]
 #[allow(clippy::unwrap_used)]
 mod tests {
     use super::*;
 
-    #[cfg(feature = "compiler")]
     #[test]
     fn compile() {
-        let contract =
-            Contract::compile("HEIGHT", ergoscript_compiler::script_env::ScriptEnv::new()).unwrap();
-        dbg!(&contract);
+        Contract::compile("HEIGHT", ergoscript_compiler::script_env::ScriptEnv::new()).unwrap();
     }
 }
diff --git a/ergo-lib/src/chain/ergo_box/box_builder.rs b/ergo-lib/src/chain/ergo_box/box_builder.rs
index 326f113e7..8958be9f0 100644
--- a/ergo-lib/src/chain/ergo_box/box_builder.rs
+++ b/ergo-lib/src/chain/ergo_box/box_builder.rs
@@ -1,7 +1,10 @@
 //! ErgoBoxCandidate builder
 
-use std::collections::HashMap;
-use std::convert::{TryFrom, TryInto};
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec::Vec;
+use core::convert::{TryFrom, TryInto};
+use hashbrown::HashMap;
 
 use ergotree_ir::chain::address::AddressEncoderError;
 use ergotree_ir::chain::ergo_box::box_value::BoxValue;
diff --git a/ergo-lib/src/chain/json.rs b/ergo-lib/src/chain/json.rs
index 211832f14..7bf8364d4 100644
--- a/ergo-lib/src/chain/json.rs
+++ b/ergo-lib/src/chain/json.rs
@@ -1,10 +1,11 @@
 //! JSON serialization
 
+use alloc::string::String;
+use alloc::vec::Vec;
 use serde::{Deserialize, Serialize};
 
 use ergotree_interpreter::sigma_protocol::prover::ProofBytes;
 
-pub(crate) mod context_extension;
 pub(crate) mod hint;
 pub(crate) mod parameters;
 pub(crate) mod transaction;
diff --git a/ergo-lib/src/chain/json/context_extension.rs b/ergo-lib/src/chain/json/context_extension.rs
deleted file mode 100644
index fe2c85af5..000000000
--- a/ergo-lib/src/chain/json/context_extension.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-use ergotree_ir::chain::context_extension::ContextExtension;
-use ergotree_ir::{mir::constant::Constant, serialization::SigmaSerializable};
-use indexmap::IndexMap;
-use serde::{ser::SerializeMap, Deserialize, Serialize};
-
-#[cfg_attr(
-    feature = "json",
-    derive(Deserialize),
-    serde(try_from = "indexmap::IndexMap<String, String>"),
-    serde(remote = "ContextExtension")
-)]
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub(crate) struct ContextExtensionSerde {
-    values: IndexMap<u8, Constant>,
-}
-
-#[cfg(feature = "json")]
-impl Serialize for ContextExtensionSerde {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        use serde::ser::Error;
-        let mut map = serializer.serialize_map(Some(self.values.len()))?;
-        for (k, v) in &self.values {
-            map.serialize_entry(
-                &format!("{}", k),
-                &base16::encode_lower(&v.sigma_serialize_bytes().map_err(Error::custom)?),
-            )?;
-        }
-        map.end()
-    }
-}
-
-impl From<ContextExtension> for ContextExtensionSerde {
-    fn from(ce: ContextExtension) -> Self {
-        ContextExtensionSerde { values: ce.values }
-    }
-}
-
-#[cfg(test)]
-#[allow(clippy::unwrap_used)]
-mod tests {
-    use ergo_chain_types::Digest32;
-
-    use crate::chain::transaction::Transaction;
-
-    use super::*;
-
-    #[test]
-    fn parse_empty_context_extension() {
-        let mut de = serde_json::Deserializer::from_str("{}");
-        let c: ContextExtension = ContextExtensionSerde::deserialize(&mut de).unwrap();
-        assert_eq!(c, ContextExtension::empty());
-    }
-
-    #[test]
-    fn parse_context_extension() {
-        let json = r#"
-        {"1" :"05b0b5cad8e6dbaef44a", "3":"048ce5d4e505"}
-        "#;
-        let mut de = serde_json::Deserializer::from_str(json);
-        let c: ContextExtension = ContextExtensionSerde::deserialize(&mut de).unwrap();
-        assert_eq!(c.values.len(), 2);
-        assert!(c.values.get(&1u8).is_some());
-        assert!(c.values.get(&3u8).is_some());
-    }
-
-    #[test]
-    fn item_order_preservation_685() {
-        let tx_json = r#"
-{
-        "id" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
-        "inputs" : [
-          {
-            "boxId" : "59f2856068c56264d290520043044ace138a3a80d414748d0e4dcd0806188546",
-            "spendingProof" : {
-              "proofBytes" : "",
-              "extension" : {
-                "0" : "04c60f",
-                "5" : "0514",
-                "10" : "0eee03101808cd0279aed8dea2b2a25316d5d49d13bf51c0b2c1dc696974bb4b0c07b5894e998e56040005e0e0a447040404060402040004000e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d005e201058c85a2010514040404c60f06010104d00f05e0e0a44704c60f0e691005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304050005000580ade2040100d803d6017300d602b2a4730100d6037302eb027201d195ed93b1a4730393b1db630872027304d804d604db63087202d605b2a5730500d606b2db63087205730600d6077e8c72060206edededededed938cb2720473070001730893c27205d07201938c72060173099272077e730a06927ec172050699997ec1a7069d9c72077e730b067e730c067e720306909c9c7e8cb27204730d0002067e7203067e730e069c9a7207730f9a9c7ec17202067e7310067e9c73117e7312050690b0ada5d90108639593c272087313c1720873147315d90108599a8c7208018c72080273167317",
-                "1" : "0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d0",
-                "6" : "0580ade204",
-                "9" : "0580b48913",
-                "2" : "05e201",
-                "7" : "0e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f",
-                "3" : "05e0e0a447",
-                "8" : "0580ade204",
-                "4" : "058c85a201"
-              }
-            }
-          }
-        ],
-        "dataInputs" : [
-        ],
-        "outputs" : [
-          {
-            "boxId" : "0586c90d0cf6a82dab48c6a79500364ddbd6f81705f5032b03aa287de43dc638",
-            "value" : 94750000,
-            "ergoTree" : "101808cd0279aed8dea2b2a25316d5d49d13bf51c0b2c1dc696974bb4b0c07b5894e998e56040005e0e0a447040404060402040004000e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d005e201058c85a2010514040404c60f06010104d00f05e0e0a44704c60f0e691005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304050005000580ade2040100d803d6017300d602b2a4730100d6037302eb027201d195ed93b1a4730393b1db630872027304d804d604db63087202d605b2a5730500d606b2db63087205730600d6077e8c72060206edededededed938cb2720473070001730893c27205d07201938c72060173099272077e730a06927ec172050699997ec1a7069d9c72077e730b067e730c067e720306909c9c7e8cb27204730d0002067e7203067e730e069c9a7207730f9a9c7ec17202067e7310067e9c73117e7312050690b0ada5d90108639593c272087313c1720873147315d90108599a8c7208018c72080273167317",
-            "assets" : [
-            ],
-            "creationHeight" : 693475,
-            "additionalRegisters" : {
-
-            },
-            "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
-            "index" : 0
-          },
-          {
-            "boxId" : "4b99c2ef8496a491d176ecaf789d9e1d9aad0c2bf3e70b32e8bad73f48c722b9",
-            "value" : 250000,
-            "ergoTree" : "100e04000500059a0505d00f04020404040608cd03c6543ac8e8059748b1c6209ee419dd49a19ffaf5712a2f34a9412016a3a1d96708cd035b736bebf0c5393f78329f6894af84d1864c7496cc65ddc250ef60cdd75df52008cd021b63e19ab452c84cdc6687242e8494957b1f11e3750c8c184a8425f8a8171d9b05060580ade2040580a8d6b907040ad806d601b2a5730000d602b0a47301d9010241639a8c720201c18c720202d6039d9c730272027303d604b2a5730400d605b2a5730500d606b2a5730600d1968306019683020193c17201720393c27201d073079683020193c17204720393c27204d073089683020193c17205720393c27205d073099683020192c17206999972029c730a7203730b93c2a7c27206927202730c93b1a5730d",
-            "assets" : [
-            ],
-            "creationHeight" : 693475,
-            "additionalRegisters" : {
-
-            },
-            "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
-            "index" : 1
-          },
-          {
-            "boxId" : "00ddbeb981c0b08536f72ea41e07a25adbf7bf104ee59b865619a21676e64715",
-            "value" : 5000000,
-            "ergoTree" : "1005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304",
-            "assets" : [
-            ],
-            "creationHeight" : 693475,
-            "additionalRegisters" : {
-
-            },
-            "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
-            "index" : 2
-          }
-        ],
-        "size" : 1562
-      }
-    "#;
-        let tx: Transaction = serde_json::from_str(tx_json).unwrap();
-        assert_eq!(
-            tx.id(),
-            Digest32::try_from(
-                "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4".to_string()
-            )
-            .unwrap()
-            .into()
-        );
-    }
-}
diff --git a/ergo-lib/src/chain/json/hint.rs b/ergo-lib/src/chain/json/hint.rs
index 4c3c34b76..b4f97f80e 100644
--- a/ergo-lib/src/chain/json/hint.rs
+++ b/ergo-lib/src/chain/json/hint.rs
@@ -1,9 +1,10 @@
-use std::collections::HashMap;
+use alloc::vec::Vec;
+use hashbrown::HashMap;
 
 use ergotree_interpreter::sigma_protocol::prover::hint::{Hint, HintsBag};
 use serde::{Deserialize, Serialize};
 
-use crate::wallet::multi_sig::TransactionHintsBag;
+use crate::wallet::TransactionHintsBag;
 
 #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
 pub struct TransactionHintsBagJson {
@@ -51,7 +52,7 @@ impl From<TransactionHintsBagJson> for TransactionHintsBag {
 
 #[cfg(test)]
 mod tests {
-    use crate::wallet::multi_sig::TransactionHintsBag;
+    use crate::wallet::TransactionHintsBag;
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergo-lib/src/chain/json/parameters.rs b/ergo-lib/src/chain/json/parameters.rs
index 26f4d561d..bb4769504 100644
--- a/ergo-lib/src/chain/json/parameters.rs
+++ b/ergo-lib/src/chain/json/parameters.rs
@@ -1,6 +1,6 @@
 use crate::chain::parameters::{Parameter, Parameters};
+use hashbrown::HashMap;
 use serde::{Deserialize, Serialize};
-use std::collections::HashMap;
 
 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
 pub struct ParametersJson {
diff --git a/ergo-lib/src/chain/json/transaction.rs b/ergo-lib/src/chain/json/transaction.rs
index 27a1d3fa3..5fda4d38b 100644
--- a/ergo-lib/src/chain/json/transaction.rs
+++ b/ergo-lib/src/chain/json/transaction.rs
@@ -1,4 +1,6 @@
-use std::convert::TryFrom;
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
 use thiserror::Error;
 
 use crate::chain::transaction::unsigned::UnsignedTransaction;
@@ -110,6 +112,7 @@ impl TryFrom<TransactionJson> for Transaction {
 mod tests {
     use crate::chain::transaction::unsigned::UnsignedTransaction;
     use crate::chain::transaction::Transaction;
+    use ergo_chain_types::Digest32;
     use proptest::prelude::*;
 
     proptest! {
@@ -133,4 +136,87 @@ mod tests {
         }
 
     }
+
+    #[test]
+    fn item_order_preservation_685() {
+        let tx_json = r#"
+{
+        "id" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
+        "inputs" : [
+          {
+            "boxId" : "59f2856068c56264d290520043044ace138a3a80d414748d0e4dcd0806188546",
+            "spendingProof" : {
+              "proofBytes" : "",
+              "extension" : {
+                "0" : "04c60f",
+                "5" : "0514",
+                "10" : "0eee03101808cd0279aed8dea2b2a25316d5d49d13bf51c0b2c1dc696974bb4b0c07b5894e998e56040005e0e0a447040404060402040004000e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d005e201058c85a2010514040404c60f06010104d00f05e0e0a44704c60f0e691005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304050005000580ade2040100d803d6017300d602b2a4730100d6037302eb027201d195ed93b1a4730393b1db630872027304d804d604db63087202d605b2a5730500d606b2db63087205730600d6077e8c72060206edededededed938cb2720473070001730893c27205d07201938c72060173099272077e730a06927ec172050699997ec1a7069d9c72077e730b067e730c067e720306909c9c7e8cb27204730d0002067e7203067e730e069c9a7207730f9a9c7ec17202067e7310067e9c73117e7312050690b0ada5d90108639593c272087313c1720873147315d90108599a8c7208018c72080273167317",
+                "1" : "0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d0",
+                "6" : "0580ade204",
+                "9" : "0580b48913",
+                "2" : "05e201",
+                "7" : "0e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f",
+                "3" : "05e0e0a447",
+                "8" : "0580ade204",
+                "4" : "058c85a201"
+              }
+            }
+          }
+        ],
+        "dataInputs" : [
+        ],
+        "outputs" : [
+          {
+            "boxId" : "0586c90d0cf6a82dab48c6a79500364ddbd6f81705f5032b03aa287de43dc638",
+            "value" : 94750000,
+            "ergoTree" : "101808cd0279aed8dea2b2a25316d5d49d13bf51c0b2c1dc696974bb4b0c07b5894e998e56040005e0e0a447040404060402040004000e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d005e201058c85a2010514040404c60f06010104d00f05e0e0a44704c60f0e691005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304050005000580ade2040100d803d6017300d602b2a4730100d6037302eb027201d195ed93b1a4730393b1db630872027304d804d604db63087202d605b2a5730500d606b2db63087205730600d6077e8c72060206edededededed938cb2720473070001730893c27205d07201938c72060173099272077e730a06927ec172050699997ec1a7069d9c72077e730b067e730c067e720306909c9c7e8cb27204730d0002067e7203067e730e069c9a7207730f9a9c7ec17202067e7310067e9c73117e7312050690b0ada5d90108639593c272087313c1720873147315d90108599a8c7208018c72080273167317",
+            "assets" : [
+            ],
+            "creationHeight" : 693475,
+            "additionalRegisters" : {
+
+            },
+            "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
+            "index" : 0
+          },
+          {
+            "boxId" : "4b99c2ef8496a491d176ecaf789d9e1d9aad0c2bf3e70b32e8bad73f48c722b9",
+            "value" : 250000,
+            "ergoTree" : "100e04000500059a0505d00f04020404040608cd03c6543ac8e8059748b1c6209ee419dd49a19ffaf5712a2f34a9412016a3a1d96708cd035b736bebf0c5393f78329f6894af84d1864c7496cc65ddc250ef60cdd75df52008cd021b63e19ab452c84cdc6687242e8494957b1f11e3750c8c184a8425f8a8171d9b05060580ade2040580a8d6b907040ad806d601b2a5730000d602b0a47301d9010241639a8c720201c18c720202d6039d9c730272027303d604b2a5730400d605b2a5730500d606b2a5730600d1968306019683020193c17201720393c27201d073079683020193c17204720393c27204d073089683020193c17205720393c27205d073099683020192c17206999972029c730a7203730b93c2a7c27206927202730c93b1a5730d",
+            "assets" : [
+            ],
+            "creationHeight" : 693475,
+            "additionalRegisters" : {
+
+            },
+            "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
+            "index" : 1
+          },
+          {
+            "boxId" : "00ddbeb981c0b08536f72ea41e07a25adbf7bf104ee59b865619a21676e64715",
+            "value" : 5000000,
+            "ergoTree" : "1005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304",
+            "assets" : [
+            ],
+            "creationHeight" : 693475,
+            "additionalRegisters" : {
+
+            },
+            "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
+            "index" : 2
+          }
+        ],
+        "size" : 1562
+      }
+    "#;
+        let tx: Transaction = serde_json::from_str(tx_json).unwrap();
+        assert_eq!(
+            tx.id(),
+            Digest32::try_from(
+                "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4".to_string()
+            )
+            .unwrap()
+            .into()
+        );
+    }
 }
diff --git a/ergo-lib/src/chain/parameters.rs b/ergo-lib/src/chain/parameters.rs
index 67ecce489..e7888f340 100644
--- a/ergo-lib/src/chain/parameters.rs
+++ b/ergo-lib/src/chain/parameters.rs
@@ -1,5 +1,5 @@
 //! Blockchain parameters. This module defines adjustable blockchain parameters that can be voted on by miners
-use std::collections::HashMap;
+use hashbrown::HashMap;
 
 #[repr(i8)]
 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
@@ -103,7 +103,7 @@ impl Parameters {
     }
 }
 
-impl std::default::Default for Parameters {
+impl Default for Parameters {
     /// Default blockchain parameters
     // Taken from https://github.com/ergoplatform/ergo/blob/master/ergo-core/src/main/scala/org/ergoplatform/settings/Parameters.scala#L291
     fn default() -> Self {
diff --git a/ergo-lib/src/chain/transaction.rs b/ergo-lib/src/chain/transaction.rs
index c9d9ec24f..928a00f03 100644
--- a/ergo-lib/src/chain/transaction.rs
+++ b/ergo-lib/src/chain/transaction.rs
@@ -7,6 +7,9 @@ pub mod reduced;
 pub(crate) mod storage_rent;
 pub mod unsigned;
 
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec::Vec;
 use bounded_vec::BoundedVec;
 use ergo_chain_types::blake2b256_hash;
 use ergotree_interpreter::eval::env::Env;
@@ -25,6 +28,7 @@ use ergotree_ir::chain::ergo_box::ErgoBox;
 use ergotree_ir::chain::ergo_box::ErgoBoxCandidate;
 use ergotree_ir::chain::token::TokenId;
 pub use ergotree_ir::chain::tx_id::TxId;
+use ergotree_ir::chain::IndexSet;
 use ergotree_ir::ergo_tree::ErgoTreeError;
 use thiserror::Error;
 
@@ -46,11 +50,9 @@ use self::ergo_transaction::TxValidationError;
 use self::storage_rent::try_spend_storage_rent;
 use self::unsigned::UnsignedTransaction;
 
-use indexmap::IndexSet;
-
-use std::convert::TryFrom;
-use std::convert::TryInto;
-use std::iter::FromIterator;
+use core::convert::TryFrom;
+use core::convert::TryInto;
+use core::iter::FromIterator;
 
 use super::ergo_state_context::ErgoStateContext;
 
@@ -303,7 +305,8 @@ impl SigmaSerializable for Transaction {
                 "too many tokens in transaction".to_string(),
             ));
         }
-        let mut token_ids = IndexSet::with_capacity(tokens_count as usize);
+        let mut token_ids =
+            IndexSet::with_capacity_and_hasher(tokens_count as usize, Default::default());
         for _ in 0..tokens_count {
             token_ids.insert(TokenId::sigma_parse(r)?);
         }
diff --git a/ergo-lib/src/chain/transaction/ergo_transaction.rs b/ergo-lib/src/chain/transaction/ergo_transaction.rs
index 3da6db931..cd3a14acb 100644
--- a/ergo-lib/src/chain/transaction/ergo_transaction.rs
+++ b/ergo-lib/src/chain/transaction/ergo_transaction.rs
@@ -8,7 +8,6 @@ use ergotree_ir::{
     },
     serialization::SigmaSerializationError,
 };
-use itertools::Itertools;
 use thiserror::Error;
 
 use crate::wallet::tx_context::TransactionContextError;
@@ -59,10 +58,10 @@ pub enum TxValidationError {
     /// Negative heights are not allowed after block v1.
     /// When using sigma-rust where heights are always unsigned, this error may be because creation height was set to be >= 2147483648
     NegativeHeight,
-    #[error("Output box size {0} > maximum {}", ErgoBox::MAX_BOX_SIZE)]
+    #[error("Output box size {0} > maximum {max_size}", max_size = ErgoBox::MAX_BOX_SIZE)]
     /// Box size is > [ErgoBox::MAX_BOX_SIZE]
     BoxSizeExceeded(usize),
-    #[error("Output box size {0} > maximum {}", ErgoBox::MAX_SCRIPT_SIZE)]
+    #[error("Output box size {0} > maximum {max_size}", max_size = ErgoBox::MAX_SCRIPT_SIZE)]
     /// Script size is > [ErgoBox::MAX_SCRIPT_SIZE]
     ScriptSizeExceeded(usize),
     #[error("TX context error: {0}")]
@@ -104,7 +103,7 @@ pub trait ErgoTransaction {
 
         // Check if there are no double-spends in input (one BoxId being spent more than once)
         let len = inputs.len();
-        let unique_count = inputs.unique().count();
+        let unique_count = inputs.collect::<hashbrown::HashSet<_>>().len();
         if unique_count != len {
             return Err(TxValidationError::DoubleSpend(unique_count, len));
         }
diff --git a/ergo-lib/src/chain/transaction/input.rs b/ergo-lib/src/chain/transaction/input.rs
index 21f194cc9..65c163088 100644
--- a/ergo-lib/src/chain/transaction/input.rs
+++ b/ergo-lib/src/chain/transaction/input.rs
@@ -11,8 +11,6 @@ use ergotree_ir::serialization::SigmaParsingError;
 use ergotree_ir::serialization::SigmaSerializable;
 use ergotree_ir::serialization::SigmaSerializeResult;
 
-#[cfg(feature = "json")]
-use crate::chain::json::context_extension::ContextExtensionSerde;
 use crate::wallet::box_selector::ErgoBoxId;
 #[cfg(feature = "json")]
 use serde::ser::SerializeStruct;
@@ -30,11 +28,7 @@ pub struct UnsignedInput {
     #[cfg_attr(feature = "json", serde(rename = "boxId"))]
     pub box_id: BoxId,
     /// user-defined variables to be put into context
-    #[cfg_attr(
-        feature = "json",
-        serde(rename = "extension",),
-        serde(with = "crate::chain::json::context_extension::ContextExtensionSerde")
-    )]
+    #[cfg_attr(feature = "json", serde(rename = "extension",))]
     pub extension: ContextExtension,
 }
 
@@ -46,10 +40,7 @@ impl Serialize for UnsignedInput {
     {
         let mut s = serializer.serialize_struct("UnsignedInput", 2)?;
         s.serialize_field("boxId", &self.box_id)?;
-        s.serialize_field(
-            "extension",
-            &ContextExtensionSerde::from(self.extension.clone()),
-        )?;
+        s.serialize_field("extension", &self.extension)?;
         s.end()
     }
 }
diff --git a/ergo-lib/src/chain/transaction/input/prover_result.rs b/ergo-lib/src/chain/transaction/input/prover_result.rs
index 6aa0be88d..a917b5d96 100644
--- a/ergo-lib/src/chain/transaction/input/prover_result.rs
+++ b/ergo-lib/src/chain/transaction/input/prover_result.rs
@@ -23,11 +23,7 @@ pub struct ProverResult {
     )]
     pub proof: ProofBytes,
     /// user-defined variables to be put into context
-    #[cfg_attr(
-        feature = "json",
-        serde(rename = "extension"),
-        serde(with = "crate::chain::json::context_extension::ContextExtensionSerde")
-    )]
+    #[cfg_attr(feature = "json", serde(rename = "extension"))]
     pub extension: ContextExtension,
 }
 
diff --git a/ergo-lib/src/chain/transaction/input/prover_result/json.rs b/ergo-lib/src/chain/transaction/input/prover_result/json.rs
index b9aae483a..6b0e0e74f 100644
--- a/ergo-lib/src/chain/transaction/input/prover_result/json.rs
+++ b/ergo-lib/src/chain/transaction/input/prover_result/json.rs
@@ -1,6 +1,7 @@
-use std::str::FromStr;
+use core::str::FromStr;
 
-use crate::chain::json::context_extension::ContextExtensionSerde;
+use alloc::string::String;
+use alloc::vec::Vec;
 use ergotree_ir::chain::context_extension::ContextExtension;
 use serde::ser::SerializeStruct;
 use serde::Serialize;
@@ -14,10 +15,7 @@ impl Serialize for ProverResult {
     {
         let mut s = serializer.serialize_struct("ProverResult", 2)?;
         s.serialize_field("proofBytes", &String::from(self.proof.clone()))?;
-        s.serialize_field(
-            "extension",
-            &ContextExtensionSerde::from(self.extension.clone()),
-        )?;
+        s.serialize_field("extension", &self.extension)?;
         s.end()
     }
 }
diff --git a/ergo-lib/src/chain/transaction/unsigned.rs b/ergo-lib/src/chain/transaction/unsigned.rs
index 507287b57..e0b3e78c8 100644
--- a/ergo-lib/src/chain/transaction/unsigned.rs
+++ b/ergo-lib/src/chain/transaction/unsigned.rs
@@ -6,16 +6,17 @@ use super::DataInput;
 use super::Transaction;
 use super::TxIoVec;
 use super::{distinct_token_ids, TransactionError};
+use alloc::vec::Vec;
 use bounded_vec::BoundedVec;
 use ergo_chain_types::blake2b256_hash;
 
+use core::convert::TryInto;
 use ergotree_ir::chain::ergo_box::ErgoBox;
 use ergotree_ir::chain::ergo_box::ErgoBoxCandidate;
 use ergotree_ir::chain::token::TokenId;
 use ergotree_ir::chain::tx_id::TxId;
+use ergotree_ir::chain::IndexSet;
 use ergotree_ir::serialization::SigmaSerializationError;
-use indexmap::IndexSet;
-use std::convert::TryInto;
 
 /// Unsigned (inputs without proofs) transaction
 #[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
diff --git a/ergo-lib/src/lib.rs b/ergo-lib/src/lib.rs
index a629bc845..e1d987d19 100644
--- a/ergo-lib/src/lib.rs
+++ b/ergo-lib/src/lib.rs
@@ -1,5 +1,7 @@
 //! ErgoTree IR
 
+#![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
 // Coding conventions
 #![forbid(unsafe_code)]
 #![deny(non_upper_case_globals)]
@@ -20,6 +22,11 @@
 #![deny(clippy::unreachable)]
 #![deny(clippy::panic)]
 
+#[cfg(all(not(feature = "std"), any(feature = "nipopow", feature = "merkle")))]
+compile_error!("ergo-nipopow and ergo-merkle-tree are not supported without std");
+
+#[macro_use]
+extern crate alloc;
 pub mod chain;
 pub mod constants;
 mod utils;
@@ -30,8 +37,10 @@ pub mod wallet;
 /// Ergo blockchain types
 pub extern crate ergo_chain_types;
 /// Ergo Merkle Tree and Merkle verification tools
+#[cfg(feature = "merkle")]
 pub extern crate ergo_merkle_tree;
 /// Ergo NiPoPoW implementation
+#[cfg(feature = "nipopow")]
 pub extern crate ergo_nipopow;
 /// Re-exported types from dependencies
 #[cfg(feature = "rest")]
diff --git a/ergo-lib/src/wallet.rs b/ergo-lib/src/wallet.rs
index e6305373d..ee58d022a 100644
--- a/ergo-lib/src/wallet.rs
+++ b/ergo-lib/src/wallet.rs
@@ -9,39 +9,44 @@ pub mod miner_fee;
 pub mod mnemonic;
 #[cfg(feature = "mnemonic_gen")]
 pub mod mnemonic_generator;
+#[cfg(feature = "std")]
 pub mod multi_sig;
 pub mod secret_key;
 pub mod signing;
 pub mod tx_builder;
 pub mod tx_context;
 
+use crate::ergotree_interpreter::sigma_protocol::prover::hint::{Hint, HintsBag};
+use alloc::boxed::Box;
+use alloc::vec::Vec;
 use ergotree_interpreter::sigma_protocol::private_input::PrivateInput;
 use ergotree_interpreter::sigma_protocol::prover::Prover;
 use ergotree_interpreter::sigma_protocol::prover::ProverError;
 use ergotree_interpreter::sigma_protocol::prover::TestProver;
+use hashbrown::HashMap;
 use secret_key::SecretKey;
-use signing::{sign_transaction, TxSigningError};
 use thiserror::Error;
 
 use crate::chain::ergo_state_context::ErgoStateContext;
 use crate::chain::transaction::reduced::reduce_tx;
 use crate::chain::transaction::reduced::ReducedTransaction;
 use crate::chain::transaction::unsigned::UnsignedTransaction;
+#[cfg(feature = "std")]
 use crate::chain::transaction::Input;
 use crate::chain::transaction::Transaction;
+#[cfg(feature = "std")]
 use crate::ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
 use crate::wallet::mnemonic::Mnemonic;
-use crate::wallet::multi_sig::{
-    generate_commitments, generate_commitments_for, TransactionHintsBag,
-};
+#[cfg(feature = "std")]
+use crate::wallet::multi_sig::{generate_commitments, generate_commitments_for};
 
 use self::ext_secret_key::ExtSecretKey;
 use self::ext_secret_key::ExtSecretKeyError;
-use self::signing::make_context;
-use self::signing::sign_message;
 use self::signing::sign_reduced_transaction;
-use self::signing::sign_tx_input;
 use self::signing::TransactionContext;
+use self::signing::TxSigningError;
+#[cfg(feature = "std")]
+use self::signing::{make_context, sign_message, sign_transaction, sign_tx_input};
 
 /// Wallet
 pub struct Wallet {
@@ -93,6 +98,7 @@ impl Wallet {
     }
 
     /// Signs a transaction
+    #[cfg(feature = "std")]
     pub fn sign_transaction(
         &self,
         tx_context: TransactionContext<UnsignedTransaction>,
@@ -104,6 +110,7 @@ impl Wallet {
     }
 
     /// Signs a reduced transaction (generating proofs for inputs)
+    #[cfg(feature = "std")]
     pub fn sign_reduced_transaction(
         &self,
         reduced_tx: ReducedTransaction,
@@ -114,6 +121,7 @@ impl Wallet {
     }
 
     /// Generate commitments for Transaction by wallet secrets
+    #[cfg(feature = "std")]
     pub fn generate_commitments(
         &self,
         tx_context: TransactionContext<UnsignedTransaction>,
@@ -129,6 +137,7 @@ impl Wallet {
     }
 
     /// Generate Commitments for reduced Transaction
+    #[cfg(feature = "std")]
     pub fn generate_commitments_for_reduced_transaction(
         &self,
         reduced_tx: ReducedTransaction,
@@ -185,10 +194,11 @@ impl Wallet {
     ) -> Result<Transaction, WalletError> {
         let reduced_tx = reduce_tx(tx_context, state_context)?;
         let hints = self.generate_deterministic_commitments(&reduced_tx, aux_rand)?;
-        self.sign_reduced_transaction(reduced_tx, Some(&hints))
+        sign_reduced_transaction(&*self.prover, reduced_tx, Some(&hints)).map_err(From::from)
     }
 
     /// Signs a message
+    #[cfg(feature = "std")]
     pub fn sign_message(
         &self,
         sigma_tree: SigmaBoolean,
@@ -198,6 +208,7 @@ impl Wallet {
     }
 
     /// Signs a transaction input
+    #[cfg(feature = "std")]
     pub fn sign_tx_input(
         &self,
         input_idx: usize,
@@ -220,3 +231,106 @@ impl Wallet {
         )?)
     }
 }
+
+#[cfg(feature = "arbitrary")]
+use proptest::prelude::Strategy;
+/// TransactionHintsBag
+#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(
+    feature = "json",
+    serde(
+        try_from = "crate::chain::json::hint::TransactionHintsBagJson",
+        into = "crate::chain::json::hint::TransactionHintsBagJson"
+    )
+)]
+#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
+#[derive(PartialEq, Debug, Clone)]
+pub struct TransactionHintsBag {
+    #[cfg_attr(
+        feature = "arbitrary",
+        proptest(
+            strategy = "proptest::collection::hash_map(proptest::prelude::any::<usize>(), proptest::prelude::any::<HintsBag>(), 0..5).prop_map(HashMap::from_iter)"
+        )
+    )]
+    pub(crate) secret_hints: HashMap<usize, HintsBag>,
+    #[cfg_attr(
+        feature = "arbitrary",
+        proptest(
+            strategy = "proptest::collection::hash_map(proptest::prelude::any::<usize>(), proptest::prelude::any::<HintsBag>(), 0..5).prop_map(HashMap::from_iter)"
+        )
+    )]
+    pub(crate) public_hints: HashMap<usize, HintsBag>,
+}
+
+impl TransactionHintsBag {
+    /// Empty TransactionHintsBag
+    pub fn empty() -> Self {
+        TransactionHintsBag {
+            secret_hints: HashMap::new(),
+            public_hints: HashMap::new(),
+        }
+    }
+
+    /// Replacing Hints for an input index
+    pub fn replace_hints_for_input(&mut self, index: usize, hints_bag: HintsBag) {
+        let public: Vec<Hint> = hints_bag
+            .hints
+            .clone()
+            .into_iter()
+            .filter(|hint| matches!(hint, Hint::CommitmentHint(_)))
+            .collect();
+        let secret: Vec<Hint> = hints_bag
+            .hints
+            .into_iter()
+            .filter(|hint| matches!(hint, Hint::SecretProven(_)))
+            .collect();
+
+        self.secret_hints.insert(index, HintsBag { hints: secret });
+        self.public_hints.insert(index, HintsBag { hints: public });
+    }
+
+    /// Adding hints for a input index
+    pub fn add_hints_for_input(&mut self, index: usize, hints_bag: HintsBag) {
+        let mut public: Vec<Hint> = hints_bag
+            .hints
+            .clone()
+            .into_iter()
+            .filter(|hint| matches!(hint, Hint::CommitmentHint(_)))
+            .collect();
+        let mut secret: Vec<Hint> = hints_bag
+            .hints
+            .into_iter()
+            .filter(|hint| matches!(hint, Hint::SecretProven(_)))
+            .collect();
+        let secret_bag = HintsBag::empty();
+        let public_bag = HintsBag::empty();
+        let old_secret: &Vec<Hint> = &self.secret_hints.get(&index).unwrap_or(&secret_bag).hints;
+        for hint in old_secret {
+            secret.push(hint.clone());
+        }
+
+        let old_public: &Vec<Hint> = &self.public_hints.get(&index).unwrap_or(&public_bag).hints;
+        for hint in old_public {
+            public.push(hint.clone());
+        }
+        self.secret_hints.insert(index, HintsBag { hints: secret });
+        self.public_hints.insert(index, HintsBag { hints: public });
+    }
+
+    /// Outputting HintsBag corresponding for an index
+    pub fn all_hints_for_input(&self, index: usize) -> HintsBag {
+        let mut hints: Vec<Hint> = Vec::new();
+        let secret_bag = HintsBag::empty();
+        let public_bag = HintsBag::empty();
+        let secrets: &Vec<Hint> = &self.secret_hints.get(&index).unwrap_or(&secret_bag).hints;
+        for hint in secrets {
+            hints.push(hint.clone());
+        }
+        let public: &Vec<Hint> = &self.public_hints.get(&index).unwrap_or(&public_bag).hints;
+        for hint in public {
+            hints.push(hint.clone());
+        }
+        let hints_bag: HintsBag = HintsBag { hints };
+        hints_bag
+    }
+}
diff --git a/ergo-lib/src/wallet/box_selector.rs b/ergo-lib/src/wallet/box_selector.rs
index 917f84948..22222ca68 100644
--- a/ergo-lib/src/wallet/box_selector.rs
+++ b/ergo-lib/src/wallet/box_selector.rs
@@ -2,8 +2,9 @@
 
 mod simple;
 
-use std::collections::HashMap;
+use hashbrown::HashMap;
 
+use alloc::vec::Vec;
 use bounded_vec::BoundedVec;
 use ergotree_ir::chain::ergo_box::box_value::BoxValue;
 use ergotree_ir::chain::ergo_box::BoxId;
diff --git a/ergo-lib/src/wallet/box_selector/simple.rs b/ergo-lib/src/wallet/box_selector/simple.rs
index da6d2c812..987aec383 100644
--- a/ergo-lib/src/wallet/box_selector/simple.rs
+++ b/ergo-lib/src/wallet/box_selector/simple.rs
@@ -1,9 +1,11 @@
 //! Naive box selector, collects inputs until target balance is reached
 
-use std::cmp::min;
-use std::collections::HashMap;
-use std::convert::TryInto;
+use core::cmp::min;
+use core::convert::TryInto;
+use hashbrown::HashMap;
 
+use alloc::string::String;
+use alloc::vec::Vec;
 use ergotree_ir::chain::ergo_box::box_value::BoxValue;
 use ergotree_ir::chain::ergo_box::BoxTokens;
 use ergotree_ir::chain::ergo_box::ErgoBox;
@@ -290,7 +292,7 @@ fn make_change_boxes(
 #[allow(clippy::unwrap_used, clippy::panic)]
 mod tests {
 
-    use std::convert::TryFrom;
+    use core::convert::TryFrom;
 
     use ergotree_ir::chain::{
         address::{AddressEncoder, NetworkPrefix},
diff --git a/ergo-lib/src/wallet/derivation_path.rs b/ergo-lib/src/wallet/derivation_path.rs
index 8b46a1fa3..8b9340621 100644
--- a/ergo-lib/src/wallet/derivation_path.rs
+++ b/ergo-lib/src/wallet/derivation_path.rs
@@ -2,8 +2,14 @@
 //! BIP-44 <https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki>
 //! and EIP-3 <https://github.com/ergoplatform/eips/blob/master/eip-0003.md>
 
+use alloc::{
+    boxed::Box,
+    collections::VecDeque,
+    string::{String, ToString},
+    vec::Vec,
+};
+use core::{fmt, num::ParseIntError, str::FromStr};
 use derive_more::From;
-use std::{collections::VecDeque, fmt, num::ParseIntError, str::FromStr};
 use thiserror::Error;
 
 /// Index for hardened derivation
diff --git a/ergo-lib/src/wallet/ext_pub_key.rs b/ergo-lib/src/wallet/ext_pub_key.rs
index d6ab42efb..cec8b3710 100644
--- a/ergo-lib/src/wallet/ext_pub_key.rs
+++ b/ergo-lib/src/wallet/ext_pub_key.rs
@@ -1,6 +1,7 @@
 //! Extended public key operations according to BIP-32
-use std::convert::TryInto;
+use core::convert::TryInto;
 
+use alloc::string::String;
 use ergo_chain_types::EcPoint;
 use ergotree_interpreter::sigma_protocol::private_input::DlogProverInput;
 use ergotree_ir::chain::address::Address;
diff --git a/ergo-lib/src/wallet/ext_secret_key.rs b/ergo-lib/src/wallet/ext_secret_key.rs
index 0d17d7e87..16bfaaa8e 100644
--- a/ergo-lib/src/wallet/ext_secret_key.rs
+++ b/ergo-lib/src/wallet/ext_secret_key.rs
@@ -1,5 +1,5 @@
 //! Extended private key operations according to BIP-32
-use std::convert::TryInto;
+use core::convert::TryInto;
 
 use super::{
     derivation_path::{ChildIndex, ChildIndexError, DerivationPath},
@@ -8,6 +8,7 @@ use super::{
     secret_key::SecretKey,
 };
 use crate::ArrLength;
+use alloc::{string::String, vec::Vec};
 use ergotree_interpreter::sigma_protocol::{private_input::DlogProverInput, wscalar::Wscalar};
 use ergotree_ir::{
     serialization::{SigmaParsingError, SigmaSerializable, SigmaSerializationError},
diff --git a/ergo-lib/src/wallet/miner_fee.rs b/ergo-lib/src/wallet/miner_fee.rs
index cbbaf0e2f..9e2d5b1dd 100644
--- a/ergo-lib/src/wallet/miner_fee.rs
+++ b/ergo-lib/src/wallet/miner_fee.rs
@@ -1,5 +1,6 @@
 //! Miner fee included in transaction
 
+use alloc::string::String;
 use ergotree_ir::chain::address::Address;
 use ergotree_ir::chain::address::AddressEncoder;
 use ergotree_ir::chain::address::NetworkPrefix;
diff --git a/ergo-lib/src/wallet/mnemonic.rs b/ergo-lib/src/wallet/mnemonic.rs
index 90c8d1714..a223c9c38 100644
--- a/ergo-lib/src/wallet/mnemonic.rs
+++ b/ergo-lib/src/wallet/mnemonic.rs
@@ -1,5 +1,6 @@
 //! Mnemonic operations according to BIP32/BIP39
 
+use alloc::string::String;
 use hmac::Hmac;
 use pbkdf2::pbkdf2;
 use sha2::Sha512;
diff --git a/ergo-lib/src/wallet/mnemonic_generator.rs b/ergo-lib/src/wallet/mnemonic_generator.rs
index c88d725ab..e824fc8e6 100644
--- a/ergo-lib/src/wallet/mnemonic_generator.rs
+++ b/ergo-lib/src/wallet/mnemonic_generator.rs
@@ -1,5 +1,6 @@
 //! Mnemonic generation
 
+use alloc::{string::String, vec::Vec};
 use bitvec::prelude::*;
 use rand::RngCore;
 use sha2::{Digest, Sha256};
diff --git a/ergo-lib/src/wallet/multi_sig.rs b/ergo-lib/src/wallet/multi_sig.rs
index 92513aea1..06d4950ed 100644
--- a/ergo-lib/src/wallet/multi_sig.rs
+++ b/ergo-lib/src/wallet/multi_sig.rs
@@ -1,4 +1,4 @@
-//! multi sig prove crate::chain::ergo_state_context::ErgoStateContext;
+//! multi sig prover
 use crate::chain::ergo_state_context::ErgoStateContext;
 use crate::chain::transaction::unsigned::UnsignedTransaction;
 use crate::chain::transaction::Transaction;
@@ -19,114 +19,14 @@ use crate::ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjecture;
 use crate::ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjectureItems;
 use crate::ergotree_ir::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
 use crate::wallet::signing::{make_context, TransactionContext, TxSigningError};
+use alloc::vec::Vec;
 use ergotree_interpreter::sigma_protocol::sig_serializer::parse_sig_compute_challenges;
 use ergotree_interpreter::sigma_protocol::unchecked_tree::UncheckedTree;
 use ergotree_interpreter::sigma_protocol::verifier::compute_commitments;
-use std::collections::HashMap;
 
 use super::signing::update_context;
 use super::tx_context::TransactionContextError;
-
-/// TransactionHintsBag
-#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(
-    feature = "json",
-    serde(
-        try_from = "crate::chain::json::hint::TransactionHintsBagJson",
-        into = "crate::chain::json::hint::TransactionHintsBagJson"
-    )
-)]
-#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
-#[derive(PartialEq, Debug, Clone)]
-pub struct TransactionHintsBag {
-    #[cfg_attr(
-        feature = "arbitrary",
-        proptest(
-            strategy = "proptest::collection::hash_map(proptest::prelude::any::<usize>(), proptest::prelude::any::<HintsBag>(), 0..5)"
-        )
-    )]
-    pub(crate) secret_hints: HashMap<usize, HintsBag>,
-    #[cfg_attr(
-        feature = "arbitrary",
-        proptest(
-            strategy = "proptest::collection::hash_map(proptest::prelude::any::<usize>(), proptest::prelude::any::<HintsBag>(), 0..5)"
-        )
-    )]
-    pub(crate) public_hints: HashMap<usize, HintsBag>,
-}
-
-impl TransactionHintsBag {
-    /// Empty TransactionHintsBag
-    pub fn empty() -> Self {
-        TransactionHintsBag {
-            secret_hints: HashMap::new(),
-            public_hints: HashMap::new(),
-        }
-    }
-
-    /// Replacing Hints for an input index
-    pub fn replace_hints_for_input(&mut self, index: usize, hints_bag: HintsBag) {
-        let public: Vec<Hint> = hints_bag
-            .hints
-            .clone()
-            .into_iter()
-            .filter(|hint| matches!(hint, Hint::CommitmentHint(_)))
-            .collect();
-        let secret: Vec<Hint> = hints_bag
-            .hints
-            .into_iter()
-            .filter(|hint| matches!(hint, Hint::SecretProven(_)))
-            .collect();
-
-        self.secret_hints.insert(index, HintsBag { hints: secret });
-        self.public_hints.insert(index, HintsBag { hints: public });
-    }
-
-    /// Adding hints for a input index
-    pub fn add_hints_for_input(&mut self, index: usize, hints_bag: HintsBag) {
-        let mut public: Vec<Hint> = hints_bag
-            .hints
-            .clone()
-            .into_iter()
-            .filter(|hint| matches!(hint, Hint::CommitmentHint(_)))
-            .collect();
-        let mut secret: Vec<Hint> = hints_bag
-            .hints
-            .into_iter()
-            .filter(|hint| matches!(hint, Hint::SecretProven(_)))
-            .collect();
-        let secret_bag = HintsBag::empty();
-        let public_bag = HintsBag::empty();
-        let old_secret: &Vec<Hint> = &self.secret_hints.get(&index).unwrap_or(&secret_bag).hints;
-        for hint in old_secret {
-            secret.push(hint.clone());
-        }
-
-        let old_public: &Vec<Hint> = &self.public_hints.get(&index).unwrap_or(&public_bag).hints;
-        for hint in old_public {
-            public.push(hint.clone());
-        }
-        self.secret_hints.insert(index, HintsBag { hints: secret });
-        self.public_hints.insert(index, HintsBag { hints: public });
-    }
-
-    /// Outputting HintsBag corresponding for an index
-    pub fn all_hints_for_input(&self, index: usize) -> HintsBag {
-        let mut hints: Vec<Hint> = Vec::new();
-        let secret_bag = HintsBag::empty();
-        let public_bag = HintsBag::empty();
-        let secrets: &Vec<Hint> = &self.secret_hints.get(&index).unwrap_or(&secret_bag).hints;
-        for hint in secrets {
-            hints.push(hint.clone());
-        }
-        let public: &Vec<Hint> = &self.public_hints.get(&index).unwrap_or(&public_bag).hints;
-        for hint in public {
-            hints.push(hint.clone());
-        }
-        let hints_bag: HintsBag = HintsBag { hints };
-        hints_bag
-    }
-}
+use super::TransactionHintsBag;
 
 /// A method which is extracting partial proofs of secret knowledge for particular secrets with their
 /// respective public images given. Useful for distributed signature applications.
@@ -392,6 +292,7 @@ mod tests {
     use crate::ergotree_ir::mir::sigma_and::SigmaAnd;
     use crate::ergotree_ir::serialization::SigmaSerializable;
     use crate::ergotree_ir::sigma_protocol::sigma_boolean::cand::Cand;
+    use core::convert::{TryFrom, TryInto};
     use ergo_chain_types::Base16DecodedBytes;
     use ergotree_interpreter::sigma_protocol::private_input::DhTupleProverInput;
     use ergotree_interpreter::sigma_protocol::wscalar::Wscalar;
@@ -403,7 +304,6 @@ mod tests {
     use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp;
     use ergotree_ir::types::stype::SType;
     use sigma_test_util::force_any_val;
-    use std::convert::{TryFrom, TryInto};
 
     #[test]
     fn extract_hint() {
diff --git a/ergo-lib/src/wallet/secret_key.rs b/ergo-lib/src/wallet/secret_key.rs
index 030760cf4..bc4d2d18e 100644
--- a/ergo-lib/src/wallet/secret_key.rs
+++ b/ergo-lib/src/wallet/secret_key.rs
@@ -1,5 +1,6 @@
 //! Secret types
 
+use alloc::vec::Vec;
 use derive_more::From;
 use ergo_chain_types::EcPoint;
 use ergotree_interpreter::sigma_protocol::private_input::DhTupleProverInput;
@@ -29,11 +30,13 @@ pub enum SecretKey {
 
 impl SecretKey {
     /// Generates random DlogProverInput
+    #[cfg(feature = "std")]
     pub fn random_dlog() -> SecretKey {
         SecretKey::DlogSecretKey(DlogProverInput::random())
     }
 
     /// Generates random DhTupleProverInput
+    #[cfg(feature = "std")]
     pub fn random_dht() -> SecretKey {
         SecretKey::DhtSecretKey(DhTupleProverInput::random())
     }
@@ -136,7 +139,7 @@ impl From<SecretKey> for PrivateInput {
 #[allow(clippy::unwrap_used)]
 mod tests {
     use super::*;
-    use std::convert::TryInto;
+    use core::convert::TryInto;
 
     #[test]
     fn dlog_roundtrip() {
diff --git a/ergo-lib/src/wallet/signing.rs b/ergo-lib/src/wallet/signing.rs
index 28283f41c..27b06552e 100644
--- a/ergo-lib/src/wallet/signing.rs
+++ b/ergo-lib/src/wallet/signing.rs
@@ -7,13 +7,14 @@ use crate::chain::{
     ergo_state_context::ErgoStateContext,
     transaction::{unsigned::UnsignedTransaction, Transaction},
 };
+use alloc::vec::Vec;
 use ergotree_interpreter::sigma_protocol::prover::hint::HintsBag;
 use ergotree_interpreter::sigma_protocol::sig_serializer::SigParsingError;
 use ergotree_ir::serialization::SigmaSerializationError;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
 
 use crate::chain::transaction::storage_rent::check_storage_rent_conditions;
-use crate::wallet::multi_sig::TransactionHintsBag;
+use crate::wallet::TransactionHintsBag;
 use ergotree_interpreter::sigma_protocol::prover::ProofBytes;
 use ergotree_interpreter::sigma_protocol::prover::Prover;
 use ergotree_interpreter::sigma_protocol::prover::ProverError;
@@ -289,11 +290,11 @@ mod tests {
     };
     use crate::wallet::secret_key::SecretKey;
     use crate::wallet::Wallet;
+    use core::convert::TryFrom;
+    use core::convert::TryInto;
     use ergotree_ir::chain::ergo_box::ErgoBoxCandidate;
     use ergotree_ir::ergo_tree::ErgoTree;
     use ergotree_ir::mir::expr::Expr;
-    use std::convert::TryFrom;
-    use std::convert::TryInto;
     use std::rc::Rc;
 
     fn verify_tx_proofs(
diff --git a/ergo-lib/src/wallet/tx_builder.rs b/ergo-lib/src/wallet/tx_builder.rs
index 160ca279a..651d5831f 100644
--- a/ergo-lib/src/wallet/tx_builder.rs
+++ b/ergo-lib/src/wallet/tx_builder.rs
@@ -1,13 +1,16 @@
 //! Builder for an UnsignedTransaction
 
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec::Vec;
+use core::convert::TryInto;
 use ergotree_ir::chain::context::TxIoVec;
 use ergotree_ir::chain::context_extension::ContextExtension;
 use ergotree_ir::chain::token::TokenAmount;
 use ergotree_ir::chain::token::TokenAmountError;
 use ergotree_ir::ergo_tree::ErgoTree;
-use std::collections::HashMap;
-use std::collections::HashSet;
-use std::convert::TryInto;
+use hashbrown::HashMap;
+use hashbrown::HashSet;
 
 use bounded_vec::BoundedVecOutOfBounds;
 use ergotree_interpreter::sigma_protocol;
@@ -379,7 +382,7 @@ fn check_unused_token_burn_permit(
 #[allow(clippy::unwrap_used, clippy::panic)]
 mod tests {
 
-    use std::convert::TryInto;
+    use core::convert::TryInto;
 
     use ergotree_ir::chain::ergo_box::arbitrary::ArbBoxParameters;
     use ergotree_ir::chain::ergo_box::box_value::checked_sum;
diff --git a/ergo-lib/src/wallet/tx_context.rs b/ergo-lib/src/wallet/tx_context.rs
index 88b583c30..80216b7f9 100644
--- a/ergo-lib/src/wallet/tx_context.rs
+++ b/ergo-lib/src/wallet/tx_context.rs
@@ -1,7 +1,8 @@
 //! Transaction context
 
-use std::collections::hash_map::Entry;
-use std::collections::HashMap;
+use alloc::vec::Vec;
+use hashbrown::hash_map::Entry;
+use hashbrown::HashMap;
 
 use crate::chain::ergo_state_context::ErgoStateContext;
 use crate::chain::transaction::ergo_transaction::{ErgoTransaction, TxValidationError};
@@ -288,6 +289,7 @@ pub enum TransactionContextError {
 mod test {
     use std::collections::HashMap;
 
+    use alloc::vec::Vec;
     use ergotree_interpreter::sigma_protocol::prover::ProofBytes;
     use ergotree_ir::chain::context::TxIoVec;
     use ergotree_ir::chain::context_extension::ContextExtension;
@@ -387,10 +389,10 @@ mod test {
         let parameters = Parameters::default();
         let sufficient_amount =
             ErgoBox::MAX_BOX_SIZE as u64 * parameters.min_value_per_byte() as u64;
-        let max_outputs = std::cmp::min(i16::MAX as u16, (input_sum / sufficient_amount) as u16);
-        let outputs = std::cmp::min(
+        let max_outputs = core::cmp::min(i16::MAX as u16, (input_sum / sufficient_amount) as u16);
+        let outputs = core::cmp::min(
             max_outputs,
-            std::cmp::max(boxes.len() + 1, rng.gen_range(0..boxes.len() * 2)) as u16,
+            core::cmp::max(boxes.len() + 1, rng.gen_range(0..boxes.len() * 2)) as u16,
         );
         assert!(outputs > 0);
         assert!(sufficient_amount * (outputs as u64) <= input_sum);
@@ -667,7 +669,6 @@ mod test {
                 .map(|b| b.creation_height)
                 .max()
                 .unwrap();
-            dbg!(height);
             let mut state_context: ErgoStateContext = force_any_val();
             state_context.pre_header.height = height;
             state_context.pre_header.version = version;
diff --git a/ergo-merkle-tree/Cargo.toml b/ergo-merkle-tree/Cargo.toml
index 9482cdce0..b1529d1ec 100644
--- a/ergo-merkle-tree/Cargo.toml
+++ b/ergo-merkle-tree/Cargo.toml
@@ -10,19 +10,19 @@ description = "Merkle tree proofs"
 
 [dependencies]
 blake2 = { workspace = true }
-base16 = { workspace = true, optional = true }
+base16 = { workspace = true, features = ["std"], optional = true }
 serde = { workspace = true, optional = true }
 serde_repr = { version = "0.1.7", optional = true }
 serde_json = { workspace = true, optional = true }
-# currently thiserror is only needed for json conversion, so it's feature-gated behind json. 
+# currently thiserror is only needed for json conversion, so it's feature-gated behind json.
 # This may change in the future
-thiserror = { workspace = true, optional = true } 
+thiserror = { workspace = true, optional = true }
 itertools = { workspace = true }
-proptest-derive = {workspace = true, optional = true }
+proptest-derive = { workspace = true, optional = true }
 sigma-ser = { workspace = true }
 ergo-chain-types = { workspace = true }
 sigma-util = { workspace = true }
-proptest = { workspace = true , optional = true }
+proptest = { workspace = true, optional = true }
 
 [features]
 default = ["json"]
diff --git a/ergo-nipopow/Cargo.toml b/ergo-nipopow/Cargo.toml
index 2c21911d4..b1cd55b92 100644
--- a/ergo-nipopow/Cargo.toml
+++ b/ergo-nipopow/Cargo.toml
@@ -6,9 +6,7 @@ authors = ["Denys Zadorozhnyi <denys@zadorozhnyi.com>"]
 repository.workspace = true
 edition.workspace = true
 description = "Ergo blockchain types"
-exclude = [
-    "proptest-regressions/*"
-]
+exclude = ["proptest-regressions/*"]
 
 [lib]
 crate-type = ["cdylib", "rlib"]
@@ -29,10 +27,15 @@ ergo-chain-types = { workspace = true }
 ergo-merkle-tree = { workspace = true }
 serde = { workspace = true }
 serde_json = { workspace = true }
-proptest = { workspace = true , optional = true }
+proptest = { workspace = true, optional = true }
 
 [dev-dependencies]
 
 [features]
-default = []
-arbitrary = ["proptest", "proptest-derive", "ergo-chain-types/arbitrary", "ergotree-ir/arbitrary"]
+default = ["sigma-ser/std", "ergo-merkle-tree/json", "serde/std"]
+arbitrary = [
+    "proptest",
+    "proptest-derive",
+    "ergo-chain-types/arbitrary",
+    "ergotree-ir/arbitrary",
+]
diff --git a/ergo-p2p/src/message/handshake.rs b/ergo-p2p/src/message/handshake.rs
index 290813b47..bc3052b82 100644
--- a/ergo-p2p/src/message/handshake.rs
+++ b/ergo-p2p/src/message/handshake.rs
@@ -8,6 +8,7 @@ use crate::PeerSpec;
 /// No further communication is possible until both peers have exchanged their handshakes.
 /// peerSpec - general (declared) information about peer
 /// time     - handshake time
+#[allow(unused)]
 pub struct Handshake {
     /// Peer specification
     pub peer_spec: PeerSpec,
diff --git a/ergo-rest/src/wasm_timer/timer/heap.rs b/ergo-rest/src/wasm_timer/timer/heap.rs
index 36ee7ae82..9c2f44cb7 100644
--- a/ergo-rest/src/wasm_timer/timer/heap.rs
+++ b/ergo-rest/src/wasm_timer/timer/heap.rs
@@ -46,7 +46,6 @@ impl<T: Ord> Heap<T> {
     /// heap, but only if the element was previously not removed from the heap.
     #[allow(clippy::panic)]
     pub fn push(&mut self, t: T) -> Slot {
-        self.assert_consistent();
         let len = self.items.len();
         let slot = SlabSlot::Full { value: len };
         let slot_idx = if self.next_index == self.index.len() {
@@ -61,17 +60,14 @@ impl<T: Ord> Heap<T> {
         };
         self.items.push((t, slot_idx));
         self.percolate_up(len);
-        self.assert_consistent();
         Slot { idx: slot_idx }
     }
 
     pub fn peek(&self) -> Option<&T> {
-        self.assert_consistent();
         self.items.get(0).map(|i| &i.0)
     }
 
     pub fn pop(&mut self) -> Option<T> {
-        self.assert_consistent();
         if self.items.len() == 0 {
             return None;
         }
@@ -83,7 +79,6 @@ impl<T: Ord> Heap<T> {
 
     #[allow(clippy::panic)]
     pub fn remove(&mut self, slot: Slot) -> T {
-        self.assert_consistent();
         let empty = SlabSlot::Empty {
             next: self.next_index,
         };
@@ -102,7 +97,6 @@ impl<T: Ord> Heap<T> {
                 self.percolate_down(idx);
             }
         }
-        self.assert_consistent();
         return item;
     }
 
@@ -164,53 +158,6 @@ impl<T: Ord> Heap<T> {
         }
         return idx;
     }
-
-    #[allow(clippy::panic)]
-    fn assert_consistent(&self) {
-        if !cfg!(assert_timer_heap_consistent) {
-            return;
-        }
-
-        assert_eq!(
-            self.items.len(),
-            self.index
-                .iter()
-                .filter(|slot| {
-                    match **slot {
-                        SlabSlot::Full { .. } => true,
-                        SlabSlot::Empty { .. } => false,
-                    }
-                })
-                .count()
-        );
-
-        for (i, &(_, j)) in self.items.iter().enumerate() {
-            let index = match self.index[j] {
-                SlabSlot::Full { value } => value,
-                SlabSlot::Empty { .. } => {
-                    panic!()
-                }
-            };
-            if index != i {
-                panic!(
-                    "self.index[j] != i : i={} j={} self.index[j]={}",
-                    i, j, index
-                );
-            }
-        }
-
-        for (i, &(ref item, _)) in self.items.iter().enumerate() {
-            if i > 0 {
-                assert!(*item >= self.items[(i - 1) / 2].0, "bad at index: {}", i);
-            }
-            if let Some(left) = self.items.get(2 * i + 1) {
-                assert!(*item <= left.0, "bad left at index: {}", i);
-            }
-            if let Some(right) = self.items.get(2 * i + 2) {
-                assert!(*item <= right.0, "bad right at index: {}", i);
-            }
-        }
-    }
 }
 
 #[allow(clippy::panic)]
diff --git a/ergotree-interpreter/Cargo.toml b/ergotree-interpreter/Cargo.toml
index cb280daff..1d1067ed3 100644
--- a/ergotree-interpreter/Cargo.toml
+++ b/ergotree-interpreter/Cargo.toml
@@ -9,7 +9,7 @@ description = "ErgoTree interpreter"
 exclude = ["proptest-regressions/*"]
 
 [lib]
-crate-type = ["cdylib", "rlib"]
+crate-type = ["rlib"]
 
 [dependencies]
 sigma-util = { workspace = true }
@@ -20,7 +20,7 @@ indexmap = { workspace = true }
 k256 = { workspace = true }
 elliptic-curve = { workspace = true }
 blake2 = { workspace = true }
-rand = { workspace = true }
+rand = { workspace = true, optional = true }
 lazy_static = { workspace = true }
 thiserror = { workspace = true }
 derive_more = { workspace = true }
@@ -29,20 +29,29 @@ base16 = { workspace = true }
 proptest-derive = { workspace = true, optional = true }
 bytes = { workspace = true }
 num-bigint = { workspace = true }
-bounded-vec = { workspace = true, features = ["serde"] }
+bounded-vec = { workspace = true }
 serde = { workspace = true, optional = true }
 serde_json = { workspace = true, optional = true }
 serde_with = { workspace = true, optional = true }
 proptest = { workspace = true, optional = true }
-ergo_avltree_rust = "0.1.0"
+ergo_avltree_rust = { version = "0.1.1" }
 gf2_192 = { version = "^0.28.0", path = "../gf2_192" }
-miette = { workspace = true }
-hashbrown = "0.14.3"
-
+miette = { workspace = true, optional = true }
+hashbrown = { workspace = true }
+core2 = { workspace = true }
 [features]
-default = ["json"]
-json = ["serde", "serde_json", "serde_with", "bounded-vec/serde"]
+json = [
+    "serde",
+    "serde_json",
+    "serde_with",
+    "bounded-vec/serde",
+    "ergotree-ir/json",
+    "ergo-chain-types/json",
+]
+default = ["json", "std"]
+std = ["rand", "miette", "ergotree-ir/std"]
 arbitrary = [
+    "std",
     "proptest",
     "proptest-derive",
     "ergotree-ir/arbitrary",
diff --git a/ergotree-interpreter/src/contracts.rs b/ergotree-interpreter/src/contracts.rs
index b3e47cc07..c73b14b55 100644
--- a/ergotree-interpreter/src/contracts.rs
+++ b/ergotree-interpreter/src/contracts.rs
@@ -1,7 +1,7 @@
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
 mod tests {
-    use std::convert::TryInto;
+    use core::convert::TryInto;
 
     use crate::eval::tests::eval_out_wo_ctx;
     use ergotree_ir::chain::address::AddressEncoder;
diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs
index d043ebdee..92991843f 100644
--- a/ergotree-interpreter/src/eval.rs
+++ b/ergotree-interpreter/src/eval.rs
@@ -1,8 +1,10 @@
 //! Interpreter
+use alloc::string::{String, ToString};
+use alloc::vec::Vec;
+use core::fmt::Display;
 use ergotree_ir::ergo_tree::ErgoTree;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp;
-use std::fmt::Display;
 
 use ergotree_ir::mir::expr::Expr;
 use ergotree_ir::mir::value::Value;
@@ -103,7 +105,7 @@ pub struct ReductionDiagnosticInfo {
 }
 
 impl Display for ReductionDiagnosticInfo {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         if let Some(expr_str) = &self.pretty_printed_expr {
             writeln!(f, "Pretty printed expr:\n{}", expr_str)?;
         }
@@ -363,8 +365,6 @@ fn smethod_eval_fn(method: &SMethod) -> Result<EvalFn, EvalError> {
 #[allow(clippy::todo)]
 pub(crate) mod tests {
 
-    #![allow(dead_code)]
-
     use super::env::Env;
     use super::*;
     use ergotree_ir::mir::bin_op::BinOp;
diff --git a/ergotree-interpreter/src/eval/and.rs b/ergotree-interpreter/src/eval/and.rs
index 3cb82bd85..94e821a7e 100644
--- a/ergotree-interpreter/src/eval/and.rs
+++ b/ergotree-interpreter/src/eval/and.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec;
 use ergotree_ir::mir::and::And;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::value::Value;
diff --git a/ergotree-interpreter/src/eval/apply.rs b/ergotree-interpreter/src/eval/apply.rs
index 34020f43a..b38d233a6 100644
--- a/ergotree-interpreter/src/eval/apply.rs
+++ b/ergotree-interpreter/src/eval/apply.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec;
 use ergotree_ir::mir::apply::Apply;
 use ergotree_ir::mir::val_def::ValId;
 use ergotree_ir::mir::value::Value;
@@ -56,7 +57,7 @@ impl Evaluable for Apply {
 #[cfg(test)]
 #[allow(clippy::unwrap_used)]
 mod tests {
-    use ergotree_ir::chain::context::Context;
+    use alloc::boxed::Box;
     use ergotree_ir::mir::bin_op::BinOp;
     use ergotree_ir::mir::bin_op::RelationOp;
     use ergotree_ir::mir::block::BlockValue;
@@ -66,9 +67,8 @@ mod tests {
     use ergotree_ir::mir::val_def::ValDef;
     use ergotree_ir::mir::val_use::ValUse;
     use ergotree_ir::types::stype::SType;
-    use sigma_test_util::force_any_val;
 
-    use crate::eval::tests::eval_out;
+    use crate::eval::tests::eval_out_wo_ctx;
 
     use super::*;
 
@@ -119,7 +119,6 @@ mod tests {
         )
         .unwrap()
         .into();
-        let ctx = force_any_val::<Context>();
-        assert!(eval_out::<bool>(&apply, &ctx));
+        assert!(eval_out_wo_ctx::<bool>(&apply));
     }
 }
diff --git a/ergotree-interpreter/src/eval/atleast.rs b/ergotree-interpreter/src/eval/atleast.rs
index 625f20ae4..b56212667 100644
--- a/ergotree-interpreter/src/eval/atleast.rs
+++ b/ergotree-interpreter/src/eval/atleast.rs
@@ -1,5 +1,7 @@
-use std::convert::TryInto;
+use core::convert::TryInto;
 
+use alloc::boxed::Box;
+use alloc::vec::Vec;
 use ergotree_ir::mir::atleast::Atleast;
 use ergotree_ir::mir::constant::TryExtractFromError;
 use ergotree_ir::mir::constant::TryExtractInto;
@@ -59,7 +61,7 @@ impl Evaluable for Atleast {
 #[allow(clippy::panic)]
 #[cfg(test)]
 mod tests {
-    use std::sync::Arc;
+    use alloc::sync::Arc;
 
     use crate::eval::tests::try_eval_out_wo_ctx;
     use ergotree_ir::mir::constant::Constant;
diff --git a/ergotree-interpreter/src/eval/bin_op.rs b/ergotree-interpreter/src/eval/bin_op.rs
index e77ab254b..3043d7015 100644
--- a/ergotree-interpreter/src/eval/bin_op.rs
+++ b/ergotree-interpreter/src/eval/bin_op.rs
@@ -20,7 +20,7 @@ use crate::eval::Context;
 use crate::eval::EvalError;
 use crate::eval::Evaluable;
 
-fn arithmetic_err<T: std::fmt::Display>(
+fn arithmetic_err<T: core::fmt::Display>(
     op: &str,
     lv_raw: T,
     rv_raw: T,
@@ -34,7 +34,7 @@ fn arithmetic_err<T: std::fmt::Display>(
 
 fn eval_plus<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result<Value<'ctx>, EvalError>
 where
-    T: Num + CheckedAdd + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + std::fmt::Display,
+    T: Num + CheckedAdd + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + core::fmt::Display,
 {
     let rv_raw = rv.try_extract_into::<T>()?;
     lv_raw
@@ -45,7 +45,7 @@ where
 
 fn eval_minus<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result<Value<'ctx>, EvalError>
 where
-    T: Num + CheckedSub + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + std::fmt::Display,
+    T: Num + CheckedSub + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + core::fmt::Display,
 {
     let rv_raw = rv.try_extract_into::<T>()?;
     lv_raw
@@ -56,7 +56,7 @@ where
 
 fn eval_mul<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result<Value<'ctx>, EvalError>
 where
-    T: Num + CheckedMul + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + std::fmt::Display,
+    T: Num + CheckedMul + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + core::fmt::Display,
 {
     let rv_raw = rv.try_extract_into::<T>()?;
     lv_raw
@@ -67,7 +67,7 @@ where
 
 fn eval_div<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result<Value<'ctx>, EvalError>
 where
-    T: Num + CheckedDiv + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + std::fmt::Display,
+    T: Num + CheckedDiv + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + core::fmt::Display,
 {
     let rv_raw = rv.try_extract_into::<T>()?;
     lv_raw
@@ -78,7 +78,7 @@ where
 
 fn eval_mod<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result<Value<'ctx>, EvalError>
 where
-    T: Num + CheckedRem + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + std::fmt::Display,
+    T: Num + CheckedRem + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + core::fmt::Display,
 {
     let rv_raw = rv.try_extract_into::<T>()?;
     lv_raw
@@ -89,7 +89,7 @@ where
 
 fn eval_bit_op<'ctx, T, F>(lv_raw: T, rv: Value<'ctx>, op: F) -> Result<Value<'ctx>, EvalError>
 where
-    T: Num + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + std::fmt::Display,
+    T: Num + TryExtractFrom<Value<'ctx>> + Into<Value<'ctx>> + core::fmt::Display,
     F: FnOnce(T, T) -> T,
 {
     let rv_raw = rv.try_extract_into::<T>()?;
@@ -326,14 +326,13 @@ impl Evaluable for BinOp {
 #[allow(clippy::unwrap_used)]
 mod tests {
     use super::*;
-    use crate::eval::tests::eval_out;
-    use crate::eval::tests::try_eval_out;
-    use ergotree_ir::chain::context::Context;
+    use crate::eval::tests::eval_out_wo_ctx;
+    use crate::eval::tests::try_eval_out_wo_ctx;
+    use alloc::boxed::Box;
     use ergotree_ir::mir::constant::Constant;
     use ergotree_ir::mir::expr::Expr;
     use num_traits::Bounded;
     use proptest::prelude::*;
-    use sigma_test_util::force_any_val;
 
     fn check_eq_neq(left: Constant, right: Constant) -> bool {
         let eq_op: Expr = BinOp {
@@ -342,15 +341,13 @@ mod tests {
             right: Box::new(right.clone().into()),
         }
         .into();
-        let ctx = force_any_val::<Context>();
         let neq_op: Expr = BinOp {
             kind: BinOpKind::Relation(RelationOp::NEq),
             left: Box::new(left.into()),
             right: Box::new(right.into()),
         }
         .into();
-        let ctx1 = force_any_val::<Context>();
-        eval_out::<bool>(&eq_op, &ctx) && !eval_out::<bool>(&neq_op, &ctx1)
+        eval_out_wo_ctx::<bool>(&eq_op) && !eval_out_wo_ctx::<bool>(&neq_op)
     }
 
     #[test]
@@ -418,8 +415,7 @@ mod tests {
             ),
         }
         .into();
-        let ctx = force_any_val::<Context>();
-        assert!(eval_out::<bool>(&e, &ctx));
+        assert!(eval_out_wo_ctx::<bool>(&e));
     }
 
     #[test]
@@ -438,8 +434,7 @@ mod tests {
             ),
         }
         .into();
-        let ctx = force_any_val::<Context>();
-        assert!(!eval_out::<bool>(&e, &ctx));
+        assert!(!eval_out_wo_ctx::<bool>(&e));
     }
 
     fn eval_arith_op<T: TryExtractFrom<Value<'static>> + Into<Constant> + 'static>(
@@ -453,8 +448,7 @@ mod tests {
             right: Box::new(right.into().into()),
         }
         .into();
-        let ctx = force_any_val::<Context>();
-        try_eval_out::<T>(&expr, &ctx)
+        try_eval_out_wo_ctx::<T>(&expr)
     }
 
     fn eval_bit_op<T: TryExtractFrom<Value<'static>> + Into<Constant> + 'static>(
@@ -468,8 +462,7 @@ mod tests {
             right: Box::new(right.into().into()),
         }
         .into();
-        let ctx = force_any_val::<Context>();
-        try_eval_out::<T>(&expr, &ctx)
+        try_eval_out_wo_ctx::<T>(&expr)
     }
 
     fn eval_relation_op<T: Into<Constant>>(op: RelationOp, left: T, right: T) -> bool {
@@ -479,8 +472,7 @@ mod tests {
             right: Box::new(right.into().into()),
         }
         .into();
-        let ctx = force_any_val::<Context>();
-        eval_out::<bool>(&expr, &ctx)
+        eval_out_wo_ctx::<bool>(&expr)
     }
 
     fn eval_logical_op<T: Into<Constant>>(op: LogicalOp, left: T, right: T) -> bool {
@@ -490,8 +482,7 @@ mod tests {
             right: Box::new(right.into().into()),
         }
         .into();
-        let ctx = force_any_val::<Context>();
-        eval_out::<bool>(&expr, &ctx)
+        eval_out_wo_ctx::<bool>(&expr)
     }
 
     #[test]
diff --git a/ergotree-interpreter/src/eval/byte_array_to_bigint.rs b/ergotree-interpreter/src/eval/byte_array_to_bigint.rs
index 2be8f4110..2826af23f 100644
--- a/ergotree-interpreter/src/eval/byte_array_to_bigint.rs
+++ b/ergotree-interpreter/src/eval/byte_array_to_bigint.rs
@@ -1,4 +1,5 @@
 #![allow(clippy::unwrap_used)]
+use alloc::vec::Vec;
 use ergotree_ir::bigint256::BigInt256;
 use ergotree_ir::mir::byte_array_to_bigint::ByteArrayToBigInt;
 use ergotree_ir::mir::constant::TryExtractInto;
@@ -38,6 +39,7 @@ mod tests {
 
     use super::*;
     use crate::eval::tests::try_eval_out_wo_ctx;
+    use alloc::boxed::Box;
     use num_bigint::{BigInt, Sign, ToBigInt};
     use num_traits::{Bounded, Num, Pow};
 
diff --git a/ergotree-interpreter/src/eval/byte_array_to_long.rs b/ergotree-interpreter/src/eval/byte_array_to_long.rs
index 98d3af2a5..84a3da488 100644
--- a/ergotree-interpreter/src/eval/byte_array_to_long.rs
+++ b/ergotree-interpreter/src/eval/byte_array_to_long.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec;
 use ergotree_ir::mir::byte_array_to_long::ByteArrayToLong;
 use ergotree_ir::mir::value::Value;
 
@@ -36,6 +37,8 @@ impl Evaluable for ByteArrayToLong {
 #[allow(clippy::unwrap_used)]
 mod tests {
 
+    use alloc::boxed::Box;
+
     use super::*;
     use crate::eval::tests::try_eval_out_wo_ctx;
 
diff --git a/ergotree-interpreter/src/eval/calc_blake2b256.rs b/ergotree-interpreter/src/eval/calc_blake2b256.rs
index f8ce4a194..278c7af3e 100644
--- a/ergotree-interpreter/src/eval/calc_blake2b256.rs
+++ b/ergotree-interpreter/src/eval/calc_blake2b256.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec;
 use ergotree_ir::mir::calc_blake2b256::CalcBlake2b256;
 use ergotree_ir::mir::value::CollKind;
 use ergotree_ir::mir::value::NativeColl;
@@ -32,6 +33,7 @@ impl Evaluable for CalcBlake2b256 {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
diff --git a/ergotree-interpreter/src/eval/calc_sha256.rs b/ergotree-interpreter/src/eval/calc_sha256.rs
index e348aaacb..e68dd7cc7 100644
--- a/ergotree-interpreter/src/eval/calc_sha256.rs
+++ b/ergotree-interpreter/src/eval/calc_sha256.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec;
 use ergotree_ir::mir::calc_sha256::CalcSha256;
 use ergotree_ir::mir::value::CollKind;
 use ergotree_ir::mir::value::NativeColl;
diff --git a/ergotree-interpreter/src/eval/coll_append.rs b/ergotree-interpreter/src/eval/coll_append.rs
index ffdb1f387..cd72aad3a 100644
--- a/ergotree-interpreter/src/eval/coll_append.rs
+++ b/ergotree-interpreter/src/eval/coll_append.rs
@@ -1,5 +1,6 @@
-use std::sync::Arc;
+use alloc::sync::Arc;
 
+use alloc::vec::Vec;
 use ergotree_ir::mir::coll_append::Append;
 // use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::value::CollKind;
diff --git a/ergotree-interpreter/src/eval/coll_exists.rs b/ergotree-interpreter/src/eval/coll_exists.rs
index 7a1eb1d16..1e8e37ead 100644
--- a/ergotree-interpreter/src/eval/coll_exists.rs
+++ b/ergotree-interpreter/src/eval/coll_exists.rs
@@ -1,3 +1,5 @@
+use alloc::string::ToString;
+use alloc::vec::Vec;
 use ergotree_ir::mir::coll_exists::Exists;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::value::Value;
@@ -73,6 +75,7 @@ mod tests {
 
     use super::*;
 
+    use alloc::boxed::Box;
     use ergotree_ir::mir::bin_op::BinOp;
     use ergotree_ir::mir::bin_op::RelationOp;
     use ergotree_ir::mir::expr::Expr;
diff --git a/ergotree-interpreter/src/eval/coll_filter.rs b/ergotree-interpreter/src/eval/coll_filter.rs
index 7209d4b4f..98605275d 100644
--- a/ergotree-interpreter/src/eval/coll_filter.rs
+++ b/ergotree-interpreter/src/eval/coll_filter.rs
@@ -1,5 +1,7 @@
-use std::sync::Arc;
+use alloc::string::ToString;
+use alloc::sync::Arc;
 
+use alloc::vec::Vec;
 use ergotree_ir::mir::coll_filter::Filter;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::value::CollKind;
@@ -84,6 +86,7 @@ impl Evaluable for Filter {
 #[allow(clippy::unwrap_used)]
 #[allow(clippy::panic)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
 
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/coll_fold.rs b/ergotree-interpreter/src/eval/coll_fold.rs
index 69128b789..878d6ecc9 100644
--- a/ergotree-interpreter/src/eval/coll_fold.rs
+++ b/ergotree-interpreter/src/eval/coll_fold.rs
@@ -1,3 +1,4 @@
+use alloc::string::ToString;
 use ergotree_ir::mir::coll_fold::Fold;
 use ergotree_ir::mir::value::CollKind;
 use ergotree_ir::mir::value::NativeColl;
@@ -66,8 +67,9 @@ impl Evaluable for Fold {
 #[allow(clippy::panic)]
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
-    use std::convert::TryInto;
+    use core::convert::TryInto;
 
     use crate::eval::tests::eval_out;
     use ergotree_ir::chain::context::Context;
diff --git a/ergotree-interpreter/src/eval/coll_forall.rs b/ergotree-interpreter/src/eval/coll_forall.rs
index ccdc22076..90aaa2132 100644
--- a/ergotree-interpreter/src/eval/coll_forall.rs
+++ b/ergotree-interpreter/src/eval/coll_forall.rs
@@ -1,3 +1,5 @@
+use alloc::string::ToString;
+use alloc::vec::Vec;
 use ergotree_ir::mir::coll_forall::ForAll;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::value::Value;
@@ -73,6 +75,7 @@ mod tests {
 
     use super::*;
 
+    use alloc::boxed::Box;
     use ergotree_ir::mir::bin_op::BinOp;
     use ergotree_ir::mir::bin_op::RelationOp;
     use ergotree_ir::mir::expr::Expr;
diff --git a/ergotree-interpreter/src/eval/coll_map.rs b/ergotree-interpreter/src/eval/coll_map.rs
index 62d576fe8..08254ee51 100644
--- a/ergotree-interpreter/src/eval/coll_map.rs
+++ b/ergotree-interpreter/src/eval/coll_map.rs
@@ -1,5 +1,7 @@
-use std::sync::Arc;
+use alloc::string::ToString;
+use alloc::sync::Arc;
 
+use alloc::vec::Vec;
 use ergotree_ir::mir::coll_map::Map;
 use ergotree_ir::mir::value::CollKind;
 use ergotree_ir::mir::value::Value;
@@ -82,6 +84,7 @@ impl Evaluable for Map {
 #[allow(clippy::panic)]
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
 
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/collection.rs b/ergotree-interpreter/src/eval/collection.rs
index c7061c7b9..297f5ac4f 100644
--- a/ergotree-interpreter/src/eval/collection.rs
+++ b/ergotree-interpreter/src/eval/collection.rs
@@ -1,4 +1,4 @@
-use std::sync::Arc;
+use alloc::sync::Arc;
 
 use ergotree_ir::mir::collection::Collection;
 use ergotree_ir::mir::constant::TryExtractFromError;
@@ -46,6 +46,7 @@ impl Evaluable for Collection {
 #[allow(clippy::unwrap_used)]
 #[allow(clippy::panic)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::eval::tests::eval_out_wo_ctx;
diff --git a/ergotree-interpreter/src/eval/costs.rs b/ergotree-interpreter/src/eval/costs.rs
index 07e496199..eb9296eb6 100644
--- a/ergotree-interpreter/src/eval/costs.rs
+++ b/ergotree-interpreter/src/eval/costs.rs
@@ -6,6 +6,8 @@ use derive_more::{From, Into};
 #[derive(PartialEq, Eq, Debug, Clone, From, Into)]
 pub struct Cost(u32);
 
+// Costing types will be reintroduced later
+#[allow(dead_code)]
 #[derive(Debug)]
 pub struct Costs {
     pub eq_const_size: Cost,
diff --git a/ergotree-interpreter/src/eval/create_avl_tree.rs b/ergotree-interpreter/src/eval/create_avl_tree.rs
index 02bd94f68..385ebc717 100644
--- a/ergotree-interpreter/src/eval/create_avl_tree.rs
+++ b/ergotree-interpreter/src/eval/create_avl_tree.rs
@@ -2,13 +2,15 @@ use super::Evaluable;
 use crate::eval::env::Env;
 use crate::eval::Context;
 use crate::eval::EvalError;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
 use ergo_chain_types::ADDigest;
 use ergotree_ir::mir::avl_tree_data::{AvlTreeData, AvlTreeFlags};
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::create_avl_tree::CreateAvlTree;
 use ergotree_ir::mir::value::Value;
 use sigma_util::AsVecU8;
-use std::convert::TryFrom;
 
 impl Evaluable for CreateAvlTree {
     fn eval<'ctx>(
@@ -38,7 +40,7 @@ impl Evaluable for CreateAvlTree {
     }
 }
 
-fn map_eval_err<T: std::fmt::Debug>(e: T) -> EvalError {
+fn map_eval_err<T: core::fmt::Debug>(e: T) -> EvalError {
     EvalError::AvlTree(format!("{:?}", e))
 }
 
diff --git a/ergotree-interpreter/src/eval/decode_point.rs b/ergotree-interpreter/src/eval/decode_point.rs
index 627b9d625..12b72b2b4 100644
--- a/ergotree-interpreter/src/eval/decode_point.rs
+++ b/ergotree-interpreter/src/eval/decode_point.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec;
 use ergotree_ir::mir::decode_point::DecodePoint;
 use ergotree_ir::mir::value::Value;
 
diff --git a/ergotree-interpreter/src/eval/downcast.rs b/ergotree-interpreter/src/eval/downcast.rs
index ed34051ca..aeef9962d 100644
--- a/ergotree-interpreter/src/eval/downcast.rs
+++ b/ergotree-interpreter/src/eval/downcast.rs
@@ -1,3 +1,4 @@
+use alloc::string::ToString;
 use ergotree_ir::bigint256::BigInt256;
 use ergotree_ir::ergo_tree::ErgoTreeVersion;
 use ergotree_ir::mir::downcast::Downcast;
@@ -9,7 +10,7 @@ use crate::eval::env::Env;
 use crate::eval::Context;
 use crate::eval::EvalError;
 use crate::eval::Evaluable;
-use std::convert::TryFrom;
+use core::convert::TryFrom;
 
 fn downcast_to_bigint<'a>(in_v: Value<'a>, ctx: &Context<'_>) -> Result<Value<'a>, EvalError> {
     match in_v {
diff --git a/ergotree-interpreter/src/eval/env.rs b/ergotree-interpreter/src/eval/env.rs
index 43b7cdc4e..7fda226cc 100644
--- a/ergotree-interpreter/src/eval/env.rs
+++ b/ergotree-interpreter/src/eval/env.rs
@@ -1,6 +1,7 @@
-use std::collections::HashMap;
-use std::fmt::Display;
+use core::fmt::Display;
+use hashbrown::HashMap;
 
+use alloc::vec::Vec;
 use ergotree_ir::mir::val_def::ValId;
 use ergotree_ir::mir::value::Value;
 
@@ -57,7 +58,7 @@ impl<'ctx> Env<'ctx> {
 }
 
 impl Display for Env<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let mut keys: Vec<&ValId> = self.store.keys().collect();
         keys.sort();
         for k in keys {
diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs
index 8e17cdbe9..28dfea55d 100644
--- a/ergotree-interpreter/src/eval/error.rs
+++ b/ergotree-interpreter/src/eval/error.rs
@@ -1,8 +1,8 @@
+use alloc::boxed::Box;
+use alloc::string::String;
+use core::fmt::Debug;
+use core::fmt::Display;
 use ergotree_ir::mir::expr::SubstDeserializeError;
-use miette::miette;
-use miette::LabeledSpan;
-use std::fmt::Debug;
-use std::fmt::Display;
 
 use bounded_vec::BoundedVecOutOfBounds;
 use derive_more::TryInto;
@@ -112,8 +112,9 @@ pub struct SpannedWithSourceEvalError {
     source: String,
 }
 
+#[cfg(feature = "std")]
 impl Display for SpannedWithSourceEvalError {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let _ = miette::set_hook(Box::new(|_| {
             Box::new(
                 miette::MietteHandlerOpts::new()
@@ -126,8 +127,8 @@ impl Display for SpannedWithSourceEvalError {
             )
         }));
         let err_msg = self.error.to_string();
-        let report = miette!(
-            labels = vec![LabeledSpan::at(self.source_span, err_msg,)],
+        let report = miette::miette!(
+            labels = vec![miette::LabeledSpan::at(self.source_span, err_msg,)],
             // help = "Help msg",
             "Evaluation error"
         )
@@ -136,8 +137,16 @@ impl Display for SpannedWithSourceEvalError {
     }
 }
 
+#[cfg(not(feature = "std"))]
+impl Display for SpannedWithSourceEvalError {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "{self}")
+    }
+}
+
+#[cfg(feature = "std")]
 impl Debug for SpannedWithSourceEvalError {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let _ = miette::set_hook(Box::new(|_| {
             Box::new(
                 miette::MietteHandlerOpts::new()
@@ -150,8 +159,8 @@ impl Debug for SpannedWithSourceEvalError {
             )
         }));
         let err_msg = self.error.to_string();
-        let report = miette!(
-            labels = vec![LabeledSpan::at(self.source_span, err_msg,)],
+        let report = miette::miette!(
+            labels = vec![miette::LabeledSpan::at(self.source_span, err_msg,)],
             // help = "Help msg",
             "Evaluation error"
         )
@@ -161,6 +170,14 @@ impl Debug for SpannedWithSourceEvalError {
     }
 }
 
+#[cfg(not(feature = "std"))]
+impl Debug for SpannedWithSourceEvalError {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "{self}")?;
+        write!(f, "Env:\n{}", self.env)
+    }
+}
+
 impl EvalError {
     /// Wrap eval error with source span
     pub fn wrap(self, source_span: SourceSpan, env: Env) -> Self {
@@ -203,6 +220,8 @@ impl<T> ExtResultEvalError<T> for Result<T, EvalError> {
 #[allow(clippy::unwrap_used, unused_imports, dead_code)]
 #[cfg(test)]
 mod tests {
+    use alloc::boxed::Box;
+    use alloc::string::ToString;
     use ergotree_ir::mir::coll_by_index::ByIndex;
     use ergotree_ir::mir::global_vars::GlobalVars;
     use ergotree_ir::source_span::SourceSpan;
@@ -227,7 +246,6 @@ mod tests {
     fn check(expr: Expr, expected_tree: expect_test::Expect) {
         let mut w = PosTrackingWriter::new();
         let spanned_expr = expr.print(&mut w).unwrap();
-        dbg!(&spanned_expr);
         let ctx = force_any_val::<Context>();
         let err_raw: SpannedEvalError = try_eval_out::<i32>(&spanned_expr, &ctx)
             .err()
@@ -246,7 +264,6 @@ mod tests {
     fn check_error_span(expr: Expr, expected_span: SourceSpan) {
         let mut w = PosTrackingWriter::new();
         let spanned_expr = expr.print(&mut w).unwrap();
-        dbg!(&spanned_expr);
         let ctx = force_any_val::<Context>();
         let err_raw: SpannedEvalError = try_eval_out::<i32>(&spanned_expr, &ctx)
             .err()
diff --git a/ergotree-interpreter/src/eval/exponentiate.rs b/ergotree-interpreter/src/eval/exponentiate.rs
index 39350de7c..c1ab600bd 100644
--- a/ergotree-interpreter/src/eval/exponentiate.rs
+++ b/ergotree-interpreter/src/eval/exponentiate.rs
@@ -37,6 +37,7 @@ impl Evaluable for Exponentiate {
 #[allow(clippy::unwrap_used)]
 #[allow(clippy::panic)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs
index b2a3d8a88..5ceed31ad 100644
--- a/ergotree-interpreter/src/eval/expr.rs
+++ b/ergotree-interpreter/src/eval/expr.rs
@@ -1,5 +1,6 @@
 //! Evaluation of ErgoTree expressions
 
+use alloc::string::ToString;
 use ergotree_ir::mir::expr::Expr;
 use ergotree_ir::mir::value::Value;
 use ergotree_ir::source_span::Spanned;
diff --git a/ergotree-interpreter/src/eval/extract_amount.rs b/ergotree-interpreter/src/eval/extract_amount.rs
index a6a287bce..73661a649 100644
--- a/ergotree-interpreter/src/eval/extract_amount.rs
+++ b/ergotree-interpreter/src/eval/extract_amount.rs
@@ -25,6 +25,7 @@ impl Evaluable for ExtractAmount {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/extract_bytes.rs b/ergotree-interpreter/src/eval/extract_bytes.rs
index 17a37137e..07ab663ea 100644
--- a/ergotree-interpreter/src/eval/extract_bytes.rs
+++ b/ergotree-interpreter/src/eval/extract_bytes.rs
@@ -26,6 +26,7 @@ impl Evaluable for ExtractBytes {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs b/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs
index a84874f06..fb24cded0 100644
--- a/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs
+++ b/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs
@@ -25,6 +25,7 @@ impl Evaluable for ExtractBytesWithNoRef {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/extract_creation_info.rs b/ergotree-interpreter/src/eval/extract_creation_info.rs
index 84badbe5b..d5ec545b9 100644
--- a/ergotree-interpreter/src/eval/extract_creation_info.rs
+++ b/ergotree-interpreter/src/eval/extract_creation_info.rs
@@ -25,6 +25,7 @@ impl Evaluable for ExtractCreationInfo {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use crate::eval::tests::eval_out;
     use crate::eval::Context;
diff --git a/ergotree-interpreter/src/eval/extract_id.rs b/ergotree-interpreter/src/eval/extract_id.rs
index 5baaf5d01..55b819c7b 100644
--- a/ergotree-interpreter/src/eval/extract_id.rs
+++ b/ergotree-interpreter/src/eval/extract_id.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec;
 use ergotree_ir::mir::extract_id::ExtractId;
 use ergotree_ir::mir::value::Value;
 
@@ -28,6 +29,7 @@ impl Evaluable for ExtractId {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/extract_reg_as.rs b/ergotree-interpreter/src/eval/extract_reg_as.rs
index 05d93502f..7c991b8a7 100644
--- a/ergotree-interpreter/src/eval/extract_reg_as.rs
+++ b/ergotree-interpreter/src/eval/extract_reg_as.rs
@@ -1,5 +1,6 @@
-use std::convert::TryInto;
+use core::convert::TryInto;
 
+use alloc::boxed::Box;
 use ergotree_ir::chain::ergo_box::ErgoBox;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::extract_reg_as::ExtractRegisterAs;
@@ -47,6 +48,7 @@ impl Evaluable for ExtractRegisterAs {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::eval::tests::{eval_out, try_eval_out};
diff --git a/ergotree-interpreter/src/eval/extract_script_bytes.rs b/ergotree-interpreter/src/eval/extract_script_bytes.rs
index 3557ddee0..64cf8ea07 100644
--- a/ergotree-interpreter/src/eval/extract_script_bytes.rs
+++ b/ergotree-interpreter/src/eval/extract_script_bytes.rs
@@ -25,6 +25,7 @@ impl Evaluable for ExtractScriptBytes {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/global_vars.rs b/ergotree-interpreter/src/eval/global_vars.rs
index c94e12f80..9709fdbd4 100644
--- a/ergotree-interpreter/src/eval/global_vars.rs
+++ b/ergotree-interpreter/src/eval/global_vars.rs
@@ -1,4 +1,5 @@
 use crate::eval::Env;
+use alloc::vec::Vec;
 use ergotree_ir::mir::global_vars::GlobalVars;
 use ergotree_ir::mir::value::Value;
 use ergotree_ir::reference::Ref;
@@ -33,6 +34,7 @@ impl Evaluable for GlobalVars {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
 
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/if_op.rs b/ergotree-interpreter/src/eval/if_op.rs
index d4704d1dc..5af5c1455 100644
--- a/ergotree-interpreter/src/eval/if_op.rs
+++ b/ergotree-interpreter/src/eval/if_op.rs
@@ -26,6 +26,7 @@ impl Evaluable for If {
 mod tests {
     use super::*;
     use crate::eval::tests::eval_out_wo_ctx;
+    use alloc::boxed::Box;
     use ergotree_ir::mir::bin_op::ArithOp;
     use ergotree_ir::mir::bin_op::BinOp;
     use ergotree_ir::mir::expr::Expr;
diff --git a/ergotree-interpreter/src/eval/long_to_byte_array.rs b/ergotree-interpreter/src/eval/long_to_byte_array.rs
index 4bc654335..c904f86ac 100644
--- a/ergotree-interpreter/src/eval/long_to_byte_array.rs
+++ b/ergotree-interpreter/src/eval/long_to_byte_array.rs
@@ -26,6 +26,8 @@ impl Evaluable for LongToByteArray {
 #[cfg(test)]
 mod tests {
 
+    use alloc::{boxed::Box, vec::Vec};
+
     use super::*;
     use crate::eval::tests::eval_out_wo_ctx;
 
diff --git a/ergotree-interpreter/src/eval/method_call.rs b/ergotree-interpreter/src/eval/method_call.rs
index 4902b527a..2b42c33b9 100644
--- a/ergotree-interpreter/src/eval/method_call.rs
+++ b/ergotree-interpreter/src/eval/method_call.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec;
 use ergotree_ir::mir::method_call::MethodCall;
 use ergotree_ir::mir::value::Value;
 
diff --git a/ergotree-interpreter/src/eval/multiply_group.rs b/ergotree-interpreter/src/eval/multiply_group.rs
index f79d54bb6..aabab7bbe 100644
--- a/ergotree-interpreter/src/eval/multiply_group.rs
+++ b/ergotree-interpreter/src/eval/multiply_group.rs
@@ -30,6 +30,7 @@ impl Evaluable for MultiplyGroup {
 #[allow(clippy::unwrap_used)]
 #[allow(clippy::panic)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/negation.rs b/ergotree-interpreter/src/eval/negation.rs
index ed2f47c43..d5ed12fb2 100644
--- a/ergotree-interpreter/src/eval/negation.rs
+++ b/ergotree-interpreter/src/eval/negation.rs
@@ -15,10 +15,10 @@ impl Evaluable for Negation {
     ) -> Result<Value<'ctx>, EvalError> {
         let input_v = self.input.eval(env, ctx)?;
 
-        fn overflow_err<T: std::fmt::Display>(v: &T) -> EvalError {
+        fn overflow_err<T: core::fmt::Display>(v: &T) -> EvalError {
             EvalError::ArithmeticException(format!("Overflow on Negation of value {}", *v))
         }
-        fn neg<'ctx, T: CheckedNeg + Into<Value<'ctx>> + std::fmt::Display>(
+        fn neg<'ctx, T: CheckedNeg + Into<Value<'ctx>> + core::fmt::Display>(
             v: &T,
         ) -> Result<Value<'ctx>, EvalError> {
             v.checked_neg()
diff --git a/ergotree-interpreter/src/eval/option_get.rs b/ergotree-interpreter/src/eval/option_get.rs
index 3b872dd22..c9f702918 100644
--- a/ergotree-interpreter/src/eval/option_get.rs
+++ b/ergotree-interpreter/src/eval/option_get.rs
@@ -1,3 +1,4 @@
+use alloc::string::ToString;
 use ergotree_ir::mir::option_get::OptionGet;
 use ergotree_ir::mir::value::Value;
 
diff --git a/ergotree-interpreter/src/eval/option_is_defined.rs b/ergotree-interpreter/src/eval/option_is_defined.rs
index dfe237f2c..5b5b7896f 100644
--- a/ergotree-interpreter/src/eval/option_is_defined.rs
+++ b/ergotree-interpreter/src/eval/option_is_defined.rs
@@ -25,6 +25,7 @@ impl Evaluable for OptionIsDefined {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::OptionIsDefined;
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/or.rs b/ergotree-interpreter/src/eval/or.rs
index 349cb54a0..68be6c62f 100644
--- a/ergotree-interpreter/src/eval/or.rs
+++ b/ergotree-interpreter/src/eval/or.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::or::Or;
 use ergotree_ir::mir::value::Value;
diff --git a/ergotree-interpreter/src/eval/property_call.rs b/ergotree-interpreter/src/eval/property_call.rs
index 4b52f5052..b38d01723 100644
--- a/ergotree-interpreter/src/eval/property_call.rs
+++ b/ergotree-interpreter/src/eval/property_call.rs
@@ -20,6 +20,7 @@ impl Evaluable for PropertyCall {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::eval::tests::eval_out;
diff --git a/ergotree-interpreter/src/eval/savltree.rs b/ergotree-interpreter/src/eval/savltree.rs
index 769c2ca32..9c6065137 100644
--- a/ergotree-interpreter/src/eval/savltree.rs
+++ b/ergotree-interpreter/src/eval/savltree.rs
@@ -1,5 +1,8 @@
-use std::convert::TryFrom;
-use std::sync::Arc;
+use alloc::boxed::Box;
+use alloc::string::ToString;
+use alloc::sync::Arc;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
 
 use bytes::Bytes;
 use ergo_avltree_rust::authenticated_tree_ops::AuthenticatedTreeOps;
@@ -429,7 +432,7 @@ pub(crate) static UPDATE_EVAL_FN: EvalFn =
         }
     };
 
-fn map_eval_err<T: std::fmt::Debug>(e: T) -> EvalError {
+fn map_eval_err<T: core::fmt::Debug>(e: T) -> EvalError {
     EvalError::AvlTree(format!("{:?}", e))
 }
 
@@ -437,7 +440,7 @@ fn map_eval_err<T: std::fmt::Debug>(e: T) -> EvalError {
 #[cfg(test)]
 #[cfg(feature = "arbitrary")]
 mod tests {
-    use std::sync::Arc;
+    use alloc::sync::Arc;
 
     use ergo_avltree_rust::batch_avl_prover::BatchAVLProver;
     use ergotree_ir::{
diff --git a/ergotree-interpreter/src/eval/sbox.rs b/ergotree-interpreter/src/eval/sbox.rs
index d53511c4c..5a142607b 100644
--- a/ergotree-interpreter/src/eval/sbox.rs
+++ b/ergotree-interpreter/src/eval/sbox.rs
@@ -1,7 +1,7 @@
-use std::convert::TryInto;
-
 use crate::eval::EvalError;
 
+use alloc::boxed::Box;
+use alloc::string::ToString;
 use ergotree_ir::chain::ergo_box::ErgoBox;
 use ergotree_ir::ergo_tree::ErgoTreeVersion;
 use ergotree_ir::mir::constant::TryExtractInto;
diff --git a/ergotree-interpreter/src/eval/scoll.rs b/ergotree-interpreter/src/eval/scoll.rs
index d22e9784d..17c796d87 100644
--- a/ergotree-interpreter/src/eval/scoll.rs
+++ b/ergotree-interpreter/src/eval/scoll.rs
@@ -1,6 +1,8 @@
 use crate::eval::EvalError;
 use crate::eval::Evaluable;
 
+use alloc::string::ToString;
+use alloc::vec::Vec;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::expr::Expr;
 use ergotree_ir::mir::value::CollKind;
@@ -12,8 +14,8 @@ use ergotree_ir::types::stype::SType::SInt;
 use super::env::Env;
 use super::Context;
 use super::EvalFn;
-use std::convert::TryFrom;
-use std::sync::Arc;
+use alloc::sync::Arc;
+use core::convert::TryFrom;
 
 pub(crate) static INDEX_OF_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, args| {
     Ok(Value::Int({
@@ -169,7 +171,7 @@ pub(crate) static INDICES_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, _args| {
     }?;
     let indices_i32 = (0..input_len)
         .map(|i| Ok(Value::Int(i32::try_from(i)?)))
-        .collect::<Result<Arc<[_]>, std::num::TryFromIntError>>();
+        .collect::<Result<Arc<[_]>, core::num::TryFromIntError>>();
     match indices_i32 {
         Ok(vec_val) => match CollKind::from_collection(SInt, vec_val) {
             Ok(coll) => Ok(Value::Coll(coll)),
@@ -336,8 +338,9 @@ pub(crate) static UPDATE_MANY_EVAL_FN: EvalFn =
 #[cfg(test)]
 #[cfg(feature = "arbitrary")]
 mod tests {
-    use std::sync::Arc;
+    use alloc::sync::Arc;
 
+    use alloc::vec::Vec;
     use ergotree_ir::mir::constant::Constant;
     use ergotree_ir::mir::constant::Literal;
     use ergotree_ir::mir::expr::Expr;
diff --git a/ergotree-interpreter/src/eval/scontext.rs b/ergotree-interpreter/src/eval/scontext.rs
index 5949d3f91..106d1c599 100644
--- a/ergotree-interpreter/src/eval/scontext.rs
+++ b/ergotree-interpreter/src/eval/scontext.rs
@@ -1,4 +1,6 @@
-use std::sync::Arc;
+use alloc::boxed::Box;
+use alloc::string::ToString;
+use alloc::sync::Arc;
 
 use ergotree_ir::mir::avl_tree_data::AvlTreeData;
 use ergotree_ir::mir::avl_tree_data::AvlTreeFlags;
diff --git a/ergotree-interpreter/src/eval/sglobal.rs b/ergotree-interpreter/src/eval/sglobal.rs
index e01508659..8bba35054 100644
--- a/ergotree-interpreter/src/eval/sglobal.rs
+++ b/ergotree-interpreter/src/eval/sglobal.rs
@@ -1,4 +1,4 @@
-use std::sync::Arc;
+use alloc::{string::ToString, sync::Arc};
 
 use crate::eval::EvalError;
 
diff --git a/ergotree-interpreter/src/eval/sgroup_elem.rs b/ergotree-interpreter/src/eval/sgroup_elem.rs
index e3181fb96..b8f633192 100644
--- a/ergotree-interpreter/src/eval/sgroup_elem.rs
+++ b/ergotree-interpreter/src/eval/sgroup_elem.rs
@@ -1,5 +1,6 @@
 use crate::eval::EvalError;
 
+use alloc::vec::Vec;
 use ergo_chain_types::EcPoint;
 use ergotree_ir::mir::value::Value;
 use ergotree_ir::reference::Ref;
@@ -34,6 +35,7 @@ pub(crate) static NEGATE_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, _args| {
 #[cfg(test)]
 #[cfg(feature = "arbitrary")]
 mod tests {
+    use alloc::vec::Vec;
     use ergotree_ir::mir::expr::Expr;
     use ergotree_ir::mir::method_call::MethodCall;
     use ergotree_ir::types::sgroup_elem;
diff --git a/ergotree-interpreter/src/eval/sheader.rs b/ergotree-interpreter/src/eval/sheader.rs
index 7a537b5f4..7253c6bf3 100644
--- a/ergotree-interpreter/src/eval/sheader.rs
+++ b/ergotree-interpreter/src/eval/sheader.rs
@@ -1,7 +1,9 @@
 //! Evaluating predefined `Header` (or SHeader) type properties
 
-use std::{convert::TryInto, sync::Arc};
+use alloc::sync::Arc;
+use core::convert::TryInto;
 
+use alloc::vec::Vec;
 use ergo_chain_types::Header;
 use ergotree_ir::{bigint256::BigInt256, mir::constant::TryExtractInto};
 
@@ -92,8 +94,9 @@ pub(crate) static VOTES_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, _args| {
 #[cfg(feature = "arbitrary")]
 #[allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
 mod tests {
-    use std::convert::{TryFrom, TryInto};
+    use core::convert::{TryFrom, TryInto};
 
+    use alloc::{boxed::Box, vec::Vec};
     use ergo_chain_types::{BlockId, Digest, Digest32, EcPoint, Votes};
     use ergotree_ir::{
         bigint256::BigInt256,
diff --git a/ergotree-interpreter/src/eval/sigma_and.rs b/ergotree-interpreter/src/eval/sigma_and.rs
index 9908e6f54..a272bfbf2 100644
--- a/ergotree-interpreter/src/eval/sigma_and.rs
+++ b/ergotree-interpreter/src/eval/sigma_and.rs
@@ -1,3 +1,4 @@
+use alloc::boxed::Box;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::sigma_and::SigmaAnd;
 use ergotree_ir::mir::value::Value;
@@ -28,10 +29,11 @@ impl Evaluable for SigmaAnd {
 #[allow(clippy::unwrap_used)]
 #[allow(clippy::panic)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
+    use core::convert::TryInto;
     use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
     use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjecture;
-    use std::convert::TryInto;
 
     use crate::eval::tests::eval_out;
     use ergotree_ir::chain::context::Context;
diff --git a/ergotree-interpreter/src/eval/sigma_or.rs b/ergotree-interpreter/src/eval/sigma_or.rs
index dc15eb152..9e0454c17 100644
--- a/ergotree-interpreter/src/eval/sigma_or.rs
+++ b/ergotree-interpreter/src/eval/sigma_or.rs
@@ -1,3 +1,4 @@
+use alloc::boxed::Box;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::sigma_or::SigmaOr;
 use ergotree_ir::mir::value::Value;
@@ -28,10 +29,11 @@ impl Evaluable for SigmaOr {
 #[allow(clippy::unwrap_used)]
 #[allow(clippy::panic)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
+    use core::convert::TryInto;
     use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
     use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjecture;
-    use std::convert::TryInto;
 
     use crate::eval::tests::eval_out;
     use ergotree_ir::chain::context::Context;
diff --git a/ergotree-interpreter/src/eval/soption.rs b/ergotree-interpreter/src/eval/soption.rs
index 7ac133c12..5352e8a70 100644
--- a/ergotree-interpreter/src/eval/soption.rs
+++ b/ergotree-interpreter/src/eval/soption.rs
@@ -1,6 +1,9 @@
 use crate::eval::EvalError;
 use crate::eval::Evaluable;
 
+use alloc::boxed::Box;
+use alloc::string::ToString;
+use alloc::vec::Vec;
 use ergotree_ir::mir::value::Value;
 use ergotree_ir::types::smethod::SMethod;
 
@@ -116,6 +119,7 @@ pub fn filter_eval<'ctx>(
 #[cfg(test)]
 #[cfg(feature = "arbitrary")]
 mod tests {
+    use alloc::boxed::Box;
     use ergotree_ir::mir::bin_op::RelationOp;
     use ergotree_ir::mir::bin_op::{ArithOp, BinOp};
     use ergotree_ir::mir::constant::Constant;
diff --git a/ergotree-interpreter/src/eval/spreheader.rs b/ergotree-interpreter/src/eval/spreheader.rs
index 4066ff3eb..4ffe4d1a9 100644
--- a/ergotree-interpreter/src/eval/spreheader.rs
+++ b/ergotree-interpreter/src/eval/spreheader.rs
@@ -1,4 +1,4 @@
-use std::sync::Arc;
+use alloc::{sync::Arc, vec::Vec};
 
 use ergo_chain_types::PreHeader;
 use ergotree_ir::mir::constant::TryExtractInto;
@@ -44,7 +44,7 @@ pub(crate) static VOTES_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, _args| {
 #[cfg(feature = "arbitrary")]
 #[allow(clippy::expect_used)]
 mod tests {
-    use std::convert::{TryFrom, TryInto};
+    use core::convert::{TryFrom, TryInto};
 
     use ergo_chain_types::{BlockId, EcPoint, Votes};
     use ergotree_ir::{
diff --git a/ergotree-interpreter/src/eval/subst_const.rs b/ergotree-interpreter/src/eval/subst_const.rs
index 725063c1d..f575706b9 100644
--- a/ergotree-interpreter/src/eval/subst_const.rs
+++ b/ergotree-interpreter/src/eval/subst_const.rs
@@ -2,6 +2,8 @@ use crate::eval::env::Env;
 use crate::eval::Context;
 use crate::eval::EvalError;
 use crate::eval::Evaluable;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
 use ergotree_ir::ergo_tree::ErgoTree;
 use ergotree_ir::mir::constant::Constant;
 use ergotree_ir::mir::constant::TryExtractInto;
@@ -12,7 +14,6 @@ use ergotree_ir::mir::value::Value;
 use ergotree_ir::serialization::SigmaSerializable;
 use sigma_util::AsVecI8;
 use sigma_util::AsVecU8;
-use std::convert::TryFrom;
 
 impl Evaluable for SubstConstants {
     fn eval<'ctx>(
@@ -83,7 +84,7 @@ impl Evaluable for SubstConstants {
     }
 }
 
-fn to_misc_err<T: std::fmt::Debug>(e: T) -> EvalError {
+fn to_misc_err<T: core::fmt::Debug>(e: T) -> EvalError {
     EvalError::Misc(format!("{:?}", e))
 }
 
diff --git a/ergotree-interpreter/src/eval/tree_lookup.rs b/ergotree-interpreter/src/eval/tree_lookup.rs
index b633ff863..4a7900ae2 100644
--- a/ergotree-interpreter/src/eval/tree_lookup.rs
+++ b/ergotree-interpreter/src/eval/tree_lookup.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+use alloc::vec::Vec;
 use bytes::Bytes;
 use ergotree_ir::mir::tree_lookup::TreeLookup;
 use ergotree_ir::mir::value::Value;
@@ -60,7 +62,7 @@ impl Evaluable for TreeLookup {
     }
 }
 
-fn map_eval_err<T: std::fmt::Debug>(e: T) -> EvalError {
+fn map_eval_err<T: core::fmt::Debug>(e: T) -> EvalError {
     EvalError::AvlTree(format!("{:?}", e))
 }
 
diff --git a/ergotree-interpreter/src/eval/xor.rs b/ergotree-interpreter/src/eval/xor.rs
index ea322a3ab..a94c0f7b9 100644
--- a/ergotree-interpreter/src/eval/xor.rs
+++ b/ergotree-interpreter/src/eval/xor.rs
@@ -1,4 +1,4 @@
-use std::sync::Arc;
+use alloc::sync::Arc;
 
 use ergotree_ir::mir::value::CollKind;
 use ergotree_ir::mir::value::NativeColl;
@@ -44,7 +44,9 @@ impl Evaluable for Xor {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::eval::tests::eval_out;
+    use crate::eval::tests::{eval_out, eval_out_wo_ctx};
+    use alloc::boxed::Box;
+    use alloc::vec::Vec;
     use ergotree_ir::chain::context::Context;
     use ergotree_ir::mir::expr::Expr;
     use proptest::prelude::*;
@@ -62,8 +64,7 @@ mod tests {
         }
         .into();
 
-        let ctx = force_any_val::<Context>();
-        assert_eq!(eval_out::<Vec<i8>>(&expr, &ctx), expected_xor);
+        assert_eq!(eval_out_wo_ctx::<Vec<i8>>(&expr), expected_xor);
     }
 
     #[test]
@@ -94,8 +95,7 @@ mod tests {
         }
         .into();
 
-        let ctx = force_any_val::<Context>();
-        assert_eq!(eval_out::<Vec<i8>>(&expr, &ctx), expected_xor);
+        assert_eq!(eval_out_wo_ctx::<Vec<i8>>(&expr), expected_xor);
     }
 
     #[test]
@@ -110,8 +110,7 @@ mod tests {
         }
         .into();
 
-        let ctx = force_any_val::<Context>();
-        assert_eq!(eval_out::<Vec<i8>>(&expr, &ctx), expected_xor);
+        assert_eq!(eval_out_wo_ctx::<Vec<i8>>(&expr), expected_xor);
     }
 
     #[test]
@@ -126,8 +125,7 @@ mod tests {
         }
         .into();
 
-        let ctx = force_any_val::<Context>();
-        assert_eq!(eval_out::<Vec<i8>>(&expr, &ctx), expected_xor);
+        assert_eq!(eval_out_wo_ctx::<Vec<i8>>(&expr), expected_xor);
     }
 
     proptest! {
@@ -143,8 +141,7 @@ mod tests {
             }
             .into();
 
-            let ctx = force_any_val::<Context>();
-            assert_eq!(&eval_out::<Vec<i8>>(&expr, &ctx)[..], &expected_xor[..]);
+            assert_eq!(&eval_out_wo_ctx::<Vec<i8>>(&expr)[..], &expected_xor[..]);
         }
     }
 }
diff --git a/ergotree-interpreter/src/eval/xor_of.rs b/ergotree-interpreter/src/eval/xor_of.rs
index 52ad3d2c1..e55c0586a 100644
--- a/ergotree-interpreter/src/eval/xor_of.rs
+++ b/ergotree-interpreter/src/eval/xor_of.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec;
 use ergotree_ir::mir::constant::TryExtractInto;
 use ergotree_ir::mir::value::Value;
 
diff --git a/ergotree-interpreter/src/json/hint.rs b/ergotree-interpreter/src/json/hint.rs
index 5c3f1ddb8..513130802 100644
--- a/ergotree-interpreter/src/json/hint.rs
+++ b/ergotree-interpreter/src/json/hint.rs
@@ -1,6 +1,9 @@
-use std::convert::TryFrom;
-use std::num::ParseIntError;
-use std::str::FromStr;
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::num::ParseIntError;
+use core::str::FromStr;
 
 use ergo_chain_types::Base16DecodedBytes;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
diff --git a/ergotree-interpreter/src/lib.rs b/ergotree-interpreter/src/lib.rs
index 05932db52..e808bf87d 100644
--- a/ergotree-interpreter/src/lib.rs
+++ b/ergotree-interpreter/src/lib.rs
@@ -1,5 +1,6 @@
 //! ErgoTree interpreter
 
+#![cfg_attr(not(feature = "std"), no_std)]
 // Coding conventions
 #![forbid(unsafe_code)]
 #![allow(clippy::needless_lifetimes)]
@@ -20,6 +21,9 @@
 #![deny(clippy::unreachable)]
 #![deny(clippy::panic)]
 
+#[macro_use]
+extern crate alloc;
+
 mod contracts;
 
 pub mod eval;
diff --git a/ergotree-interpreter/src/sigma_protocol.rs b/ergotree-interpreter/src/sigma_protocol.rs
index 6f4b4a03a..fb10dc8cf 100644
--- a/ergotree-interpreter/src/sigma_protocol.rs
+++ b/ergotree-interpreter/src/sigma_protocol.rs
@@ -7,6 +7,7 @@ pub mod prover;
 pub mod verifier;
 
 pub(crate) mod challenge;
+#[cfg(feature = "std")]
 mod crypto_utils;
 pub mod dht_protocol;
 pub mod dlog_protocol;
@@ -18,9 +19,11 @@ pub mod unchecked_tree;
 pub mod unproven_tree;
 pub mod wscalar;
 
-use std::array::TryFromSliceError;
-use std::convert::TryFrom;
-use std::convert::TryInto;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::array::TryFromSliceError;
+use core::convert::TryFrom;
+use core::convert::TryInto;
 
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
 
diff --git a/ergotree-interpreter/src/sigma_protocol/challenge.rs b/ergotree-interpreter/src/sigma_protocol/challenge.rs
index 11ab1ad5b..9bb150395 100644
--- a/ergotree-interpreter/src/sigma_protocol/challenge.rs
+++ b/ergotree-interpreter/src/sigma_protocol/challenge.rs
@@ -1,24 +1,26 @@
 use super::{fiat_shamir::FiatShamirHash, SOUNDNESS_BYTES};
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
 use ergotree_ir::serialization::sigma_byte_reader::SigmaByteRead;
 use ergotree_ir::serialization::sigma_byte_writer::SigmaByteWrite;
 #[cfg(feature = "arbitrary")]
 use proptest_derive::Arbitrary;
-use std::convert::TryFrom;
 
 /// Challenge in Sigma protocol
 #[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
 #[derive(PartialEq, Eq, Clone)]
-#[cfg(feature = "json")]
-#[derive(serde::Serialize, serde::Deserialize)]
+#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
 pub struct Challenge(pub(crate) FiatShamirHash);
 
-impl std::fmt::Debug for Challenge {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Debug for Challenge {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         "Challenge:***".fmt(f)
     }
 }
 
 impl Challenge {
+    #[cfg(feature = "std")]
     pub fn secure_random() -> Self {
         Self(FiatShamirHash::secure_random())
     }
@@ -35,12 +37,12 @@ impl Challenge {
         FiatShamirHash::try_from(res.as_slice()).unwrap().into()
     }
 
-    pub fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> Result<(), std::io::Error> {
+    pub fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> Result<(), core2::io::Error> {
         w.write_all(self.0 .0.as_ref())?;
         Ok(())
     }
 
-    pub fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, std::io::Error> {
+    pub fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, core2::io::Error> {
         let mut chal_bytes: [u8; super::SOUNDNESS_BYTES] = [0; super::SOUNDNESS_BYTES];
         r.read_exact(&mut chal_bytes)?;
         Ok(Challenge::from(FiatShamirHash(Box::new(chal_bytes))))
diff --git a/ergotree-interpreter/src/sigma_protocol/dht_protocol.rs b/ergotree-interpreter/src/sigma_protocol/dht_protocol.rs
index 637550bc7..fefcf236b 100644
--- a/ergotree-interpreter/src/sigma_protocol/dht_protocol.rs
+++ b/ergotree-interpreter/src/sigma_protocol/dht_protocol.rs
@@ -2,6 +2,8 @@
 
 use super::wscalar::Wscalar;
 use super::ProverMessage;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
 use ergo_chain_types::EcPoint;
 use ergotree_ir::serialization::SigmaSerializable;
 
@@ -47,13 +49,11 @@ pub struct SecondDhTupleProverMessage {
 /// Interactive prover
 pub mod interactive_prover {
 
-    use std::ops::Mul;
+    use core::ops::Mul;
 
     use super::*;
-    use crate::sigma_protocol::crypto_utils;
     use crate::sigma_protocol::private_input::DhTupleProverInput;
     use crate::sigma_protocol::Challenge;
-    use ergotree_ir::sigma_protocol::dlog_group;
     use ergotree_ir::sigma_protocol::sigma_boolean::ProveDhTuple;
     use k256::Scalar;
 
@@ -61,13 +61,17 @@ pub mod interactive_prover {
     /// For every leaf marked “simulated”, use the simulator of the sigma protocol for that leaf
     /// to compute the commitment "a" and the response "z", given the challenge "e" that
     /// is already stored in the leaf
+    #[cfg(feature = "std")]
     pub(crate) fn simulate(
         public_input: &ProveDhTuple,
         challenge: &Challenge,
     ) -> (FirstDhTupleProverMessage, SecondDhTupleProverMessage) {
         use ergo_chain_types::ec_point::exponentiate;
+        use ergotree_ir::sigma_protocol::dlog_group;
         //SAMPLE a random z <- Zq
-        let z = dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng());
+        let z = dlog_group::random_scalar_in_group_range(
+            crate::sigma_protocol::crypto_utils::secure_rng(),
+        );
 
         // COMPUTE a = g^z*u^(-e) and b = h^z*v^{-e}  (where -e here means -e mod q)
         let e: Scalar = challenge.clone().into();
@@ -89,9 +93,13 @@ pub mod interactive_prover {
     /// that leaf to compute the necessary randomness "r" and the commitment "a"
     ///
     /// In this case (DH tuple) "a" is also a tuple
+    #[cfg(feature = "std")]
     pub fn first_message(public_input: &ProveDhTuple) -> (Wscalar, FirstDhTupleProverMessage) {
         use ergo_chain_types::ec_point::exponentiate;
-        let r = dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng());
+        use ergotree_ir::sigma_protocol::dlog_group;
+        let r = dlog_group::random_scalar_in_group_range(
+            crate::sigma_protocol::crypto_utils::secure_rng(),
+        );
         let a = exponentiate(&public_input.g, &r);
         let b = exponentiate(&public_input.h, &r);
         (r.into(), FirstDhTupleProverMessage::new(a, b))
diff --git a/ergotree-interpreter/src/sigma_protocol/dlog_protocol.rs b/ergotree-interpreter/src/sigma_protocol/dlog_protocol.rs
index effcf21f4..55e02e87e 100644
--- a/ergotree-interpreter/src/sigma_protocol/dlog_protocol.rs
+++ b/ergotree-interpreter/src/sigma_protocol/dlog_protocol.rs
@@ -2,6 +2,8 @@
 
 use super::wscalar::Wscalar;
 use super::ProverMessage;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
 use ergo_chain_types::EcPoint;
 use ergotree_ir::serialization::SigmaSerializable;
 
@@ -38,10 +40,10 @@ pub struct SecondDlogProverMessage {
 
 /// Interactive prover
 pub mod interactive_prover {
-    use std::ops::Mul;
+    use alloc::boxed::Box;
+    use core::ops::Mul;
 
     use super::{FirstDlogProverMessage, SecondDlogProverMessage};
-    use crate::sigma_protocol::crypto_utils;
     use crate::sigma_protocol::wscalar::Wscalar;
     use crate::sigma_protocol::{private_input::DlogProverInput, Challenge};
     use blake2::Blake2b;
@@ -52,7 +54,6 @@ pub mod interactive_prover {
         EcPoint,
     };
     use ergotree_ir::serialization::SigmaSerializable;
-    use ergotree_ir::sigma_protocol::dlog_group;
     use ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
     use k256::elliptic_curve::ops::Reduce;
     use k256::{ProjectivePoint, Scalar};
@@ -61,12 +62,16 @@ pub mod interactive_prover {
     /// For every leaf marked “simulated”, use the simulator of the sigma protocol for that leaf
     /// to compute the commitment "a" and the response "z", given the challenge "e" that
     /// is already stored in the leaf
+    #[cfg(feature = "std")]
     pub(crate) fn simulate(
         public_input: &ProveDlog,
         challenge: &Challenge,
     ) -> (FirstDlogProverMessage, SecondDlogProverMessage) {
+        use ergotree_ir::sigma_protocol::dlog_group;
         //SAMPLE a random z <- Zq
-        let z = dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng());
+        let z = dlog_group::random_scalar_in_group_range(
+            crate::sigma_protocol::crypto_utils::secure_rng(),
+        );
 
         //COMPUTE a = g^z*h^(-e)  (where -e here means -e mod q)
         let e: Scalar = challenge.clone().into();
@@ -83,8 +88,12 @@ pub mod interactive_prover {
     /// Step 6 from <https://ergoplatform.org/docs/ErgoScript.pdf>
     /// For every leaf marked “real”, use the first prover step of the sigma protocol for
     /// that leaf to compute the necessary randomness "r" and the commitment "a"
+    #[cfg(feature = "std")]
     pub fn first_message() -> (Wscalar, FirstDlogProverMessage) {
-        let r = dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng());
+        use ergotree_ir::sigma_protocol::dlog_group;
+        let r = dlog_group::random_scalar_in_group_range(
+            crate::sigma_protocol::crypto_utils::secure_rng(),
+        );
         let g = generator();
         let a = exponentiate(&g, &r);
         (r.into(), FirstDlogProverMessage { a: a.into() })
diff --git a/ergotree-interpreter/src/sigma_protocol/fiat_shamir.rs b/ergotree-interpreter/src/sigma_protocol/fiat_shamir.rs
index a64e422f4..288b8e06b 100644
--- a/ergotree-interpreter/src/sigma_protocol/fiat_shamir.rs
+++ b/ergotree-interpreter/src/sigma_protocol/fiat_shamir.rs
@@ -1,10 +1,16 @@
 //! Fiat-Shamir transformation
 
-use super::crypto_utils::secure_random_bytes;
 use super::proof_tree::ProofTreeKind;
 use crate::sigma_protocol::unchecked_tree::{UncheckedConjecture, UncheckedTree};
 use crate::sigma_protocol::unproven_tree::{UnprovenConjecture, UnprovenTree};
 use crate::sigma_protocol::ProverMessage;
+use alloc::boxed::Box;
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec::Vec;
+use core::array::TryFromSliceError;
+use core::convert::{TryFrom, TryInto};
+use core::fmt::Formatter;
 use ergo_chain_types::{Base16DecodedBytes, Base16EncodedBytes};
 use ergotree_ir::ergo_tree::{ErgoTree, ErgoTreeHeader};
 use ergotree_ir::mir::expr::Expr;
@@ -13,9 +19,6 @@ use ergotree_ir::serialization::sigma_byte_writer::SigmaByteWriter;
 use ergotree_ir::serialization::SigmaSerializable;
 use ergotree_ir::sigma_protocol::sigma_boolean::{SigmaBoolean, SigmaProp};
 use sigma_util::hash::blake2b256_hash;
-use std::array::TryFromSliceError;
-use std::convert::{TryFrom, TryInto};
-use std::fmt::Formatter;
 use thiserror::Error;
 
 #[cfg(feature = "arbitrary")]
@@ -38,9 +41,10 @@ use super::SOUNDNESS_BYTES;
 pub struct FiatShamirHash(pub Box<[u8; SOUNDNESS_BYTES]>);
 
 impl FiatShamirHash {
+    #[cfg(feature = "std")]
     pub fn secure_random() -> Self {
         #[allow(clippy::unwrap_used)] // since we set the correct size
-        secure_random_bytes(SOUNDNESS_BYTES)
+        super::crypto_utils::secure_random_bytes(SOUNDNESS_BYTES)
             .as_slice()
             .try_into()
             .unwrap()
@@ -85,8 +89,8 @@ impl TryFrom<&[u8]> for FiatShamirHash {
     }
 }
 
-impl std::fmt::Debug for FiatShamirHash {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Debug for FiatShamirHash {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         f.write_str("FSH:")?;
         f.write_str(&base16::encode_lower(&(*self.0)))
     }
@@ -95,10 +99,10 @@ impl std::fmt::Debug for FiatShamirHash {
 /// Invalid byte array size
 #[derive(Error, Debug)]
 #[error("Invalid byte array size ({0})")]
-pub struct FiatShamirHashError(std::array::TryFromSliceError);
+pub struct FiatShamirHashError(core::array::TryFromSliceError);
 
-impl From<std::array::TryFromSliceError> for FiatShamirHashError {
-    fn from(err: std::array::TryFromSliceError) -> Self {
+impl From<core::array::TryFromSliceError> for FiatShamirHashError {
+    fn from(err: core::array::TryFromSliceError) -> Self {
         FiatShamirHashError(err)
     }
 }
@@ -122,8 +126,14 @@ pub(crate) fn fiat_shamir_tree_to_bytes(
 pub enum FiatShamirTreeSerializationError {
     #[error("empty commitment in leaf with proposition {0:?} ")]
     EmptyCommitmentInLeaf(SigmaBoolean),
-    #[error("io errro {0:?} ")]
-    IoError(#[from] std::io::Error),
+    #[error("io errror {0:?} ")]
+    IoError(String),
+}
+
+impl From<core2::io::Error> for FiatShamirTreeSerializationError {
+    fn from(error: core2::io::Error) -> FiatShamirTreeSerializationError {
+        FiatShamirTreeSerializationError::IoError(error.to_string())
+    }
 }
 
 fn fiat_shamir_write_bytes<W: SigmaByteWrite>(
diff --git a/ergotree-interpreter/src/sigma_protocol/gf2_192.rs b/ergotree-interpreter/src/sigma_protocol/gf2_192.rs
index 3be2ba24a..3ca01f18a 100644
--- a/ergotree-interpreter/src/sigma_protocol/gf2_192.rs
+++ b/ergotree-interpreter/src/sigma_protocol/gf2_192.rs
@@ -1,6 +1,7 @@
-use std::convert::TryFrom;
+use core::convert::TryFrom;
 
 use super::{challenge::Challenge, fiat_shamir::FiatShamirHash, SOUNDNESS_BYTES};
+use alloc::{boxed::Box, vec::Vec};
 use gf2_192::{
     gf2_192::Gf2_192,
     gf2_192poly::{CoefficientsByteRepr, Gf2_192Poly},
diff --git a/ergotree-interpreter/src/sigma_protocol/private_input.rs b/ergotree-interpreter/src/sigma_protocol/private_input.rs
index 09ba86d8e..4b8ebed3d 100644
--- a/ergotree-interpreter/src/sigma_protocol/private_input.rs
+++ b/ergotree-interpreter/src/sigma_protocol/private_input.rs
@@ -1,10 +1,10 @@
 //! Private input types for the prover's secrets
-use std::convert::TryInto;
-use std::fmt::Formatter;
+use core::convert::TryInto;
+use core::fmt::Formatter;
 
+use alloc::vec::Vec;
 use ergo_chain_types::EcPoint;
 use ergotree_ir::serialization::SigmaSerializable;
-use ergotree_ir::sigma_protocol::dlog_group;
 use ergotree_ir::sigma_protocol::sigma_boolean::ProveDhTuple;
 use ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
 
@@ -16,7 +16,6 @@ use k256::elliptic_curve::PrimeField;
 use num_bigint::BigUint;
 use num_traits::ToPrimitive;
 
-use super::crypto_utils;
 use super::wscalar::Wscalar;
 
 /// Secret key of discrete logarithm signature protocol
@@ -28,8 +27,8 @@ pub struct DlogProverInput {
     pub w: Wscalar,
 }
 
-impl std::fmt::Debug for DlogProverInput {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Debug for DlogProverInput {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         // to avoid leaking it in error messages, logs, etc.
         "DLOGPI:***".fmt(f)
     }
@@ -40,9 +39,13 @@ impl DlogProverInput {
     pub const SIZE_BYTES: usize = 32;
 
     /// generates random secret in the range [0, n), where n is DLog group order.
+    #[cfg(feature = "std")]
     pub fn random() -> DlogProverInput {
         DlogProverInput {
-            w: dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng()).into(),
+            w: ergotree_ir::sigma_protocol::dlog_group::random_scalar_in_group_range(
+                super::crypto_utils::secure_rng(),
+            )
+            .into(),
         }
     }
 
@@ -56,8 +59,8 @@ impl DlogProverInput {
 
     /// Attempts to parse the given Base16-encoded byte array as an SEC-1-encoded scalar(secret key).
     /// Returns None if the byte array does not contain a big-endian integer in the range [0, modulus).
-    pub fn from_base16_str(str: String) -> Option<DlogProverInput> {
-        base16::decode(&str)
+    pub fn from_base16_str(str: &str) -> Option<DlogProverInput> {
+        base16::decode(str)
             .ok()
             .and_then(|bytes| bytes.as_slice().try_into().ok().map(Self::from_bytes))
             .flatten()
@@ -116,8 +119,8 @@ pub struct DhTupleProverInput {
     pub common_input: ProveDhTuple,
 }
 
-impl std::fmt::Debug for DhTupleProverInput {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Debug for DhTupleProverInput {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         // to avoid leaking it in error messages, logs, etc.
         "DHTPI:***".fmt(f)
     }
@@ -129,14 +132,16 @@ impl DhTupleProverInput {
 
     /// Create random secret and Diffie-Hellman tuple
     #[allow(clippy::many_single_char_names)]
+    #[cfg(feature = "std")]
     pub fn random() -> DhTupleProverInput {
         use ergo_chain_types::ec_point::{exponentiate, generator};
+        use ergotree_ir::sigma_protocol::dlog_group;
         let g = generator();
         let h = exponentiate(
             &generator(),
-            &dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng()),
+            &dlog_group::random_scalar_in_group_range(super::crypto_utils::secure_rng()),
         );
-        let w = dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng());
+        let w = dlog_group::random_scalar_in_group_range(super::crypto_utils::secure_rng());
         let u = exponentiate(&g, &w);
         let v = exponentiate(&h, &w);
         let common_input = ProveDhTuple::new(g, h, u, v);
diff --git a/ergotree-interpreter/src/sigma_protocol/proof_tree.rs b/ergotree-interpreter/src/sigma_protocol/proof_tree.rs
index cef7af695..887ba375a 100644
--- a/ergotree-interpreter/src/sigma_protocol/proof_tree.rs
+++ b/ergotree-interpreter/src/sigma_protocol/proof_tree.rs
@@ -2,7 +2,7 @@
 
 extern crate derive_more;
 
-use std::fmt::Debug;
+use core::fmt::Debug;
 
 use derive_more::From;
 use derive_more::TryInto;
diff --git a/ergotree-interpreter/src/sigma_protocol/prover.rs b/ergotree-interpreter/src/sigma_protocol/prover.rs
index b00a2de87..7a3193131 100644
--- a/ergotree-interpreter/src/sigma_protocol/prover.rs
+++ b/ergotree-interpreter/src/sigma_protocol/prover.rs
@@ -6,10 +6,9 @@ pub mod hint;
 
 use crate::eval::reduce_to_crypto;
 use crate::eval::ReductionDiagnosticInfo;
-use crate::sigma_protocol::crypto_utils::secure_random_bytes;
+use crate::sigma_protocol::dht_protocol;
 use crate::sigma_protocol::fiat_shamir::fiat_shamir_hash_fn;
 use crate::sigma_protocol::fiat_shamir::fiat_shamir_tree_to_bytes;
-use crate::sigma_protocol::gf2_192::gf2_192poly_from_byte_array;
 use crate::sigma_protocol::proof_tree::ProofTree;
 use crate::sigma_protocol::unchecked_tree::{UncheckedDhTuple, UncheckedLeaf};
 use crate::sigma_protocol::unproven_tree::CandUnproven;
@@ -18,14 +17,13 @@ use crate::sigma_protocol::unproven_tree::NodePosition;
 use crate::sigma_protocol::unproven_tree::UnprovenDhTuple;
 use crate::sigma_protocol::Challenge;
 use crate::sigma_protocol::UnprovenLeaf;
-use crate::sigma_protocol::SOUNDNESS_BYTES;
-use crate::sigma_protocol::{crypto_utils, dht_protocol};
+use alloc::vec::Vec;
+use core::convert::TryInto;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjectureItems;
 use gf2_192::gf2_192poly::Gf2_192Poly;
 use gf2_192::gf2_192poly::Gf2_192PolyError;
 use gf2_192::Gf2_192Error;
-use std::convert::TryInto;
 
 use ergotree_ir::ergo_tree::ErgoTree;
 use ergotree_ir::ergo_tree::ErgoTreeError;
@@ -54,9 +52,6 @@ use super::FirstProverMessage::FirstDlogProverMessage;
 use crate::eval::EvalError;
 use ergotree_ir::chain::context::Context;
 
-use crate::sigma_protocol::dht_protocol::SecondDhTupleProverMessage;
-use crate::sigma_protocol::dlog_protocol::SecondDlogProverMessage;
-use ergotree_ir::sigma_protocol::dlog_group;
 use thiserror::Error;
 
 /// Prover errors
@@ -95,6 +90,9 @@ pub enum ProverError {
     /// Error while tree serialization for Fiat-Shamir hash
     #[error("Fiat-Shamir tree serialization error: {0}")]
     FiatShamirTreeSerializationError(FiatShamirTreeSerializationError),
+    /// Unsupported operation
+    #[error("RNG is not available in no_std environments, can't generate signature without Hint")]
+    Unsupported,
 }
 
 impl From<ErgoTreeError> for ProverError {
@@ -458,21 +456,32 @@ fn step4_real_conj(
         //real OR Threshold case
         UnprovenConjecture::CorUnproven(_) | UnprovenConjecture::CthresholdUnproven(_) => {
             let new_children = cast_to_unp(uc.children())?
-                .mapped(|c| {
+                .try_mapped(|c| -> Result<_, ProverError> {
                     if c.is_real() {
-                        c
+                        Ok(c)
                     } else {
                         // take challenge from previously done proof stored in the hints bag,
                         // or generate random challenge for simulated child
-                        let new_challenge: Challenge = hints_bag
+                        let new_challenge: Challenge = if let Some(new_challenge) = hints_bag
                             .proofs()
                             .into_iter()
                             .find(|p| p.position() == c.position())
                             .map(|p| p.challenge().clone())
-                            .unwrap_or_else(Challenge::secure_random);
-                        c.with_challenge(new_challenge)
+                        {
+                            new_challenge
+                        } else {
+                            #[cfg(feature = "std")]
+                            {
+                                Challenge::secure_random()
+                            }
+                            #[cfg(not(feature = "std"))]
+                            {
+                                return Err(ProverError::Unsupported);
+                            }
+                        };
+                        Ok(c.with_challenge(new_challenge))
                     }
-                })
+                })?
                 .mapped(|c| c.into());
             Ok(Some(
                 uc.with_children(new_children).into(), // CorUnproven {
@@ -507,6 +516,7 @@ fn step4_simulated_and_conj(cand: CandUnproven) -> Result<Option<ProofTree>, Pro
     }
 }
 
+#[cfg(feature = "std")]
 fn step4_simulated_or_conj(cor: CorUnproven) -> Result<Option<ProofTree>, ProverError> {
     // If the node is OR, then each of its children except one gets a fresh uniformly random
     // challenge in {0,1}^t. The remaining child gets a challenge computed as an XOR of the challenges of all
@@ -551,10 +561,16 @@ fn step4_simulated_or_conj(cor: CorUnproven) -> Result<Option<ProofTree>, Prover
         ))
     }
 }
+#[cfg(not(feature = "std"))]
+fn step4_simulated_or_conj(_cor: CorUnproven) -> Result<Option<ProofTree>, ProverError> {
+    Err(ProverError::Unsupported)
+}
 
+#[cfg(feature = "std")]
 fn step4_simulated_threshold_conj(
     ct: CthresholdUnproven,
 ) -> Result<Option<ProofTree>, ProverError> {
+    use crate::sigma_protocol::gf2_192::gf2_192poly_from_byte_array;
     // The faster algorithm is as follows. Pick n-k fresh uniformly random values
     // q_1, ..., q_{n-k} from {0,1}^t and let q_0=e_0.
     // Viewing 1, 2, ..., n and q_0, ..., q_{n-k} as elements of GF(2^t),
@@ -566,7 +582,7 @@ fn step4_simulated_threshold_conj(
         let n = ct.children.len();
         let q = gf2_192poly_from_byte_array(
             challenge,
-            secure_random_bytes(SOUNDNESS_BYTES * (n - ct.k as usize)),
+            super::crypto_utils::secure_random_bytes(super::SOUNDNESS_BYTES * (n - ct.k as usize)),
         )?;
         let new_children = unproven_children
             .enumerated()
@@ -588,6 +604,13 @@ fn step4_simulated_threshold_conj(
     }
 }
 
+#[cfg(not(feature = "std"))]
+fn step4_simulated_threshold_conj(
+    _ct: CthresholdUnproven,
+) -> Result<Option<ProofTree>, ProverError> {
+    Err(ProverError::Unsupported)
+}
+
 fn step5_schnorr(
     us: UnprovenSchnorr,
     hints_bag: &HintsBag,
@@ -615,6 +638,7 @@ fn step5_schnorr(
             .into();
             pt
         }
+        #[cfg(feature = "std")]
         None => {
             if us.simulated {
                 // Step 5 (simulated leaf -- complete the simulation)
@@ -646,6 +670,8 @@ fn step5_schnorr(
                 ))
             }?
         }
+        #[cfg(not(feature = "std"))]
+        None => return Err(ProverError::Unsupported),
     };
     Ok(Some(res))
 }
@@ -678,6 +704,7 @@ fn step5_diffie_hellman_tuple(
         .unwrap_or_else(|| {
             if dhu.simulated {
                 // Step 5 (simulated leaf -- complete the simulation)
+                #[cfg(feature = "std")]
                 if let Some(dhu_challenge) = dhu.challenge_opt.clone() {
                     let (fm, sm) = dht_protocol::interactive_prover::simulate(
                         &dhu.proposition,
@@ -693,7 +720,12 @@ fn step5_diffie_hellman_tuple(
                 } else {
                     Err(ProverError::SimulatedLeafWithoutChallenge)
                 }
+                #[cfg(not(feature = "std"))]
+                return Err(ProverError::Unsupported);
+
             } else {
+                #[cfg(feature = "std")]
+                {
                 // Step 6 -- compute the commitment
                 let (r, fm) =
                     dht_protocol::interactive_prover::first_message(&dhu.proposition);
@@ -703,6 +735,11 @@ fn step5_diffie_hellman_tuple(
                     ..dhu.clone()
                 }
                     .into())
+                }
+                #[cfg(not(feature = "std"))]
+                {
+                    Err(ProverError::Unsupported)
+                }
             }
         });
     Ok(Some(res?))
@@ -919,9 +956,19 @@ fn step9_real_schnorr<P: Prover + ?Sized>(
                     }
                 }
                 None => {
-                    let bs =
-                        dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng()).into();
-                    SecondDlogProverMessage { z: bs }
+                    #[cfg(feature = "std")]
+                    {
+                        let bs =
+                            ergotree_ir::sigma_protocol::dlog_group::random_scalar_in_group_range(
+                                crate::sigma_protocol::crypto_utils::secure_rng(),
+                            )
+                            .into();
+                        dlog_protocol::SecondDlogProverMessage { z: bs }
+                    }
+                    #[cfg(not(feature = "std"))]
+                    {
+                        return Err(ProverError::Unsupported);
+                    }
                 }
             },
         };
@@ -996,9 +1043,19 @@ fn step9_real_dh_tuple<P: Prover + ?Sized>(
                     }
                 }
                 None => {
-                    let z =
-                        dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng()).into();
-                    SecondDhTupleProverMessage { z }
+                    #[cfg(feature = "std")]
+                    {
+                        let z =
+                            ergotree_ir::sigma_protocol::dlog_group::random_scalar_in_group_range(
+                                super::crypto_utils::secure_rng(),
+                            )
+                            .into();
+                        dht_protocol::SecondDhTupleProverMessage { z }
+                    }
+                    #[cfg(not(feature = "std"))]
+                    {
+                        return Err(ProverError::Unsupported);
+                    }
                 }
             },
         };
@@ -1205,6 +1262,7 @@ mod tests {
     use super::*;
     use crate::sigma_protocol::private_input::DhTupleProverInput;
     use crate::sigma_protocol::private_input::DlogProverInput;
+    use core::convert::TryFrom;
     use ergotree_ir::mir::atleast::Atleast;
     use ergotree_ir::mir::collection::Collection;
     use ergotree_ir::mir::constant::Constant;
@@ -1215,7 +1273,6 @@ mod tests {
     use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp;
     use ergotree_ir::types::stype::SType;
     use sigma_test_util::force_any_val;
-    use std::convert::TryFrom;
 
     #[test]
     fn test_prove_true_prop() {
diff --git a/ergotree-interpreter/src/sigma_protocol/prover/hint.rs b/ergotree-interpreter/src/sigma_protocol/prover/hint.rs
index 5e59d9847..eadd08940 100644
--- a/ergotree-interpreter/src/sigma_protocol/prover/hint.rs
+++ b/ergotree-interpreter/src/sigma_protocol/prover/hint.rs
@@ -1,5 +1,6 @@
 //! Hints for a prover which helps the prover to prove a statement.
 
+use alloc::vec::Vec;
 use derive_more::From;
 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
 
diff --git a/ergotree-interpreter/src/sigma_protocol/prover/prover_result.rs b/ergotree-interpreter/src/sigma_protocol/prover/prover_result.rs
index be47c51ea..186222472 100644
--- a/ergotree-interpreter/src/sigma_protocol/prover/prover_result.rs
+++ b/ergotree-interpreter/src/sigma_protocol/prover/prover_result.rs
@@ -1,4 +1,7 @@
 //! ProverResult
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec::Vec;
 use ergotree_ir::chain::context_extension::ContextExtension;
 use ergotree_ir::serialization::sigma_byte_reader::SigmaByteRead;
 use ergotree_ir::serialization::sigma_byte_writer::SigmaByteWrite;
@@ -6,7 +9,7 @@ use ergotree_ir::serialization::SigmaParsingError;
 use ergotree_ir::serialization::SigmaSerializable;
 use ergotree_ir::serialization::SigmaSerializeResult;
 
-use std::convert::TryFrom;
+use core::convert::TryFrom;
 
 /// Serialized proof generated by ['Prover']
 #[derive(PartialEq, Eq, Hash, Debug, Clone)]
diff --git a/ergotree-interpreter/src/sigma_protocol/sig_serializer.rs b/ergotree-interpreter/src/sigma_protocol/sig_serializer.rs
index 0fada38dc..c6e296425 100644
--- a/ergotree-interpreter/src/sigma_protocol/sig_serializer.rs
+++ b/ergotree-interpreter/src/sigma_protocol/sig_serializer.rs
@@ -1,6 +1,6 @@
 //! Serialization of proof tree signatures
 
-use std::convert::TryInto;
+use core::convert::TryInto;
 
 use super::gf2_192::gf2_192poly_from_byte_array;
 use super::prover::ProofBytes;
@@ -16,6 +16,8 @@ use crate::sigma_protocol::Challenge;
 use crate::sigma_protocol::GroupSizedBytes;
 use crate::sigma_protocol::UncheckedSchnorr;
 
+use alloc::boxed::Box;
+use alloc::vec::Vec;
 use ergotree_ir::serialization::sigma_byte_reader;
 use ergotree_ir::serialization::sigma_byte_reader::SigmaByteRead;
 use ergotree_ir::serialization::sigma_byte_writer::SigmaByteWrite;
@@ -47,7 +49,7 @@ fn sig_write_bytes<W: SigmaByteWrite>(
     node: &UncheckedTree,
     w: &mut W,
     write_challenges: bool,
-) -> Result<(), std::io::Error> {
+) -> Result<(), core2::io::Error> {
     if write_challenges {
         node.challenge().sigma_serialize(w)?;
     }
@@ -287,7 +289,7 @@ pub enum SigParsingError {
 #[cfg(test)]
 #[allow(clippy::unwrap_used)]
 mod test {
-    use std::io::Cursor;
+    use core2::io::Cursor;
 
     use ergotree_ir::serialization::{
         constant_store::ConstantStore, sigma_byte_reader::SigmaByteReader,
diff --git a/ergotree-interpreter/src/sigma_protocol/unchecked_tree.rs b/ergotree-interpreter/src/sigma_protocol/unchecked_tree.rs
index 08b70749e..48d7841ff 100644
--- a/ergotree-interpreter/src/sigma_protocol/unchecked_tree.rs
+++ b/ergotree-interpreter/src/sigma_protocol/unchecked_tree.rs
@@ -1,5 +1,6 @@
 //! Unchecked proof tree types
 
+use alloc::vec::Vec;
 use ergo_chain_types::Base16EncodedBytes;
 use ergotree_ir::sigma_protocol::sigma_boolean::ProveDhTuple;
 use ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
@@ -332,7 +333,7 @@ impl ProofTreeConjecture for UncheckedConjecture {
 #[cfg(feature = "arbitrary")]
 #[allow(clippy::unwrap_used)]
 mod arbitrary {
-    use std::convert::TryInto;
+    use core::convert::TryInto;
 
     use crate::sigma_protocol::gf2_192::gf2_192poly_from_byte_array;
 
diff --git a/ergotree-interpreter/src/sigma_protocol/unproven_tree.rs b/ergotree-interpreter/src/sigma_protocol/unproven_tree.rs
index d07b61f05..b6de29614 100644
--- a/ergotree-interpreter/src/sigma_protocol/unproven_tree.rs
+++ b/ergotree-interpreter/src/sigma_protocol/unproven_tree.rs
@@ -10,6 +10,7 @@ use super::wscalar::Wscalar;
 use super::{dlog_protocol::FirstDlogProverMessage, Challenge, FirstProverMessage};
 use crate::sigma_protocol::proof_tree::ProofTreeLeaf;
 use crate::sigma_protocol::SOUNDNESS_BYTES;
+use alloc::vec::Vec;
 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::cthreshold::Cthreshold;
@@ -395,11 +396,13 @@ impl UnprovenDhTuple {
 /// Please note that "0" prefix is for a crypto tree. There are several kinds of trees during evaluation.
 /// Initial mixed tree (ergoTree) would have another prefix.
 #[derive(PartialEq, Eq, Debug, Clone)]
-#[cfg(feature = "json")]
-#[derive(serde::Serialize, serde::Deserialize)]
-#[serde(
-    try_from = "crate::json::hint::NodePositionJson",
-    into = "crate::json::hint::NodePositionJson"
+#[cfg_attr(
+    feature = "json",
+    derive(serde::Serialize, serde::Deserialize),
+    serde(
+        try_from = "crate::json::hint::NodePositionJson",
+        into = "crate::json::hint::NodePositionJson"
+    )
 )]
 #[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
 pub struct NodePosition {
diff --git a/ergotree-interpreter/src/sigma_protocol/verifier.rs b/ergotree-interpreter/src/sigma_protocol/verifier.rs
index a08569369..64202fcc6 100644
--- a/ergotree-interpreter/src/sigma_protocol/verifier.rs
+++ b/ergotree-interpreter/src/sigma_protocol/verifier.rs
@@ -172,7 +172,7 @@ impl Verifier for TestVerifier {}
 #[cfg(test)]
 #[cfg(feature = "arbitrary")]
 mod tests {
-    use std::convert::TryFrom;
+    use core::convert::TryFrom;
 
     use crate::sigma_protocol::private_input::{DhTupleProverInput, DlogProverInput, PrivateInput};
     use crate::sigma_protocol::prover::hint::HintsBag;
diff --git a/ergotree-interpreter/src/sigma_protocol/wscalar.rs b/ergotree-interpreter/src/sigma_protocol/wscalar.rs
index 9aee5bbd5..28634fb1c 100644
--- a/ergotree-interpreter/src/sigma_protocol/wscalar.rs
+++ b/ergotree-interpreter/src/sigma_protocol/wscalar.rs
@@ -1,9 +1,9 @@
 //! Wrapper for Scalar
 //! mainly for Arbitrary impl and JSON encoding
 
-use std::array::TryFromSliceError;
-use std::convert::TryFrom;
-use std::fmt::Formatter;
+use core::array::TryFromSliceError;
+use core::convert::TryFrom;
+use core::fmt::Formatter;
 
 use derive_more::From;
 use derive_more::Into;
@@ -72,8 +72,8 @@ impl TryFrom<Base16DecodedBytes> for Wscalar {
     }
 }
 
-impl std::fmt::Debug for Wscalar {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Debug for Wscalar {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         f.write_str("Wscalar:")?;
         f.write_str(&base16::encode_lower(&(*self.0.to_bytes())))
     }
diff --git a/ergotree-ir/Cargo.toml b/ergotree-ir/Cargo.toml
index ef185305d..241e9ff94 100644
--- a/ergotree-ir/Cargo.toml
+++ b/ergotree-ir/Cargo.toml
@@ -9,7 +9,7 @@ description = "ErgoTree IR, serialization"
 exclude = ["proptest-regressions/*"]
 
 [lib]
-crate-type = ["cdylib", "rlib"]
+crate-type = ["rlib"]
 
 [dependencies]
 sigma-ser = { workspace = true }
@@ -35,14 +35,24 @@ serde_json = { workspace = true, optional = true }
 serde_with = { workspace = true, optional = true }
 bnum = { version = "0.12.0", features = ["numtraits"] }
 impl-trait-for-tuples = "0.2.0"
-strum = "0.21"
-strum_macros = "0.21"
-miette = { workspace = true }
-
+strum = { version = "0.26.2", default-features = false, features = ["derive"] }
+strum_macros = { version = "0.26.4", default-features = false }
+miette = { workspace = true, optional = true }
+hashbrown = { workspace = true }
+core2 = { workspace = true }
+foldhash = { version = "0.1.3", default-features = false }
 [features]
-default = ["json"]
-arbitrary = ["proptest", "proptest-derive", "ergo-chain-types/arbitrary"]
-json = ["serde", "serde_json", "serde_with", "bounded-vec/serde"]
+default = ["json", "std"]
+arbitrary = ["std", "proptest", "proptest-derive", "ergo-chain-types/arbitrary"]
+json = [
+    "serde",
+    "serde_json",
+    "serde_with",
+    "bounded-vec/serde",
+    "ergo-chain-types/json",
+    "indexmap/serde",
+]
+std = ["core2/std", "dep:miette", "ergo-chain-types/std", "sigma-ser/std"]
 
 [dev-dependencies]
 sigma-test-util = { workspace = true }
diff --git a/ergotree-ir/src/base16_str.rs b/ergotree-ir/src/base16_str.rs
index 6be0cf155..d342febe4 100644
--- a/ergotree-ir/src/base16_str.rs
+++ b/ergotree-ir/src/base16_str.rs
@@ -1,6 +1,7 @@
 //! Trait for base16-encoded serialized bytes
 
 use crate::serialization::SigmaSerializationError;
+use alloc::string::String;
 
 /// Encodes serialized bytes as Base16
 pub trait Base16Str {
diff --git a/ergotree-ir/src/bigint256.rs b/ergotree-ir/src/bigint256.rs
index cd1848068..425cfd52f 100644
--- a/ergotree-ir/src/bigint256.rs
+++ b/ergotree-ir/src/bigint256.rs
@@ -1,6 +1,9 @@
 //! 256-bit signed integer type
 
-use std::ops::{Div, Mul, Neg, Rem};
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::ops::{Div, Mul, Neg, Rem};
 
 use bnum::cast::As;
 use bnum::types::I256;
@@ -285,6 +288,7 @@ mod arbitrary {
 mod tests {
     use super::*;
     use num_traits::Num;
+    #[cfg(feature = "arbitrary")]
     use proptest::{prelude::*, proptest};
 
     #[cfg(feature = "arbitrary")]
diff --git a/ergotree-ir/src/chain.rs b/ergotree-ir/src/chain.rs
index 11a2895c5..6d1e63f2e 100644
--- a/ergotree-ir/src/chain.rs
+++ b/ergotree-ir/src/chain.rs
@@ -8,3 +8,8 @@ pub mod ergo_box;
 pub mod json;
 pub mod token;
 pub mod tx_id;
+
+/// Index Map
+pub type IndexMap<K, V> = indexmap::IndexMap<K, V, foldhash::fast::RandomState>;
+/// Index Set
+pub type IndexSet<T> = indexmap::IndexSet<T, foldhash::fast::RandomState>;
diff --git a/ergotree-ir/src/chain/address.rs b/ergotree-ir/src/chain/address.rs
index 8a1d981b3..0c2c33fdf 100644
--- a/ergotree-ir/src/chain/address.rs
+++ b/ergotree-ir/src/chain/address.rs
@@ -24,57 +24,64 @@ use crate::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
 use crate::sigma_protocol::sigma_boolean::SigmaProp;
 use crate::source_span::Spanned;
 use crate::types::stype::SType;
+
+use alloc::boxed::Box;
+use alloc::string::{String, ToString};
+use alloc::sync::Arc;
+use alloc::vec;
+use alloc::vec::Vec;
+
 use ergo_chain_types::EcPoint;
 
+use core::convert::{TryFrom, TryInto};
 use sigma_util::hash::blake2b256_hash;
 use sigma_util::AsVecU8;
-use std::convert::{TryFrom, TryInto};
-use std::sync::Arc;
 use thiserror::Error;
 
 /**
- * An address is a short string corresponding to some script used to protect a box. Unlike (string-encoded) binary
- * representation of a script, an address has some useful characteristics:
- *
- * - Integrity of an address could be checked., as it is incorporating a checksum.
- * - A prefix of address is showing network and an address type.
- * - An address is using an encoding (namely, Base58) which is avoiding similarly l0Oking characters, friendly to
- * double-clicking and line-breaking in emails.
- *
- *
- *
- * An address is encoding network type, address type, checksum, and enough information to watch for a particular scripts.
- *
- * Possible network types are:
- * Mainnet - 0x00
- * Testnet - 0x10
- *
- * For an address type, we form content bytes as follows:
- *
- * P2PK - serialized (compressed) public key
- * P2SH - first 192 bits of the Blake2b256 hash of serialized script bytes
- * P2S  - serialized script
- *
- * Address examples for testnet:
- *
- * 3   - P2PK (3WvsT2Gm4EpsM9Pg18PdY6XyhNNMqXDsvJTbbf6ihLvAmSb7u5RN)
- * ?   - P2SH (rbcrmKEYduUvADj9Ts3dSVSG27h54pgrq5fPuwB)
- * ?   - P2S (Ms7smJwLGbUAjuWQ)
- *
- * for mainnet:
- *
- * 9  - P2PK (9fRAWhdxEsTcdb8PhGNrZfwqa65zfkuYHAMmkQLcic1gdLSV5vA)
- * ?  - P2SH (8UApt8czfFVuTgQmMwtsRBZ4nfWquNiSwCWUjMg)
- * ?  - P2S (4MQyML64GnzMxZgm, BxKBaHkvrTvLZrDcZjcsxsF7aSsrN73ijeFZXtbj4CXZHHcvBtqSxQ)
- *
- *
- * Prefix byte = network type + address type
- *
- * checksum = blake2b256(prefix byte ++ content bytes)
- *
- * address = prefix byte ++ content bytes ++ checksum
- *
- */
+* An address is a short string corresponding to some script used to protect a box. Unlike (string-encoded) binary
+* representation of a script, an address has some useful characteristics:
+*
+* - Integrity of an address could be checked., as it is incorporating a checksum.
+* - A prefix of address is showing network and an address type.
+* - An address is using an encoding (namely, Base58) which is avoiding similarly l0Oking characters, friendly to
+
+* double-clicking and line-breaking in emails.
+*
+*
+*
+* An address is encoding network type, address type, checksum, and enough information to watch for a particular scripts.
+*
+* Possible network types are:
+* Mainnet - 0x00
+* Testnet - 0x10
+*
+* For an address type, we form content bytes as follows:
+*
+* P2PK - serialized (compressed) public key
+* P2SH - first 192 bits of the Blake2b256 hash of serialized script bytes
+* P2S  - serialized script
+*
+* Address examples for testnet:
+*
+* 3   - P2PK (3WvsT2Gm4EpsM9Pg18PdY6XyhNNMqXDsvJTbbf6ihLvAmSb7u5RN)
+* ?   - P2SH (rbcrmKEYduUvADj9Ts3dSVSG27h54pgrq5fPuwB)
+* ?   - P2S (Ms7smJwLGbUAjuWQ)
+*
+* for mainnet:
+*
+* 9  - P2PK (9fRAWhdxEsTcdb8PhGNrZfwqa65zfkuYHAMmkQLcic1gdLSV5vA)
+* ?  - P2SH (8UApt8czfFVuTgQmMwtsRBZ4nfWquNiSwCWUjMg)
+* ?  - P2S (4MQyML64GnzMxZgm, BxKBaHkvrTvLZrDcZjcsxsF7aSsrN73ijeFZXtbj4CXZHHcvBtqSxQ)
+*
+*
+* Prefix byte = network type + address type
+*
+* checksum = blake2b256(prefix byte ++ content bytes)
+*
+* address = prefix byte ++ content bytes ++ checksum
+*
+*/
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub enum Address {
     /// serialized (compressed) public key
@@ -582,9 +589,11 @@ pub(crate) mod arbitrary {
 #[cfg(test)]
 #[allow(clippy::unwrap_used)]
 #[allow(clippy::panic)]
+#[cfg(feature = "arbitrary")]
 mod tests {
 
     use super::*;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/chain/context_extension.rs b/ergotree-ir/src/chain/context_extension.rs
index 8197ee048..2881fa829 100644
--- a/ergotree-ir/src/chain/context_extension.rs
+++ b/ergotree-ir/src/chain/context_extension.rs
@@ -5,13 +5,22 @@ use crate::serialization::sigma_byte_writer::SigmaByteWrite;
 use crate::serialization::SigmaParsingError;
 use crate::serialization::SigmaSerializable;
 use crate::serialization::SigmaSerializeResult;
-use indexmap::IndexMap;
-use std::convert::TryFrom;
-use std::fmt;
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::fmt;
+use core::hash::BuildHasher;
 use thiserror::Error;
 
+use super::IndexMap;
+
 /// User-defined variables to be put into context
 #[derive(Debug, PartialEq, Eq, Clone)]
+#[cfg_attr(
+    feature = "json",
+    derive(serde::Deserialize),
+    serde(try_from = "IndexMap<String, String>")
+)]
 pub struct ContextExtension {
     /// key-value pairs of variable id and it's value
     pub values: IndexMap<u8, Constant>,
@@ -21,7 +30,7 @@ impl ContextExtension {
     /// Returns an empty ContextExtension
     pub fn empty() -> Self {
         Self {
-            values: IndexMap::new(),
+            values: IndexMap::with_hasher(Default::default()),
         }
     }
 }
@@ -45,7 +54,8 @@ impl SigmaSerializable for ContextExtension {
 
     fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
         let values_count = r.get_u8()?;
-        let mut values: IndexMap<u8, Constant> = IndexMap::with_capacity(values_count as usize);
+        let mut values: IndexMap<u8, Constant> =
+            IndexMap::with_capacity_and_hasher(values_count as usize, Default::default());
         for _ in 0..values_count {
             let idx = r.get_u8()?;
             values.insert(idx, Constant::sigma_parse(r)?);
@@ -60,11 +70,11 @@ impl SigmaSerializable for ContextExtension {
 pub struct ConstantParsingError(pub String);
 
 // for JSON encoding in ergo-lib
-impl TryFrom<IndexMap<String, String>> for ContextExtension {
+impl<H: BuildHasher> TryFrom<indexmap::IndexMap<String, String, H>> for ContextExtension {
     type Error = ConstantParsingError;
-    fn try_from(values_str: IndexMap<String, String>) -> Result<Self, Self::Error> {
+    fn try_from(values_str: indexmap::IndexMap<String, String, H>) -> Result<Self, Self::Error> {
         let values = values_str.iter().try_fold(
-            IndexMap::with_capacity(values_str.len()),
+            IndexMap::with_capacity_and_hasher(values_str.len(), Default::default()),
             |mut acc, pair| {
                 let idx: u8 = pair.0.parse().map_err(|_| {
                     ConstantParsingError(format!("cannot parse index from {0:?}", pair.0))
@@ -91,6 +101,25 @@ impl TryFrom<IndexMap<String, String>> for ContextExtension {
     }
 }
 
+#[cfg(feature = "json")]
+impl serde::Serialize for ContextExtension {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        use serde::ser::Error;
+        use serde::ser::SerializeMap;
+        let mut map = serializer.serialize_map(Some(self.values.len()))?;
+        for (k, v) in &self.values {
+            map.serialize_entry(
+                &format!("{}", k),
+                &base16::encode_lower(&v.sigma_serialize_bytes().map_err(Error::custom)?),
+            )?;
+        }
+        map.end()
+    }
+}
+
 #[cfg(feature = "arbitrary")]
 mod arbitrary {
     use super::*;
@@ -117,7 +146,7 @@ mod arbitrary {
 
 #[cfg(test)]
 #[cfg(feature = "arbitrary")]
-#[allow(clippy::panic)]
+#[allow(clippy::panic, clippy::unwrap_used)]
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
@@ -130,4 +159,24 @@ mod tests {
             prop_assert_eq![sigma_serialize_roundtrip(&v), v];
         }
     }
+    #[cfg(feature = "json")]
+    mod json {
+        use super::*;
+        #[test]
+        fn parse_empty_context_extension() {
+            let c: ContextExtension = serde_json::from_str("{}").unwrap();
+            assert_eq!(c, ContextExtension::empty());
+        }
+
+        #[test]
+        fn parse_context_extension() {
+            let json = r#"
+            {"1" :"05b0b5cad8e6dbaef44a", "3":"048ce5d4e505"}
+            "#;
+            let c: ContextExtension = serde_json::from_str(json).unwrap();
+            assert_eq!(c.values.len(), 2);
+            assert!(c.values.get(&1u8).is_some());
+            assert!(c.values.get(&3u8).is_some());
+        }
+    }
 }
diff --git a/ergotree-ir/src/chain/ergo_box.rs b/ergotree-ir/src/chain/ergo_box.rs
index 2e7b5e843..49a68d3e8 100644
--- a/ergotree-ir/src/chain/ergo_box.rs
+++ b/ergotree-ir/src/chain/ergo_box.rs
@@ -13,17 +13,19 @@ use crate::serialization::SigmaSerializable;
 use crate::serialization::SigmaSerializationError;
 use crate::serialization::SigmaSerializeResult;
 
+use alloc::string::ToString;
+use alloc::vec::Vec;
 pub use box_id::*;
 use ergo_chain_types::Digest32;
 pub use register::*;
 
+use super::IndexSet;
 use bounded_vec::BoundedVec;
-use indexmap::IndexSet;
+use core::convert::TryFrom;
 use sigma_util::hash::blake2b256_hash;
 use sigma_util::AsVecI8;
-use std::convert::TryFrom;
 
-use std::convert::TryInto;
+use core::convert::TryInto;
 
 use self::box_value::BoxValue;
 
@@ -403,7 +405,7 @@ pub mod arbitrary {
         pub creation_height: BoxedStrategy<u32>,
         pub registers: BoxedStrategy<NonMandatoryRegisters>,
     }
-    impl std::default::Default for ArbBoxParameters {
+    impl core::default::Default for ArbBoxParameters {
         fn default() -> Self {
             Self {
                 value_range: ArbBoxValueRange::default(),
@@ -478,10 +480,12 @@ pub mod arbitrary {
 #[allow(clippy::panic)]
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::chain::token::arbitrary::ArbTokenIdParam;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::collection::SizeRange;
     use proptest::prelude::*;
     use sigma_test_util::force_any_val;
diff --git a/ergotree-ir/src/chain/ergo_box/box_id.rs b/ergotree-ir/src/chain/ergo_box/box_id.rs
index 193a45799..9d771cdec 100644
--- a/ergotree-ir/src/chain/ergo_box/box_id.rs
+++ b/ergotree-ir/src/chain/ergo_box/box_id.rs
@@ -1,7 +1,9 @@
 //! Box id type
-use std::convert::TryFrom;
+use core::convert::TryFrom;
 
 use crate::serialization::SigmaSerializeResult;
+use alloc::string::String;
+use alloc::vec::Vec;
 use sigma_ser::ScorexSerializable;
 
 use crate::serialization::{
@@ -56,8 +58,8 @@ impl From<BoxId> for Vec<i8> {
     }
 }
 
-impl std::fmt::Display for BoxId {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for BoxId {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         write!(f, "{}", self.0)
     }
 }
@@ -75,9 +77,11 @@ impl SigmaSerializable for BoxId {
 #[allow(clippy::unwrap_used)]
 #[allow(clippy::panic)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/chain/ergo_box/box_value.rs b/ergotree-ir/src/chain/ergo_box/box_value.rs
index ff44e2013..94c94eff6 100644
--- a/ergotree-ir/src/chain/ergo_box/box_value.rs
+++ b/ergotree-ir/src/chain/ergo_box/box_value.rs
@@ -7,8 +7,9 @@ use crate::serialization::SigmaSerializeResult;
 use crate::serialization::{
     sigma_byte_reader::SigmaByteRead, SigmaParsingError, SigmaSerializable,
 };
+
+use core::convert::TryFrom;
 use derive_more::FromStr;
-use std::convert::TryFrom;
 use thiserror::Error;
 
 #[cfg(not(feature = "json"))]
@@ -114,7 +115,7 @@ impl BoxValue {
 }
 
 impl PartialOrd for BoxValue {
-    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
         self.0.partial_cmp(other.as_u64())
     }
 }
@@ -211,9 +212,9 @@ pub fn checked_sum<I: Iterator<Item = BoxValue>>(mut iter: I) -> Result<BoxValue
 /// Arbitrary
 #[cfg(feature = "arbitrary")]
 pub mod arbitrary {
+    use core::ops::Range;
     use derive_more::{From, Into};
     use proptest::{arbitrary::Arbitrary, prelude::*};
-    use std::ops::Range;
 
     use super::*;
 
@@ -240,9 +241,12 @@ pub mod arbitrary {
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
 pub mod tests {
-    use std::convert::TryInto;
+    use core::convert::TryInto;
 
     use super::*;
+    use alloc::vec;
+    use alloc::vec::Vec;
+    #[cfg(feature = "arbitrary")]
     use proptest::{collection::vec, prelude::*};
 
     extern crate derive_more;
@@ -321,6 +325,7 @@ pub mod tests {
         assert!(checked_sum(input.into_iter()).is_err());
     }
 
+    #[cfg(feature = "arbitrary")]
     proptest! {
 
         #[test]
diff --git a/ergotree-ir/src/chain/ergo_box/register.rs b/ergotree-ir/src/chain/ergo_box/register.rs
index 503111b15..13ecabee6 100644
--- a/ergotree-ir/src/chain/ergo_box/register.rs
+++ b/ergotree-ir/src/chain/ergo_box/register.rs
@@ -8,9 +8,14 @@ use crate::serialization::SigmaParsingError;
 use crate::serialization::SigmaSerializable;
 use crate::serialization::SigmaSerializationError;
 use crate::serialization::SigmaSerializeResult;
+
+use alloc::string::ToString;
+use alloc::vec;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::convert::TryInto;
 use ergo_chain_types::Base16EncodedBytes;
-use std::convert::TryInto;
-use std::{collections::HashMap, convert::TryFrom};
+use hashbrown::HashMap;
 use thiserror::Error;
 
 mod id;
@@ -41,8 +46,8 @@ impl NonMandatoryRegisters {
     }
 
     /// Create new from map
-    pub fn new(
-        regs: HashMap<NonMandatoryRegisterId, Constant>,
+    pub fn new<I: IntoIterator<Item = (NonMandatoryRegisterId, Constant)>>(
+        regs: I,
     ) -> Result<NonMandatoryRegisters, NonMandatoryRegistersError> {
         NonMandatoryRegisters::try_from(
             regs.into_iter()
@@ -217,6 +222,31 @@ impl TryFrom<HashMap<NonMandatoryRegisterId, RegisterValue>> for NonMandatoryReg
     }
 }
 
+#[cfg(feature = "std")]
+impl TryFrom<std::collections::HashMap<NonMandatoryRegisterId, RegisterValue>>
+    for NonMandatoryRegisters
+{
+    type Error = NonMandatoryRegistersError;
+    fn try_from(
+        reg_map: std::collections::HashMap<NonMandatoryRegisterId, RegisterValue>,
+    ) -> Result<Self, Self::Error> {
+        let regs_num = reg_map.len();
+        if regs_num > NonMandatoryRegisters::MAX_SIZE {
+            Err(NonMandatoryRegistersError::InvalidSize(regs_num))
+        } else {
+            let mut res: Vec<RegisterValue> = vec![];
+            NonMandatoryRegisterId::REG_IDS
+                .iter()
+                .take(regs_num)
+                .try_for_each(|reg_id| match reg_map.get(reg_id) {
+                    Some(v) => Ok(res.push(v.clone())),
+                    None => Err(NonMandatoryRegistersError::NonDenselyPacked(*reg_id as u8)),
+                })?;
+            Ok(NonMandatoryRegisters(res))
+        }
+    }
+}
+
 #[cfg(feature = "json")]
 impl TryFrom<HashMap<NonMandatoryRegisterId, crate::chain::json::ergo_box::ConstantHolder>>
     for NonMandatoryRegisters
@@ -282,9 +312,12 @@ pub(crate) mod arbitrary {
 #[cfg(test)]
 mod tests {
     use super::*;
+    #[cfg(feature = "arbitrary")]
     use crate::serialization::sigma_serialize_roundtrip;
+    #[cfg(feature = "arbitrary")]
     use proptest::prelude::*;
 
+    #[cfg(feature = "arbitrary")]
     proptest! {
 
         #[test]
diff --git a/ergotree-ir/src/chain/ergo_box/register/id.rs b/ergotree-ir/src/chain/ergo_box/register/id.rs
index 85bf1cca3..9d641fcbc 100644
--- a/ergotree-ir/src/chain/ergo_box/register/id.rs
+++ b/ergotree-ir/src/chain/ergo_box/register/id.rs
@@ -1,5 +1,6 @@
-use std::fmt::Display;
+use core::fmt::Display;
 
+use alloc::{format, string::String};
 use derive_more::From;
 use thiserror::Error;
 
@@ -66,7 +67,7 @@ impl From<RegisterId> for u8 {
 }
 
 impl Display for RegisterId {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self {
             RegisterId::MandatoryRegisterId(id) => write!(f, "{}", id),
             RegisterId::NonMandatoryRegisterId(id) => write!(f, "{}", id),
diff --git a/ergotree-ir/src/chain/ergo_box/register/value.rs b/ergotree-ir/src/chain/ergo_box/register/value.rs
index f55ee2149..7dbf4a445 100644
--- a/ergotree-ir/src/chain/ergo_box/register/value.rs
+++ b/ergotree-ir/src/chain/ergo_box/register/value.rs
@@ -1,3 +1,6 @@
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec::Vec;
 use derive_more::From;
 use thiserror::Error;
 
diff --git a/ergotree-ir/src/chain/json.rs b/ergotree-ir/src/chain/json.rs
index cf550d91a..dd877d0d9 100644
--- a/ergotree-ir/src/chain/json.rs
+++ b/ergotree-ir/src/chain/json.rs
@@ -1,8 +1,8 @@
 //! JSON serialization
 
-use std::fmt;
-use std::marker::PhantomData;
-use std::str::FromStr;
+use core::fmt;
+use core::marker::PhantomData;
+use core::str::FromStr;
 
 use serde::de;
 use serde::de::MapAccess;
@@ -32,7 +32,7 @@ pub fn t_as_string_or_struct<'de, T, D, E>(deserializer: D) -> Result<T, D::Erro
 where
     T: Deserialize<'de> + FromStr<Err = E>,
     D: Deserializer<'de>,
-    E: std::fmt::Display,
+    E: core::fmt::Display,
 {
     // This is a Visitor that forwards string types to T's `FromStr` impl and
     // forwards map types to T's `Deserialize` impl. The `PhantomData` is to
@@ -44,7 +44,7 @@ where
     impl<'de, T, FromStrErr> Visitor<'de> for StringOrStruct<T>
     where
         T: Deserialize<'de> + FromStr<Err = FromStrErr>,
-        FromStrErr: std::fmt::Display,
+        FromStrErr: core::fmt::Display,
     {
         type Value = T;
 
diff --git a/ergotree-ir/src/chain/json/box_value.rs b/ergotree-ir/src/chain/json/box_value.rs
index 985058dcf..681daff20 100644
--- a/ergotree-ir/src/chain/json/box_value.rs
+++ b/ergotree-ir/src/chain/json/box_value.rs
@@ -1,6 +1,8 @@
 //! Code to implement `BoxValue` JSON encoding
 
-use std::convert::TryFrom;
+use core::convert::TryFrom;
+
+use alloc::string::String;
 
 use crate::chain::ergo_box::box_value::BoxValue;
 
diff --git a/ergotree-ir/src/chain/json/ergo_box.rs b/ergotree-ir/src/chain/json/ergo_box.rs
index e55d337c1..83b4c5d4d 100644
--- a/ergotree-ir/src/chain/json/ergo_box.rs
+++ b/ergotree-ir/src/chain/json/ergo_box.rs
@@ -10,10 +10,12 @@ use crate::chain::tx_id::TxId;
 use crate::ergo_tree::ErgoTree;
 use crate::serialization::SigmaParsingError;
 use crate::serialization::SigmaSerializationError;
+use alloc::string::ToString;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::convert::TryInto;
+use core::str::FromStr;
 use ergo_chain_types::Base16DecodedBytes;
-use std::convert::TryFrom;
-use std::convert::TryInto;
-use std::str::FromStr;
 
 extern crate derive_more;
 use derive_more::From;
@@ -241,8 +243,9 @@ impl FromStr for RichConstant {
 #[allow(clippy::panic)]
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
-    use std::convert::TryInto;
+    use core::convert::TryInto;
 
     use crate::chain::ergo_box::ErgoBox;
     use crate::chain::ergo_box::NonMandatoryRegisterId;
diff --git a/ergotree-ir/src/chain/json/ergo_box/box_value.rs b/ergotree-ir/src/chain/json/ergo_box/box_value.rs
index 82130aef3..b8f88c4b4 100644
--- a/ergotree-ir/src/chain/json/ergo_box/box_value.rs
+++ b/ergotree-ir/src/chain/json/ergo_box/box_value.rs
@@ -2,7 +2,7 @@
 #[cfg(test)]
 mod tests {
     use crate::chain::ergo_box::box_value::BoxValue;
-    use std::convert::TryInto;
+    use core::convert::TryInto;
 
     #[test]
     fn parse_value_as_str() {
diff --git a/ergotree-ir/src/chain/json/ergo_tree.rs b/ergotree-ir/src/chain/json/ergo_tree.rs
index c4347f9fe..dd2c786d2 100644
--- a/ergotree-ir/src/chain/json/ergo_tree.rs
+++ b/ergotree-ir/src/chain/json/ergo_tree.rs
@@ -2,6 +2,7 @@
 
 use crate::ergo_tree::ErgoTree;
 use crate::serialization::SigmaSerializable;
+use alloc::string::{String, ToString};
 use serde::{Deserialize, Deserializer, Serializer};
 
 use super::serialize_bytes;
diff --git a/ergotree-ir/src/chain/json/sigma_protocol.rs b/ergotree-ir/src/chain/json/sigma_protocol.rs
index 9e28d2644..434950db4 100644
--- a/ergotree-ir/src/chain/json/sigma_protocol.rs
+++ b/ergotree-ir/src/chain/json/sigma_protocol.rs
@@ -1,6 +1,7 @@
-use std::convert::TryFrom;
-use std::convert::TryInto;
+use core::convert::TryFrom;
+use core::convert::TryInto;
 
+use alloc::vec::Vec;
 use bounded_vec::BoundedVecOutOfBounds;
 use ergo_chain_types::EcPoint;
 use serde::Deserialize;
diff --git a/ergotree-ir/src/chain/json/token.rs b/ergotree-ir/src/chain/json/token.rs
index 1b5cd5cf2..03024d27e 100644
--- a/ergotree-ir/src/chain/json/token.rs
+++ b/ergotree-ir/src/chain/json/token.rs
@@ -1,6 +1,8 @@
 //! Code to implement `TokenAmount` JSON encoding
 
-use std::convert::TryFrom;
+use core::convert::TryFrom;
+
+use alloc::string::String;
 
 use crate::chain::token::TokenAmount;
 
diff --git a/ergotree-ir/src/chain/token.rs b/ergotree-ir/src/chain/token.rs
index e15c8853f..a42984ec2 100644
--- a/ergotree-ir/src/chain/token.rs
+++ b/ergotree-ir/src/chain/token.rs
@@ -5,9 +5,11 @@ use crate::serialization::{
     sigma_byte_reader::SigmaByteRead, sigma_byte_writer::SigmaByteWrite, SigmaParsingError,
     SigmaSerializable,
 };
-use std::convert::TryFrom;
+use core::convert::TryFrom;
 
 use super::ergo_box::BoxId;
+use alloc::string::String;
+use alloc::vec::Vec;
 use derive_more::From;
 use derive_more::Into;
 use ergo_chain_types::{Digest32, DigestNError};
@@ -198,7 +200,7 @@ pub mod arbitrary {
     use super::TokenAmount;
     use super::TokenId;
 
-    use std::convert::TryFrom;
+    use core::convert::TryFrom;
 
     /// How to generate a token id
     #[derive(Default)]
@@ -277,10 +279,12 @@ pub mod arbitrary {
 
 #[allow(clippy::panic)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
 
     use crate::chain::token::TokenId;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/chain/tx_id.rs b/ergotree-ir/src/chain/tx_id.rs
index 339e7c4d1..1a015ae10 100644
--- a/ergotree-ir/src/chain/tx_id.rs
+++ b/ergotree-ir/src/chain/tx_id.rs
@@ -1,4 +1,5 @@
 //! Transaction id type
+use alloc::string::String;
 use derive_more::Display;
 
 use derive_more::From;
diff --git a/ergotree-ir/src/ergo_tree.rs b/ergotree-ir/src/ergo_tree.rs
index 7c7942a3e..7316d33ac 100644
--- a/ergotree-ir/src/ergo_tree.rs
+++ b/ergotree-ir/src/ergo_tree.rs
@@ -11,13 +11,19 @@ use crate::serialization::{
 };
 use crate::sigma_protocol::sigma_boolean::ProveDlog;
 use crate::types::stype::SType;
-use io::Cursor;
+
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec;
+use alloc::vec::Vec;
 use sigma_ser::vlq_encode::WriteSigmaVlqExt;
 
 use crate::serialization::constant_store::ConstantStore;
+use core::convert::TryFrom;
+use core2::io;
 use derive_more::From;
-use std::convert::TryFrom;
-use std::io;
+use io::Cursor;
+#[cfg(feature = "std")]
 use std::sync::OnceLock;
 use thiserror::Error;
 
@@ -30,6 +36,7 @@ pub struct ParsedErgoTree {
     header: ErgoTreeHeader,
     constants: Vec<Constant>,
     root: Expr,
+    #[cfg(feature = "std")]
     has_deserialize: OnceLock<bool>,
 }
 
@@ -40,7 +47,7 @@ impl ParsedErgoTree {
         let mut new_constants = self.constants.clone();
         if let Some(old_constant) = self.constants.get(index) {
             if constant.tpe == old_constant.tpe {
-                let _ = std::mem::replace(&mut new_constants[index], constant);
+                let _ = core::mem::replace(&mut new_constants[index], constant);
                 Ok(Self {
                     constants: new_constants,
                     ..self
@@ -157,6 +164,7 @@ impl ErgoTree {
         let was_deserialize = r.was_deserialize();
         r.set_deserialize(false);
         let root = Expr::sigma_parse(r)?;
+        #[allow(unused)]
         let has_deserialize = r.was_deserialize();
         r.set_deserialize(was_deserialize);
         if root.tpe() != SType::SSigmaProp {
@@ -166,6 +174,7 @@ impl ErgoTree {
             header,
             constants,
             root,
+            #[cfg(feature = "std")]
             has_deserialize: has_deserialize.into(),
         })
     }
@@ -208,6 +217,7 @@ impl ErgoTree {
                 header,
                 constants,
                 root: parsed_expr,
+                #[cfg(feature = "std")]
                 has_deserialize: OnceLock::new(),
             })
         } else {
@@ -215,6 +225,7 @@ impl ErgoTree {
                 header,
                 constants: Vec::new(),
                 root: expr.clone(),
+                #[cfg(feature = "std")]
                 has_deserialize: OnceLock::new(),
             })
         })
@@ -240,12 +251,14 @@ impl ErgoTree {
     pub fn has_deserialize(&self) -> bool {
         match self {
             ErgoTree::Unparsed { .. } => false,
+            #[cfg(feature = "std")]
             ErgoTree::Parsed(ParsedErgoTree {
-                header: _,
-                constants: _,
                 root,
                 has_deserialize,
+                ..
             }) => *has_deserialize.get_or_init(|| root.has_deserialize()),
+            #[cfg(not(feature = "std"))]
+            ErgoTree::Parsed(ParsedErgoTree { root, .. }) => root.has_deserialize(),
         }
     }
 
@@ -366,11 +379,11 @@ impl SigmaSerializable for ErgoTree {
     }
 
     fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
-        let start_pos = r.stream_position()?;
+        let start_pos = r.position()?;
         let header = ErgoTreeHeader::sigma_parse(r)?;
         if header.has_size() {
             let tree_size_bytes = r.get_u32()?;
-            let body_pos = r.stream_position()?;
+            let body_pos = r.position()?;
             let mut buf = vec![0u8; tree_size_bytes as usize];
             r.read_exact(buf.as_mut_slice())?;
             let mut inner_r =
@@ -400,6 +413,7 @@ impl SigmaSerializable for ErgoTree {
                 header,
                 constants,
                 root,
+                #[cfg(feature = "std")]
                 has_deserialize: OnceLock::new(),
             }))
         }
@@ -425,8 +439,8 @@ impl TryFrom<ErgoTree> for ProveDlog {
     }
 }
 
-impl From<std::io::Error> for ErgoTreeError {
-    fn from(e: std::io::Error) -> Self {
+impl From<core2::io::Error> for ErgoTreeError {
+    fn from(e: core2::io::Error) -> Self {
         ErgoTreeError::IoError(e.to_string())
     }
 }
diff --git a/ergotree-ir/src/ergo_tree/tree_header.rs b/ergotree-ir/src/ergo_tree/tree_header.rs
index e7d5108c2..12e96b83e 100644
--- a/ergotree-ir/src/ergo_tree/tree_header.rs
+++ b/ergotree-ir/src/ergo_tree/tree_header.rs
@@ -1,5 +1,6 @@
 //! ErgoTree header
 
+use alloc::string::{String, ToString};
 use derive_more::From;
 use thiserror::Error;
 
@@ -32,7 +33,7 @@ pub struct ErgoTreeHeader {
 
 impl ErgoTreeHeader {
     /// Serialization
-    pub fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> Result<(), std::io::Error> {
+    pub fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> Result<(), core2::io::Error> {
         w.put_u8(self.serialized())
     }
     /// Deserialization
diff --git a/ergotree-ir/src/lib.rs b/ergotree-ir/src/lib.rs
index 37e697db6..ee4d6e7eb 100644
--- a/ergotree-ir/src/lib.rs
+++ b/ergotree-ir/src/lib.rs
@@ -1,5 +1,6 @@
 //! ErgoTree, MIR (Middle-level Internal Representation)
 
+#![cfg_attr(not(feature = "std"), no_std)]
 // Coding conventions
 #![forbid(unsafe_code)]
 #![deny(non_upper_case_globals)]
@@ -19,6 +20,9 @@
 #![deny(clippy::unreachable)]
 #![deny(clippy::panic)]
 
+#[macro_use]
+extern crate alloc;
+
 mod has_opcode;
 
 pub mod base16_str;
diff --git a/ergotree-ir/src/mir/and.rs b/ergotree-ir/src/mir/and.rs
index 10d41b65a..9da374cb8 100644
--- a/ergotree-ir/src/mir/and.rs
+++ b/ergotree-ir/src/mir/and.rs
@@ -1,5 +1,7 @@
 //! AND logical conjunction
 
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
@@ -69,11 +71,13 @@ mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
     use crate::mir::expr::Expr;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/apply.rs b/ergotree-ir/src/mir/apply.rs
index 8660b45f4..42c637169 100644
--- a/ergotree-ir/src/mir/apply.rs
+++ b/ergotree-ir/src/mir/apply.rs
@@ -1,5 +1,9 @@
 //! Application of function
 
+use alloc::boxed::Box;
+
+use alloc::vec::Vec;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
@@ -111,6 +115,7 @@ pub mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 #[allow(clippy::unwrap_used)]
 mod tests {
diff --git a/ergotree-ir/src/mir/atleast.rs b/ergotree-ir/src/mir/atleast.rs
index cf42750dd..e6a561827 100644
--- a/ergotree-ir/src/mir/atleast.rs
+++ b/ergotree-ir/src/mir/atleast.rs
@@ -1,4 +1,6 @@
 //! THRESHOLD composition for sigma expressions
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
@@ -100,6 +102,7 @@ mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
diff --git a/ergotree-ir/src/mir/avl_tree_data.rs b/ergotree-ir/src/mir/avl_tree_data.rs
index a0b12f024..c03c4d664 100644
--- a/ergotree-ir/src/mir/avl_tree_data.rs
+++ b/ergotree-ir/src/mir/avl_tree_data.rs
@@ -1,3 +1,4 @@
+use alloc::boxed::Box;
 use ergo_chain_types::ADDigest;
 use sigma_ser::ScorexSerializable;
 
@@ -134,12 +135,14 @@ mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::unwrap_used)]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
     use crate::mir::expr::Expr;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/bin_op.rs b/ergotree-ir/src/mir/bin_op.rs
index 70cc7307c..55feffcf8 100644
--- a/ergotree-ir/src/mir/bin_op.rs
+++ b/ergotree-ir/src/mir/bin_op.rs
@@ -1,6 +1,7 @@
 //! Operators in ErgoTree
 
-use std::fmt::Display;
+use alloc::boxed::Box;
+use core::fmt::Display;
 
 use super::expr::Expr;
 use crate::has_opcode::HasOpCode;
@@ -48,7 +49,7 @@ impl From<ArithOp> for OpCode {
 }
 
 impl Display for ArithOp {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self {
             ArithOp::Plus => write!(f, "+"),
             ArithOp::Minus => write!(f, "-"),
@@ -93,7 +94,7 @@ impl From<RelationOp> for OpCode {
 }
 
 impl Display for RelationOp {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self {
             RelationOp::Eq => write!(f, "=="),
             RelationOp::NEq => write!(f, "!="),
@@ -128,7 +129,7 @@ impl From<LogicalOp> for OpCode {
 }
 
 impl Display for LogicalOp {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self {
             LogicalOp::And => write!(f, "&&"),
             LogicalOp::Or => write!(f, "||"),
@@ -160,7 +161,7 @@ impl From<BitOp> for OpCode {
 }
 
 impl Display for BitOp {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self {
             BitOp::BitOr => write!(f, "|"),
             BitOp::BitAnd => write!(f, "&"),
@@ -195,7 +196,7 @@ impl From<BinOpKind> for OpCode {
 }
 
 impl Display for BinOpKind {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self {
             BinOpKind::Arith(op) => write!(f, "{}", op),
             BinOpKind::Relation(op) => write!(f, "{}", op),
@@ -334,18 +335,23 @@ mod tests {
     use crate::mir::constant::Constant;
     use crate::mir::constant::Literal::Boolean;
     use crate::mir::expr::Expr;
-    use crate::serialization::sigma_serialize_roundtrip;
     use crate::serialization::SigmaSerializable;
-    use proptest::prelude::*;
 
-    proptest! {
+    #[cfg(feature = "arbitrary")]
+    mod proptests {
+        use super::BinOp;
+        use super::Expr;
+        use crate::serialization::sigma_serialize_roundtrip;
+        use proptest::prelude::*;
+
+        proptest! {
+            #[test]
+            fn ser_roundtrip(v in any::<BinOp>()) {
+                let expr: Expr = v.into();
+                prop_assert_eq![sigma_serialize_roundtrip(&expr), expr];
+            }
 
-        #[test]
-        fn ser_roundtrip(v in any::<BinOp>()) {
-            let expr: Expr = v.into();
-            prop_assert_eq![sigma_serialize_roundtrip(&expr), expr];
         }
-
     }
 
     // Test that binop with boolean literals serialized correctly
diff --git a/ergotree-ir/src/mir/bit_inversion.rs b/ergotree-ir/src/mir/bit_inversion.rs
index 2cedd892d..d4ae665f5 100644
--- a/ergotree-ir/src/mir/bit_inversion.rs
+++ b/ergotree-ir/src/mir/bit_inversion.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
 use super::unary_op::OneArgOp;
@@ -90,6 +92,7 @@ mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
diff --git a/ergotree-ir/src/mir/block.rs b/ergotree-ir/src/mir/block.rs
index 6ecae13d2..c87d75acd 100644
--- a/ergotree-ir/src/mir/block.rs
+++ b/ergotree-ir/src/mir/block.rs
@@ -1,5 +1,8 @@
 //! Block of statements ending with an expression
 
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+
 use super::expr::Expr;
 use crate::has_opcode::HasStaticOpCode;
 use crate::serialization::op_code::OpCode;
@@ -79,6 +82,7 @@ mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 pub mod tests {
     use crate::mir::block::BlockValue;
diff --git a/ergotree-ir/src/mir/bool_to_sigma.rs b/ergotree-ir/src/mir/bool_to_sigma.rs
index 9a020632d..286026cd1 100644
--- a/ergotree-ir/src/mir/bool_to_sigma.rs
+++ b/ergotree-ir/src/mir/bool_to_sigma.rs
@@ -1,4 +1,6 @@
 //! Embedding of Boolean values to SigmaProp
+use alloc::boxed::Box;
+
 use crate::has_opcode::HasStaticOpCode;
 use crate::mir::unary_op::OneArgOp;
 use crate::mir::unary_op::OneArgOpTryBuild;
diff --git a/ergotree-ir/src/mir/byte_array_to_bigint.rs b/ergotree-ir/src/mir/byte_array_to_bigint.rs
index bfcd774ad..c45aa5359 100644
--- a/ergotree-ir/src/mir/byte_array_to_bigint.rs
+++ b/ergotree-ir/src/mir/byte_array_to_bigint.rs
@@ -1,5 +1,6 @@
 //! Convert byte array to SBigInt
-use std::sync::Arc;
+use alloc::boxed::Box;
+use alloc::sync::Arc;
 
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
@@ -77,6 +78,7 @@ mod arbitrary {
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/byte_array_to_long.rs b/ergotree-ir/src/mir/byte_array_to_long.rs
index 87029e66b..43018d2f9 100644
--- a/ergotree-ir/src/mir/byte_array_to_long.rs
+++ b/ergotree-ir/src/mir/byte_array_to_long.rs
@@ -1,5 +1,6 @@
 //! Convert byte array to SLong
-use std::sync::Arc;
+use alloc::boxed::Box;
+use alloc::sync::Arc;
 
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
@@ -77,6 +78,7 @@ mod arbitrary {
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/calc_blake2b256.rs b/ergotree-ir/src/mir/calc_blake2b256.rs
index afb84f892..923dbbdfe 100644
--- a/ergotree-ir/src/mir/calc_blake2b256.rs
+++ b/ergotree-ir/src/mir/calc_blake2b256.rs
@@ -1,4 +1,5 @@
-use std::sync::Arc;
+use alloc::boxed::Box;
+use alloc::sync::Arc;
 
 use crate::has_opcode::HasStaticOpCode;
 use crate::serialization::op_code::OpCode;
@@ -76,6 +77,7 @@ mod arbitrary {
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/calc_sha256.rs b/ergotree-ir/src/mir/calc_sha256.rs
index d36897286..e415d0b32 100644
--- a/ergotree-ir/src/mir/calc_sha256.rs
+++ b/ergotree-ir/src/mir/calc_sha256.rs
@@ -1,4 +1,5 @@
-use std::sync::Arc;
+use alloc::boxed::Box;
+use alloc::sync::Arc;
 
 use crate::has_opcode::HasStaticOpCode;
 use crate::serialization::op_code::OpCode;
@@ -76,6 +77,7 @@ mod arbitrary {
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/coll_append.rs b/ergotree-ir/src/mir/coll_append.rs
index 8fc9bd8d7..054e6b0dd 100644
--- a/ergotree-ir/src/mir/coll_append.rs
+++ b/ergotree-ir/src/mir/coll_append.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
diff --git a/ergotree-ir/src/mir/coll_by_index.rs b/ergotree-ir/src/mir/coll_by_index.rs
index 8cedfc7ba..cb3c5bf35 100644
--- a/ergotree-ir/src/mir/coll_by_index.rs
+++ b/ergotree-ir/src/mir/coll_by_index.rs
@@ -1,4 +1,6 @@
-use std::sync::Arc;
+use alloc::boxed::Box;
+
+use alloc::sync::Arc;
 
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
diff --git a/ergotree-ir/src/mir/coll_exists.rs b/ergotree-ir/src/mir/coll_exists.rs
index b605181bf..97e7bfb83 100644
--- a/ergotree-ir/src/mir/coll_exists.rs
+++ b/ergotree-ir/src/mir/coll_exists.rs
@@ -1,4 +1,6 @@
-use std::sync::Arc;
+use alloc::boxed::Box;
+
+use alloc::sync::Arc;
 
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
@@ -84,6 +86,7 @@ mod arbitrary {
     use super::*;
     use crate::mir::expr::arbitrary::ArbExprParams;
     use crate::types::sfunc::SFunc;
+    use alloc::vec;
     use proptest::prelude::*;
 
     impl Arbitrary for Exists {
diff --git a/ergotree-ir/src/mir/coll_filter.rs b/ergotree-ir/src/mir/coll_filter.rs
index b245da250..9dd22c079 100644
--- a/ergotree-ir/src/mir/coll_filter.rs
+++ b/ergotree-ir/src/mir/coll_filter.rs
@@ -1,4 +1,6 @@
-use std::sync::Arc;
+use alloc::boxed::Box;
+
+use alloc::sync::Arc;
 
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
@@ -84,6 +86,7 @@ mod arbitrary {
     use super::*;
     use crate::mir::expr::arbitrary::ArbExprParams;
     use crate::types::sfunc::SFunc;
+    use alloc::vec;
     use proptest::prelude::*;
 
     impl Arbitrary for Filter {
diff --git a/ergotree-ir/src/mir/coll_fold.rs b/ergotree-ir/src/mir/coll_fold.rs
index bd9f96f3c..51c7320ce 100644
--- a/ergotree-ir/src/mir/coll_fold.rs
+++ b/ergotree-ir/src/mir/coll_fold.rs
@@ -1,3 +1,7 @@
+use alloc::boxed::Box;
+
+use alloc::vec;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
diff --git a/ergotree-ir/src/mir/coll_forall.rs b/ergotree-ir/src/mir/coll_forall.rs
index 75f375525..f24a56d0a 100644
--- a/ergotree-ir/src/mir/coll_forall.rs
+++ b/ergotree-ir/src/mir/coll_forall.rs
@@ -1,4 +1,6 @@
-use std::sync::Arc;
+use alloc::boxed::Box;
+
+use alloc::sync::Arc;
 
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
@@ -84,6 +86,7 @@ mod arbitrary {
     use super::*;
     use crate::mir::expr::arbitrary::ArbExprParams;
     use crate::types::sfunc::SFunc;
+    use alloc::vec;
     use proptest::prelude::*;
 
     impl Arbitrary for ForAll {
diff --git a/ergotree-ir/src/mir/coll_map.rs b/ergotree-ir/src/mir/coll_map.rs
index 42f3d85f7..a52038e62 100644
--- a/ergotree-ir/src/mir/coll_map.rs
+++ b/ergotree-ir/src/mir/coll_map.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
@@ -84,6 +86,7 @@ impl_traversable_expr!(Map, boxed input, boxed mapper);
 mod arbitrary {
     use super::*;
     use crate::mir::expr::arbitrary::ArbExprParams;
+    use alloc::vec;
     use proptest::prelude::*;
 
     impl Arbitrary for Map {
diff --git a/ergotree-ir/src/mir/coll_size.rs b/ergotree-ir/src/mir/coll_size.rs
index f837ee403..9808d8d67 100644
--- a/ergotree-ir/src/mir/coll_size.rs
+++ b/ergotree-ir/src/mir/coll_size.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
 
diff --git a/ergotree-ir/src/mir/coll_slice.rs b/ergotree-ir/src/mir/coll_slice.rs
index 3d2bc06e0..bc53d4b34 100644
--- a/ergotree-ir/src/mir/coll_slice.rs
+++ b/ergotree-ir/src/mir/coll_slice.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
diff --git a/ergotree-ir/src/mir/collection.rs b/ergotree-ir/src/mir/collection.rs
index 4b653f4f5..19792dadd 100644
--- a/ergotree-ir/src/mir/collection.rs
+++ b/ergotree-ir/src/mir/collection.rs
@@ -1,3 +1,6 @@
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+
 use crate::has_opcode::HasOpCode;
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
@@ -83,13 +86,13 @@ impl Traversable for Collection {
     fn children(&self) -> Box<dyn Iterator<Item = &Expr> + '_> {
         match self {
             Self::Exprs { elem_tpe: _, items } => Box::new(items.iter()),
-            Self::BoolConstants(_) => Box::new(std::iter::empty()),
+            Self::BoolConstants(_) => Box::new(core::iter::empty()),
         }
     }
     fn children_mut(&mut self) -> Box<dyn Iterator<Item = &mut Expr> + '_> {
         match self {
             Self::Exprs { elem_tpe: _, items } => Box::new(items.iter_mut()),
-            Self::BoolConstants(_) => Box::new(std::iter::empty()),
+            Self::BoolConstants(_) => Box::new(core::iter::empty()),
         }
     }
 }
diff --git a/ergotree-ir/src/mir/constant.rs b/ergotree-ir/src/mir/constant.rs
index ae61153e9..f07107bbd 100644
--- a/ergotree-ir/src/mir/constant.rs
+++ b/ergotree-ir/src/mir/constant.rs
@@ -17,6 +17,15 @@ use crate::types::stuple::STuple;
 use crate::types::stuple::TupleItems;
 use crate::types::stype::LiftIntoSType;
 use crate::types::stype::SType;
+use alloc::boxed::Box;
+
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::sync::Arc;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::convert::TryInto;
+use core::fmt::Formatter;
 use ergo_chain_types::ADDigest;
 use ergo_chain_types::Base16DecodedBytes;
 use ergo_chain_types::Digest32;
@@ -24,10 +33,6 @@ use ergo_chain_types::EcPoint;
 use impl_trait_for_tuples::impl_for_tuples;
 use sigma_util::AsVecI8;
 use sigma_util::AsVecU8;
-use std::convert::TryFrom;
-use std::convert::TryInto;
-use std::fmt::Formatter;
-use std::sync::Arc;
 
 mod constant_placeholder;
 
@@ -83,20 +88,20 @@ pub enum Literal {
     Tup(TupleItems<Literal>),
 }
 
-impl std::fmt::Debug for Constant {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Debug for Constant {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         format!("{:?}: {:?}", self.v, self.tpe).fmt(f)
     }
 }
 
-impl std::fmt::Display for Constant {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for Constant {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         self.v.fmt(f)
     }
 }
 
-impl std::fmt::Debug for Literal {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Debug for Literal {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         match self {
             Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => {
                 base16::encode_lower(&i8_bytes.as_vec_u8()).fmt(f)
@@ -119,8 +124,8 @@ impl std::fmt::Debug for Literal {
     }
 }
 
-impl std::fmt::Display for Literal {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for Literal {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         match self {
             Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => {
                 write!(f, "Coll[Byte](")?;
@@ -755,13 +760,13 @@ impl<T: TryExtractFrom<Literal> + StoreWrapped> TryExtractFrom<Literal> for Vec<
                 } => v.iter().cloned().map(T::try_extract_from).collect(),
                 _ => Err(TryExtractFromError(format!(
                     "expected {:?}, found {:?}",
-                    std::any::type_name::<Self>(),
+                    core::any::type_name::<Self>(),
                     coll
                 ))),
             },
             _ => Err(TryExtractFromError(format!(
                 "expected {:?}, found {:?}",
-                std::any::type_name::<Self>(),
+                core::any::type_name::<Self>(),
                 c
             ))),
         }
@@ -775,13 +780,13 @@ impl TryExtractFrom<Literal> for Vec<i8> {
                 CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs.iter().copied().collect()), // TODO: optimize
                 _ => Err(TryExtractFromError(format!(
                     "expected {:?}, found {:?}",
-                    std::any::type_name::<Self>(),
+                    core::any::type_name::<Self>(),
                     v
                 ))),
             },
             _ => Err(TryExtractFromError(format!(
                 "expected {:?}, found {:?}",
-                std::any::type_name::<Self>(),
+                core::any::type_name::<Self>(),
                 v
             ))),
         }
@@ -823,7 +828,7 @@ impl TryExtractFrom<Literal> for BigInt256 {
             Literal::BigInt(bi) => Ok(bi),
             _ => Err(TryExtractFromError(format!(
                 "expected {:?}, found {:?}",
-                std::any::type_name::<Self>(),
+                core::any::type_name::<Self>(),
                 v
             ))),
         }
@@ -836,7 +841,7 @@ impl TryExtractFrom<Literal> for AvlTreeData {
             Literal::AvlTree(a) => Ok(*a),
             _ => Err(TryExtractFromError(format!(
                 "expected {:?}, found {:?}",
-                std::any::type_name::<Self>(),
+                core::any::type_name::<Self>(),
                 v
             ))),
         }
@@ -926,7 +931,7 @@ impl TryFrom<Base16DecodedBytes> for Constant {
 #[allow(clippy::todo)]
 /// Arbitrary impl
 pub(crate) mod arbitrary {
-    use std::convert::TryFrom;
+    use core::convert::TryFrom;
 
     use super::*;
     use crate::mir::value::CollKind;
@@ -1092,6 +1097,7 @@ pub(crate) mod arbitrary {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 pub mod tests {
     use super::*;
diff --git a/ergotree-ir/src/mir/create_avl_tree.rs b/ergotree-ir/src/mir/create_avl_tree.rs
index 0ef8feb8d..3959b3468 100644
--- a/ergotree-ir/src/mir/create_avl_tree.rs
+++ b/ergotree-ir/src/mir/create_avl_tree.rs
@@ -1,5 +1,7 @@
 //! Create an AVL tree
 
+use alloc::boxed::Box;
+
 use super::expr::Expr;
 use crate::has_opcode::HasStaticOpCode;
 use crate::mir::expr::InvalidArgumentError;
@@ -32,7 +34,7 @@ impl CreateAvlTree {
         value_length: Option<Box<Expr>>,
     ) -> Result<Self, InvalidArgumentError> {
         flags.check_post_eval_tpe(&SType::SByte)?;
-        digest.check_post_eval_tpe(&SType::SColl(std::sync::Arc::new(SType::SByte)))?;
+        digest.check_post_eval_tpe(&SType::SColl(alloc::sync::Arc::new(SType::SByte)))?;
         key_length.check_post_eval_tpe(&SType::SInt)?;
         if !value_length
             .clone()
@@ -86,7 +88,7 @@ impl_traversable_expr!(CreateAvlTree, boxed flags, boxed digest, boxed key_lengt
 #[cfg(feature = "arbitrary")]
 /// Arbitrary impl
 mod arbitrary {
-    use std::sync::Arc;
+    use alloc::sync::Arc;
 
     use crate::mir::expr::arbitrary::ArbExprParams;
 
diff --git a/ergotree-ir/src/mir/create_prove_dh_tuple.rs b/ergotree-ir/src/mir/create_prove_dh_tuple.rs
index 3da6f8563..27c8f2152 100644
--- a/ergotree-ir/src/mir/create_prove_dh_tuple.rs
+++ b/ergotree-ir/src/mir/create_prove_dh_tuple.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
diff --git a/ergotree-ir/src/mir/create_provedlog.rs b/ergotree-ir/src/mir/create_provedlog.rs
index f7828ca94..de4ea5d8a 100644
--- a/ergotree-ir/src/mir/create_provedlog.rs
+++ b/ergotree-ir/src/mir/create_provedlog.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
 
diff --git a/ergotree-ir/src/mir/decode_point.rs b/ergotree-ir/src/mir/decode_point.rs
index 8db2d17ff..15fd10e58 100644
--- a/ergotree-ir/src/mir/decode_point.rs
+++ b/ergotree-ir/src/mir/decode_point.rs
@@ -1,6 +1,7 @@
 //! Decode byte array to EC point
 
-use std::sync::Arc;
+use alloc::boxed::Box;
+use alloc::sync::Arc;
 
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
@@ -72,11 +73,13 @@ mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
     use crate::mir::expr::Expr;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/deserialize_register.rs b/ergotree-ir/src/mir/deserialize_register.rs
index 33ab5645f..397bdc9bb 100644
--- a/ergotree-ir/src/mir/deserialize_register.rs
+++ b/ergotree-ir/src/mir/deserialize_register.rs
@@ -1,5 +1,8 @@
 //! Extract register of SELF box as `Coll[Byte]`, deserialize it into Value and inline into executing script.
 
+use alloc::boxed::Box;
+use alloc::string::ToString;
+
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
 use crate::chain::ergo_box::RegisterId;
@@ -71,6 +74,7 @@ mod arbitrary {
 
     use super::*;
 
+    use alloc::boxed::Box;
     use proptest::option;
     use proptest::prelude::*;
 
diff --git a/ergotree-ir/src/mir/downcast.rs b/ergotree-ir/src/mir/downcast.rs
index 0b9a34e1c..35f7160c2 100644
--- a/ergotree-ir/src/mir/downcast.rs
+++ b/ergotree-ir/src/mir/downcast.rs
@@ -1,5 +1,7 @@
 //! Numerical downcast
 
+use alloc::boxed::Box;
+
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
 use crate::serialization::op_code::OpCode;
diff --git a/ergotree-ir/src/mir/exponentiate.rs b/ergotree-ir/src/mir/exponentiate.rs
index a93cebc81..28ab7be92 100644
--- a/ergotree-ir/src/mir/exponentiate.rs
+++ b/ergotree-ir/src/mir/exponentiate.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs
index 9f48d128e..7e7054b0a 100644
--- a/ergotree-ir/src/mir/expr.rs
+++ b/ergotree-ir/src/mir/expr.rs
@@ -1,7 +1,11 @@
 //! IR expression
 
-use std::convert::Infallible;
-use std::convert::TryFrom;
+use alloc::boxed::Box;
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::convert::Infallible;
+use core::convert::TryFrom;
+use core::convert::TryInto;
 
 use crate::chain::context::Context;
 use crate::chain::ergo_box::RegisterId;
@@ -324,8 +328,10 @@ impl Expr {
         if &expr_tpe == expected_tpe {
             Ok(())
         } else {
-            use std::backtrace::Backtrace;
-            let backtrace = Backtrace::capture();
+            #[cfg(feature = "std")]
+            let backtrace = std::backtrace::Backtrace::capture();
+            #[cfg(not(feature = "std"))]
+            let backtrace = "Backtraces not supported without std";
             Err(InvalidExprEvalTypeError(format!(
                 "expected: {0:?}, got: {1:?}\nBacktrace:\n{backtrace}",
                 expected_tpe, expr_tpe
@@ -485,7 +491,7 @@ impl Traversable for Expr {
 
     fn children<'a>(&'a self) -> Box<dyn Iterator<Item = &Expr> + '_> {
         match self {
-            Expr::Const(_) => Box::new(std::iter::empty()),
+            Expr::Const(_) => Box::new(core::iter::empty()),
             Expr::SubstConstants(op) => op.children(),
             Expr::ByteArrayToLong(op) => op.children(),
             Expr::ByteArrayToBigInt(op) => op.children(),
@@ -498,8 +504,8 @@ impl Traversable for Expr {
             Expr::MethodCall(op) => op.children(),
             Expr::PropertyCall(op) => op.children(),
             Expr::BinOp(op) => op.children(),
-            Expr::Global => Box::new(std::iter::empty()),
-            Expr::Context => Box::new(std::iter::empty()),
+            Expr::Global => Box::new(core::iter::empty()),
+            Expr::Context => Box::new(core::iter::empty()),
             Expr::OptionGet(v) => v.children(),
             Expr::Apply(op) => op.children(),
             Expr::FuncValue(op) => op.children(),
@@ -507,7 +513,7 @@ impl Traversable for Expr {
             Expr::BlockValue(op) => op.children(),
             Expr::SelectField(op) => op.children(),
             Expr::ExtractAmount(op) => op.children(),
-            Expr::ConstPlaceholder(_) => Box::new(std::iter::empty()),
+            Expr::ConstPlaceholder(_) => Box::new(core::iter::empty()),
             Expr::Collection(op) => op.children(),
             Expr::ValDef(op) => op.children(),
             Expr::And(op) => op.children(),
@@ -555,7 +561,7 @@ impl Traversable for Expr {
     }
     fn children_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &mut Expr> + '_> {
         match self {
-            Expr::Const(_) => Box::new(std::iter::empty()),
+            Expr::Const(_) => Box::new(core::iter::empty()),
             Expr::SubstConstants(op) => op.children_mut(),
             Expr::ByteArrayToLong(op) => op.children_mut(),
             Expr::ByteArrayToBigInt(op) => op.children_mut(),
@@ -568,8 +574,8 @@ impl Traversable for Expr {
             Expr::MethodCall(op) => op.children_mut(),
             Expr::PropertyCall(op) => op.children_mut(),
             Expr::BinOp(op) => op.children_mut(),
-            Expr::Global => Box::new(std::iter::empty()),
-            Expr::Context => Box::new(std::iter::empty()),
+            Expr::Global => Box::new(core::iter::empty()),
+            Expr::Context => Box::new(core::iter::empty()),
             Expr::OptionGet(v) => v.children_mut(),
             Expr::Apply(op) => op.children_mut(),
             Expr::FuncValue(op) => op.children_mut(),
@@ -577,7 +583,7 @@ impl Traversable for Expr {
             Expr::BlockValue(op) => op.children_mut(),
             Expr::SelectField(op) => op.children_mut(),
             Expr::ExtractAmount(op) => op.children_mut(),
-            Expr::ConstPlaceholder(_) => Box::new(std::iter::empty()),
+            Expr::ConstPlaceholder(_) => Box::new(core::iter::empty()),
             Expr::Collection(op) => op.children_mut(),
             Expr::ValDef(op) => op.children_mut(),
             Expr::And(op) => op.children_mut(),
@@ -680,7 +686,7 @@ impl<T: TryFrom<Expr>> TryExtractFrom<Expr> for T {
         let res: Result<Self, TryExtractFromError> = v.clone().try_into().map_err(|_| {
             TryExtractFromError(format!(
                 "Cannot extract {0:?} from {1:?}",
-                std::any::type_name::<T>(),
+                core::any::type_name::<T>(),
                 v
             ))
         });
@@ -698,9 +704,10 @@ pub(crate) mod arbitrary {
     use crate::mir::func_value::FuncArg;
     use crate::sigma_protocol::sigma_boolean::ProveDlog;
     use crate::types::sfunc::SFunc;
+    use alloc::sync::Arc;
+    use alloc::vec;
     use proptest::collection::*;
     use proptest::prelude::*;
-    use std::sync::Arc;
 
     /// Parameters for arbitrary Expr generation
     #[derive(PartialEq, Eq, Debug, Clone)]
diff --git a/ergotree-ir/src/mir/extract_amount.rs b/ergotree-ir/src/mir/extract_amount.rs
index 206d77fb4..e189f1936 100644
--- a/ergotree-ir/src/mir/extract_amount.rs
+++ b/ergotree-ir/src/mir/extract_amount.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
 
@@ -46,6 +48,8 @@ impl OneArgOpTryBuild for ExtractAmount {
 #[cfg(test)]
 #[cfg(feature = "arbitrary")]
 mod tests {
+    use alloc::boxed::Box;
+
     use crate::mir::global_vars::GlobalVars;
     use crate::serialization::sigma_serialize_roundtrip;
 
diff --git a/ergotree-ir/src/mir/extract_bytes.rs b/ergotree-ir/src/mir/extract_bytes.rs
index c866be5e9..b7bdb009c 100644
--- a/ergotree-ir/src/mir/extract_bytes.rs
+++ b/ergotree-ir/src/mir/extract_bytes.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
 
diff --git a/ergotree-ir/src/mir/extract_bytes_with_no_ref.rs b/ergotree-ir/src/mir/extract_bytes_with_no_ref.rs
index 2771e12b4..6afa79184 100644
--- a/ergotree-ir/src/mir/extract_bytes_with_no_ref.rs
+++ b/ergotree-ir/src/mir/extract_bytes_with_no_ref.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
 
diff --git a/ergotree-ir/src/mir/extract_creation_info.rs b/ergotree-ir/src/mir/extract_creation_info.rs
index eb34b74e3..f1ed83157 100644
--- a/ergotree-ir/src/mir/extract_creation_info.rs
+++ b/ergotree-ir/src/mir/extract_creation_info.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::types::stuple::STuple;
 use crate::types::stype::SType;
diff --git a/ergotree-ir/src/mir/extract_id.rs b/ergotree-ir/src/mir/extract_id.rs
index e33a3ce72..bca53f090 100644
--- a/ergotree-ir/src/mir/extract_id.rs
+++ b/ergotree-ir/src/mir/extract_id.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
 
@@ -46,6 +48,8 @@ impl OneArgOpTryBuild for ExtractId {
 #[cfg(test)]
 #[cfg(feature = "arbitrary")]
 mod tests {
+    use alloc::boxed::Box;
+
     use crate::mir::global_vars::GlobalVars;
     use crate::serialization::sigma_serialize_roundtrip;
 
diff --git a/ergotree-ir/src/mir/extract_reg_as.rs b/ergotree-ir/src/mir/extract_reg_as.rs
index a1ce698f8..fe4e1b800 100644
--- a/ergotree-ir/src/mir/extract_reg_as.rs
+++ b/ergotree-ir/src/mir/extract_reg_as.rs
@@ -1,4 +1,6 @@
-use std::sync::Arc;
+use alloc::boxed::Box;
+
+use alloc::sync::Arc;
 
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
diff --git a/ergotree-ir/src/mir/extract_script_bytes.rs b/ergotree-ir/src/mir/extract_script_bytes.rs
index 5f14803b6..cfa8be5ab 100644
--- a/ergotree-ir/src/mir/extract_script_bytes.rs
+++ b/ergotree-ir/src/mir/extract_script_bytes.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
 
diff --git a/ergotree-ir/src/mir/func_value.rs b/ergotree-ir/src/mir/func_value.rs
index 6d4fa5ca8..0380d0f42 100644
--- a/ergotree-ir/src/mir/func_value.rs
+++ b/ergotree-ir/src/mir/func_value.rs
@@ -1,4 +1,7 @@
-use std::fmt;
+use alloc::boxed::Box;
+use alloc::vec;
+use alloc::vec::Vec;
+use core::fmt;
 
 use crate::has_opcode::HasStaticOpCode;
 use crate::serialization::op_code::OpCode;
@@ -14,12 +17,12 @@ use crate::types::stype::SType;
 use super::expr::Expr;
 use super::val_def::ValId;
 
-#[cfg(test)]
+#[cfg(feature = "arbitrary")]
 use proptest_derive::Arbitrary;
 
 /// Argument parameter for the user-defined function [`FuncValue`]
 #[derive(PartialEq, Eq, Debug, Clone)]
-#[cfg_attr(test, derive(Arbitrary))]
+#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
 pub struct FuncArg {
     /// Value id (defined with [`super::val_def::ValDef`])
     pub idx: ValId,
@@ -40,7 +43,7 @@ impl SigmaSerializable for FuncArg {
     }
 }
 
-impl std::fmt::Display for FuncArg {
+impl core::fmt::Display for FuncArg {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "v{}: {}", self.idx, self.tpe)
     }
diff --git a/ergotree-ir/src/mir/get_var.rs b/ergotree-ir/src/mir/get_var.rs
index cd480b2c1..6b1c0e949 100644
--- a/ergotree-ir/src/mir/get_var.rs
+++ b/ergotree-ir/src/mir/get_var.rs
@@ -65,11 +65,13 @@ mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
     use crate::mir::expr::Expr;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/global_vars.rs b/ergotree-ir/src/mir/global_vars.rs
index 09165e735..8335a3f20 100644
--- a/ergotree-ir/src/mir/global_vars.rs
+++ b/ergotree-ir/src/mir/global_vars.rs
@@ -1,7 +1,7 @@
 //! Global variables
 
-use std::fmt::Display;
-use std::sync::Arc;
+use alloc::sync::Arc;
+use core::fmt::Display;
 
 use crate::has_opcode::HasOpCode;
 use crate::serialization::op_code::OpCode;
@@ -56,7 +56,7 @@ impl HasOpCode for GlobalVars {
 }
 
 impl Display for GlobalVars {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self {
             GlobalVars::SelfBox => write!(f, "SELF"),
             GlobalVars::Inputs => write!(f, "INPUTS"),
diff --git a/ergotree-ir/src/mir/if_op.rs b/ergotree-ir/src/mir/if_op.rs
index 1298f3e30..ce842494f 100644
--- a/ergotree-ir/src/mir/if_op.rs
+++ b/ergotree-ir/src/mir/if_op.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use super::expr::Expr;
 use crate::has_opcode::HasStaticOpCode;
 use crate::serialization::op_code::OpCode;
diff --git a/ergotree-ir/src/mir/logical_not.rs b/ergotree-ir/src/mir/logical_not.rs
index cdb0cc664..da77e303c 100644
--- a/ergotree-ir/src/mir/logical_not.rs
+++ b/ergotree-ir/src/mir/logical_not.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
 use super::unary_op::OneArgOp;
@@ -68,6 +70,7 @@ mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
diff --git a/ergotree-ir/src/mir/long_to_byte_array.rs b/ergotree-ir/src/mir/long_to_byte_array.rs
index bd01a0b4b..609a7b491 100644
--- a/ergotree-ir/src/mir/long_to_byte_array.rs
+++ b/ergotree-ir/src/mir/long_to_byte_array.rs
@@ -1,4 +1,6 @@
 //! Convert SLong to byte array
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
 
@@ -78,6 +80,7 @@ mod arbitrary {
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/method_call.rs b/ergotree-ir/src/mir/method_call.rs
index 6d6e8ccac..e21d6f6c0 100644
--- a/ergotree-ir/src/mir/method_call.rs
+++ b/ergotree-ir/src/mir/method_call.rs
@@ -1,4 +1,9 @@
-use std::collections::HashMap;
+use hashbrown::HashMap;
+
+use alloc::boxed::Box;
+
+use alloc::vec;
+use alloc::vec::Vec;
 
 use crate::serialization::op_code::OpCode;
 use crate::traversable::impl_traversable_expr;
@@ -52,7 +57,7 @@ impl MethodCall {
             .method_raw
             .explicit_type_args
             .iter()
-            .find(|tpe| !explicit_type_args.contains_key(tpe))
+            .find(|&tpe| !explicit_type_args.contains_key(tpe))
         {
             return Err(InvalidArgumentError(format!(
                 "MethodCall: explicit_type_args does not include substitution for STypeVar {missing_tpe:?}",
diff --git a/ergotree-ir/src/mir/multiply_group.rs b/ergotree-ir/src/mir/multiply_group.rs
index 97e4c4ec7..725303a79 100644
--- a/ergotree-ir/src/mir/multiply_group.rs
+++ b/ergotree-ir/src/mir/multiply_group.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
diff --git a/ergotree-ir/src/mir/negation.rs b/ergotree-ir/src/mir/negation.rs
index 16b3d42eb..683288add 100644
--- a/ergotree-ir/src/mir/negation.rs
+++ b/ergotree-ir/src/mir/negation.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
 use super::unary_op::OneArgOp;
@@ -87,10 +89,12 @@ mod arbitrary {
 
 #[cfg(test)]
 #[allow(clippy::panic)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::mir::expr::Expr;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/option_get.rs b/ergotree-ir/src/mir/option_get.rs
index 571c50aa2..8920f344d 100644
--- a/ergotree-ir/src/mir/option_get.rs
+++ b/ergotree-ir/src/mir/option_get.rs
@@ -1,4 +1,6 @@
-use std::sync::Arc;
+use alloc::boxed::Box;
+
+use alloc::sync::Arc;
 
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
diff --git a/ergotree-ir/src/mir/option_get_or_else.rs b/ergotree-ir/src/mir/option_get_or_else.rs
index 299752f82..24d322115 100644
--- a/ergotree-ir/src/mir/option_get_or_else.rs
+++ b/ergotree-ir/src/mir/option_get_or_else.rs
@@ -9,7 +9,9 @@ use crate::serialization::SigmaSerializable;
 use crate::serialization::SigmaSerializeResult;
 use crate::traversable::impl_traversable_expr;
 use crate::types::stype::SType;
-use std::sync::Arc;
+use alloc::boxed::Box;
+
+use alloc::sync::Arc;
 
 /// Returns the Option's value or error if no value
 #[derive(PartialEq, Eq, Debug, Clone)]
diff --git a/ergotree-ir/src/mir/option_is_defined.rs b/ergotree-ir/src/mir/option_is_defined.rs
index 6adb2a28a..c52fd4ec6 100644
--- a/ergotree-ir/src/mir/option_is_defined.rs
+++ b/ergotree-ir/src/mir/option_is_defined.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
 use super::unary_op::OneArgOp;
diff --git a/ergotree-ir/src/mir/or.rs b/ergotree-ir/src/mir/or.rs
index 52526961e..d3654c277 100644
--- a/ergotree-ir/src/mir/or.rs
+++ b/ergotree-ir/src/mir/or.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use super::expr::Expr;
 use super::unary_op::OneArgOp;
 use crate::has_opcode::HasStaticOpCode;
@@ -77,6 +79,7 @@ mod arbitrary {
 
 #[cfg(test)]
 #[allow(clippy::panic)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::mir::expr::Expr;
diff --git a/ergotree-ir/src/mir/property_call.rs b/ergotree-ir/src/mir/property_call.rs
index 0f0f078ff..d08d49898 100644
--- a/ergotree-ir/src/mir/property_call.rs
+++ b/ergotree-ir/src/mir/property_call.rs
@@ -1,3 +1,7 @@
+use alloc::boxed::Box;
+
+use alloc::vec;
+
 use crate::serialization::op_code::OpCode;
 use crate::traversable::impl_traversable_expr;
 use crate::types::smethod::SMethod;
diff --git a/ergotree-ir/src/mir/select_field.rs b/ergotree-ir/src/mir/select_field.rs
index d033b40c0..4b4e78262 100644
--- a/ergotree-ir/src/mir/select_field.rs
+++ b/ergotree-ir/src/mir/select_field.rs
@@ -1,4 +1,6 @@
-use std::convert::TryFrom;
+use core::convert::TryFrom;
+
+use alloc::boxed::Box;
 
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
@@ -126,7 +128,7 @@ impl_traversable_expr!(SelectField, boxed input);
 #[cfg(feature = "arbitrary")]
 #[allow(clippy::unwrap_used)]
 mod tests {
-    use std::convert::TryInto;
+    use core::convert::TryInto;
 
     use crate::serialization::sigma_serialize_roundtrip;
 
diff --git a/ergotree-ir/src/mir/sigma_and.rs b/ergotree-ir/src/mir/sigma_and.rs
index 6659aa762..cf66e09cc 100644
--- a/ergotree-ir/src/mir/sigma_and.rs
+++ b/ergotree-ir/src/mir/sigma_and.rs
@@ -1,6 +1,8 @@
 //! AND conjunction for sigma propositions
 
-use std::convert::TryInto;
+use core::convert::TryInto;
+
+use alloc::vec::Vec;
 
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
@@ -97,6 +99,7 @@ mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
diff --git a/ergotree-ir/src/mir/sigma_or.rs b/ergotree-ir/src/mir/sigma_or.rs
index af24d4b97..cc49176be 100644
--- a/ergotree-ir/src/mir/sigma_or.rs
+++ b/ergotree-ir/src/mir/sigma_or.rs
@@ -1,6 +1,8 @@
 //! OR conjunction for sigma propositions
 
-use std::convert::TryInto;
+use core::convert::TryInto;
+
+use alloc::vec::Vec;
 
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
@@ -97,6 +99,7 @@ mod arbitrary {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
diff --git a/ergotree-ir/src/mir/sigma_prop_bytes.rs b/ergotree-ir/src/mir/sigma_prop_bytes.rs
index 9db3ae51a..5d7e26d81 100644
--- a/ergotree-ir/src/mir/sigma_prop_bytes.rs
+++ b/ergotree-ir/src/mir/sigma_prop_bytes.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
 
diff --git a/ergotree-ir/src/mir/subst_const.rs b/ergotree-ir/src/mir/subst_const.rs
index afb8a23f8..46537a689 100644
--- a/ergotree-ir/src/mir/subst_const.rs
+++ b/ergotree-ir/src/mir/subst_const.rs
@@ -1,4 +1,6 @@
 //! Substitution of constants in serialized sigma expression
+use alloc::boxed::Box;
+
 use super::expr::Expr;
 use crate::has_opcode::HasStaticOpCode;
 use crate::mir::expr::InvalidArgumentError;
diff --git a/ergotree-ir/src/mir/tree_lookup.rs b/ergotree-ir/src/mir/tree_lookup.rs
index 918131f27..bb23e1936 100644
--- a/ergotree-ir/src/mir/tree_lookup.rs
+++ b/ergotree-ir/src/mir/tree_lookup.rs
@@ -1,4 +1,6 @@
 //! Lookup in AVL tree
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::traversable::impl_traversable_expr;
 use crate::types::stype::SType;
@@ -66,7 +68,7 @@ impl_traversable_expr!(TreeLookup, boxed tree, boxed key, boxed proof);
 /// Arbitrary impl
 mod arbitrary {
     use crate::mir::expr::arbitrary::ArbExprParams;
-    use std::sync::Arc;
+    use alloc::sync::Arc;
 
     use super::*;
     use proptest::prelude::*;
diff --git a/ergotree-ir/src/mir/tuple.rs b/ergotree-ir/src/mir/tuple.rs
index 90b8cfcd1..262b220d8 100644
--- a/ergotree-ir/src/mir/tuple.rs
+++ b/ergotree-ir/src/mir/tuple.rs
@@ -1,4 +1,6 @@
-use std::convert::TryInto;
+use core::convert::TryInto;
+
+use alloc::vec::Vec;
 
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
diff --git a/ergotree-ir/src/mir/upcast.rs b/ergotree-ir/src/mir/upcast.rs
index 79bd82bcf..09919de80 100644
--- a/ergotree-ir/src/mir/upcast.rs
+++ b/ergotree-ir/src/mir/upcast.rs
@@ -1,5 +1,7 @@
 //! Numerical upcast
 
+use alloc::boxed::Box;
+
 use super::expr::Expr;
 use super::expr::InvalidArgumentError;
 use crate::serialization::op_code::OpCode;
diff --git a/ergotree-ir/src/mir/val_def.rs b/ergotree-ir/src/mir/val_def.rs
index d241b024a..38e56da96 100644
--- a/ergotree-ir/src/mir/val_def.rs
+++ b/ergotree-ir/src/mir/val_def.rs
@@ -10,6 +10,7 @@ use crate::types::stype::SType;
 use super::expr::Expr;
 
 extern crate derive_more;
+use alloc::boxed::Box;
 use derive_more::Display;
 use derive_more::From;
 
@@ -23,7 +24,7 @@ use proptest_derive::Arbitrary;
 pub struct ValId(pub u32);
 
 impl ValId {
-    pub(crate) fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> std::io::Result<()> {
+    pub(crate) fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> core2::io::Result<()> {
         w.put_u32(self.0)
     }
 
@@ -38,7 +39,7 @@ impl ValId {
  * This representation is more compact in serialized form.
  * @param id unique identifier of the variable in the current scope. */
 #[derive(PartialEq, Eq, Debug, Clone)]
-#[cfg_attr(test, derive(Arbitrary))]
+#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
 pub struct ValDef {
     /// Variable id
     pub id: ValId,
diff --git a/ergotree-ir/src/mir/val_use.rs b/ergotree-ir/src/mir/val_use.rs
index 684d7e03a..bf7f8449d 100644
--- a/ergotree-ir/src/mir/val_use.rs
+++ b/ergotree-ir/src/mir/val_use.rs
@@ -55,6 +55,9 @@ mod tests {
 
     use super::*;
 
+    use alloc::boxed::Box;
+
+    use alloc::vec;
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/mir/value.rs b/ergotree-ir/src/mir/value.rs
index 9f01c9b69..9991bb703 100644
--- a/ergotree-ir/src/mir/value.rs
+++ b/ergotree-ir/src/mir/value.rs
@@ -1,8 +1,12 @@
 //! Ergo data type
 
-use std::convert::TryInto;
-use std::fmt::Formatter;
-use std::sync::Arc;
+use alloc::boxed::Box;
+
+use alloc::string::ToString;
+use alloc::sync::Arc;
+use alloc::vec::Vec;
+use core::convert::TryInto;
+use core::fmt::Formatter;
 
 use impl_trait_for_tuples::impl_for_tuples;
 use sigma_util::AsVecI8;
@@ -329,8 +333,8 @@ impl From<Literal> for Value<'static> {
     }
 }
 
-impl std::fmt::Display for Value<'_> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for Value<'_> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         match self {
             Value::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => {
                 write!(f, "Coll[Byte](")?;
@@ -558,13 +562,13 @@ impl<'ctx, T: TryExtractFrom<Value<'ctx>> + StoreWrapped> TryExtractFrom<Value<'
                 } => v.iter().cloned().map(T::try_extract_from).collect(),
                 _ => Err(TryExtractFromError(format!(
                     "expected {:?}, found {:?}",
-                    std::any::type_name::<Self>(),
+                    core::any::type_name::<Self>(),
                     coll
                 ))),
             },
             _ => Err(TryExtractFromError(format!(
                 "expected {:?}, found {:?}",
-                std::any::type_name::<Self>(),
+                core::any::type_name::<Self>(),
                 c
             ))),
         }
@@ -587,17 +591,17 @@ impl<'ctx, T: TryExtractFrom<Value<'ctx>> + StoreWrapped, const N: usize>
                         .map(T::try_extract_from)
                         .collect::<Result<Vec<_>, _>>()?;
                     let len = v.len();
-                    v.try_into().map_err(|_| TryExtractFromError(format!("can't convert vec of {:?} with length of {:?} to array with length of {:?}", std::any::type_name::<T>(), len, N)))
+                    v.try_into().map_err(|_| TryExtractFromError(format!("can't convert vec of {:?} with length of {:?} to array with length of {:?}", core::any::type_name::<T>(), len, N)))
                 }
                 _ => Err(TryExtractFromError(format!(
                     "expected {:?}, found {:?}",
-                    std::any::type_name::<Self>(),
+                    core::any::type_name::<Self>(),
                     coll
                 ))),
             },
             _ => Err(TryExtractFromError(format!(
                 "expected {:?}, found {:?}",
-                std::any::type_name::<Self>(),
+                core::any::type_name::<Self>(),
                 c
             ))),
         }
@@ -611,13 +615,13 @@ impl TryExtractFrom<Value<'_>> for Vec<i8> {
                 CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs.iter().copied().collect()),
                 _ => Err(TryExtractFromError(format!(
                     "expected {:?}, found {:?}",
-                    std::any::type_name::<Self>(),
+                    core::any::type_name::<Self>(),
                     v
                 ))),
             },
             _ => Err(TryExtractFromError(format!(
                 "expected {:?}, found {:?}",
-                std::any::type_name::<Self>(),
+                core::any::type_name::<Self>(),
                 v
             ))),
         }
@@ -643,7 +647,7 @@ impl TryExtractFrom<Value<'_>> for BigInt256 {
             Value::BigInt(bi) => Ok(bi),
             _ => Err(TryExtractFromError(format!(
                 "expected {:?}, found {:?}",
-                std::any::type_name::<Self>(),
+                core::any::type_name::<Self>(),
                 v
             ))),
         }
@@ -656,7 +660,7 @@ impl TryExtractFrom<Value<'_>> for AvlTreeData {
             Value::AvlTree(a) => Ok(*a),
             _ => Err(TryExtractFromError(format!(
                 "expected {:?}, found {:?}",
-                std::any::type_name::<Self>(),
+                core::any::type_name::<Self>(),
                 v
             ))),
         }
diff --git a/ergotree-ir/src/mir/xor.rs b/ergotree-ir/src/mir/xor.rs
index 8258d7919..6560f64aa 100644
--- a/ergotree-ir/src/mir/xor.rs
+++ b/ergotree-ir/src/mir/xor.rs
@@ -9,7 +9,9 @@ use crate::serialization::SigmaSerializable;
 use crate::serialization::SigmaSerializeResult;
 use crate::traversable::impl_traversable_expr;
 use crate::types::stype::SType;
-use std::sync::Arc;
+use alloc::boxed::Box;
+
+use alloc::sync::Arc;
 
 /// Byte-wise XOR op on byte arrays
 #[derive(PartialEq, Eq, Debug, Clone)]
diff --git a/ergotree-ir/src/mir/xor_of.rs b/ergotree-ir/src/mir/xor_of.rs
index 6665552e5..16e26be5a 100644
--- a/ergotree-ir/src/mir/xor_of.rs
+++ b/ergotree-ir/src/mir/xor_of.rs
@@ -1,5 +1,7 @@
 //! XOR for collection of booleans
 
+use alloc::boxed::Box;
+
 use crate::serialization::op_code::OpCode;
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
@@ -70,10 +72,12 @@ mod arbitrary {
 
 #[cfg(test)]
 #[allow(clippy::panic)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::mir::expr::Expr;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs
index 345ce1b01..eee5beb1d 100644
--- a/ergotree-ir/src/pretty_printer.rs
+++ b/ergotree-ir/src/pretty_printer.rs
@@ -1,8 +1,9 @@
 //! Pretty printer for ErgoTree IR
 
-use std::fmt::Write;
+use core::fmt::Write;
 
 mod print;
+use alloc::string::String;
 pub use print::Print;
 
 // TODO: extract to a separate module
@@ -17,7 +18,7 @@ pub trait Printer: Write {
     /// Get current indent
     fn get_indent(&self) -> usize;
     /// Print the current indent
-    fn print_indent(&mut self) -> std::fmt::Result {
+    fn print_indent(&mut self) -> core::fmt::Result {
         write!(self, "{:indent$}", "", indent = self.get_indent())
     }
 }
@@ -30,7 +31,7 @@ pub struct PosTrackingWriter {
 }
 
 impl Write for PosTrackingWriter {
-    fn write_str(&mut self, s: &str) -> std::fmt::Result {
+    fn write_str(&mut self, s: &str) -> core::fmt::Result {
         let len = s.len();
         self.current_pos += len;
         write!(self.print_buf, "{}", s)
@@ -101,6 +102,7 @@ mod tests {
     use crate::mir::val_use::ValUse;
     use crate::serialization::SigmaSerializable;
     use crate::types::stype::SType;
+    use alloc::boxed::Box;
 
     use super::*;
 
diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs
index 1b30ffe39..3aeba4e57 100644
--- a/ergotree-ir/src/pretty_printer/print.rs
+++ b/ergotree-ir/src/pretty_printer/print.rs
@@ -1,3 +1,8 @@
+use alloc::borrow::ToOwned;
+use alloc::boxed::Box;
+
+use alloc::string::String;
+use alloc::vec::Vec;
 use thiserror::Error;
 
 use crate::mir::and::And;
@@ -77,7 +82,7 @@ use super::Printer;
 #[derive(PartialEq, Eq, Debug, Clone, Error)]
 pub enum PrintError {
     #[error("fmt error: {0:?}")]
-    FmtError(#[from] std::fmt::Error),
+    FmtError(#[from] core::fmt::Error),
 }
 
 impl Expr {
diff --git a/ergotree-ir/src/reference.rs b/ergotree-ir/src/reference.rs
index 9dfd0ad68..08de65ab4 100644
--- a/ergotree-ir/src/reference.rs
+++ b/ergotree-ir/src/reference.rs
@@ -1,5 +1,7 @@
 //! Reference type used extensively throughout interpreter. a Ref<'ctx, T> can either borrow from Context or be `Arc<T>`
-use std::{ops::Deref, sync::Arc};
+use core::ops::Deref;
+
+use alloc::sync::Arc;
 
 #[derive(Clone, Debug, Eq)]
 /// A wrapper type that provides immutable access to T. Ref can either be [`Ref::Borrowed`], holding a reference to some data in Context, or [`Ref::Arc`]
@@ -10,9 +12,9 @@ pub enum Ref<'ctx, T> {
     Arc(Arc<T>),
 }
 
-impl<T> std::cmp::PartialEq for Ref<'_, T>
+impl<T> core::cmp::PartialEq for Ref<'_, T>
 where
-    T: std::cmp::PartialEq,
+    T: core::cmp::PartialEq,
 {
     fn eq(&self, other: &Self) -> bool {
         self.deref() == other.deref()
@@ -50,7 +52,7 @@ impl<'ctx, T> From<T> for Ref<'ctx, T> {
     }
 }
 
-impl<'ctx, T> std::ops::Deref for Ref<'ctx, T> {
+impl<'ctx, T> core::ops::Deref for Ref<'ctx, T> {
     type Target = T;
     fn deref(&self) -> &T {
         match self {
@@ -61,6 +63,7 @@ impl<'ctx, T> std::ops::Deref for Ref<'ctx, T> {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod test {
     use crate::reference::Ref;
     use proptest::prelude::*;
diff --git a/ergotree-ir/src/serialization/bin_op.rs b/ergotree-ir/src/serialization/bin_op.rs
index 6f0b040a6..e27e8f024 100644
--- a/ergotree-ir/src/serialization/bin_op.rs
+++ b/ergotree-ir/src/serialization/bin_op.rs
@@ -1,3 +1,5 @@
+use alloc::boxed::Box;
+
 use crate::mir::bin_op::BinOp;
 use crate::mir::bin_op::BinOpKind;
 use crate::mir::constant::Constant;
@@ -72,6 +74,7 @@ mod proptests {
     use super::*;
     use crate::mir::expr::arbitrary::ArbExprParams;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
@@ -85,6 +88,7 @@ mod proptests {
 }
 
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use sigma_test_util::force_any_val_with;
 
diff --git a/ergotree-ir/src/serialization/constant.rs b/ergotree-ir/src/serialization/constant.rs
index 04eee7572..ae2d9ee01 100644
--- a/ergotree-ir/src/serialization/constant.rs
+++ b/ergotree-ir/src/serialization/constant.rs
@@ -39,8 +39,9 @@ mod tests {
     use super::*;
     use crate::mir::constant::arbitrary::ArbConstantParams;
     use crate::serialization::sigma_serialize_roundtrip;
+
+    use alloc::sync::Arc;
     use proptest::prelude::*;
-    use std::sync::Arc;
 
     proptest! {
 
@@ -63,9 +64,6 @@ mod tests {
         let constant_bytes_str = "0c63028092f401104904000e200137c91882b759ad46a20e39aa4d035ce32525dc76d021ee643e71d09446400f04020e20f6ff8b7210015545d4b3ac5fc60c908092d035a1a16155c029e8d511627c7a2c0e20efc4f603dea6041286a89f5bd516ac96ea5b25da4f08d76c6927e01d61b22adf040204000402040004000402040c044c04010404040404020e20f5918eb4b0283c669bdd8a195640766c19e40a693a6697b775b08e09052523d40e20767caa80b98e496ad8a9f689c4410ae453327f0f95e95084c0ae206350793b7704000402040004020412040005809bee0204000400040004000402040404000402041205d00f040304000402040204420580897a0e20012aec95af24812a01775de090411ba70a648fe859013f896ca2a1a95882ce5f040204040400041004100402041005000402040004100400040004000400040004100410040204100402040205000404040404020402040404040100d80dd601db6501fed602b27201730000d6037301d604b27201730200d605dc640be4c6720204640283020e73037304e4e3000ed606e4c6a70410d607b27206730500d608b2a5730600d609e4c672080410d60ab27209730700d60be3044005d60ce4720bd60d8c720c01d196830301938cb2db63087202730800017203938cb2db6308720473090001b4e4b27205730a00730b730c95ed947207720a937207730dd80cd60eb27201730e00d60fdb6308a7d610e4c6a70511d611720bd612720cd613b47210730fb17210d6148c721202d615b2a5731000d616dc640be4c6720e04640283020e73117312e4e3010ed617b2db63087215731300d6188cb2720f73140002d6197cb4e4b272167315007316731796830401938cb2db6308720e7318000172039683080193c27208c2a792c1720899c1a7731993b2db63087208731a00b2720f731b0093b27209731c00b27206731d0093e4c672080511721093e4c672080664e4c6a7066493720a9591b27210731e009d9cb2e4c672040511731f007cb4e4b27205732000732173227323720d7324edafdb0c0e7213d9011a049593721a720d93b27213721a00721490b27213721a00721491b17213720d91db6903db6503feb272107325009683040193cbc27215b4e4b272167326007327732892c172157329938c721701732a928c72170295927218721972187219d802d60ee4c6a70511d60fe4c6720805119594720e720fd809d610b2a4732b00d611e4c6b2a4732c00050ed612adb4db0c0e7211732d9db17211732ed90112047cb472119c7212732f9c9a721273307331d613b072127332d90113599a8c7213018c721302d614e4c6a70664d615e4c67210050ed616dc640a7214027215e4e3010ed617e67216d618e4e3020e96830801927cb4e4dc640ae4c672040464028cb2db6308721073330001e4e3030e73347335721393c27208c2a792c17208c1a793b2db63087208733600b2db6308a7733700937209720693b2720f733800b2720e733900957217d802d619e47216d61aadb4db0c0e7219733a9db17219733bd9011a047cb472199c721a733c9c9a721a733d733e9683020193b2720f733f009a99b2720e734000b0721a7341d9011b599a8c721b018c721b02721393b4720f7342b1720faddc0c1db4720e7343b1720e01addc0c1d721a017212d9011b59998c721b028c721b01d9011b599a8c721b018c721b029683020193b2720f7344009ab2720e734500721393b4720f7346b1720faddc0c1db4720e7347b1720e017212d90119599a8c7219018c72190293db6401e4c672080664db6401957217e4dc640d72140283013c0e0e8602721572117218e4dc640c72140283013c0e0e86027215721172187348efc13b02010b4858ce0425ed4748d0d3a59f2dbf874166a2caaf734655ac5e3f88a68cdd01012aec95af24812a01775de090411ba70a648fe859013f896ca2a1a95882ce5f904e0310020001110400000000644ec61f485b98eb87153f7c57db4f5ecd75556fddbc403b41acf8441fde8e1609000720003b6fd893695e655e17804641c3ed2074731ff34281dafb0e5b50688d0627717300c0843d10230400040204000402040604040500050004000e200137c91882b759ad46a20e39aa4d035ce32525dc76d021ee643e71d09446400f04000e20010b4858ce0425ed4748d0d3a59f2dbf874166a2caaf734655ac5e3f88a68cdd0400040204080400040204040502040604080400040004020402040004020e20c7c537e6c635930ecb4ace95a54926b3ab77698d9f4922f0b1c58ea87156483b0400040204420404040205000502d80ed601db6501fed602b27201730000d603b27201730100d604e4c672030410d605e4c6a70411d606b27205730200d607b27205730300d608b27205730400d609b27205730500d60a9172097306d60be4c6a7050c63d60cb1720bd60db1a5d60ed9010e0c63b0dc0c0f720e01d9011063db630872107307d90110414d0e9a8c7210018c8c72100202d196830701938cb2db6308720273080001730996830301938cb2db63087203730a0001730b937eb27204730c00057206937eb27204730d0005720792db6903db6503fe720895720ad804d60fe4c6a7050c63d610b2a5b1720f00d611e4c672100411d612b27205730e009683090192c17210c1a793db63087210db6308a793b27211730f00720693b27211731000720793b27211731100997209731293b272117313009a7208721293b27211731400721293e4c67210050c63720f93c27210c2a7efaea5d9010f63aedb6308720fd901114d0e938c7211018cb2db6308a773150001afdc0c1d720b01b4a5731699720c7317d9010f3c636393c48c720f01c48c720f0293720d9a9a720c95720a731873199593cbc2b2a599720d731a00b4e4b2dc640be4c6720204640283010e731be4e3000e731c00731d731e731f732093da720e01a49ada720e01a595720a73217322efc13b0100b44a84993674c57c4fc23c6c1bb221470463e4e711b2260ffd8ed01f1aab420102110500020000000c6301c0843d0008cd02e4cb952261186ec0fd2dc4c2baa8dbfd9c8f6012c5efa9f702f9450a58fe221eefc13b01012aec95af24812a01775de090411ba70a648fe859013f896ca2a1a95882ce5fc0843d00c9ffc2d2fd948bd3217a245eab2c9d829abd0cd3b41a8069006ff2bb38b06e2d00cb93d676f11faa9b7204a875fdb34d55619fc0e933ae956af8c7d8ce4c9e20ca00";
         let constant_bytes = base16::decode(constant_bytes_str).unwrap();
         let c_res = Constant::sigma_parse_bytes(&constant_bytes);
-        if let Err(e) = &c_res {
-            println!("Failed to parse constant: {}", e);
-        }
         assert!(c_res.is_ok());
         assert_eq!(c_res.unwrap().tpe, SType::SColl(Arc::new(SType::SBox)));
     }
diff --git a/ergotree-ir/src/serialization/constant_placeholder.rs b/ergotree-ir/src/serialization/constant_placeholder.rs
index 4ad229747..b8dbf57c2 100644
--- a/ergotree-ir/src/serialization/constant_placeholder.rs
+++ b/ergotree-ir/src/serialization/constant_placeholder.rs
@@ -36,8 +36,10 @@ mod tests {
         constant_store::ConstantStore, sigma_byte_reader::SigmaByteReader,
         sigma_byte_writer::SigmaByteWriter,
     };
+
+    use alloc::vec::Vec;
+    use core2::io::Cursor;
     use proptest::prelude::*;
-    use std::io::Cursor;
 
     proptest! {
 
diff --git a/ergotree-ir/src/serialization/constant_store.rs b/ergotree-ir/src/serialization/constant_store.rs
index 78f374da3..d33f69485 100644
--- a/ergotree-ir/src/serialization/constant_store.rs
+++ b/ergotree-ir/src/serialization/constant_store.rs
@@ -1,5 +1,8 @@
 //! Constant store for Sigma byte reader
 
+use alloc::vec;
+use alloc::vec::Vec;
+
 use crate::mir::constant::{Constant, ConstantPlaceholder};
 
 /// Storage for constants used in ErgoTree constant segregation
diff --git a/ergotree-ir/src/serialization/data.rs b/ergotree-ir/src/serialization/data.rs
index 49a1ef5e1..cf2a56e43 100644
--- a/ergotree-ir/src/serialization/data.rs
+++ b/ergotree-ir/src/serialization/data.rs
@@ -1,3 +1,8 @@
+use alloc::boxed::Box;
+
+use alloc::string::ToString;
+use alloc::vec;
+use alloc::vec::Vec;
 use sigma_util::AsVecU8;
 
 use crate::bigint256::BigInt256;
@@ -19,8 +24,8 @@ use crate::types::stype::SType;
 use ergo_chain_types::EcPoint;
 
 use super::sigma_byte_writer::SigmaByteWrite;
-use std::convert::TryInto;
-use std::sync::Arc;
+use alloc::sync::Arc;
+use core::convert::TryInto;
 
 /// Used to serialize and parse `Literal` and `Value`.
 pub struct DataSerializer {}
diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs
index 4abb5eef8..3d3f578e1 100644
--- a/ergotree-ir/src/serialization/expr.rs
+++ b/ergotree-ir/src/serialization/expr.rs
@@ -503,7 +503,6 @@ mod tests {
         let p2s_addr_str = "HfdbQC2Zwr5vfAUxdmjmX6b3TxQbq5w764pwsz9LLKyZVhv7SpifLB22PieCgvzSaFLomv8HNr9dxxQSSYaQg6ZyFL37nPfuVib3hVL8h42jajp754NXGqv1s4eKcbPsKkBMeTmYVSSGrpnZHzjqvcT4oN8rqKGUtLVXHs4QKyBwwNQKS5KNC8DLkdvHUQRNv5r8pCJ6ehTi31h1rfLVTsaMhAeDcYCs1uS7YMXk3msfH36krAskv8TgApoFJ1DarszwiacTuE1o4N6o4PJJifAgJ1WH4XuGRieYE1k3fo631benRDQw9nQ49p4oqAda5aXTNmabAsfCgAR8jbmUzzi3UCyYJgRUtXp7ijaGfr6o3hXd5VHDZe4gM6Vw4Ly3s881WZX2WWNedrXNqKKMVXKk55jbgn3ZmFpZiLtvPHSBCG7ULyARrTz2rAUC16StdYBqPuhHpRKEx3QYeFTYJGcMbsMGompAkCxG37X7ZVs7m7xCpPuP3AqxWtWdxkTzw5FCHALsu6ZD334n8mFgn9kiif4tbShpBo1AJu6dP22XvPU3S93q5LuNaXx6d7u5VFrpQKSN6WnhkU4LUfh3t8YU1ZBATrQDGRkaji59pqoNDuwVSfn7g1UhcMWdMnwzrCNNq1jsX2KrkX7o81aS7LEmz6xAySdyvubGh51oXNd2cmgbJ9at2Tp3hNi9FwWG5iEk882AZ7gby6QktknAwyaw9CL5qdodeh4t659H42SoqK2ATtfrZgjU5b5pYAzNp9EjFHCKkYxTo7t5G1vHHZUXjTbkzc22ggJdH3BvZYEcdQtUCLbEFJSCiMp2RjxEmyh";
         let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
         let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
-        let script = addr.script().unwrap().proposition().unwrap();
-        dbg!(&script);
+        addr.script().unwrap().proposition().unwrap();
     }
 }
diff --git a/ergotree-ir/src/serialization/method_call.rs b/ergotree-ir/src/serialization/method_call.rs
index b1fc31282..10d8f5519 100644
--- a/ergotree-ir/src/serialization/method_call.rs
+++ b/ergotree-ir/src/serialization/method_call.rs
@@ -1,4 +1,6 @@
-use std::collections::HashMap;
+use hashbrown::HashMap;
+
+use alloc::vec::Vec;
 
 use crate::mir::expr::Expr;
 use crate::mir::method_call::MethodCall;
@@ -40,7 +42,7 @@ impl SigmaSerializable for MethodCall {
             .explicit_type_args
             .iter()
             .cloned()
-            .zip(std::iter::from_fn(|| Some(SType::sigma_parse(r))))
+            .zip(core::iter::from_fn(|| Some(SType::sigma_parse(r))))
             .map(|(tpe, res)| -> Result<(STypeVar, SType), SigmaParsingError> { Ok((tpe, res?)) })
             .collect::<Result<HashMap<STypeVar, SType>, _>>()?;
         Ok(MethodCall::with_type_args(
@@ -56,6 +58,8 @@ impl SigmaSerializable for MethodCall {
 #[cfg(feature = "arbitrary")]
 #[allow(clippy::unwrap_used)]
 mod tests {
+    use alloc::vec;
+
     use crate::mir::expr::Expr;
     use crate::mir::method_call::MethodCall;
     use crate::serialization::sigma_serialize_roundtrip;
diff --git a/ergotree-ir/src/serialization/property_call.rs b/ergotree-ir/src/serialization/property_call.rs
index 1a33d86c3..9f1f3429d 100644
--- a/ergotree-ir/src/serialization/property_call.rs
+++ b/ergotree-ir/src/serialization/property_call.rs
@@ -1,3 +1,5 @@
+use alloc::vec::Vec;
+
 use crate::mir::expr::Expr;
 use crate::mir::property_call::PropertyCall;
 use crate::types::smethod::MethodId;
diff --git a/ergotree-ir/src/serialization/serializable.rs b/ergotree-ir/src/serialization/serializable.rs
index e51dec4ac..4b50d9566 100644
--- a/ergotree-ir/src/serialization/serializable.rs
+++ b/ergotree-ir/src/serialization/serializable.rs
@@ -11,12 +11,16 @@ use super::{
     sigma_byte_writer::{SigmaByteWrite, SigmaByteWriter},
 };
 use crate::types::smethod::MethodId;
+use alloc::boxed::Box;
+
+use alloc::string::{String, ToString};
+use alloc::vec::Vec;
 use bounded_vec::BoundedVec;
 use bounded_vec::BoundedVecOutOfBounds;
+use core::convert::TryInto;
+use core2::io;
 use io::Cursor;
 use sigma_ser::{vlq_encode, ScorexParsingError, ScorexSerializationError};
-use std::convert::TryInto;
-use std::io;
 use thiserror::Error;
 
 /// Ways serialization might fail
@@ -132,7 +136,7 @@ pub type SigmaSerializeResult = Result<(), SigmaSerializationError>;
 pub trait SigmaSerializable: Sized {
     /// Write `self` to the given `writer`.
     /// This function has a `sigma_` prefix to alert the reader that the
-    /// serialization in use is consensus-critical serialization    
+    /// serialization in use is consensus-critical serialization
     // fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult;
     fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult;
 
diff --git a/ergotree-ir/src/serialization/sigma_byte_reader.rs b/ergotree-ir/src/serialization/sigma_byte_reader.rs
index cfa63d03b..1e224ce68 100644
--- a/ergotree-ir/src/serialization/sigma_byte_reader.rs
+++ b/ergotree-ir/src/serialization/sigma_byte_reader.rs
@@ -1,10 +1,10 @@
 //! Sigma byte stream writer
 use super::constant_store::ConstantStore;
 use super::val_def_type_store::ValDefTypeStore;
+use core2::io::Cursor;
+use core2::io::Read;
+use core2::io::Seek;
 use sigma_ser::vlq_encode::ReadSigmaVlqExt;
-use std::io::Cursor;
-use std::io::Read;
-use std::io::Seek;
 
 /// Implementation of SigmaByteRead
 pub struct SigmaByteReader<R> {
@@ -73,24 +73,38 @@ pub trait SigmaByteRead: ReadSigmaVlqExt {
 
     /// Set that deserialization node was read
     fn set_deserialize(&mut self, has_deserialize: bool);
+
+    /// Get position of reader in buffer. This is functionally equivalent to [`std::io::Seek::stream_position`] but redefined here so it can be used in no_std contexts
+    fn position(&mut self) -> core2::io::Result<u64> {
+        #[cfg(feature = "std")]
+        {
+            <Self as Seek>::stream_position(self)
+        }
+        #[cfg(not(feature = "std"))]
+        {
+            self.seek(core2::io::SeekFrom::Current(0))
+        }
+    }
 }
 
 impl<R: Read> Read for SigmaByteReader<R> {
-    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+    fn read(&mut self, buf: &mut [u8]) -> core2::io::Result<usize> {
         self.inner.read(buf)
     }
 }
 
 impl<R: Seek> Seek for SigmaByteReader<R> {
-    fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
+    fn seek(&mut self, pos: core2::io::SeekFrom) -> core2::io::Result<u64> {
         self.inner.seek(pos)
     }
 
-    fn rewind(&mut self) -> std::io::Result<()> {
+    #[cfg(feature = "std")]
+    fn rewind(&mut self) -> core2::io::Result<()> {
         self.inner.rewind()
     }
 
-    fn stream_position(&mut self) -> std::io::Result<u64> {
+    #[cfg(feature = "std")]
+    fn stream_position(&mut self) -> core2::io::Result<u64> {
         self.inner.stream_position()
     }
 }
diff --git a/ergotree-ir/src/serialization/sigma_byte_writer.rs b/ergotree-ir/src/serialization/sigma_byte_writer.rs
index fb591322d..36feba4ce 100644
--- a/ergotree-ir/src/serialization/sigma_byte_writer.rs
+++ b/ergotree-ir/src/serialization/sigma_byte_writer.rs
@@ -1,7 +1,7 @@
 //! Sigma byte stream writer
 use super::constant_store::ConstantStore;
+use core2::io::Write;
 use sigma_ser::vlq_encode::WriteSigmaVlqExt;
-use std::io::Write;
 
 /// Implementation for SigmaByteWrite
 pub struct SigmaByteWriter<'a, W> {
@@ -27,11 +27,11 @@ pub trait SigmaByteWrite: WriteSigmaVlqExt {
 }
 
 impl<'a, W: Write> Write for SigmaByteWriter<'a, W> {
-    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+    fn write(&mut self, buf: &[u8]) -> core2::io::Result<usize> {
         self.inner.write(buf)
     }
 
-    fn flush(&mut self) -> std::io::Result<()> {
+    fn flush(&mut self) -> core2::io::Result<()> {
         self.inner.flush()
     }
 }
diff --git a/ergotree-ir/src/serialization/sigmaboolean.rs b/ergotree-ir/src/serialization/sigmaboolean.rs
index f8f8702d5..cf20ba6a2 100644
--- a/ergotree-ir/src/serialization/sigmaboolean.rs
+++ b/ergotree-ir/src/serialization/sigmaboolean.rs
@@ -7,6 +7,7 @@ use crate::serialization::{
 use crate::sigma_protocol::sigma_boolean::{
     ProveDhTuple, ProveDlog, SigmaBoolean, SigmaConjecture, SigmaProofOfKnowledgeTree,
 };
+
 use ergo_chain_types::EcPoint;
 
 use crate::sigma_protocol::sigma_boolean::cand::Cand;
diff --git a/ergotree-ir/src/serialization/types.rs b/ergotree-ir/src/serialization/types.rs
index 32a008191..850a2ff5f 100644
--- a/ergotree-ir/src/serialization/types.rs
+++ b/ergotree-ir/src/serialization/types.rs
@@ -8,9 +8,11 @@ use crate::serialization::{
 use crate::types::stuple;
 use crate::types::stype::SType;
 use crate::types::stype_param;
+use alloc::string::ToString;
+use alloc::vec::Vec;
+use core::convert::TryInto;
 use num_derive::FromPrimitive;
 use num_traits::FromPrimitive;
-use std::convert::TryInto;
 
 #[allow(non_camel_case_types)]
 #[allow(clippy::upper_case_acronyms)] // to differentiate from similarly named SType enum variants
@@ -332,10 +334,12 @@ impl SType {
 /// - emitting typeCode of each node (see special case for collections below)
 /// - then recursively serializing subtrees from left to right on each level
 /// - for each collection of primitive type there is special type code to emit single byte instead of two bytes
+///
 /// Types code intervals
 /// - (1 .. MaxPrimTypeCode)  // primitive types
 /// - (CollectionTypeCode .. CollectionTypeCode + MaxPrimTypeCode) // collections of primitive types
 /// - (MaxCollectionTypeCode ..)  // Other types
+///
 /// Collection of non-primitive type is serialized as (CollectionTypeCode, serialize(elementType))
 impl SigmaSerializable for SType {
     fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
@@ -561,6 +565,7 @@ impl SigmaSerializable for SType {
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/serialization/val_def_type_store.rs b/ergotree-ir/src/serialization/val_def_type_store.rs
index 02e2706d9..ec6bc33f6 100644
--- a/ergotree-ir/src/serialization/val_def_type_store.rs
+++ b/ergotree-ir/src/serialization/val_def_type_store.rs
@@ -1,4 +1,4 @@
-use std::collections::HashMap;
+use hashbrown::HashMap;
 
 use crate::mir::val_def::ValId;
 use crate::types::stype::SType;
diff --git a/ergotree-ir/src/sigma_protocol/dlog_group.rs b/ergotree-ir/src/sigma_protocol/dlog_group.rs
index f8a3ff7c1..c339fb417 100644
--- a/ergotree-ir/src/sigma_protocol/dlog_group.rs
+++ b/ergotree-ir/src/sigma_protocol/dlog_group.rs
@@ -104,6 +104,7 @@ pub fn order_bigint() -> BigInt {
 
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean.rs
index 2f67f3fd4..218f6b0ec 100644
--- a/ergotree-ir/src/sigma_protocol/sigma_boolean.rs
+++ b/ergotree-ir/src/sigma_protocol/sigma_boolean.rs
@@ -10,9 +10,12 @@ use crate::mir::constant::Constant;
 use crate::mir::expr::Expr;
 use crate::serialization::op_code::OpCode;
 use crate::serialization::SigmaSerializable;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::convert::TryInto;
+use core::fmt::Formatter;
 use ergo_chain_types::EcPoint;
-use std::convert::TryFrom;
-use std::fmt::Formatter;
 
 extern crate derive_more;
 use bounded_vec::BoundedVec;
@@ -53,8 +56,8 @@ impl From<EcPoint> for ProveDlog {
     }
 }
 
-impl std::fmt::Display for ProveDlog {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for ProveDlog {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         write!(f, "proveDlog({})", self.h)
     }
 }
@@ -92,8 +95,8 @@ impl ProveDhTuple {
     }
 }
 
-impl std::fmt::Display for ProveDhTuple {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for ProveDhTuple {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         write!(
             f,
             "ProveDhTuple(g: {}, h: {}, u: {}, v: {})",
@@ -141,8 +144,8 @@ impl HasOpCode for SigmaConjecture {
     }
 }
 
-impl std::fmt::Display for SigmaConjecture {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for SigmaConjecture {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         match self {
             SigmaConjecture::Cand(c) => write!(f, "{}", c),
             SigmaConjecture::Cor(c) => write!(f, "{}", c),
@@ -272,8 +275,8 @@ impl From<Cthreshold> for SigmaBoolean {
     }
 }
 
-impl std::fmt::Display for SigmaBoolean {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for SigmaBoolean {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         match self {
             SigmaBoolean::TrivialProp(b) => write!(f, "sigmaProp({})", b),
             SigmaBoolean::ProofOfKnowledge(kt) => write!(f, "{}", kt),
@@ -417,10 +420,12 @@ mod arbitrary {
 
 #[allow(clippy::panic)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
+
     use proptest::prelude::*;
 
     proptest! {
diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs
index 957f46354..db561fb73 100644
--- a/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs
+++ b/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs
@@ -1,5 +1,7 @@
 //! AND conjunction for sigma proposition
-use std::convert::TryInto;
+use core::convert::TryInto;
+
+use alloc::vec::Vec;
 
 use super::SigmaBoolean;
 use super::SigmaConjectureItems;
@@ -48,8 +50,8 @@ impl Cand {
     }
 }
 
-impl std::fmt::Display for Cand {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for Cand {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         f.write_str("(")?;
         for (i, item) in self.items.iter().enumerate() {
             if i > 0 {
@@ -103,13 +105,16 @@ mod arbitrary {
 #[allow(clippy::panic)]
 #[allow(clippy::unwrap_used)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
     use crate::sigma_protocol::sigma_boolean::ProveDlog;
+
+    use alloc::vec;
+    use core::convert::TryInto;
     use proptest::prelude::*;
     use sigma_test_util::force_any_val;
-    use std::convert::TryInto;
 
     #[test]
     fn trivial_true() {
diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs
index acf0c3f9e..9bb0eec91 100644
--- a/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs
+++ b/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs
@@ -1,5 +1,7 @@
 //! OR conjunction for sigma proposition
-use std::convert::TryInto;
+use core::convert::TryInto;
+
+use alloc::vec::Vec;
 
 use super::SigmaBoolean;
 use super::SigmaConjectureItems;
@@ -49,8 +51,8 @@ impl Cor {
     }
 }
 
-impl std::fmt::Display for Cor {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for Cor {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         f.write_str("(")?;
         for (i, item) in self.items.iter().enumerate() {
             if i > 0 {
@@ -105,13 +107,16 @@ mod arbitrary {
 #[allow(clippy::unwrap_used)]
 #[allow(clippy::panic)]
 #[cfg(test)]
+#[cfg(feature = "arbitrary")]
 mod tests {
     use super::*;
     use crate::serialization::sigma_serialize_roundtrip;
     use crate::sigma_protocol::sigma_boolean::ProveDlog;
+
+    use alloc::vec;
+    use core::convert::TryInto;
     use proptest::prelude::*;
     use sigma_test_util::force_any_val;
-    use std::convert::TryInto;
 
     #[test]
     fn trivial_true() {
diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean/cthreshold.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean/cthreshold.rs
index 125661d68..868cb79cb 100644
--- a/ergotree-ir/src/sigma_protocol/sigma_boolean/cthreshold.rs
+++ b/ergotree-ir/src/sigma_protocol/sigma_boolean/cthreshold.rs
@@ -1,6 +1,9 @@
 //! THRESHOLD conjunction for sigma proposition
 
-use std::convert::TryInto;
+use core::convert::TryInto;
+
+use alloc::string::ToString;
+use alloc::vec::Vec;
 
 use super::cand::Cand;
 use super::cor::Cor;
@@ -81,8 +84,8 @@ impl Cthreshold {
     }
 }
 
-impl std::fmt::Display for Cthreshold {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for Cthreshold {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         f.write_str("atLeast(")?;
         f.write_str(self.k.to_string().as_str())?;
         f.write_str(", (")?;
diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs
index b744d8101..fd2a11161 100644
--- a/ergotree-ir/src/source_span.rs
+++ b/ergotree-ir/src/source_span.rs
@@ -1,5 +1,7 @@
 //! Source position for an IR node in the source code
 
+use alloc::boxed::Box;
+
 use crate::mir::and::And;
 use crate::mir::bin_op::BinOp;
 use crate::mir::block::BlockValue;
@@ -58,6 +60,7 @@ impl From<(usize, usize)> for SourceSpan {
     }
 }
 
+#[cfg(feature = "std")]
 impl From<SourceSpan> for miette::SourceSpan {
     fn from(value: SourceSpan) -> Self {
         miette::SourceSpan::new(value.offset.into(), value.length.into())
diff --git a/ergotree-ir/src/traversable.rs b/ergotree-ir/src/traversable.rs
index 88d7006b0..87d69e0f3 100644
--- a/ergotree-ir/src/traversable.rs
+++ b/ergotree-ir/src/traversable.rs
@@ -1,6 +1,7 @@
 //! Traversable trait
 
 use crate::mir::{expr::Expr, unary_op::OneArgOp};
+use alloc::boxed::Box;
 
 /// Trait for types that have child nodes.
 /// In ergotree-ir this is used for traversing trees of [`Expr`] and doing rewriting operations such as replacing [ConstantPlaceholder](crate::mir::constant::ConstantPlaceholder)s with [`Constant`](crate::mir::constant::Constant)s
@@ -17,10 +18,10 @@ impl<T: OneArgOp> Traversable for T {
     type Item = Expr;
 
     fn children<'a>(&'a self) -> Box<dyn Iterator<Item = &Self::Item> + 'a> {
-        Box::new(std::iter::once(self.input()))
+        Box::new(core::iter::once(self.input()))
     }
     fn children_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &mut Self::Item> + 'a> {
-        Box::new(std::iter::once(self.input_mut()))
+        Box::new(core::iter::once(self.input_mut()))
     }
 }
 
@@ -32,7 +33,7 @@ macro_rules! iter_from {
         $self.$x.iter().chain(crate::traversable::iter_from!($self, $($y)*))
     };
     ($self:ident, boxed $x:tt, $($y:tt)*) => {
-        std::iter::once(&*$self.$x).chain(crate::traversable::iter_from!($self, $($y)*))
+        core::iter::once(&*$self.$x).chain(crate::traversable::iter_from!($self, $($y)*))
     };
     ($self:ident, opt $x:tt) => {
         $self.$x.as_deref().into_iter()
@@ -41,10 +42,10 @@ macro_rules! iter_from {
         $self.$x.iter()
     };
     ($self:ident, boxed $x:tt) => {
-        std::iter::once(&*$self.$x)
+        core::iter::once(&*$self.$x)
     };
     ($self:ident) => {
-        std::iter::empty()
+        core::iter::empty()
     }
 }
 
@@ -56,7 +57,7 @@ macro_rules! iter_from_mut {
         $self.$x.iter_mut().chain(crate::traversable::iter_from_mut!($self, $($y)*))
     };
     ($self:ident, boxed $x:tt, $($y:tt)*) => {
-        std::iter::once(&mut *$self.$x).chain(crate::traversable::iter_from_mut!($self, $($y)*))
+        core::iter::once(&mut *$self.$x).chain(crate::traversable::iter_from_mut!($self, $($y)*))
     };
     ($self:ident, opt $x:tt) => {
         $self.$x.as_deref_mut().into_iter()
@@ -65,10 +66,10 @@ macro_rules! iter_from_mut {
         $self.$x.iter_mut()
     };
     ($self:ident, boxed $x:tt) => {
-        std::iter::once(&mut *$self.$x)
+        core::iter::once(&mut *$self.$x)
     };
     ($self:ident) => {
-        std::iter::empty()
+        core::iter::empty()
     }
 }
 
@@ -77,11 +78,11 @@ macro_rules! impl_traversable_expr {
     ($op:ident $(, $($args:tt)+ )? ) => {
         impl crate::traversable::Traversable for $op {
             type Item = Expr;
-            fn children(&self) -> Box<dyn Iterator<Item = &Self::Item> + '_> {
-                Box::new(crate::traversable::iter_from!(self $(, $($args)*)?))
+            fn children(&self) -> alloc::boxed::Box<dyn Iterator<Item = &Self::Item> + '_> {
+                alloc::boxed::Box::new(crate::traversable::iter_from!(self $(, $($args)*)?))
             }
-            fn children_mut(&mut self) -> Box<dyn Iterator<Item = &mut Self::Item> + '_> {
-                Box::new(crate::traversable::iter_from_mut!(self $(, $($args)*)?))
+            fn children_mut(&mut self) -> alloc::boxed::Box<dyn Iterator<Item = &mut Self::Item> + '_> {
+                alloc::boxed::Box::new(crate::traversable::iter_from_mut!(self $(, $($args)*)?))
             }
         }
     };
@@ -93,6 +94,8 @@ pub(crate) use iter_from_mut;
 
 #[cfg(test)]
 mod test {
+    use alloc::{boxed::Box, vec::Vec};
+
     use crate::mir::{constant::Constant, expr::Expr};
 
     use super::Traversable;
diff --git a/ergotree-ir/src/type_check.rs b/ergotree-ir/src/type_check.rs
index 447db8593..25fb63f5e 100644
--- a/ergotree-ir/src/type_check.rs
+++ b/ergotree-ir/src/type_check.rs
@@ -1,5 +1,7 @@
 //! Type checking
 
+use alloc::string::String;
+
 use crate::mir::expr::Expr;
 use crate::source_span::Spanned;
 
diff --git a/ergotree-ir/src/types/savltree.rs b/ergotree-ir/src/types/savltree.rs
index 216779748..bd5cb911a 100644
--- a/ergotree-ir/src/types/savltree.rs
+++ b/ergotree-ir/src/types/savltree.rs
@@ -1,4 +1,6 @@
-use std::sync::Arc;
+use alloc::sync::Arc;
+use alloc::vec;
+use alloc::vec::Vec;
 
 use crate::serialization::types::TypeCode;
 
diff --git a/ergotree-ir/src/types/sbox.rs b/ergotree-ir/src/types/sbox.rs
index b898604b0..c99b0514d 100644
--- a/ergotree-ir/src/types/sbox.rs
+++ b/ergotree-ir/src/types/sbox.rs
@@ -1,5 +1,8 @@
 use crate::serialization::types::TypeCode;
-use std::sync::Arc;
+use alloc::boxed::Box;
+use alloc::sync::Arc;
+use alloc::vec;
+use alloc::vec::Vec;
 
 use super::sfunc::SFunc;
 use super::smethod::MethodId;
@@ -103,7 +106,7 @@ mod tests {
 
     #[test]
     fn test_getreg_serialization_roundtrip() {
-        let type_args = std::iter::once((STypeVar::t(), SType::SInt)).collect();
+        let type_args = core::iter::once((STypeVar::t(), SType::SInt)).collect();
         let mc = MethodCall::with_type_args(
             GlobalVars::SelfBox.into(),
             GET_REG_METHOD.clone().with_concrete_types(&type_args),
diff --git a/ergotree-ir/src/types/scoll.rs b/ergotree-ir/src/types/scoll.rs
index 11400aea6..d0fad2023 100644
--- a/ergotree-ir/src/types/scoll.rs
+++ b/ergotree-ir/src/types/scoll.rs
@@ -1,7 +1,9 @@
 use crate::serialization::types::TypeCode;
 use crate::types::stuple::STuple;
 use crate::types::stype_companion::STypeCompanion;
-use std::sync::Arc;
+use alloc::sync::Arc;
+use alloc::vec;
+use alloc::vec::Vec;
 
 use super::sfunc::SFunc;
 use super::smethod::MethodId;
diff --git a/ergotree-ir/src/types/scontext.rs b/ergotree-ir/src/types/scontext.rs
index b6d6638ed..f46f661ff 100644
--- a/ergotree-ir/src/types/scontext.rs
+++ b/ergotree-ir/src/types/scontext.rs
@@ -8,6 +8,8 @@ use super::smethod::SMethod;
 use super::smethod::SMethodDesc;
 use super::stype::SType;
 use super::stype::SType::{SAvlTree, SBox, SByte, SColl, SHeader, SInt, SPreHeader};
+use alloc::vec;
+use alloc::vec::Vec;
 use lazy_static::lazy_static;
 
 /// SContext type code
diff --git a/ergotree-ir/src/types/sfunc.rs b/ergotree-ir/src/types/sfunc.rs
index b00e0e5e4..6570f74b2 100644
--- a/ergotree-ir/src/types/sfunc.rs
+++ b/ergotree-ir/src/types/sfunc.rs
@@ -1,4 +1,8 @@
-use std::collections::HashMap;
+use hashbrown::HashMap;
+
+use alloc::boxed::Box;
+use alloc::vec;
+use alloc::vec::Vec;
 
 use super::stype::SType;
 use super::stype_param::STypeParam;
@@ -15,8 +19,8 @@ pub struct SFunc {
     pub tpe_params: Vec<STypeParam>,
 }
 
-impl std::fmt::Display for SFunc {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for SFunc {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         write!(f, "(")?;
         for (i, item) in self.t_dom.iter().enumerate() {
             if i > 0 {
diff --git a/ergotree-ir/src/types/sglobal.rs b/ergotree-ir/src/types/sglobal.rs
index 9e90c2e75..53442425d 100644
--- a/ergotree-ir/src/types/sglobal.rs
+++ b/ergotree-ir/src/types/sglobal.rs
@@ -6,6 +6,8 @@ use super::smethod::SMethodDesc;
 use super::stype::SType;
 use crate::types::smethod::SMethod;
 use crate::types::stype_companion::STypeCompanion;
+use alloc::vec;
+use alloc::vec::Vec;
 use lazy_static::lazy_static;
 
 /// SGlobal type code
diff --git a/ergotree-ir/src/types/sgroup_elem.rs b/ergotree-ir/src/types/sgroup_elem.rs
index f389f49ee..1623c1630 100644
--- a/ergotree-ir/src/types/sgroup_elem.rs
+++ b/ergotree-ir/src/types/sgroup_elem.rs
@@ -1,6 +1,8 @@
 use crate::serialization::types::TypeCode;
 use crate::types::stype_companion::STypeCompanion;
-use std::sync::Arc;
+use alloc::sync::Arc;
+use alloc::vec;
+use alloc::vec::Vec;
 
 use super::sfunc::SFunc;
 use super::smethod::MethodId;
diff --git a/ergotree-ir/src/types/sheader.rs b/ergotree-ir/src/types/sheader.rs
index adf083a2b..22784ad3b 100644
--- a/ergotree-ir/src/types/sheader.rs
+++ b/ergotree-ir/src/types/sheader.rs
@@ -1,5 +1,7 @@
 #![allow(missing_docs)]
 
+use alloc::vec;
+use alloc::vec::Vec;
 use lazy_static::lazy_static;
 
 use crate::serialization::types::TypeCode;
diff --git a/ergotree-ir/src/types/smethod.rs b/ergotree-ir/src/types/smethod.rs
index f369904a3..d0e59545b 100644
--- a/ergotree-ir/src/types/smethod.rs
+++ b/ergotree-ir/src/types/smethod.rs
@@ -1,9 +1,12 @@
+use alloc::vec;
+use alloc::vec::Vec;
+
 use crate::serialization::sigma_byte_reader::SigmaByteRead;
 use crate::serialization::sigma_byte_writer::SigmaByteWrite;
 use crate::serialization::types::TypeCode;
 use crate::serialization::SigmaParsingError;
-use std::collections::HashMap;
-use std::convert::TryFrom;
+use core::convert::TryFrom;
+use hashbrown::HashMap;
 
 use super::sfunc::SFunc;
 use super::stype::SType;
@@ -18,11 +21,11 @@ use crate::serialization::SigmaParsingError::UnknownMethodId;
 pub struct MethodId(pub u8);
 
 impl MethodId {
-    pub(crate) fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> std::io::Result<()> {
+    pub(crate) fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> core2::io::Result<()> {
         w.put_u8(self.0)
     }
 
-    pub(crate) fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> std::io::Result<Self> {
+    pub(crate) fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> core2::io::Result<Self> {
         Ok(Self(r.get_u8()?))
     }
 }
diff --git a/ergotree-ir/src/types/soption.rs b/ergotree-ir/src/types/soption.rs
index 2a3dccb08..ec50c4f15 100644
--- a/ergotree-ir/src/types/soption.rs
+++ b/ergotree-ir/src/types/soption.rs
@@ -7,6 +7,8 @@ use super::stype::SType;
 use super::stype_companion::STypeCompanion;
 use super::stype_param::STypeVar;
 use crate::types::smethod::MethodId;
+use alloc::vec;
+use alloc::vec::Vec;
 use lazy_static::lazy_static;
 
 /// SOption type code
diff --git a/ergotree-ir/src/types/spreheader.rs b/ergotree-ir/src/types/spreheader.rs
index 23ebed87e..5eebac8af 100644
--- a/ergotree-ir/src/types/spreheader.rs
+++ b/ergotree-ir/src/types/spreheader.rs
@@ -6,6 +6,8 @@ use super::smethod::{MethodId, SMethod, SMethodDesc};
 use super::stype::SType;
 use super::stype_companion::STypeCompanion;
 use crate::types::stype::SType::{SByte, SColl};
+use alloc::vec;
+use alloc::vec::Vec;
 use lazy_static::lazy_static;
 
 /// SPreHeader type code
diff --git a/ergotree-ir/src/types/stuple.rs b/ergotree-ir/src/types/stuple.rs
index 71596f3d7..00c555a9b 100644
--- a/ergotree-ir/src/types/stuple.rs
+++ b/ergotree-ir/src/types/stuple.rs
@@ -1,7 +1,9 @@
-use std::collections::HashMap;
-use std::convert::TryFrom;
-use std::convert::TryInto;
+use core::convert::TryFrom;
+use core::convert::TryInto;
+use hashbrown::HashMap;
 
+use alloc::vec;
+use alloc::vec::Vec;
 use bounded_vec::BoundedVec;
 use bounded_vec::BoundedVecOutOfBounds;
 
@@ -28,14 +30,14 @@ pub struct STuple {
     pub items: TupleItems<SType>,
 }
 
-impl std::fmt::Debug for STuple {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Debug for STuple {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         self.items.clone().to_vec().fmt(f)
     }
 }
 
-impl std::fmt::Display for STuple {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for STuple {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         write!(f, "(")?;
         for (i, item) in self.items.iter().enumerate() {
             if i > 0 {
diff --git a/ergotree-ir/src/types/stype.rs b/ergotree-ir/src/types/stype.rs
index 41efd553d..f73ffc0d2 100644
--- a/ergotree-ir/src/types/stype.rs
+++ b/ergotree-ir/src/types/stype.rs
@@ -1,9 +1,10 @@
 //! SType hierarchy
 
-use std::collections::HashMap;
-use std::convert::TryInto;
-use std::fmt::Debug;
-use std::sync::Arc;
+use alloc::sync::Arc;
+use alloc::vec::Vec;
+use core::convert::TryInto;
+use core::fmt::Debug;
+use hashbrown::HashMap;
 
 use impl_trait_for_tuples::impl_for_tuples;
 
@@ -128,8 +129,8 @@ impl From<SFunc> for SType {
     }
 }
 
-impl std::fmt::Display for SType {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for SType {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self {
             SType::STypeVar(t) => write!(f, "{}", t.as_string()),
             SType::SAny => write!(f, "Any"),
@@ -277,6 +278,7 @@ impl LiftIntoSType for Tuple {
 #[allow(clippy::unwrap_used)]
 pub(crate) mod tests {
     use super::*;
+    use alloc::vec;
     use proptest::prelude::*;
 
     pub(crate) fn primitive_type() -> BoxedStrategy<SType> {
diff --git a/ergotree-ir/src/types/stype_companion.rs b/ergotree-ir/src/types/stype_companion.rs
index 07f500817..82901e57f 100644
--- a/ergotree-ir/src/types/stype_companion.rs
+++ b/ergotree-ir/src/types/stype_companion.rs
@@ -1,5 +1,5 @@
-use std::convert::TryFrom;
-use std::fmt::Debug;
+use core::convert::TryFrom;
+use core::fmt::Debug;
 
 use crate::serialization::types::TypeCode;
 use crate::serialization::SigmaParsingError;
@@ -16,6 +16,8 @@ use super::smethod::SMethod;
 use super::smethod::SMethodDesc;
 use super::soption;
 use super::spreheader;
+
+use alloc::vec::Vec;
 use strum::IntoEnumIterator;
 use strum_macros::EnumIter;
 
diff --git a/ergotree-ir/src/types/stype_param.rs b/ergotree-ir/src/types/stype_param.rs
index 39e7c2f59..ae760caf1 100644
--- a/ergotree-ir/src/types/stype_param.rs
+++ b/ergotree-ir/src/types/stype_param.rs
@@ -1,7 +1,11 @@
-use std::convert::TryInto;
-use std::fmt::Formatter;
-use std::hash::Hash;
+use core::convert::TryInto;
+use core::fmt::Formatter;
+use core::hash::Hash;
 
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec;
+use alloc::vec::Vec;
 use bounded_vec::BoundedVec;
 
 use crate::mir::expr::InvalidArgumentError;
@@ -20,8 +24,8 @@ pub struct STypeVar {
     name_bytes: BoundedVec<u8, 1, 254>,
 }
 
-impl std::fmt::Debug for STypeVar {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Debug for STypeVar {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         self.as_string().fmt(f)
     }
 }
diff --git a/ergotree-ir/src/types/type_unify.rs b/ergotree-ir/src/types/type_unify.rs
index e1ce3f950..f08d44fb9 100644
--- a/ergotree-ir/src/types/type_unify.rs
+++ b/ergotree-ir/src/types/type_unify.rs
@@ -1,7 +1,10 @@
-use std::collections::HashMap;
+use hashbrown::HashMap;
 
 use super::stype::SType;
 use super::stype_param::STypeVar;
+
+use alloc::string::String;
+use alloc::vec::Vec;
 use SType::*;
 
 #[allow(clippy::unnecessary_wraps)]
@@ -79,14 +82,19 @@ pub fn unify_one(t1: &SType, t2: &SType) -> Result<HashMap<STypeVar, SType>, Typ
 #[cfg(test)]
 #[allow(clippy::panic)]
 mod tests {
-    use std::sync::Arc;
 
+    use alloc::sync::Arc;
+    use alloc::vec;
+
+    #[cfg(feature = "arbitrary")]
     use super::super::stype::tests::primitive_type;
     use super::*;
     use crate::types::sfunc::SFunc;
     use crate::types::stuple::STuple;
+    #[cfg(feature = "arbitrary")]
     use proptest::prelude::*;
 
+    #[cfg(feature = "arbitrary")]
     proptest! {
 
         #[test]
diff --git a/gf2_192/Cargo.toml b/gf2_192/Cargo.toml
index f2299ba16..17bd7ebcf 100644
--- a/gf2_192/Cargo.toml
+++ b/gf2_192/Cargo.toml
@@ -9,10 +9,12 @@ edition.workspace = true
 
 [dependencies]
 derive_more = { workspace = true }
-rand = { workspace = true }
 thiserror = { workspace = true }
 proptest-derive = { workspace = true, optional = true }
-proptest = { workspace = true , optional = true }
+proptest = { workspace = true, optional = true }
+
+[dev-dependencies]
+rand = { workspace = true }
 
 [features]
 arbitrary = ["proptest", "proptest-derive"]
diff --git a/gf2_192/src/gf2_192.rs b/gf2_192/src/gf2_192.rs
index b77dcec85..74e97912e 100644
--- a/gf2_192/src/gf2_192.rs
+++ b/gf2_192/src/gf2_192.rs
@@ -281,7 +281,7 @@ impl Default for Gf2_192 {
     }
 }
 
-impl std::ops::Add for Gf2_192 {
+impl core::ops::Add for Gf2_192 {
     type Output = Self;
     fn add(self, rhs: Self) -> Self {
         let mut word = [0, 0, 0];
@@ -292,7 +292,7 @@ impl std::ops::Add for Gf2_192 {
     }
 }
 
-impl std::ops::Mul for Gf2_192 {
+impl core::ops::Mul for Gf2_192 {
     type Output = Self;
 
     fn mul(self, rhs: Self) -> Self {
@@ -665,6 +665,8 @@ static POW_TABLE_2: [[i64; 192]; 7]  = [
 #[allow(clippy::unwrap_used)]
 mod tests {
     use super::*;
+    use alloc::vec;
+    use alloc::vec::Vec;
     use rand::{thread_rng, Rng};
 
     #[derive(PartialEq, Eq, Clone)]
@@ -675,7 +677,7 @@ mod tests {
     impl GF2Slow {
         fn equals(e: &GF2Slow, that: &[i64]) -> bool {
             let mut i = 0;
-            while i < std::cmp::min(e.x.len(), that.len()) {
+            while i < core::cmp::min(e.x.len(), that.len()) {
                 if e.x[i] != that[i] {
                     return false;
                 }
@@ -700,7 +702,7 @@ mod tests {
 
         #[allow(clippy::needless_range_loop)]
         fn mul_bits(a: &[i64], b: &[i64]) -> GF2Slow {
-            let mut c: Vec<_> = std::iter::repeat(0).take(a.len() + b.len()).collect();
+            let mut c: Vec<_> = core::iter::repeat(0).take(a.len() + b.len()).collect();
 
             for i in 0..a.len() {
                 for i1 in 0..64 {
@@ -739,7 +741,7 @@ mod tests {
     impl Modulus {
         fn new(sparse_modulus: &[i32]) -> Modulus {
             let degree = sparse_modulus[0];
-            let mut offset: Vec<_> = std::iter::repeat(0).take(sparse_modulus.len()).collect();
+            let mut offset: Vec<_> = core::iter::repeat(0).take(sparse_modulus.len()).collect();
             for i in 1..sparse_modulus.len() {
                 offset[i] = degree - sparse_modulus[i];
             }
@@ -752,7 +754,7 @@ mod tests {
     static PENTANOMIAL: [i32; 5] = [192, 7, 2, 1, 0];
 
     fn generate_test_values() -> Vec<Gf2_192> {
-        let mut test_values: Vec<[i64; 3]> = std::iter::repeat([0, 0, 0]).take(250).collect();
+        let mut test_values: Vec<[i64; 3]> = core::iter::repeat([0, 0, 0]).take(250).collect();
         let mut rng = thread_rng();
 
         // Test single 1s in every bit position but last
diff --git a/gf2_192/src/gf2_192poly.rs b/gf2_192/src/gf2_192poly.rs
index f6b0938dd..19bdedd37 100644
--- a/gf2_192/src/gf2_192poly.rs
+++ b/gf2_192/src/gf2_192poly.rs
@@ -24,6 +24,7 @@
 //!
 //!  For more information, please refer to <http://unlicense.org>
 
+use alloc::vec::Vec;
 use thiserror::Error;
 
 use crate::{gf2_192::Gf2_192, Gf2_192Error};
@@ -129,7 +130,7 @@ impl Gf2_192Poly {
     /// NOT including the degree-zero coefficient. Each coefficient takes 24 bytes for a total of
     /// `self.degree * 24` bytes
     pub fn to_bytes(&self) -> Vec<u8> {
-        let mut res: Vec<_> = std::iter::repeat(0).take(self.degree * 24).collect();
+        let mut res: Vec<_> = core::iter::repeat(0).take(self.degree * 24).collect();
         for i in 1..=self.degree {
             #[allow(clippy::unwrap_used)]
             self.coefficients[i]
@@ -168,7 +169,7 @@ impl Gf2_192Poly {
     /// Constructs a constant polynomial (degree 0) which takes value of `constant_term`.
     /// `max_degree` specifies the maximum degree of the polynomial (to allocate space).
     fn make_constant(max_degree: usize, constant_term: i32) -> Gf2_192Poly {
-        let mut coefficients: Vec<_> = std::iter::repeat_with(Gf2_192::new)
+        let mut coefficients: Vec<_> = core::iter::repeat_with(Gf2_192::new)
             .take(max_degree + 1)
             .collect();
         coefficients[0] = Gf2_192::from(constant_term);
@@ -225,7 +226,7 @@ mod tests {
         let mut rng = thread_rng();
 
         for len in 1..100 {
-            let mut points: Vec<_> = std::iter::repeat(0).take(len).collect();
+            let mut points: Vec<_> = core::iter::repeat(0).take(len).collect();
             // Generate a byte that's not an element of `points` nor 0
             let mut j = 0;
             while j < points.len() {
diff --git a/gf2_192/src/lib.rs b/gf2_192/src/lib.rs
index 8c759bd79..8a8862325 100644
--- a/gf2_192/src/lib.rs
+++ b/gf2_192/src/lib.rs
@@ -1,6 +1,7 @@
 //! Implementation of finite field arithmetic and polynomial interpolation/evaluation in Galois
 //! field GF(2^192).
 
+#![no_std]
 // Coding conventions
 #![forbid(unsafe_code)]
 #![deny(non_upper_case_globals)]
@@ -19,6 +20,8 @@
 #![deny(clippy::unimplemented)]
 #![deny(clippy::panic)]
 
+extern crate alloc;
+
 use derive_more::From;
 use gf2_192poly::Gf2_192PolyError;
 use thiserror::Error;
diff --git a/rust-toolchain b/rust-toolchain
index 9242d8e7a..ea3769f29 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,1 +1,1 @@
-1.76
+1.81
diff --git a/sigma-ser/Cargo.toml b/sigma-ser/Cargo.toml
index d2dad76ee..e33893620 100644
--- a/sigma-ser/Cargo.toml
+++ b/sigma-ser/Cargo.toml
@@ -7,13 +7,15 @@ repository.workspace = true
 edition.workspace = true
 description = "Ergo binary serialization primitives"
 
-[lib]
-crate-type = ["cdylib", "rlib"]
+[features]
+default = ["std"]
+std = ["core2/std"]
 
 [dependencies]
 thiserror = { workspace = true }
 bitvec = { workspace = true }
 bounded-vec = { workspace = true }
+core2 = { workspace = true }
 
 [dev-dependencies]
 proptest = { workspace = true }
diff --git a/sigma-ser/src/lib.rs b/sigma-ser/src/lib.rs
index 20792b1d3..b648bd265 100644
--- a/sigma-ser/src/lib.rs
+++ b/sigma-ser/src/lib.rs
@@ -1,5 +1,6 @@
 //! Sigma serialization
 
+#![cfg_attr(not(feature = "std"), no_std)]
 // Coding conventions
 #![forbid(unsafe_code)]
 #![deny(non_upper_case_globals)]
@@ -9,7 +10,6 @@
 #![deny(dead_code)]
 #![deny(unused_imports)]
 #![deny(missing_docs)]
-#![forbid(unsafe_code)]
 #![deny(clippy::unwrap_used)]
 #![deny(clippy::expect_used)]
 #![deny(clippy::todo)]
@@ -17,6 +17,8 @@
 #![deny(clippy::panic)]
 #![deny(clippy::wildcard_enum_match_arm)]
 
+extern crate alloc;
+
 /// ScoreX Serialization
 mod scorex_serialize;
 pub use scorex_serialize::{
diff --git a/sigma-ser/src/scorex_serialize.rs b/sigma-ser/src/scorex_serialize.rs
index fc43fc2b0..f1c76ddbf 100644
--- a/sigma-ser/src/scorex_serialize.rs
+++ b/sigma-ser/src/scorex_serialize.rs
@@ -1,5 +1,10 @@
-use std::io;
-use std::{convert::TryInto, io::Cursor};
+use alloc::boxed::Box;
+use alloc::string::ToString;
+use alloc::vec::Vec;
+use alloc::{string::String, vec};
+use core::convert::TryInto;
+use core2::io;
+use core2::io::Cursor;
 
 use crate::vlq_encode;
 use crate::vlq_encode::*;
@@ -20,7 +25,7 @@ pub enum ScorexSerializationError {
     NotSupported(&'static str),
     /// Integer type conversion failed
     #[error("Bounds check error: {0}")]
-    TryFrom(#[from] std::num::TryFromIntError),
+    TryFrom(#[from] core::num::TryFromIntError),
     /// Misc error
     #[error("error: {0}")]
     Misc(&'static str),
@@ -32,12 +37,23 @@ impl From<io::Error> for ScorexSerializationError {
     }
 }
 
+#[cfg(feature = "std")]
 impl From<ScorexSerializationError> for io::Error {
     fn from(e: ScorexSerializationError) -> Self {
         io::Error::new(io::ErrorKind::InvalidInput, e.to_string())
     }
 }
 
+#[cfg(not(feature = "std"))]
+impl From<ScorexSerializationError> for io::Error {
+    fn from(_e: ScorexSerializationError) -> Self {
+        io::Error::new(
+            io::ErrorKind::InvalidInput,
+            "Error messages are only supported on std target",
+        )
+    }
+}
+
 /// Ways parsing might fail
 #[derive(Error, Eq, PartialEq, Debug, Clone)]
 pub enum ScorexParsingError {
@@ -79,7 +95,7 @@ pub enum ScorexParsingError {
     BoundedVecOutOfBounds(#[from] BoundedVecOutOfBounds),
     /// Failed to convert integer type
     #[error("Bounds check error: {0}")]
-    TryFrom(#[from] std::num::TryFromIntError),
+    TryFrom(#[from] core::num::TryFromIntError),
 }
 
 impl From<io::Error> for ScorexParsingError {
diff --git a/sigma-ser/src/vlq_encode.rs b/sigma-ser/src/vlq_encode.rs
index c8f22dff2..48f23b208 100644
--- a/sigma-ser/src/vlq_encode.rs
+++ b/sigma-ser/src/vlq_encode.rs
@@ -1,6 +1,11 @@
 use super::zig_zag_encode;
-use std::convert::TryFrom;
-use std::io;
+use alloc::{
+    string::{String, ToString},
+    vec,
+    vec::Vec,
+};
+use core::convert::TryFrom;
+use core2::io;
 
 use bitvec::order::Lsb0;
 use bitvec::prelude::BitVec;
@@ -16,7 +21,7 @@ pub enum VlqEncodingError {
     Io(String),
     /// value bounds check error
     #[error("Bounds check error: {1} for input: {0}")]
-    TryFrom(String, std::num::TryFromIntError),
+    TryFrom(String, core::num::TryFromIntError),
     /// Fail to decode a value from bytes
     #[error("VLQ decoding failed")]
     VlqDecodingFailed,
@@ -126,8 +131,12 @@ pub trait WriteSigmaVlqExt: io::Write {
     /// Put a short string (< 256 bytes) into the writer. Writes length (as u8) and string bytes to the writer
     fn put_short_string(&mut self, s: &str) -> io::Result<()> {
         if s.len() > 255 {
+            #[cfg(feature = "std")]
+            let err_kind = io::ErrorKind::Unsupported;
+            #[cfg(not(feature = "std"))]
+            let err_kind = io::ErrorKind::Uncategorized;
             return Err(io::Error::new(
-                io::ErrorKind::Unsupported,
+                err_kind,
                 "Serializing strings with more than 255 bytes is not allowed",
             ));
         }
@@ -166,7 +175,7 @@ pub trait ReadSigmaVlqExt: io::Read + io::Seek {
     }
 
     /// Read u8 without decoding
-    fn get_u8(&mut self) -> std::result::Result<u8, io::Error> {
+    fn get_u8(&mut self) -> Result<u8, io::Error> {
         let mut slice = [0u8; 1];
         self.read_exact(&mut slice)?;
         Ok(slice[0])
@@ -265,10 +274,12 @@ mod tests {
     // See corresponding test suite in
     // https://github.com/ScorexFoundation/scorex-util/blob/9adb6c68b8a1c00ec17730e6da11c2976a892ad8/src/test/scala/scorex/util/serialization/VLQReaderWriterSpecification.scala#L11
     use super::*;
+    use alloc::format;
+    use alloc::vec;
+    use core2::io::Cursor;
+    use core2::io::Read;
+    use core2::io::Write;
     use proptest::collection;
-    use std::io::Cursor;
-    use std::io::Read;
-    use std::io::Write;
 
     extern crate derive_more;
     use derive_more::From;
@@ -944,7 +955,7 @@ mod tests {
             w.put_short_string(&s).unwrap();
             let inner = w.into_inner();
             prop_assert_eq!(inner[0] as usize, s.len());
-            prop_assert_eq!(std::str::from_utf8(&inner[1..]), Ok(&*s));
+            prop_assert_eq!(core::str::from_utf8(&inner[1..]), Ok(&*s));
         }
 
         #[test]
diff --git a/sigma-ser/src/zig_zag_encode.rs b/sigma-ser/src/zig_zag_encode.rs
index fd025f7f2..86942fc43 100644
--- a/sigma-ser/src/zig_zag_encode.rs
+++ b/sigma-ser/src/zig_zag_encode.rs
@@ -42,6 +42,7 @@ pub fn decode_u64(v: u64) -> i64 {
 #[allow(clippy::panic)]
 mod tests {
     use super::*;
+    use alloc::format;
 
     #[allow(overflowing_literals)]
     #[test]
diff --git a/sigma-util/Cargo.toml b/sigma-util/Cargo.toml
index 1b03ae0da..17eab0a2d 100644
--- a/sigma-util/Cargo.toml
+++ b/sigma-util/Cargo.toml
@@ -7,9 +7,6 @@ repository.workspace = true
 edition.workspace = true
 description = "Ergo primitives"
 
-[lib]
-crate-type = ["cdylib", "rlib"]
-
 [dependencies]
 blake2 = { workspace = true }
 sha2 = { workspace = true }
diff --git a/sigma-util/src/hash.rs b/sigma-util/src/hash.rs
index 418d74c23..8a65fec45 100644
--- a/sigma-util/src/hash.rs
+++ b/sigma-util/src/hash.rs
@@ -1,5 +1,7 @@
 //! Hash functions
 
+use alloc::boxed::Box;
+
 /// Blake2b256 hash (256 bit)
 pub fn blake2b256_hash(bytes: &[u8]) -> Box<[u8; 32]> {
     use blake2::digest::typenum::U32;
diff --git a/sigma-util/src/lib.rs b/sigma-util/src/lib.rs
index 8c65bee1a..c8100f069 100644
--- a/sigma-util/src/lib.rs
+++ b/sigma-util/src/lib.rs
@@ -1,5 +1,5 @@
 //! Ergo primitives
-
+#![no_std]
 // Coding conventions
 #![forbid(unsafe_code)]
 #![deny(non_upper_case_globals)]
@@ -13,6 +13,8 @@
 #![allow(clippy::unit_arg)]
 #![deny(rustdoc::broken_intra_doc_links)]
 
+extern crate alloc;
+
 pub mod hash;
 mod vec_ext;
 
diff --git a/sigma-util/src/vec_ext.rs b/sigma-util/src/vec_ext.rs
index 07cd53225..a222521e1 100644
--- a/sigma-util/src/vec_ext.rs
+++ b/sigma-util/src/vec_ext.rs
@@ -1,6 +1,8 @@
 //! Vec extensions
 
-use std::sync::Arc;
+use alloc::sync::Arc;
+
+use alloc::vec::Vec;
 
 /// Vec<i8> to Vec<u8> conversion
 pub trait FromVecI8 {


Test patch:
diff --git a/ergotree-interpreter/tests/signing_spec_tests.rs b/ergotree-interpreter/tests/signing_spec_tests.rs
index 04b69bceb..85fbedaf3 100644
--- a/ergotree-interpreter/tests/signing_spec_tests.rs
+++ b/ergotree-interpreter/tests/signing_spec_tests.rs
@@ -1,3 +1,4 @@
+use core::convert::TryInto;
 use ergotree_interpreter::sigma_protocol::private_input::DlogProverInput;
 use ergotree_interpreter::sigma_protocol::verifier::{TestVerifier, Verifier};
 use ergotree_ir::chain::context::Context;
@@ -13,7 +14,6 @@ use ergotree_ir::sigma_protocol::sigma_boolean::{ProveDhTuple, SigmaProp};
 use ergotree_ir::types::stype::SType;
 use num_bigint::BigUint;
 use sigma_test_util::force_any_val;
-use std::convert::TryInto;
 
 #[test]
 fn sig_test_vector_provedlog() {
diff --git a/sigma-test-util/Cargo.toml b/sigma-test-util/Cargo.toml
index 03c5e36dc..20a250753 100644
--- a/sigma-test-util/Cargo.toml
+++ b/sigma-test-util/Cargo.toml
@@ -11,7 +11,5 @@ description = "Test utilities for Ergo"
 crate-type = ["cdylib", "rlib"]
 
 [dependencies]
-proptest = {version = "1.0.0"}
-proptest-derive = {version = "0.3.0"}
-
+proptest = { workspace = true }
 [dev-dependencies]