diff --git a/Cargo.lock b/Cargo.lock index b4757eab..571f5199 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -390,6 +390,18 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -1021,6 +1033,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.31" @@ -1210,6 +1228,12 @@ dependencies = [ "crunchy", ] +[[package]] +name = "hamming" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1" + [[package]] name = "hashbrown" version = "0.12.3" @@ -2503,6 +2527,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -3131,6 +3161,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" version = "3.14.0" @@ -3426,8 +3462,10 @@ checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" name = "uplc" version = "1.1.7" dependencies = [ + "bitvec", "blst", "cryptoxide", + "hamming", "hex", "indexmap 1.9.3", "indoc", @@ -3852,6 +3890,15 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "xdg" version = "2.5.2" diff --git a/crates/uplc/Cargo.toml b/crates/uplc/Cargo.toml index 432c7b69..9073aa43 100644 --- a/crates/uplc/Cargo.toml +++ b/crates/uplc/Cargo.toml @@ -33,6 +33,8 @@ strum_macros = "0.24.3" thiserror = "1.0.39" blst = "0.3.11" once_cell = "1.18.0" +hamming = "0.1.3" +bitvec = "1.0.1" [target.'cfg(not(target_family="wasm"))'.dependencies] secp256k1 = { version = "0.26.0" } diff --git a/crates/uplc/src/machine/runtime.rs b/crates/uplc/src/machine/runtime.rs index 216b276c..bc44267f 100644 --- a/crates/uplc/src/machine/runtime.rs +++ b/crates/uplc/src/machine/runtime.rs @@ -9,8 +9,9 @@ use crate::{ machine::value::integer_log2, plutus_data_to_bytes, }; +use bitvec::{order::Lsb0, vec::BitVec}; use itertools::Itertools; -use num_bigint::{BigInt, Sign}; +use num_bigint::BigInt; use num_integer::Integer; use num_traits::{FromPrimitive, Signed, Zero}; use once_cell::sync::Lazy; @@ -1664,34 +1665,62 @@ impl DefaultFunction { let byte_length = bytes.len(); - if BigInt::from_usize(byte_length).unwrap() * 8 < shift.abs() { + if BigInt::from_usize(byte_length).unwrap() * 8 <= shift.abs() { let mut new_vec = vec![]; new_vec.resize(byte_length, 0); return Ok(Value::byte_string(new_vec)); } - let bytes = BigInt::from_bytes_be(Sign::NoSign, bytes); - let is_shl = shift >= &0.into(); - let bytes = if is_shl { - bytes << usize::try_from(shift.abs()).unwrap() - } else { - bytes >> usize::try_from(shift.abs()).unwrap() - } - .to_bytes_be() - .1 - .into_iter() - .take(byte_length) - .collect_vec(); + let mut bv = BitVec::::from_vec(bytes.clone()); - Ok(Value::byte_string(bytes)) + if is_shl { + bv.shift_left(usize::try_from(shift.abs()).unwrap()); + } else { + bv.shift_right(usize::try_from(shift.abs()).unwrap()); + } + + Ok(Value::byte_string(bv.into_vec())) + } + DefaultFunction::RotateByteString => { + let bytes = args[0].unwrap_byte_string()?; + let shift = args[1].unwrap_integer()?; + + let byte_length = bytes.len(); + + let shift = shift % byte_length; + + let mut bv = BitVec::::from_vec(bytes.clone()); + + bv.rotate_right(usize::try_from(shift).unwrap()); + + Ok(Value::byte_string(bv.into_vec())) + } + DefaultFunction::CountSetBits => { + let bytes = args[0].unwrap_byte_string()?; + + Ok(Value::integer(hamming::weight(bytes).into())) } - DefaultFunction::RotateByteString => todo!(), - DefaultFunction::CountSetBits => todo!(), DefaultFunction::FindFirstSetBit => todo!(), - DefaultFunction::Ripemd_160 => todo!(), + DefaultFunction::Ripemd_160 => { + use cryptoxide::{digest::Digest, ripemd160::Ripemd160}; + + let arg1 = args[0].unwrap_byte_string()?; + + let mut hasher = Ripemd160::new(); + + hasher.input(arg1); + + let mut bytes = vec![0; hasher.output_bytes()]; + + hasher.result(&mut bytes); + + let value = Value::byte_string(bytes); + + Ok(value) + } DefaultFunction::ExpModInteger => todo!(), } }