diff --git a/Cargo.lock b/Cargo.lock index 0fe29ee33..d79e4af48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,6 +144,12 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + [[package]] name = "cast" version = "0.3.0" @@ -358,6 +364,7 @@ dependencies = [ "hex-literal", "k256", "lazy_static", + "malachite-bigint", "num-bigint", "num-integer", "num-traits", @@ -402,7 +409,7 @@ dependencies = [ "clap", "criterion-plot", "is-terminal", - "itertools", + "itertools 0.10.5", "num-traits", "once_cell", "oorandom", @@ -423,7 +430,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -580,6 +587,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -751,6 +764,15 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash", +] + [[package]] name = "heck" version = "0.5.0" @@ -800,7 +822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.5", ] [[package]] @@ -835,6 +857,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -905,6 +936,12 @@ dependencies = [ "cc", ] +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -927,6 +964,43 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "malachite-base" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8b6f86fdbb1eb9955946be91775239dfcb0acdb1a51bb07d5fc9b8c854f5ccd" +dependencies = [ + "hashbrown 0.16.1", + "itertools 0.14.0", + "libm", + "ryu", +] + +[[package]] +name = "malachite-bigint" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fcd6e504ffc67db2b3c6d5e90e08054646e2b04f42115a5460bf1c1e37d3bc" +dependencies = [ + "malachite-base", + "malachite-nz", + "num-integer", + "num-traits", + "paste", +] + +[[package]] +name = "malachite-nz" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0197a2f5cfee19d59178e282985c6ca79a9233e26a2adcf40acb693896aa09f6" +dependencies = [ + "itertools 0.14.0", + "libm", + "malachite-base", + "wide", +] + [[package]] name = "memchr" version = "2.7.4" @@ -1042,6 +1116,12 @@ dependencies = [ "sha2", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1376,9 +1456,18 @@ checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "safe_arch" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f7caad094bd561859bcd467734a720c3c1f5d1f338995351fefe2190c45efed" +dependencies = [ + "bytemuck", +] [[package]] name = "same-file" @@ -1746,6 +1835,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "wide" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac11b009ebeae802ed758530b6496784ebfee7a87b9abfbcaf3bbe25b814eb25" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi-util" version = "0.1.8" diff --git a/Cargo.toml b/Cargo.toml index 5eeb7c5b6..102957dd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ bitvec = "1.0.1" arbitrary = { version = "1.4.2", features = ["derive"] } bumpalo = "3.19.0" anyhow = "1.0.100" +malachite-bigint = "0.9.1" [dependencies] bitflags = { workspace = true } @@ -90,6 +91,7 @@ hex = { workspace = true } sha1 = { workspace = true } bumpalo = { workspace = true } thiserror = "1.0.69" +malachite-bigint = { workspace = true } [dev-dependencies] diff --git a/src/allocator.rs b/src/allocator.rs index 6f237175f..3ee1bbd69 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,6 +1,7 @@ use crate::error::{EvalErr, Result}; -use crate::number::{Number, number_from_u8}; +use crate::number::{Malachite, Number, malachite_number_from_u8, number_from_u8}; use chia_bls::{G1Element, G2Element}; +use num_traits::ToPrimitive; use std::borrow::Borrow; use std::fmt; use std::hash::Hash; @@ -472,15 +473,39 @@ impl Allocator { } pub fn new_number(&mut self, v: Number) -> Result { - use num_traits::ToPrimitive; - if let Some(val) = v.to_u32() + if let Some(ptr) = self.new_small_number_from_bigint(&v)? { + return Ok(ptr); + } + + let bytes = v.to_signed_bytes_be(); + + self.new_atom_from_bigint_bytes(bytes.as_slice()) + } + + pub fn new_malachite_number(&mut self, v: Malachite) -> Result { + if let Some(ptr) = self.new_small_number_from_bigint(&v)? { + return Ok(ptr); + } + + let bytes = v.to_signed_bytes_be(); + + self.new_atom_from_bigint_bytes(bytes.as_slice()) + } + + fn new_small_number_from_bigint( + &mut self, + value: &impl ToPrimitive, + ) -> Result> { + if let Some(val) = value.to_u32() && val <= NODE_PTR_IDX_MASK { - return self.new_small_number(val); + return Ok(Some(self.new_small_number(val)?)); } - let bytes: Vec = v.to_signed_bytes_be(); - let mut slice = bytes.as_slice(); + Ok(None) + } + + fn new_atom_from_bigint_bytes(&mut self, mut slice: &[u8]) -> Result { // make number minimal by removing leading zeros while (!slice.is_empty()) && (slice[0] == 0) { if slice.len() > 1 && (slice[1] & 0x80 == 0x80) { @@ -488,6 +513,7 @@ impl Allocator { } slice = &slice[1..]; } + self.new_atom(slice) } @@ -831,6 +857,24 @@ impl Allocator { } } + pub fn malachite_number(&self, node: NodePtr) -> Malachite { + #[cfg(feature = "allocator-debug")] + self.validate_node(node); + + let index = node.index(); + + match node.object_type() { + ObjectType::Bytes => { + let atom = self.atom_vec[index as usize]; + malachite_number_from_u8(&self.u8_vec[atom.start as usize..atom.end as usize]) + } + ObjectType::SmallAtom => Malachite::from(index), + _ => { + panic!("number() called on pair"); + } + } + } + pub fn g1(&self, node: NodePtr) -> Result { #[cfg(feature = "allocator-debug")] self.validate_node(node); diff --git a/src/more_ops.rs b/src/more_ops.rs index cc81b44a0..a3394698a 100644 --- a/src/more_ops.rs +++ b/src/more_ops.rs @@ -8,7 +8,9 @@ use std::ops::BitXorAssign; use crate::allocator::{Allocator, NodePtr, NodeVisitor, SExp, len_for_value}; use crate::cost::{Cost, check_cost}; use crate::error::EvalErr; +use crate::number::Malachite; use crate::number::Number; +use crate::number::malachite_number_from_u8; use crate::op_utils::{ MALLOC_COST_PER_BYTE, atom, atom_len, get_args, get_varargs, i32_atom, int_atom, match_args, mod_group_order, new_atom_and_cost, nilp, u32_from_u8, @@ -402,7 +404,7 @@ pub fn op_sha256(a: &mut Allocator, mut input: NodePtr, max_cost: Cost) -> Respo pub fn op_add(a: &mut Allocator, mut input: NodePtr, max_cost: Cost) -> Response { let mut cost = ARITH_BASE_COST; - let mut total: Number = 0.into(); + let mut total: Malachite = 0.into(); while let Some((arg, rest)) = a.next(input) { input = rest; cost += ARITH_COST_PER_ARG; @@ -412,8 +414,7 @@ pub fn op_add(a: &mut Allocator, mut input: NodePtr, max_cost: Cost) -> Response cost += ARITH_COST_PER_BYTE * (buf.len() as Cost); check_cost(cost, max_cost)?; - use crate::number::number_from_u8; - total += number_from_u8(buf); + total += malachite_number_from_u8(buf); } NodeVisitor::U32(val) => { cost += len_for_value(val) as Cost * ARITH_COST_PER_BYTE; @@ -428,7 +429,7 @@ pub fn op_add(a: &mut Allocator, mut input: NodePtr, max_cost: Cost) -> Response } } } - let total = a.new_number(total)?; + let total = a.new_malachite_number(total)?; Ok(malloc_cost(a, cost, total)) } @@ -740,7 +741,7 @@ fn test_op_ash() { )); let node = test_shift(op_ash, &mut a, &[1], &[0x80, 0]).unwrap().1; - assert_eq!(a.atom(node).as_ref(), &[]); + assert_eq!(a.atom(node).as_ref(), &[0; 0]); assert!(matches!( test_shift(op_ash, &mut a, &[1], &[0x7f, 0, 0, 0]).unwrap_err(), @@ -795,7 +796,7 @@ fn test_op_lsh() { )); let node = test_shift(op_lsh, &mut a, &[1], &[0x80, 0]).unwrap().1; - assert_eq!(a.atom(node).as_ref(), &[]); + assert_eq!(a.atom(node).as_ref(), &[0; 0]); assert!(matches!( test_shift(op_lsh, &mut a, &[1], &[0x7f, 0, 0, 0]).unwrap_err(), diff --git a/src/number.rs b/src/number.rs index 0220ac5d9..6ebf9fa3f 100644 --- a/src/number.rs +++ b/src/number.rs @@ -1,6 +1,7 @@ use num_bigint::BigInt; pub type Number = BigInt; +pub type Malachite = malachite_bigint::BigInt; // This low-level conversion function is meant to be used by the Allocator, for // logic interacting with the CLVM heap/allocator, use new_number() and number() @@ -14,6 +15,15 @@ pub fn number_from_u8(v: &[u8]) -> Number { } } +pub fn malachite_number_from_u8(v: &[u8]) -> Malachite { + let len = v.len(); + if len == 0 { + 0.into() + } else { + Malachite::from_signed_bytes_be(v) + } +} + #[cfg(test)] mod tests { use num_bigint::{BigUint, Sign}; diff --git a/src/serde/write_atom.rs b/src/serde/write_atom.rs index 4eb02913a..4515b07cf 100644 --- a/src/serde/write_atom.rs +++ b/src/serde/write_atom.rs @@ -70,7 +70,7 @@ mod tests { for v in 0..0x7f { let mut buf = Vec::::new(); assert!(write_atom_encoding_prefix_with_size(&mut buf, v, 1).is_ok()); - assert_eq!(buf, vec![]); + assert_eq!(buf, vec![0; 0]); } for v in 0x80..0xff {