From 7fd518365aca205072d063eb35f7fb5cb4963ccb Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Mon, 7 Sep 2026 14:17:23 +0000 Subject: [PATCH 1/6] Add FLOAT_PI beside FLOAT_E The 67-digit coefficient at exponent -66, pi rounded to nearest at 66 places, packed like FLOAT_E; testFloatPi pins it through packLossless. rainlang's pi word reads it from here once its pin moves. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QyCCzi9WZPhuXcU1hwr2bq --- src/lib/LibDecimalFloat.sol | 5 +++++ test/src/lib/LibDecimalFloat.constants.t.sol | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/src/lib/LibDecimalFloat.sol b/src/lib/LibDecimalFloat.sol index d06a9afb..6d0cb0b1 100644 --- a/src/lib/LibDecimalFloat.sol +++ b/src/lib/LibDecimalFloat.sol @@ -109,6 +109,11 @@ library LibDecimalFloat { Float constant FLOAT_E = Float.wrap(bytes32(uint256(0xffffffbe19cfc6ef4f44cf88f14500d013df534fcaad48fca1d5ca47bea26fcc))); + /// Pi + /// 3.141592653589793238462643383279502884197169399375105820974944592308e66, -66 + Float constant FLOAT_PI = + Float.wrap(bytes32(uint256(0xffffffbe1dd4c9e873614f593bba9c6007d9a7ac8d03a4b6c700a65cb537a1b4))); + /// Convert a fixed point decimal value to a signed coefficient and exponent. /// The conversion can be lossy if the unsigned value is too large to fit in /// the signed coefficient. diff --git a/test/src/lib/LibDecimalFloat.constants.t.sol b/test/src/lib/LibDecimalFloat.constants.t.sol index f570c1c1..2b6c6a4c 100644 --- a/test/src/lib/LibDecimalFloat.constants.t.sol +++ b/test/src/lib/LibDecimalFloat.constants.t.sol @@ -70,6 +70,14 @@ contract LibDecimalFloatConstantsTest is Test { assertEq(Float.unwrap(e), Float.unwrap(expected)); } + function testFloatPi() external pure { + Float pi = LibDecimalFloat.FLOAT_PI; + Float expected = LibDecimalFloat.packLossless( + int224(3.141592653589793238462643383279502884197169399375105820974944592308e66), -66 + ); + assertEq(Float.unwrap(pi), Float.unwrap(expected)); + } + function testFloatZero() external pure { Float zero = LibDecimalFloat.FLOAT_ZERO; Float expected = LibDecimalFloat.packLossless(MAXIMIZED_ZERO_SIGNED_COEFFICIENT, MAXIMIZED_ZERO_EXPONENT); From d997227b7c267506972be712c55e7abd46b00df5 Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Mon, 7 Sep 2026 14:39:20 +0000 Subject: [PATCH 2/6] Cross-reference FLOAT_PI and FLOAT_E against values derived in Rust crates/constants is a test-only crate, never published. It binds src/lib/LibDecimalFloat.sol at compile time, reads the packed words for FLOAT_PI and FLOAT_E out of that source, unpacks exponent and coefficient, and asserts them equal to pi (Machin's formula) and e (the 1/k! series) derived in 512-bit integer arithmetic with guard digits and rounded to nearest at 66 places. No digits are copied; a change to either constant in the library is a change to what the tests check. rainix rs-test and rs-static workflows run it. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QyCCzi9WZPhuXcU1hwr2bq --- .github/workflows/rainix-rs-static.yaml | 5 + .github/workflows/rainix-rs-test.yaml | 5 + .gitignore | 1 + .soldeerignore | 3 + CLAUDE.md | 5 +- Cargo.lock | 433 ++++++++++++++++++++++++ Cargo.toml | 8 + REUSE.toml | 3 + crates/constants/Cargo.toml | 11 + crates/constants/src/lib.rs | 131 +++++++ 10 files changed, 604 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/rainix-rs-static.yaml create mode 100644 .github/workflows/rainix-rs-test.yaml create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 crates/constants/Cargo.toml create mode 100644 crates/constants/src/lib.rs diff --git a/.github/workflows/rainix-rs-static.yaml b/.github/workflows/rainix-rs-static.yaml new file mode 100644 index 00000000..4ad44f55 --- /dev/null +++ b/.github/workflows/rainix-rs-static.yaml @@ -0,0 +1,5 @@ +name: rainix-rs-static +on: [push] +jobs: + rs-static: + uses: rainlanguage/rainix/.github/workflows/rainix-rs-static.yaml@main diff --git a/.github/workflows/rainix-rs-test.yaml b/.github/workflows/rainix-rs-test.yaml new file mode 100644 index 00000000..ce9b0417 --- /dev/null +++ b/.github/workflows/rainix-rs-test.yaml @@ -0,0 +1,5 @@ +name: rainix-rs-test +on: [push] +jobs: + rs-test: + uses: rainlanguage/rainix/.github/workflows/rainix-rs-test.yaml@main diff --git a/.gitignore b/.gitignore index 5b81aff1..cd6e7aed 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ temp .fixes .pre-commit-config.yaml .claude +target diff --git a/.soldeerignore b/.soldeerignore index fc92760c..bf48b8ca 100644 --- a/.soldeerignore +++ b/.soldeerignore @@ -25,3 +25,6 @@ CLAUDE.md /target /test /REUSE.toml +/crates +Cargo.toml +Cargo.lock diff --git a/CLAUDE.md b/CLAUDE.md index d4ef26b6..dfbc7c09 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,7 +14,10 @@ rather than producing special values. This repository is the library half of the rain.math.float split. It publishes only the `rain-math-float` Soldeer package. The deployed concrete contract, the on-chain deploy pins/snapshot, the deploy scripts/tests, and the Rust/WASM/npm -bindings live in `rain.math.float.deploy` and publish from there. +bindings live in `rain.math.float.deploy` and publish from there. The one Rust +crate here, `crates/constants`, is test-only and never published: it reads the +packed constants out of `LibDecimalFloat.sol` and checks them against values +derived in integer arithmetic. ## Build Commands diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..2c1c31b8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,433 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "alloy-primitives" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce7b00f0cb42c66ec353076ded1dff1fbf818f6e0e26c40c8a8456c04483fca4" +dependencies = [ + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "itoa", + "paste", + "ruint", + "sha3", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "const-hex" +version = "1.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e2a781ebdf4467d1428dc4593067825fb646f6871475098d8577421af73558" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "proptest", + "serde_core", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "hybrid-array" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" +dependencies = [ + "typenum", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "keccak" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +dependencies = [ + "bitflags", + "num-traits", + "rand 0.9.5", + "rand_chacha", + "rand_xorshift", + "unarray", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rain-math-float-constants" +version = "0.0.0" +dependencies = [ + "alloy-primitives", +] + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "ruint" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e99bff0393163bb25029a6af25d3d8d202ba5b5438a74d1bd8789f5c822970" +dependencies = [ + "proptest", + "rand 0.8.8", + "rand 0.9.5", + "ruint-macro", + "serde_core", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "zerocopy" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..be06f5a3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[workspace] +members = ["crates/*"] +resolver = "2" + +[workspace.package] +edition = "2024" +license = "LicenseRef-DCL-1.0" +homepage = "https://github.com/rainlanguage/rain.math.float" diff --git a/REUSE.toml b/REUSE.toml index eeae38fb..89caa54e 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -9,6 +9,9 @@ path = [ ".soldeerignore", "audit/**/", ".gitignore", + "Cargo.lock", + "Cargo.toml", + "crates/**/", ".gitmodules", "CLAUDE.md", "README.md", diff --git a/crates/constants/Cargo.toml b/crates/constants/Cargo.toml new file mode 100644 index 00000000..99bc7861 --- /dev/null +++ b/crates/constants/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rain-math-float-constants" +version = "0.0.0" +publish = false +edition.workspace = true +license.workspace = true +homepage.workspace = true +description = "Cross-references the constants LibDecimalFloat.sol packs against values derived in Rust." + +[dependencies] +alloy-primitives = { version = "1.0.9", default-features = false } diff --git a/crates/constants/src/lib.rs b/crates/constants/src/lib.rs new file mode 100644 index 00000000..759c10c1 --- /dev/null +++ b/crates/constants/src/lib.rs @@ -0,0 +1,131 @@ +//! Cross-references the constants `LibDecimalFloat.sol` packs against values +//! derived here in integer arithmetic. The Solidity source is bound at compile +//! time and the packed words are read out of it, so a change to a constant in +//! the library is a change to what these tests check. + +#[cfg(test)] +mod tests { + use alloy_primitives::aliases::{I224, U224}; + use alloy_primitives::{U256, U512}; + + /// The library source, as committed. + const LIB: &str = include_str!("../../../src/lib/LibDecimalFloat.sol"); + + /// Decimal places the library packs the constants at. + const PLACES: u32 = 66; + + /// Extra digits carried through the series so rounding at `PLACES` is + /// exact. + const GUARD: u32 = 12; + + /// The packed word `LibDecimalFloat.sol` assigns to the constant `name`: + /// the 64 hex digits following its `=`. + fn packed_constant(name: &str) -> U256 { + let decl = format!("constant {name} ="); + let at = LIB + .find(&decl) + .unwrap_or_else(|| panic!("{name} is not declared in LibDecimalFloat.sol")); + let rest = &LIB[at + decl.len()..]; + let hex_at = rest + .find("0x") + .expect("no hex literal after the declaration"); + let hex = &rest[hex_at + 2..hex_at + 2 + 64]; + U256::from_str_radix(hex, 16).expect("64 hex digits") + } + + /// Splits a packed `Float` into its signed 224-bit coefficient and signed + /// 32-bit exponent: the exponent is the high 32 bits, the coefficient the + /// low 224. + fn unpack(word: U256) -> (I224, i32) { + let exponent = (word >> 224usize).to::() as i32; + let mask = (U256::from(1u8) << 224usize) - U256::from(1u8); + let coefficient = I224::from_raw((word & mask).to::()); + (coefficient, exponent) + } + + fn ten_pow(n: u32) -> U512 { + U512::from(10u64).pow(U512::from(n)) + } + + /// `atan(1/x) * 10^scale` by the alternating series, truncated once a term + /// underflows the scale. Every intermediate is an integer. + fn atan_inv(x: u64, scale: u32) -> U512 { + let x = U512::from(x); + let x2 = x * x; + let mut power = ten_pow(scale) / x; + let mut sum = U512::ZERO; + let mut k = 0u64; + loop { + let term = power / U512::from(2 * k + 1); + if term.is_zero() { + break; + } + if k.is_multiple_of(2) { + sum += term; + } else { + sum -= term; + } + power /= x2; + k += 1; + } + sum + } + + /// `pi * 10^scale` by Machin's formula. + fn pi_scaled(scale: u32) -> U512 { + U512::from(16u64) * atan_inv(5, scale) - U512::from(4u64) * atan_inv(239, scale) + } + + /// `e * 10^scale` by the series sum of 1/k!. + fn e_scaled(scale: u32) -> U512 { + let mut term = ten_pow(scale); + let mut sum = U512::ZERO; + let mut k = 1u64; + while !term.is_zero() { + sum += term; + term /= U512::from(k); + k += 1; + } + sum + } + + /// Drops `GUARD` digits, rounding to nearest. + fn round_to_places(scaled: U512) -> I224 { + let divisor = ten_pow(GUARD); + let (q, r) = (scaled / divisor, scaled % divisor); + let rounded = if r * U512::from(2u64) >= divisor { + q + U512::from(1u64) + } else { + q + }; + I224::from_dec_str(&rounded.to_string()).unwrap() + } + + #[test] + fn float_pi_is_pi_rounded_to_nearest() { + let (coefficient, exponent) = unpack(packed_constant("FLOAT_PI")); + assert_eq!(exponent, -(PLACES as i32)); + assert_eq!(coefficient, round_to_places(pi_scaled(PLACES + GUARD))); + } + + #[test] + fn float_e_is_e_rounded_to_nearest() { + let (coefficient, exponent) = unpack(packed_constant("FLOAT_E")); + assert_eq!(exponent, -(PLACES as i32)); + assert_eq!(coefficient, round_to_places(e_scaled(PLACES + GUARD))); + } + + #[test] + fn derivations_start_with_the_known_digits() { + assert!( + pi_scaled(PLACES + GUARD) + .to_string() + .starts_with("314159265358979323846264338327950288") + ); + assert!( + e_scaled(PLACES + GUARD) + .to_string() + .starts_with("271828182845904523536028747135266249") + ); + } +} From 57211550e5d82022f0930a34d4e92eb8926ffa40 Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Mon, 7 Sep 2026 16:27:13 +0000 Subject: [PATCH 3/6] Run the bindings' library tests here, over this source The Rust tests of library logic lived in the deploy repo's bindings crate, over the pinned package, one release behind this source. `crates/tests` (was `crates/constants`) runs them through the `rain-math-float` bindings over `test/concrete/TestDecimalFloat.sol` compiled from `src/`, whose constructor deploys the log tables, and `TestDecimalFloatHarness.sol` for packing and the tables. `build.rs` runs `forge build`; `.cargo/config.toml` points the bindings at the artifacts and runs their constructors. The log-table tests read the tables from the harness instead of copies pasted into Rust. The tests of the bindings' own Rust API stay in the deploy crate. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QyCCzi9WZPhuXcU1hwr2bq --- .cargo/config.toml | 6 + .soldeerignore | 1 + CLAUDE.md | 6 +- Cargo.lock | 3725 ++++++++++++++++- REUSE.toml | 1 + crates/constants/Cargo.toml | 11 - crates/constants/src/lib.rs | 131 - crates/tests/Cargo.toml | 19 + crates/tests/build.rs | 25 + crates/tests/proptest-regressions/float.txt | 11 + .../tests/proptest-regressions/fuzz_ops.txt | 7 + crates/tests/src/constants.rs | 128 + crates/tests/src/float.rs | 985 +++++ crates/tests/src/fuzz_ops.rs | 305 ++ crates/tests/src/lib.rs | 13 + crates/tests/src/tables.rs | 316 ++ test/abstract/LogTest.sol | 25 +- test/concrete/TestDecimalFloat.sol | 185 + test/concrete/TestDecimalFloatHarness.sol | 44 + test/lib/LibTestLogTables.sol | 32 + 20 files changed, 5605 insertions(+), 371 deletions(-) create mode 100644 .cargo/config.toml delete mode 100644 crates/constants/Cargo.toml delete mode 100644 crates/constants/src/lib.rs create mode 100644 crates/tests/Cargo.toml create mode 100644 crates/tests/build.rs create mode 100644 crates/tests/proptest-regressions/float.txt create mode 100644 crates/tests/proptest-regressions/fuzz_ops.txt create mode 100644 crates/tests/src/constants.rs create mode 100644 crates/tests/src/float.rs create mode 100644 crates/tests/src/fuzz_ops.rs create mode 100644 crates/tests/src/lib.rs create mode 100644 crates/tests/src/tables.rs create mode 100644 test/concrete/TestDecimalFloat.sol create mode 100644 test/concrete/TestDecimalFloatHarness.sol create mode 100644 test/lib/LibTestLogTables.sol diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..05d39b4f --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,6 @@ +# The rain-math-float bindings run over the test concretes compiled from this +# source (crates/tests/build.rs), through their constructors. +[env] +RAIN_MATH_FLOAT_ARTIFACT = { value = "out/TestDecimalFloat.sol/TestDecimalFloat.json", relative = true } +RAIN_MATH_FLOAT_TEST_ARTIFACT = { value = "out/TestDecimalFloatHarness.sol/TestDecimalFloatHarness.json", relative = true } +RAIN_MATH_FLOAT_DEPLOY_MODE = "create" diff --git a/.soldeerignore b/.soldeerignore index bf48b8ca..abf98e67 100644 --- a/.soldeerignore +++ b/.soldeerignore @@ -26,5 +26,6 @@ CLAUDE.md /test /REUSE.toml /crates +/.cargo Cargo.toml Cargo.lock diff --git a/CLAUDE.md b/CLAUDE.md index dfbc7c09..c2a31a7d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -15,8 +15,10 @@ This repository is the library half of the rain.math.float split. It publishes only the `rain-math-float` Soldeer package. The deployed concrete contract, the on-chain deploy pins/snapshot, the deploy scripts/tests, and the Rust/WASM/npm bindings live in `rain.math.float.deploy` and publish from there. The one Rust -crate here, `crates/constants`, is test-only and never published: it reads the -packed constants out of `LibDecimalFloat.sol` and checks them against values +crate here, `crates/tests`, is test-only and never published. It runs the +bindings' library tests over `test/concrete/TestDecimalFloat.sol` compiled from +this source (`.cargo/config.toml` points the bindings at the artifacts and runs +their constructors) and cross-references the packed constants against values derived in integer arithmetic. ## Build Commands diff --git a/Cargo.lock b/Cargo.lock index 2c1c31b8..cc7b18c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,409 +2,3706 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alloy" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50ab0cd8afe573d1f7dc2353698a51b1f93aec362c8211e28cfd3948c6adba39" +dependencies = [ + "alloy-consensus", + "alloy-core", + "alloy-eips", + "alloy-rpc-types", + "alloy-serde", + "alloy-trie", +] + +[[package]] +name = "alloy-consensus" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f16daaf7e1f95f62c6c3bf8a3fc3d78b08ae9777810c0bb5e94966c7cd57ef0" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-trie", + "alloy-tx-macros", + "arbitrary", + "auto_impl", + "borsh", + "c-kzg", + "derive_more", + "either", + "k256", + "once_cell", + "rand 0.8.8", + "secp256k1 0.30.0", + "serde", + "serde_json", + "serde_with", + "thiserror", +] + +[[package]] +name = "alloy-consensus-any" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "118998d9015332ab1b4720ae1f1e3009491966a0349938a1f43ff45a8a4c6299" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "arbitrary", + "serde", +] + +[[package]] +name = "alloy-core" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa2d25cf04344ea5eeb47e0cd21c794e646a029959bf5700bd8c05342c0353fe" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives", + "alloy-rlp", + "alloy-sol-types", +] + +[[package]] +name = "alloy-dyn-abi" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201b9e973fe90b2effd9ab356d4f2a46ab56046ba9d46f163367553e72c045b0" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "arbitrary", + "itoa", + "proptest", + "serde", + "serde_json", + "winnow", +] + +[[package]] +name = "alloy-eip2124" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arbitrary", + "crc", + "rand 0.8.8", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eip2930" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64579d931b3f8eacc7c9ab0b220e87e9c4816e5c724ede1947b55c2f8e92ae5" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arbitrary", + "borsh", + "rand 0.8.8", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2919c5a56a1007492da313e7a3b6d45ef5edc5d33416fdec63c0d7a2702a0d20" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arbitrary", + "borsh", + "k256", + "rand 0.8.8", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eip7928" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b827a6d7784fe3eb3489d40699407a4cdcce74271421a01bdffe60cf573bb16" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arbitrary", + "borsh", + "once_cell", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eips" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ef28c9fdad22d4eec52d894f5f2673a0895f1e5ef196734568e68c0f6caca8" +dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", + "alloy-eip7928", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "arbitrary", + "auto_impl", + "borsh", + "c-kzg", + "derive_more", + "either", + "serde", + "serde_with", + "sha2", +] + +[[package]] +name = "alloy-json-abi" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dba4e59c3581a39e03e0b0b4a46ee9c41315b5d843b1e903271952b32bedb7c" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-network-primitives" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb82711d59a43fdfd79727c99f270b974c784ec4eb5728a0d0d22f26716c87ef" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "serde", +] + [[package]] name = "alloy-primitives" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce7b00f0cb42c66ec353076ded1dff1fbf818f6e0e26c40c8a8456c04483fca4" dependencies = [ + "alloy-rlp", + "arbitrary", "bytes", "cfg-if", "const-hex", "derive_more", + "fixed-cache", + "foldhash", + "hashbrown 0.17.1", + "indexmap 2.14.2", "itoa", + "k256", + "keccak-asm", "paste", + "proptest", + "proptest-derive 0.8.0", + "rand 0.9.5", + "rapidhash", "ruint", + "rustc-hash", + "secp256k1 0.31.1", + "serde", "sha3", ] [[package]] -name = "autocfg" -version = "1.5.1" +name = "alloy-rlp" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +checksum = "24671b1f62edcf0f9b62994c7bf72cd621a04a4b99f5020ece1a647b40e2f103" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] [[package]] -name = "bitflags" -version = "2.13.1" +name = "alloy-rlp-derive" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +checksum = "9d4311c03125e8a18296504560b9de3d75ecbd0dcda7f71e6cf2a196d57e6fba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] [[package]] -name = "block-buffer" -version = "0.12.1" +name = "alloy-rpc-types" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +checksum = "4faad925d3a669ffc15f43b3deec7fbdf2adeb28a4d6f9cf4bc661698c0f8f4b" dependencies = [ - "hybrid-array", + "alloy-primitives", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", ] [[package]] -name = "bytes" -version = "1.12.1" +name = "alloy-rpc-types-engine" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +checksum = "bb9b97b6e7965679ad22df297dda809b11cebc13405c1b537e5cffecc95834fa" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "arbitrary", + "derive_more", + "rand 0.8.8", + "serde", + "strum", +] [[package]] -name = "cfg-if" -version = "1.0.4" +name = "alloy-rpc-types-eth" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c095f92c4e1ff4981d89e9aa02d5f98c762a1980ab66bec49c44be11349da2" +dependencies = [ + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "arbitrary", + "itertools 0.14.0", + "serde", + "serde_json", + "serde_with", + "thiserror", +] + +[[package]] +name = "alloy-serde" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ece63b89294b8614ab3f483560c08d016930f842bf36da56bf0b764a15c11e" +dependencies = [ + "alloy-primitives", + "arbitrary", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-sol-macro" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64558980fb038cd34b4285ec2b36a2a8bd8d4ddd13b3f6e42d97cb5ee29938e" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error3", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffb0e793abdbaea9d01259493c8272c3af295d03389e70a2acdf53b57ad1edf" +dependencies = [ + "alloy-json-abi", + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap 2.14.2", + "proc-macro-error3", + "proc-macro2", + "quote", + "sha3", + "syn 2.0.119", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32c2c0ec8425d9663dac939ba75750f17d2933d2f020814b4f8fde4a60da6d26" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck", + "macro-string", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.119", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b37db6a7ad8170596345f864522f789cc7af093f516d6cdf34bbdcfba8adab" +dependencies = [ + "serde", + "winnow", +] + +[[package]] +name = "alloy-sol-types" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f40e33a0f588dde548c3b6767a71e61b593421a8c1b253b9cf1441dc7cf7ab5" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "serde", +] + +[[package]] +name = "alloy-trie" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f14b5d9b2c2173980202c6ff470d96e7c5e202c65a9f67884ad565226df7fbb" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arbitrary", + "derive_arbitrary", + "derive_more", + "nybbles", + "proptest", + "proptest-derive 0.7.0", + "serde", + "smallvec", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-tx-macros" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69722eddcdf1ce096c3ab66cf8116999363f734eb36fe94a148f4f71c85da84" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-r1cs-std", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a806ac6c8307b929df4645776290a50ee2aac754ad09d8bdf73391309e43af" +dependencies = [ + "ark-ff-asm 0.6.0", + "ark-ff-macros 0.6.0", + "ark-serialize 0.6.0", + "ark-std 0.6.0", + "digest 0.10.7", + "educe", + "num-bigint", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-ff-asm" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1479009684adc073dff49a1025d3a7065b317a9ead25aaaca38cdc70058ba8a2" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-ff-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0691ed21ef00ef89c1e9bda832eba493dda3ec2f8d892fb25b705f73f06bb8" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-relations", + "ark-std 0.5.0", + "educe", + "num-bigint", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff 0.5.0", + "ark-std 0.5.0", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74dd304fd536fb95d0a328e72be759209cc496a9da094c5bc56e5fea4f9e86b" +dependencies = [ + "ark-serialize-derive 0.6.0", + "ark-std 0.6.0", + "digest 0.10.7", + "num-bigint", + "serde_with", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f153690697a2b91e5e1251ff98411ee5371500a111a0fd317a70e588eb300f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.8", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.8", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.8", +] + +[[package]] +name = "ark-std" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "367c9c827ed431bff6868b7aa926e05b16eb46603cc8b6e768e4a5553fa1d155" +dependencies = [ + "num-traits", + "rand 0.8.8", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "aurora-engine-modexp" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518bc5745a6264b5fd7b09dffb9667e400ee9e2bbe18555fac75e1fe9afa0df9" +dependencies = [ + "hex", + "num", +] + +[[package]] +name = "auto_impl" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitcoin-consensus-encoding" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6712f9c6fd6785b3b270884e57c441c403dc5d7e19ca45368c97c7a1de3000ec" +dependencies = [ + "bitcoin-internals", + "hex-conservative 1.3.0", + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d573f4cf32996a8dce612e4348cece65a241f1882ed594047c9ba348e8869fa5" + +[[package]] +name = "bitcoin-io" +version = "0.1.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb5de036369d1ac59d3c1819ebc4d850f89466f5401c571a285b6ed564a4cb78" +dependencies = [ + "bitcoin-consensus-encoding", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.14.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca4c7abb40c8817d77403c880988cfd484f23ab2365726afb2f798363e2c4a2" +dependencies = [ + "bitcoin-io", + "hex-conservative 0.2.3", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bitvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" +dependencies = [ + "funty", + "radium", + "serde", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "blst" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20659f9bbee16cbbd2f7393e40ab6309f5a98f76a2eb57a995ec508b72387fe" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "borsh" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cdfe656708a01f89b451a7d36466e6fe6c414de0aa18fc54f864f6f9ca9f56" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "2.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d04308254695569fdb9bfe3bacc1c91837a670d0806605eb82d63748fbd3a6" +dependencies = [ + "arbitrary", + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + +[[package]] +name = "cc" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "005ec2760ca554fae18df7a11195552ec576cd665632a881bc011d5bb2fd4d80" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "const-hex" +version = "1.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e2a781ebdf4467d1428dc4593067825fb646f6871475098d8577421af73558" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "proptest", + "serde_core", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" +dependencies = [ + "const_format_proc_macros", + "konst", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "serde", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive-where" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.119", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "serdect", + "signature", + "spki", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" +dependencies = [ + "serde", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d" + +[[package]] +name = "fixed-cache" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fe63500644ef0269fe6b744e7e5dc5c20b5eebf3d881bc2be53f194636f6583" +dependencies = [ + "equivalent", + "rapidhash", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.8", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash", + "serde", + "serde_core", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-conservative" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3fef046dca3ca91ee1408a8c1b80ab777e80a4d308d1bf4e7adb3fcb047e08" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex-conservative" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271e0d19bcb473b6675739a2b536076b24a082316cb5199ad918edce10c599e8" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hybrid-array" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" +dependencies = [ + "typenum", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "arbitrary", + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668b7183bd07af9a4885f5c35b0cc5c83c4607a913c16b7e17291832910d2dcc" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link", +] + +[[package]] +name = "jiff-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09" +dependencies = [ + "defmt", +] + +[[package]] +name = "jiff-static" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a69dcb3a21cfb32ce1cd056169337ca284af0766dd766e7878819b251a49204" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "serdect", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", +] + +[[package]] +name = "keccak-asm" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5dc2c0d691cbf7595cde551ced329cca99c2387c2cbc97754c5d0cd045d3ee" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "macro-string" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a9dbbfc75d2688ed057456ce8a3ee3f48d12eec09229f560f3643b9f275653" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "nybbles" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210" +dependencies = [ + "alloy-rlp", + "arbitrary", + "cfg-if", + "proptest", + "ruint", + "serde", + "smallvec", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pest" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d45aeb61b4bf818e12d4205f2466f8c4748f85f4fce0146d1c03d69d753f0ad" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr3" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82366fd7d8b7a440d66d13418820c69df9b3908bcb1a0476d7f5ce5d12f5a04d" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error3" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b511283ea8a74b4b39447b128c5d00f03a356b7424554b13e298a5550100d9ac" +dependencies = [ + "proc-macro-error-attr3", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.13.1", + "num-traits", + "rand 0.9.5", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "proptest-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb6dc647500e84a25a85b100e76c85b8ace114c209432dc174f20aac11d4ed6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "proptest-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c57924a81864dddafba92e1bf92f9bf82f97096c44489548a60e888e1547549b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rain-math-float" +version = "0.1.11" +source = "git+https://github.com/rainlanguage/rain.math.float.deploy?rev=643aa1726741fb113874b9152814ade10449e7c2#643aa1726741fb113874b9152814ade10449e7c2" +dependencies = [ + "alloy", + "getrandom 0.2.17", + "revm", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-utils", +] + +[[package]] +name = "rain-math-float-tests" +version = "0.0.0" +dependencies = [ + "alloy", + "alloy-primitives", + "proptest", + "rain-math-float", +] + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "serde", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", + "serde", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", + "serde", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rapidhash" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da7e78a036ce858e8d55b7e7dc8ba3a88b78350fd2155d3591bbd966b58589e" +dependencies = [ + "rustversion", +] + +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "revm" +version = "36.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0abc15d09cd211e9e73410ada10134069c794d4bcdb787dfc16a1bf0939849c" +dependencies = [ + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database", + "revm-database-interface", + "revm-handler", + "revm-inspector", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", +] + +[[package]] +name = "revm-bytecode" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86e468df3cf5cf59fa7ef71a3e9ccabb76bb336401ea2c0674f563104cf3c5e" +dependencies = [ + "bitvec", + "phf", + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-context" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb1f0a76b14d684a444fc52f7bf6b7564bf882599d91ee62e76d602e7a187c7" +dependencies = [ + "bitvec", + "cfg-if", + "derive-where", + "revm-bytecode", + "revm-context-interface", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-context-interface" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc256b27743e2912ca16899568e6652a372eb5d1d573e6edb16c7836b16cf487" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "auto_impl", + "either", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c0a7d6da41061f2c50f99a2632571026b23684b5449ff319914151f4449b6c8" +dependencies = [ + "alloy-eips", + "revm-bytecode", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database-interface" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd497a38a79057b94a049552cb1f925ad15078bc1a479c132aeeebd1d2ccc768" +dependencies = [ + "auto_impl", + "either", + "revm-primitives", + "revm-state", + "serde", + "thiserror", +] + +[[package]] +name = "revm-handler" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1eed729ca9b228ae98688f352235871e9b8be3d568d488e4070f64c56e9d3d" +dependencies = [ + "auto_impl", + "derive-where", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database-interface", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-inspector" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf5102391706513689f91cb3cb3d97b5f13a02e8647e6e9cb7620877ef84847" +dependencies = [ + "auto_impl", + "either", + "revm-context", + "revm-database-interface", + "revm-handler", + "revm-interpreter", + "revm-primitives", + "revm-state", + "serde", + "serde_json", +] + +[[package]] +name = "revm-interpreter" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf22f80612bb8f58fd1f578750281f2afadb6c93835b14ae6a4d6b75ca26f445" +dependencies = [ + "revm-bytecode", + "revm-context-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-precompile" +version = "32.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2ec11f45deec71e4945e1809736bb20d454285f9167ab53c5159dae1deb603f" +dependencies = [ + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "arrayref", + "aurora-engine-modexp", + "blst", + "c-kzg", + "cfg-if", + "k256", + "p256", + "revm-primitives", + "ripemd", + "secp256k1 0.31.1", + "sha2", +] + +[[package]] +name = "revm-primitives" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfb5ce6cf18b118932bcdb7da05cd9c250f2cb9f64131396b55f3fe3537c35" +dependencies = [ + "alloy-primitives", + "num_enum", + "once_cell", + "serde", +] + +[[package]] +name = "revm-state" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29404707763da607e5d6e4771cb203998c28159279c2f64cc32de08d2814651" +dependencies = [ + "alloy-eip7928", + "bitflags 2.13.1", + "revm-bytecode", + "revm-primitives", + "serde", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e99bff0393163bb25029a6af25d3d8d202ba5b5438a74d1bd8789f5c822970" +dependencies = [ + "alloy-rlp", + "arbitrary", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "ark-ff 0.5.0", + "ark-ff 0.6.0", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint", + "num-integer", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.8", + "rand 0.9.5", + "rlp", + "ruint-macro", + "serde_core", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.28", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.8", + "secp256k1-sys 0.10.1", + "serde", +] + +[[package]] +name = "secp256k1" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" +dependencies = [ + "bitcoin_hashes", + "rand 0.9.5", + "secp256k1-sys 0.11.0", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "secp256k1-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" +dependencies = [ + "cc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "serde_derive_internals" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e578a843d40b4189a4d66bba51d7684f57da5bd7c304c64e14bd63efbef49509" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "indexmap 2.14.2", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_with" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee78f1fbe43ac4a0e47aadb3dbd357b69eb0d3793e948624cd03dd2750ab1c0a" +dependencies = [ + "base64", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.2", + "jiff", + "schemars 0.9.0", + "schemars 1.2.2", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8705578779c2b6bd90d84d66eb2e206b708b1a4d7b9f17641b293545bf1c7e46" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6287fd675f713484342a89cbf0a386abef5f15919cfad607e5e1f19e1e15331" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9be42f50aa861c555654aa3a37f52f4b1074bacf4e48fe0ef7fa584e80f1f0f" +dependencies = [ + "arbitrary", + "serde", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6415502cd1e9ed58b3ceb415164b812d5572757b1a6f0e280ae806723c1fab" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] -name = "const-hex" -version = "1.19.1" +name = "time-macros" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e2a781ebdf4467d1428dc4593067825fb646f6871475098d8577421af73558" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "proptest", - "serde_core", + "num-conv", + "time-core", ] [[package]] -name = "convert_case" -version = "0.10.0" +name = "tinyvec" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +checksum = "4cf0ded5c4e56918d8f8a339e1bb67d038d3bc6d144ac407904015ba2e4cde9b" dependencies = [ - "unicode-segmentation", + "tinyvec_macros", ] [[package]] -name = "cpufeatures" -version = "0.2.17" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ - "libc", + "serde_core", ] [[package]] -name = "cpufeatures" -version = "0.3.1" +name = "toml_edit" +version = "0.25.13+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" dependencies = [ - "libc", + "indexmap 2.14.2", + "toml_datetime", + "toml_parser", + "winnow", ] [[package]] -name = "crypto-common" -version = "0.2.2" +name = "toml_parser" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "hybrid-array", + "winnow", ] [[package]] -name = "derive_more" -version = "2.1.1" +name = "tracing" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "derive_more-impl", + "pin-project-lite", + "tracing-attributes", + "tracing-core", ] [[package]] -name = "derive_more-impl" -version = "2.1.1" +name = "tracing-attributes" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ - "convert_case", "proc-macro2", "quote", - "rustc_version", "syn 2.0.119", - "unicode-xid", ] [[package]] -name = "digest" -version = "0.11.3" +name = "tracing-core" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ - "block-buffer", - "crypto-common", + "once_cell", + "valuable", ] [[package]] -name = "hybrid-array" -version = "0.4.14" +name = "tracing-subscriber" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" dependencies = [ - "typenum", + "tracing-core", ] [[package]] -name = "itoa" -version = "1.0.18" +name = "tsify" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "d6b26cf145f2f3b9ff84e182c448eaf05468e247f148cf3d2a7d67d78ff023a0" +dependencies = [ + "serde", + "serde-wasm-bindgen 0.5.0", + "tsify-macros", + "wasm-bindgen", +] [[package]] -name = "keccak" -version = "0.2.2" +name = "tsify-macros" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598" +checksum = "7a94b0f0954b3e59bfc2c246b4c8574390d94a4ad4ad246aaf2fb07d7dfd3b47" dependencies = [ - "cfg-if", - "cpufeatures 0.3.1", + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.119", ] [[package]] -name = "libc" -version = "0.2.189" +name = "typenum" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] -name = "libm" -version = "0.2.16" +name = "ucd-trie" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] -name = "num-traits" -version = "0.2.19" +name = "uint" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ - "autocfg", - "libm", + "byteorder", + "crunchy", + "hex", + "static_assertions", ] [[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" +name = "unarray" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] -name = "proc-macro2" -version = "1.0.107" +name = "unicode-ident" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" -dependencies = [ - "unicode-ident", -] +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] -name = "proptest" -version = "1.11.0" +name = "unicode-segmentation" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" -dependencies = [ - "bitflags", - "num-traits", - "rand 0.9.5", - "rand_chacha", - "rand_xorshift", - "unarray", -] +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] -name = "quote" -version = "1.0.47" +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rain-math-float-constants" -version = "0.0.0" -dependencies = [ - "alloy-primitives", -] +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "rand" -version = "0.8.8" +name = "valuable" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" -dependencies = [ - "rand_core 0.6.4", -] +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] -name = "rand" +name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" -dependencies = [ - "rand_core 0.9.5", -] +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "rand_chacha" -version = "0.9.0" +name = "wait-timeout" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", + "libc", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "rand_core" -version = "0.9.5" +name = "wasip2" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "rand_xorshift" -version = "0.4.0" +name = "wasm-bindgen" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" dependencies = [ - "rand_core 0.9.5", + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] -name = "ruint" -version = "1.20.0" +name = "wasm-bindgen-futures" +version = "0.4.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e99bff0393163bb25029a6af25d3d8d202ba5b5438a74d1bd8789f5c822970" +checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928" dependencies = [ - "proptest", - "rand 0.8.8", - "rand 0.9.5", - "ruint-macro", - "serde_core", - "valuable", - "zeroize", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "ruint-macro" -version = "1.2.1" +name = "wasm-bindgen-macro" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] [[package]] -name = "rustc_version" -version = "0.4.1" +name = "wasm-bindgen-macro-support" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" dependencies = [ - "semver", + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.5", + "wasm-bindgen-shared", ] [[package]] -name = "semver" -version = "1.0.28" +name = "wasm-bindgen-shared" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" +dependencies = [ + "unicode-ident", +] [[package]] -name = "serde_core" -version = "1.0.229" +name = "wasm-bindgen-utils" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +checksum = "83ead9e122abfd725c8a2ac0ec27540fdc9585dc0cc3eaaba98cb2d0ff3d8026" dependencies = [ - "serde_derive", + "js-sys", + "paste", + "serde", + "serde-wasm-bindgen 0.6.5", + "tsify", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-utils-macros", ] [[package]] -name = "serde_derive" -version = "1.0.229" +name = "wasm-bindgen-utils-macros" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +checksum = "40ca0b2e5d68b4faad662b20de1f2ad95fb04a491b0200376aefd4dbc49647d4" dependencies = [ "proc-macro2", "quote", - "syn 3.0.5", + "syn 2.0.119", ] [[package]] -name = "sha3" -version = "0.11.0" +name = "windows-core" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "digest", - "keccak", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "syn" -version = "2.0.119" +name = "windows-implement" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "unicode-ident", + "syn 2.0.119", ] [[package]] -name = "syn" -version = "3.0.5" +name = "windows-interface" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "unicode-ident", + "syn 2.0.119", ] [[package]] -name = "typenum" -version = "1.20.1" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "unarray" -version = "0.1.4" +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] [[package]] -name = "unicode-ident" -version = "1.0.24" +name = "windows-strings" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] [[package]] -name = "unicode-segmentation" -version = "1.13.3" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] -name = "unicode-xid" -version = "0.2.6" +name = "winnow" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] [[package]] -name = "valuable" -version = "0.1.1" +name = "wit-bindgen" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] [[package]] name = "zerocopy" @@ -431,3 +3728,23 @@ name = "zeroize" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/REUSE.toml b/REUSE.toml index 89caa54e..e05b6dd4 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -12,6 +12,7 @@ path = [ "Cargo.lock", "Cargo.toml", "crates/**/", + ".cargo/**/", ".gitmodules", "CLAUDE.md", "README.md", diff --git a/crates/constants/Cargo.toml b/crates/constants/Cargo.toml deleted file mode 100644 index 99bc7861..00000000 --- a/crates/constants/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "rain-math-float-constants" -version = "0.0.0" -publish = false -edition.workspace = true -license.workspace = true -homepage.workspace = true -description = "Cross-references the constants LibDecimalFloat.sol packs against values derived in Rust." - -[dependencies] -alloy-primitives = { version = "1.0.9", default-features = false } diff --git a/crates/constants/src/lib.rs b/crates/constants/src/lib.rs deleted file mode 100644 index 759c10c1..00000000 --- a/crates/constants/src/lib.rs +++ /dev/null @@ -1,131 +0,0 @@ -//! Cross-references the constants `LibDecimalFloat.sol` packs against values -//! derived here in integer arithmetic. The Solidity source is bound at compile -//! time and the packed words are read out of it, so a change to a constant in -//! the library is a change to what these tests check. - -#[cfg(test)] -mod tests { - use alloy_primitives::aliases::{I224, U224}; - use alloy_primitives::{U256, U512}; - - /// The library source, as committed. - const LIB: &str = include_str!("../../../src/lib/LibDecimalFloat.sol"); - - /// Decimal places the library packs the constants at. - const PLACES: u32 = 66; - - /// Extra digits carried through the series so rounding at `PLACES` is - /// exact. - const GUARD: u32 = 12; - - /// The packed word `LibDecimalFloat.sol` assigns to the constant `name`: - /// the 64 hex digits following its `=`. - fn packed_constant(name: &str) -> U256 { - let decl = format!("constant {name} ="); - let at = LIB - .find(&decl) - .unwrap_or_else(|| panic!("{name} is not declared in LibDecimalFloat.sol")); - let rest = &LIB[at + decl.len()..]; - let hex_at = rest - .find("0x") - .expect("no hex literal after the declaration"); - let hex = &rest[hex_at + 2..hex_at + 2 + 64]; - U256::from_str_radix(hex, 16).expect("64 hex digits") - } - - /// Splits a packed `Float` into its signed 224-bit coefficient and signed - /// 32-bit exponent: the exponent is the high 32 bits, the coefficient the - /// low 224. - fn unpack(word: U256) -> (I224, i32) { - let exponent = (word >> 224usize).to::() as i32; - let mask = (U256::from(1u8) << 224usize) - U256::from(1u8); - let coefficient = I224::from_raw((word & mask).to::()); - (coefficient, exponent) - } - - fn ten_pow(n: u32) -> U512 { - U512::from(10u64).pow(U512::from(n)) - } - - /// `atan(1/x) * 10^scale` by the alternating series, truncated once a term - /// underflows the scale. Every intermediate is an integer. - fn atan_inv(x: u64, scale: u32) -> U512 { - let x = U512::from(x); - let x2 = x * x; - let mut power = ten_pow(scale) / x; - let mut sum = U512::ZERO; - let mut k = 0u64; - loop { - let term = power / U512::from(2 * k + 1); - if term.is_zero() { - break; - } - if k.is_multiple_of(2) { - sum += term; - } else { - sum -= term; - } - power /= x2; - k += 1; - } - sum - } - - /// `pi * 10^scale` by Machin's formula. - fn pi_scaled(scale: u32) -> U512 { - U512::from(16u64) * atan_inv(5, scale) - U512::from(4u64) * atan_inv(239, scale) - } - - /// `e * 10^scale` by the series sum of 1/k!. - fn e_scaled(scale: u32) -> U512 { - let mut term = ten_pow(scale); - let mut sum = U512::ZERO; - let mut k = 1u64; - while !term.is_zero() { - sum += term; - term /= U512::from(k); - k += 1; - } - sum - } - - /// Drops `GUARD` digits, rounding to nearest. - fn round_to_places(scaled: U512) -> I224 { - let divisor = ten_pow(GUARD); - let (q, r) = (scaled / divisor, scaled % divisor); - let rounded = if r * U512::from(2u64) >= divisor { - q + U512::from(1u64) - } else { - q - }; - I224::from_dec_str(&rounded.to_string()).unwrap() - } - - #[test] - fn float_pi_is_pi_rounded_to_nearest() { - let (coefficient, exponent) = unpack(packed_constant("FLOAT_PI")); - assert_eq!(exponent, -(PLACES as i32)); - assert_eq!(coefficient, round_to_places(pi_scaled(PLACES + GUARD))); - } - - #[test] - fn float_e_is_e_rounded_to_nearest() { - let (coefficient, exponent) = unpack(packed_constant("FLOAT_E")); - assert_eq!(exponent, -(PLACES as i32)); - assert_eq!(coefficient, round_to_places(e_scaled(PLACES + GUARD))); - } - - #[test] - fn derivations_start_with_the_known_digits() { - assert!( - pi_scaled(PLACES + GUARD) - .to_string() - .starts_with("314159265358979323846264338327950288") - ); - assert!( - e_scaled(PLACES + GUARD) - .to_string() - .starts_with("271828182845904523536028747135266249") - ); - } -} diff --git a/crates/tests/Cargo.toml b/crates/tests/Cargo.toml new file mode 100644 index 00000000..c00f3deb --- /dev/null +++ b/crates/tests/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "rain-math-float-tests" +version = "0.0.0" +publish = false +edition.workspace = true +license.workspace = true +homepage.workspace = true +description = "Tests of the library through the rain-math-float bindings, over concretes compiled from this source." + +[dev-dependencies] +alloy = { version = "1.0.9", default-features = false, features = [ + "sol-types", + "arbitrary", +] } +alloy-primitives = { version = "1.0.9", default-features = false } +proptest = "1.7.0" +rain-math-float = { git = "https://github.com/rainlanguage/rain.math.float.deploy", rev = "643aa1726741fb113874b9152814ade10449e7c2", features = [ + "test-harness", +] } diff --git a/crates/tests/build.rs b/crates/tests/build.rs new file mode 100644 index 00000000..c44e56ce --- /dev/null +++ b/crates/tests/build.rs @@ -0,0 +1,25 @@ +//! Compiles the Solidity, so the bindings run over the test concretes built +//! from this source: `.cargo/config.toml` points them at the artifacts. + +use std::path::Path; +use std::process::Command; + +fn main() { + let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../.."); + for watched in ["foundry.toml", "soldeer.lock", "src", "test"] { + println!("cargo:rerun-if-changed={}", root.join(watched).display()); + } + if !root.join("dependencies").is_dir() { + forge(&root, &["soldeer", "install"]); + } + forge(&root, &["build"]); +} + +fn forge(root: &Path, args: &[&str]) { + let status = Command::new("forge") + .args(args) + .current_dir(root) + .status() + .unwrap_or_else(|e| panic!("forge {}: {e}", args.join(" "))); + assert!(status.success(), "forge {} failed", args.join(" ")); +} diff --git a/crates/tests/proptest-regressions/float.txt b/crates/tests/proptest-regressions/float.txt new file mode 100644 index 00000000..af82acb8 --- /dev/null +++ b/crates/tests/proptest-regressions/float.txt @@ -0,0 +1,11 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc f6dbf2daa643e3af6e5ef64882d35c2bbb0c4fb6a3c3af266dc9aa86d9a02109 # shrinks to float = Float(0x0000000000000001000000000000000000000000000000000000000000000000) +cc 2cc26b3c1b4b599834ec3685c77bdd3acafd77455cadfa8dfa4b0be9e713782a # shrinks to a = Float(0x0000000000000000000000000000000000000000000000000000000000000000) +cc 642cb26314dc2fb6c09ab7f626896905e09d18c54629a4e715d1ea5a62e011db # shrinks to a = Float(0x0000000000000000000000000000000000000000000000000000000000000000) +cc 4c7984d448d28df4f7f767c60b599e740b85045c82e164dddcf8ca804dcd6858 # shrinks to float = Float(0xffffffff00000000000000000000000000000000000000000000000000000001) +cc 890df2dbb989cbefae9594af8f895b34638eac35b461fdcb6e6585564a3f6fd6 # shrinks to a = Float(0xffffffff00000000000000000000000000000000000000000000000000000001), b = Float(0x0000000000000000000000000000000000000000000000000000000000000000) diff --git a/crates/tests/proptest-regressions/fuzz_ops.txt b/crates/tests/proptest-regressions/fuzz_ops.txt new file mode 100644 index 00000000..98d76c1f --- /dev/null +++ b/crates/tests/proptest-regressions/fuzz_ops.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 90fd005104a53dbf42191fdeca18dbab87a6c22e4d33eb305cd81b7d9bf9d290 # shrinks to a = Float(0x0000000000000000000000000000000000000000000000000000000000000001), b = Float(0x0000000000000000000000000000000000000000000000000000000000000000) diff --git a/crates/tests/src/constants.rs b/crates/tests/src/constants.rs new file mode 100644 index 00000000..d5a739f2 --- /dev/null +++ b/crates/tests/src/constants.rs @@ -0,0 +1,128 @@ +//! Cross-references the constants `LibDecimalFloat.sol` packs against values +//! derived here in integer arithmetic. The Solidity source is bound at compile +//! time and the packed words are read out of it, so a change to a constant in +//! the library is a change to what these tests check. + +use alloy_primitives::aliases::{I224, U224}; +use alloy_primitives::{U256, U512}; + +/// The library source, as committed. +const LIB: &str = include_str!("../../../src/lib/LibDecimalFloat.sol"); + +/// Decimal places the library packs the constants at. +const PLACES: u32 = 66; + +/// Extra digits carried through the series so rounding at `PLACES` is +/// exact. +const GUARD: u32 = 12; + +/// The packed word `LibDecimalFloat.sol` assigns to the constant `name`: +/// the 64 hex digits following its `=`. +fn packed_constant(name: &str) -> U256 { + let decl = format!("constant {name} ="); + let at = LIB + .find(&decl) + .unwrap_or_else(|| panic!("{name} is not declared in LibDecimalFloat.sol")); + let rest = &LIB[at + decl.len()..]; + let hex_at = rest + .find("0x") + .expect("no hex literal after the declaration"); + let hex = &rest[hex_at + 2..hex_at + 2 + 64]; + U256::from_str_radix(hex, 16).expect("64 hex digits") +} + +/// Splits a packed `Float` into its signed 224-bit coefficient and signed +/// 32-bit exponent: the exponent is the high 32 bits, the coefficient the +/// low 224. +fn unpack(word: U256) -> (I224, i32) { + let exponent = (word >> 224usize).to::() as i32; + let mask = (U256::from(1u8) << 224usize) - U256::from(1u8); + let coefficient = I224::from_raw((word & mask).to::()); + (coefficient, exponent) +} + +fn ten_pow(n: u32) -> U512 { + U512::from(10u64).pow(U512::from(n)) +} + +/// `atan(1/x) * 10^scale` by the alternating series, truncated once a term +/// underflows the scale. Every intermediate is an integer. +fn atan_inv(x: u64, scale: u32) -> U512 { + let x = U512::from(x); + let x2 = x * x; + let mut power = ten_pow(scale) / x; + let mut sum = U512::ZERO; + let mut k = 0u64; + loop { + let term = power / U512::from(2 * k + 1); + if term.is_zero() { + break; + } + if k.is_multiple_of(2) { + sum += term; + } else { + sum -= term; + } + power /= x2; + k += 1; + } + sum +} + +/// `pi * 10^scale` by Machin's formula. +fn pi_scaled(scale: u32) -> U512 { + U512::from(16u64) * atan_inv(5, scale) - U512::from(4u64) * atan_inv(239, scale) +} + +/// `e * 10^scale` by the series sum of 1/k!. +fn e_scaled(scale: u32) -> U512 { + let mut term = ten_pow(scale); + let mut sum = U512::ZERO; + let mut k = 1u64; + while !term.is_zero() { + sum += term; + term /= U512::from(k); + k += 1; + } + sum +} + +/// Drops `GUARD` digits, rounding to nearest. +fn round_to_places(scaled: U512) -> I224 { + let divisor = ten_pow(GUARD); + let (q, r) = (scaled / divisor, scaled % divisor); + let rounded = if r * U512::from(2u64) >= divisor { + q + U512::from(1u64) + } else { + q + }; + I224::from_dec_str(&rounded.to_string()).unwrap() +} + +#[test] +fn float_pi_is_pi_rounded_to_nearest() { + let (coefficient, exponent) = unpack(packed_constant("FLOAT_PI")); + assert_eq!(exponent, -(PLACES as i32)); + assert_eq!(coefficient, round_to_places(pi_scaled(PLACES + GUARD))); +} + +#[test] +fn float_e_is_e_rounded_to_nearest() { + let (coefficient, exponent) = unpack(packed_constant("FLOAT_E")); + assert_eq!(exponent, -(PLACES as i32)); + assert_eq!(coefficient, round_to_places(e_scaled(PLACES + GUARD))); +} + +#[test] +fn derivations_start_with_the_known_digits() { + assert!( + pi_scaled(PLACES + GUARD) + .to_string() + .starts_with("314159265358979323846264338327950288") + ); + assert!( + e_scaled(PLACES + GUARD) + .to_string() + .starts_with("271828182845904523536028747135266249") + ); +} diff --git a/crates/tests/src/float.rs b/crates/tests/src/float.rs new file mode 100644 index 00000000..cce4dad3 --- /dev/null +++ b/crates/tests/src/float.rs @@ -0,0 +1,985 @@ +//! The library's arithmetic, comparisons, conversions and errors, through the +//! bindings. + +use alloy::primitives::aliases::I224; +use alloy::primitives::{U256, fixed_bytes}; +use core::str::FromStr; +use proptest::prelude::*; +use rain_math_float::DecimalFloat::DecimalFloatErrors; +use rain_math_float::{Float, FloatError}; +use std::ops::Neg; + +/// Float::zero() is_zero, formats as "0" and equals parsed "0". +#[test] +fn test_zero() { + let zero = Float::zero().unwrap(); + assert!(zero.is_zero().unwrap()); + assert_eq!(zero.format().unwrap(), "0"); + + // Test that zero equals parsed zero + let parsed_zero = Float::parse("0".to_string()).unwrap(); + assert!(zero.eq(parsed_zero).unwrap()); +} + +prop_compose! { + fn arb_float()( + coefficient in any::(), + exponent in any::(), + ) -> Float { + Float::pack_lossless(coefficient, exponent).unwrap() + } +} + +prop_compose! { + fn reasonable_float()( + int_part in -10i128.pow(18)..10i128.pow(18), + decimal_part in 0u128..10u128.pow(18u32) + ) -> Float { + let num_str = if decimal_part == 0 { + format!("{int_part}") + } else { + format!("{int_part}.{decimal_part}") + }; + + Float::parse(num_str).unwrap() + } +} + +/// Parsing an empty string returns a DecimalFloatSelector error. +#[test] +fn test_parse_empty_string_error() { + let err = Float::parse("".to_string()).unwrap_err(); + // We don't know the exact selector here, just ensure the error path is hit. + assert!(matches!(err, FloatError::DecimalFloatSelector(_))); +} + +#[test] +fn test_parse_exponent_overflow_error() { + // Extremely large exponent expected to overflow (exponent >> i32::MAX). + let err = Float::parse("1e3000000000".to_string()).unwrap_err(); + assert!(matches!( + err, + FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentOverflow(_)) + )); +} + +/// Malformed inputs ("1.2.3", "abc") return specific error selectors. +#[test] +fn test_parse_edge_cases() { + let err = Float::parse("1.2.3".to_string()).unwrap_err(); + assert!(matches!( + err, + FloatError::DecimalFloatSelector(Err(selector)) + if selector == fixed_bytes!("ad384e87") + )); + + let err = Float::parse("abc".to_string()).unwrap_err(); + assert!(matches!( + err, + FloatError::DecimalFloatSelector(Err(selector)) + if selector == fixed_bytes!("34bd2069") + )); +} + +/// Boundary constants are distinct, correctly signed, correctly ordered, +/// and bound normal values like 1 and -1. +#[test] +fn test_float_constants() { + // Test that all constant methods return valid floats + let max_pos = Float::max_positive_value().unwrap(); + let min_pos = Float::min_positive_value().unwrap(); + let max_neg = Float::max_negative_value().unwrap(); + let min_neg = Float::min_negative_value().unwrap(); + + let zero = Float::parse("0".to_string()).unwrap(); + + // Test mathematical properties without exposing binary representation + + // All constants should be distinct + assert!(!max_pos.eq(min_pos).unwrap()); + assert!(!max_neg.eq(min_neg).unwrap()); + assert!(!max_pos.eq(max_neg).unwrap()); + assert!(!min_pos.eq(min_neg).unwrap()); + + // Test sign properties + assert!(min_pos.gt(zero).unwrap()); // min positive should be > 0 + assert!(max_pos.gt(zero).unwrap()); // max positive should be > 0 + assert!(max_neg.lt(zero).unwrap()); // max negative should be < 0 + assert!(min_neg.lt(zero).unwrap()); // min negative should be < 0 + + // Test ordering relationships + assert!(min_pos.lt(max_pos).unwrap()); // min positive < max positive + assert!(min_neg.lt(max_neg).unwrap()); // min negative < max negative + + // Test boundary properties + let one = Float::parse("1".to_string()).unwrap(); + let neg_one = Float::parse("-1".to_string()).unwrap(); + + // Positive constants should be greater than normal values + assert!(max_pos.gt(one).unwrap()); + assert!(min_pos.lt(one).unwrap()); + + // Negative constants should be more extreme than normal negative values + assert!(max_neg.gt(neg_one).unwrap()); + assert!(min_neg.lt(neg_one).unwrap()); +} + +proptest! { + #[test] + /// format() then parse() round-trips to an equal value. + fn test_format_parse(float in reasonable_float()) { + let formatted = float.format().unwrap(); + let parsed = Float::parse(formatted.clone()).unwrap(); + prop_assert!(float.eq(parsed).unwrap()); + } +} + +/// Adding two max-exponent floats overflows with ExponentOverflow. +#[test] +fn test_add_exponent_overflow_error() { + let max_coeff_str = "13479973333575319897333507543509815336818572211270286240551805124607"; + let large_coeff_i224 = I224::from_str(max_coeff_str).unwrap(); + let exponent_max = i32::MAX; + + let a = Float::pack_lossless(large_coeff_i224, exponent_max).unwrap(); + + let err = (a + a).unwrap_err(); + + assert!(matches!( + err, + FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentOverflow(_)) + )); +} + +/// Subtracting opposite-sign max-exponent floats overflows. +#[test] +fn test_sub_exponent_overflow_error() { + let max_coeff_str = "13479973333575319897333507543509815336818572211270286240551805124607"; + let large_coeff_i224 = I224::from_str(max_coeff_str).unwrap(); + let exponent_max = i32::MAX; + + let a = Float::pack_lossless(large_coeff_i224, exponent_max).unwrap(); + let b = Float::pack_lossless(-large_coeff_i224, exponent_max).unwrap(); + + let err = (b - a).unwrap_err(); + + assert!(matches!( + err, + FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentOverflow(_)) + )); +} + +proptest! { + #[test] + /// Addition does not panic for reasonable inputs. + fn test_add(a in reasonable_float(), b in reasonable_float()) { + (a + b).unwrap(); + } +} + +proptest! { + #[test] + /// Subtraction does not panic for reasonable inputs. + fn test_sub(a in reasonable_float(), b in reasonable_float()) { + (a - b).unwrap(); + } +} + +proptest! { + #[test] + /// (a + b) - b == a: subtraction inverts addition. + fn test_add_sub(a in reasonable_float(), b in reasonable_float()) { + let sum = (a + b).unwrap(); + let diff = (sum - b).unwrap(); + prop_assert_eq!( + a.format().unwrap(), + diff.format().unwrap(), + "a: {}, b: {}", + a.format().unwrap(), + b.format().unwrap(), + ); + } +} + +/// Manual check: -1 < 0 < 3, with correct lt/eq/gt for each pair. +#[test] +fn test_lt_eq_gt() { + let negone = Float::parse("-1".to_string()).unwrap(); + let zero = Float::parse("0".to_string()).unwrap(); + let three = Float::parse("3".to_string()).unwrap(); + + assert!(negone.lt(zero).unwrap()); + assert!(!negone.eq(zero).unwrap()); + assert!(!negone.gt(zero).unwrap()); + + assert!(!three.lt(zero).unwrap()); + assert!(!three.eq(zero).unwrap()); + assert!(three.gt(zero).unwrap()); + + assert!(zero.lt(three).unwrap()); + assert!(!zero.eq(three).unwrap()); + assert!(!zero.gt(three).unwrap()); +} + +proptest! { + #[test] + /// a == a, a-1 < a, a+1 > a for all reasonable floats. + fn test_lt_eq_gt_with_add(a in reasonable_float()) { + let b = a; + let eq = a.eq(b).unwrap(); + prop_assert!(eq); + + let one = Float::parse("1".to_string()).unwrap(); + + let a = (a - one).unwrap(); + let lt = a.lt(b).unwrap(); + prop_assert!(lt); + + let a = (a + one).unwrap(); + let eq = a.eq(b).unwrap(); + prop_assert!(eq); + + let a = (a + one).unwrap(); + let gt = a.gt(b).unwrap(); + prop_assert!(gt); + } + + #[test] + /// Trichotomy: exactly one of lt, eq, gt is true for any two floats. + fn test_exactly_one_lt_eq_gt(a in arb_float(), b in arb_float()) { + let eq = a.eq(b).unwrap(); + let lt = a.lt(b).unwrap(); + let gt = a.gt(b).unwrap(); + + let a_str = a.show_unpacked().unwrap(); + let b_str = b.show_unpacked().unwrap(); + + prop_assert!(lt || eq || gt, "a: {a_str}, b: {b_str}"); + prop_assert!(!(lt && eq), "both less than and equal: a: {a_str}, b: {b_str}"); + prop_assert!(!(eq && gt), "both equal and greater than: a: {a_str}, b: {b_str}"); + prop_assert!(!(lt && gt), "both less than and greater than: a: {a_str}, b: {b_str}"); + } +} + +/// abs(-x) == abs(x) == |x| for manual positive, negative, and zero cases. +#[test] +fn test_abs() { + let float = Float::parse("-3613.1324123".to_string()).unwrap(); + let abs = float.abs().unwrap(); + let formatted = abs.format().unwrap(); + assert_eq!(formatted, "3613.1324123"); + + let float = Float::parse("3613.1324123".to_string()).unwrap(); + let abs = float.abs().unwrap(); + let formatted = abs.format().unwrap(); + assert_eq!(formatted, "3613.1324123"); + + let float = Float::parse("0".to_string()).unwrap(); + let abs = float.abs().unwrap(); + let formatted = abs.format().unwrap(); + assert_eq!(formatted, "0"); +} + +proptest! { + #[test] + /// Multiplication does not panic for reasonable inputs. + fn test_mul(a in reasonable_float(), b in reasonable_float()) { + (a * b).unwrap(); + } +} + +/// Negating a negative produces positive format; negating zero stays "0". +#[test] +fn test_minus_format() { + let float = Float::parse("-123.1234234625468391".to_string()).unwrap(); + let negated = float.neg().unwrap(); + + let formatted_decimal = negated.format_with_scientific(false).unwrap(); + assert_eq!(formatted_decimal, "123.1234234625468391"); + + let float = Float::parse("0".to_string()).unwrap(); + let negated = float.neg().unwrap(); + let formatted = negated.format().unwrap(); + assert_eq!(formatted, "0"); +} + +proptest! { + #[test] + /// Double negation is identity: -(-a) == a. + fn test_minus_minus(float in arb_float()) { + let negated = float.neg().unwrap(); + let renegated = negated.neg().unwrap(); + prop_assert!(float.eq(renegated).unwrap()); + } +} + +proptest! { + #[test] + /// a * inv(a) ≈ 1 within ±1e-37 for nonzero a. + fn test_inv_prod(float in reasonable_float()) { + let zero = Float::parse("0".to_string()).unwrap(); + prop_assume!(!float.eq(zero).unwrap()); + + let inv = float.inv().unwrap(); + let product = (float * inv).unwrap(); + let one = Float::parse("1".to_string()).unwrap(); + + // Allow for minor rounding errors introduced by the lossy + // `inv` implementation. We consider the property to + // hold if the product is within `±1e-37` of 1. + + let eps = Float::parse("1e-37".to_string()).unwrap(); + let one_plus_eps = (one + eps).unwrap(); + let one_minus_eps = (one - eps).unwrap(); + + let within_upper = !product.gt(one_plus_eps).unwrap(); + let within_lower = !product.lt(one_minus_eps).unwrap(); + + prop_assert!( + within_upper && within_lower, + "float: {}, inv: {}, product: {} (not within ±ε)", + float.show_unpacked().unwrap(), + inv.show_unpacked().unwrap(), + product.show_unpacked().unwrap(), + ); + } +} + +proptest! { + #[test] + /// abs() never produces a string starting with "-". + fn test_abs_no_minus_sign(float in reasonable_float()) { + let abs = float.abs().unwrap(); + let formatted = abs.format().unwrap(); + prop_assert!(!formatted.starts_with("-")); + } + + #[test] + /// abs is idempotent: abs(abs(a)) == abs(a). + fn test_abs_abs(float in arb_float()) { + let abs = float.abs().unwrap(); + let abs_abs = abs.abs().unwrap(); + prop_assert!(abs.eq(abs_abs).unwrap()); + } +} + +proptest! { + #[test] + /// Division does not panic for nonzero divisor. + fn test_div(a in reasonable_float(), b in reasonable_float()) { + let zero = Float::parse("0".to_string()).unwrap(); + prop_assume!(!b.eq(zero).unwrap()); + + (a / b).unwrap(); + } +} + +prop_compose! { + fn small_int_float()(int_part in -1_000_000_000_000i128..1_000_000_000_000i128) -> Float { + Float::parse(int_part.to_string()).unwrap() + } +} + +proptest! { + #[test] + /// (a * b) / b == a: division inverts multiplication for small integers. + fn test_mul_div_int(a in small_int_float(), b in small_int_float()) { + let zero = Float::parse("0".to_string()).unwrap(); + prop_assume!(!b.eq(zero).unwrap()); + + let product = (a * b).unwrap(); + let quotient = (product / b).unwrap(); + + prop_assert!( + a.eq(quotient).unwrap(), + "a: {}, quotient: {}, b: {}", + a.show_unpacked().unwrap(), + quotient.show_unpacked().unwrap(), + b.show_unpacked().unwrap() + ); + } +} + +/// 6/3 == 2 and 2*3 == 6. +#[test] +fn test_mul_div_manual() { + let two = Float::parse("2".to_string()).unwrap(); + let three = Float::parse("3".to_string()).unwrap(); + let six = Float::parse("6".to_string()).unwrap(); + + assert!(two.eq((six / three).unwrap()).unwrap()); + assert!(six.eq((two * three).unwrap()).unwrap()); +} + +/// 1/0 returns DivisionByZero error. +#[test] +fn test_divide_by_zero_error() { + let one = Float::parse("1".to_string()).unwrap(); + let zero = Float::parse("0".to_string()).unwrap(); + let err = (one / zero).unwrap_err(); + + assert!(matches!( + err, + FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::DivisionByZero(_)) + )); +} + +/// Multiplying near-max exponents overflows. +#[test] +fn test_mul_exponent_overflow_error() { + let near_max_exp = Float::parse("1e2147483646".to_string()).unwrap(); + let one_e_two = Float::parse("1e2".to_string()).unwrap(); + + let err = (near_max_exp * one_e_two).unwrap_err(); + assert!(matches!( + err, + FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentOverflow(_)) + )); +} + +/// Dividing near-max exponent by small exponent overflows. +#[test] +fn test_div_exponent_overflow_error() { + let near_max_exp = Float::parse("1e2147483646".to_string()).unwrap(); + let one_e_neg_hundred = Float::parse("1e-100".to_string()).unwrap(); + + let err = (near_max_exp / one_e_neg_hundred).unwrap_err(); + assert!(matches!( + err, + FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentOverflow(_)) + )); +} + +/// Multiplying near-min exponents underflows; the public arithmetic +/// surface reverts with `ExponentUnderflow` rather than silently +/// producing zero. +#[test] +fn test_mul_exponent_underflow_error() { + let near_min_exp = Float::parse("1e-2147483646".to_string()).unwrap(); + let one_e_neg_three = Float::parse("1e-3".to_string()).unwrap(); + + let err = (near_min_exp * one_e_neg_three).unwrap_err(); + assert!(matches!( + err, + FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentUnderflow(_)) + )); +} + +/// from_fixed_decimal for known value/decimals pairs matches parsed strings. +#[test] +fn test_from_fixed_decimal() { + let cases = vec![ + (U256::from(0u128), 0u8, "0"), + (U256::from(0u128), 18u8, "0"), + (U256::from(1u128), 18u8, "1e-18"), + (U256::from(123456789u128), 0u8, "123456789"), + (U256::from(123456789u128), 2u8, "123456789e-2"), + (U256::from(1000000000000000000u128), 18u8, "1"), + ]; + + for (amount, decimals, expected) in cases { + let float = Float::from_fixed_decimal(amount, decimals).expect("should convert"); + let expected = Float::parse(expected.to_string()).unwrap(); + assert!(float.eq(expected).unwrap()); + } +} + +/// U256::MAX with 1 decimal overflows (LossyConversionToFloat). +#[test] +fn test_from_fixed_decimal_err() { + let err = Float::from_fixed_decimal(U256::MAX, 1).unwrap_err(); + assert!(matches!( + err, + FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::LossyConversionToFloat(_)) + )); +} + +/// to_fixed_decimal for known inputs matches expected U256 values. +#[test] +fn test_to_fixed_decimal() { + let cases = vec![ + ("0", 0u8, 0u128), + ("0", 18u8, 0u128), + ("1e-18", 18u8, 1u128), + ("123456789", 0u8, 123456789u128), + ("123456789e-2", 2u8, 123456789u128), + ("1", 18u8, 1000000000000000000u128), + ]; + + for (input, decimals, expected) in cases { + let float = Float::parse(input.to_string()).unwrap(); + let fixed = float.to_fixed_decimal(decimals).unwrap(); + assert_eq!(fixed, U256::from(expected)); + } +} + +/// For integers: floor == self, frac == 0, and floor + frac == self. +#[test] +fn test_frac_and_floor_integers() { + let int_float = Float::parse("12345".to_string()).unwrap(); + let floor = int_float.floor().unwrap(); + let frac = int_float.frac().unwrap(); + let zero = Float::parse("0".to_string()).unwrap(); + + assert!(int_float.eq(floor).unwrap()); + assert!(frac.eq(zero).unwrap()); + + let int_float = Float::parse("-98765".to_string()).unwrap(); + let floor = int_float.floor().unwrap(); + let frac = int_float.frac().unwrap(); + let zero = Float::parse("0".to_string()).unwrap(); + + assert!(int_float.eq(floor).unwrap()); + assert!(frac.eq(zero).unwrap()); + + let recombined = (floor + frac).unwrap(); + assert!(int_float.eq(recombined).unwrap()); +} + +/// floor(12345.6789) == 12345, frac(12345.6789) == 0.6789. +#[test] +fn test_frac_and_floor_floats() { + let float = Float::parse("12345.6789".to_string()).unwrap(); + let floor = float.floor().unwrap(); + let frac = float.frac().unwrap(); + + let expected_floor = Float::parse("12345".to_string()).unwrap(); + let expected_frac = Float::parse("0.6789".to_string()).unwrap(); + + assert!(floor.eq(expected_floor).unwrap()); + assert!(frac.eq(expected_frac).unwrap()); +} + +/// integer(12345.6789) == 12345, and integer + frac == original. +#[test] +fn test_integer_positive() { + let float = Float::parse("12345.6789".to_string()).unwrap(); + let int = float.integer().unwrap(); + let expected = Float::parse("12345".to_string()).unwrap(); + assert!(int.eq(expected).unwrap()); + + let frac = float.frac().unwrap(); + let recombined = (int + frac).unwrap(); + assert!(float.eq(recombined).unwrap()); +} + +/// integer truncates toward zero: integer(-12345.6789) == -12345. +#[test] +fn test_integer_negative() { + let float = Float::parse("-12345.6789".to_string()).unwrap(); + let int = float.integer().unwrap(); + let frac = float.frac().unwrap(); + + // integer truncates toward zero, so -12345.6789 -> -12345 + let expected_int = Float::parse("-12345".to_string()).unwrap(); + let expected_frac = Float::parse("-0.6789".to_string()).unwrap(); + + assert!(int.eq(expected_int).unwrap()); + assert!(frac.eq(expected_frac).unwrap()); + + // integer + frac == original + let recombined = (int + frac).unwrap(); + assert!(float.eq(recombined).unwrap()); +} + +/// integer(42) == 42, frac(42) == 0 for positive and negative whole numbers. +#[test] +fn test_integer_whole_numbers() { + let pos = Float::parse("42".to_string()).unwrap(); + assert!(pos.integer().unwrap().eq(pos).unwrap()); + let zero = Float::parse("0".to_string()).unwrap(); + assert!(pos.frac().unwrap().eq(zero).unwrap()); + + let neg = Float::parse("-42".to_string()).unwrap(); + assert!(neg.integer().unwrap().eq(neg).unwrap()); + assert!(neg.frac().unwrap().eq(zero).unwrap()); +} + +proptest! { + #[test] + /// from_fixed_decimal then to_fixed_decimal round-trips for any non-negative I224. + fn test_from_to_fixed_decimal_valid_range(coeff in any::(), decimals in 0u8..=66u8) { + prop_assume!(coeff >= I224::ZERO); + + let exponent = -(decimals as i32); + let value = U256::from(coeff); + + let float = Float::from_fixed_decimal(value, decimals).unwrap(); + let expected = Float::pack_lossless(coeff, exponent).unwrap(); + prop_assert!(float.eq(expected).unwrap()); + + let fixed = float.to_fixed_decimal(decimals).unwrap(); + assert_eq!(fixed, value); + } +} + +proptest! { + #[test] + /// integer(a) + frac(a) == a, frac has no integer part, integer has + /// no fractional part, and |frac| < 1. + fn test_int_frac_properties(float in arb_float()) { + let int = float.integer().unwrap(); + let frac = float.frac().unwrap(); + + let zero = Float::parse("0".to_string()).unwrap(); + + prop_assert!( + int.frac().unwrap().eq(zero).unwrap(), + "int.frac() is not zero: {}", + int.show_unpacked().unwrap() + ); + + prop_assert!( + frac.integer().unwrap().eq(zero).unwrap(), + "frac.integer() is not zero: {}", + frac.show_unpacked().unwrap() + ); + + let recombined = (int + frac).unwrap(); + prop_assert!( + float.eq(recombined).unwrap(), + "original: {}, int: {}, frac: {}, recombined: {}", + float.show_unpacked().unwrap(), + int.show_unpacked().unwrap(), + frac.show_unpacked().unwrap(), + recombined.show_unpacked().unwrap() + ); + + let one = Float::parse("1".to_string()).unwrap(); + let neg_one = one.neg().unwrap(); + prop_assert!( + frac.lt(one).unwrap(), + "frac not < 1: {}", + frac.show_unpacked().unwrap() + ); + prop_assert!( + frac.gt(neg_one).unwrap(), + "frac not > -1: {}", + frac.show_unpacked().unwrap() + ); + } +} + +/// min/max for known value pairs, including identical arguments. +#[test] +fn test_min_max_manual() { + let negone = Float::parse("-1".to_string()).unwrap(); + let zero = Float::parse("0".to_string()).unwrap(); + let three = Float::parse("3".to_string()).unwrap(); + let seven = Float::parse("7".to_string()).unwrap(); + + // --- min --- + assert!(negone.eq(negone.min(zero).unwrap()).unwrap()); + assert!(negone.eq(negone.min(three).unwrap()).unwrap()); + assert!(zero.eq(zero.min(three).unwrap()).unwrap()); + // min with identical arguments should return that argument + assert!(seven.eq(seven.min(seven).unwrap()).unwrap()); + + // --- max --- + assert!(zero.eq(negone.max(zero).unwrap()).unwrap()); + assert!(three.eq(negone.max(three).unwrap()).unwrap()); + assert!(three.eq(zero.max(three).unwrap()).unwrap()); + // max with identical arguments should return that argument + assert!(seven.eq(seven.max(seven).unwrap()).unwrap()); +} + +/// is_zero for "0", "-0", "0.0" (all true) and "1" (false). +#[test] +fn test_is_zero_manual() { + let zero = Float::parse("0".to_string()).unwrap(); + assert!(zero.is_zero().unwrap()); + + // Alternative zero representations that should also be considered zero. + let neg_zero = Float::parse("-0".to_string()).unwrap(); + assert!(neg_zero.is_zero().unwrap()); + let zero_point = Float::parse("0.0".to_string()).unwrap(); + assert!(zero_point.is_zero().unwrap()); + + let one = Float::parse("1".to_string()).unwrap(); + assert!(!one.is_zero().unwrap()); +} + +proptest! { + #[test] + /// min(a,b) <= both, max(a,b) >= both, each equals one operand, + /// and min <= max. + fn test_min_max_properties(a in reasonable_float(), b in reasonable_float()) { + let min = a.min(b).unwrap(); + let max = a.max(b).unwrap(); + + prop_assert!( + !min.gt(a).unwrap(), + "min > a: min={}, a={}", + min.show_unpacked().unwrap(), + a.show_unpacked().unwrap() + ); + prop_assert!( + !min.gt(b).unwrap(), + "min > b: min={}, b={}", + min.show_unpacked().unwrap(), + b.show_unpacked().unwrap() + ); + + prop_assert!( + !max.lt(a).unwrap(), + "max < a: max={}, a={}", + max.show_unpacked().unwrap(), + a.show_unpacked().unwrap() + ); + prop_assert!( + !max.lt(b).unwrap(), + "max < b: max={}, b={}", + max.show_unpacked().unwrap(), + b.show_unpacked().unwrap() + ); + + let min_is_a = min.eq(a).unwrap(); + let min_is_b = min.eq(b).unwrap(); + prop_assert!( + min_is_a || min_is_b, + "min is not equal to either operand: a={}, b={}, min={}", + a.show_unpacked().unwrap(), + b.show_unpacked().unwrap(), + min.show_unpacked().unwrap() + ); + + let max_is_a = max.eq(a).unwrap(); + let max_is_b = max.eq(b).unwrap(); + prop_assert!( + max_is_a || max_is_b, + "max is not equal to either operand: a={}, b={}, max={}", + a.show_unpacked().unwrap(), + b.show_unpacked().unwrap(), + max.show_unpacked().unwrap() + ); + + prop_assert!( + !min.gt(max).unwrap(), + "min > max: min={}, max={}", + min.show_unpacked().unwrap(), + max.show_unpacked().unwrap() + ); + } +} + +/// Manual lte/gte checks: -1 <= 0 <= 3, 0 >= -1, 3 >= 0. +#[test] +fn test_lte_gte() { + let negone = Float::parse("-1".to_string()).unwrap(); + let zero = Float::parse("0".to_string()).unwrap(); + let three = Float::parse("3".to_string()).unwrap(); + + assert!(negone.lte(zero).unwrap()); + assert!(zero.lte(three).unwrap()); + assert!(negone.lte(three).unwrap()); + + assert!(zero.gte(negone).unwrap()); + assert!(three.gte(zero).unwrap()); + assert!(three.gte(negone).unwrap()); +} + +proptest! { + #[test] + /// a-1 lte a, a lte a and gte a, a+1 gte a. + fn test_lte_gte_fuzz(a in reasonable_float()) { + let b = a; + let one = Float::parse("1".to_string()).unwrap(); + + let a = (a - one).unwrap(); + let lte = a.lte(b).unwrap(); + prop_assert!(lte); // lt + + let a = (a + one).unwrap(); + let gte = a.gte(b).unwrap(); + let lte = a.lte(b).unwrap(); + prop_assert!(gte); // eq + prop_assert!(lte); // eq + + let a = (a + one).unwrap(); + let gte = a.gte(b).unwrap(); + prop_assert!(gte); // gt + } +} + +/// from_fixed_decimal_lossy: lossless for small values, lossy for U256::MAX. +#[test] +fn test_from_fixed_decimal_lossy() { + // Test lossless conversions (values that fit in Float's precision) + let lossless_cases = vec![ + (U256::from(0u128), 0u8, "0"), + (U256::from(0u128), 18u8, "0"), + (U256::from(1u128), 18u8, "1e-18"), + (U256::from(123456789u128), 0u8, "123456789"), + (U256::from(123456789u128), 2u8, "123456789e-2"), + (U256::from(1000000000000000000u128), 18u8, "1"), + ]; + + for (amount, decimals, expected) in lossless_cases { + let (float, lossless) = + Float::from_fixed_decimal_lossy(amount, decimals).expect("should convert"); + let expected = Float::parse(expected.to_string()).unwrap(); + assert!(float.eq(expected).unwrap()); + assert!( + lossless, + "conversion should be lossless for amount={}, decimals={}", + amount, decimals + ); + } + + // Test lossy conversion with U256::MAX (too large to fit in Float's 224-bit coefficient) + let (float, lossless) = Float::from_fixed_decimal_lossy(U256::MAX, 1).unwrap(); + assert!(!lossless, "U256::MAX conversion should be lossy"); + assert!(!float.is_zero().unwrap(), "result should not be zero"); +} + +/// to_fixed_decimal_lossy: correctly reports lossy/lossless for precision loss. +#[test] +fn test_to_fixed_decimal_lossy() { + // Test lossy conversions (loss of precision) + let lossy_cases = vec![ + (U256::from(1), 18u8, 0u128), + (U256::from(123456789), 0u8, 12345678u128), + (U256::from(123456789), 2u8, 12345678u128), + ]; + + for (input, decimals, expected) in lossy_cases { + let float = Float::from_fixed_decimal(input, decimals + 1).unwrap(); + let (fixed, lossless) = float.to_fixed_decimal_lossy(decimals).unwrap(); + assert_eq!( + fixed, + U256::from(expected), + "wrong value for input={}, decimals={}", + input, + decimals + ); + assert!( + !lossless, + "should be lossy for input={}, decimals={}", + input, decimals + ); + } + + // Test lossless conversions (no loss of precision) + let lossless_cases = vec![ + // Zero is always lossless + (U256::from(0), 0u8, 0u128), + (U256::from(0), 18u8, 0u128), + // Converting 12340 with 3 decimals (12.340) to 2 decimals (12.34) is lossless + (U256::from(12340), 3u8, 1234u128), + ]; + + for (input, decimals, expected) in lossless_cases { + let float = Float::from_fixed_decimal(input, decimals + 1).unwrap(); + let (fixed, lossless) = float.to_fixed_decimal_lossy(decimals).unwrap(); + assert_eq!( + fixed, + U256::from(expected), + "wrong value for input={}, decimals={}", + input, + decimals + ); + assert!( + lossless, + "should be lossless for input={}, decimals={}", + input, decimals + ); + } +} + +proptest! { + #[test] + /// Lossy fixed-decimal round-trip: from(decimals+1) then to(decimals) is + /// lossy iff the last digit is nonzero. + fn test_from_to_fixed_decimal_lossy_valid_range(coeff in any::(), decimals in 0u8..=66u8) { + prop_assume!(coeff >= I224::ZERO); + + let exponent = -(decimals as i32 + 1); + let value = U256::from(coeff); + + let (float, from_lossless) = Float::from_fixed_decimal_lossy(value, decimals + 1).unwrap(); + let expected = Float::pack_lossless(coeff, exponent).unwrap(); + prop_assert!(float.eq(expected).unwrap()); + + // from_fixed_decimal_lossy should be lossless for values that fit in Float's precision + prop_assert!(from_lossless, "from_fixed_decimal_lossy should be lossless for coeff={coeff}"); + + let (fixed, to_lossless) = float.to_fixed_decimal_lossy(decimals).unwrap(); + assert_eq!(fixed, value / U256::from(10)); + + // Converting from decimals+1 to decimals should be lossy unless the value is zero or + // the last digit is zero (divisible by 10) + if value == U256::ZERO || value % U256::from(10) == U256::ZERO { + prop_assert!(to_lossless, "to_fixed_decimal_lossy should be lossless when last digit is 0: value={}", value); + } else { + prop_assert!(!to_lossless, "to_fixed_decimal_lossy should be lossy when losing precision: value={}", value); + } + } +} + +proptest! { + #[test] + /// All reasonable positive floats are bounded by min/max_positive_value, + /// all negative by min/max_negative_value. + fn test_constants_relationships(float in reasonable_float()) { + let max_pos = Float::max_positive_value().unwrap(); + let min_pos = Float::min_positive_value().unwrap(); + let max_neg = Float::max_negative_value().unwrap(); + let min_neg = Float::min_negative_value().unwrap(); + let zero = Float::parse("0".to_string()).unwrap(); + + // Test that constants are the extremes + // Any reasonable positive float should be <= max_positive and >= min_positive + if float.gt(zero).unwrap() { + prop_assert!(float.lte(max_pos).unwrap()); + prop_assert!(float.gte(min_pos).unwrap()); + } + + // Any reasonable negative float should be <= max_negative and >= min_negative + // (max_negative is closest to zero, min_negative is furthest from zero) + if float.lt(zero).unwrap() { + prop_assert!(float.lte(max_neg).unwrap()); + prop_assert!(float.gte(min_neg).unwrap()); + } + + // Constants should be consistent regardless of arbitrary float + prop_assert!(max_pos.gt(zero).unwrap()); + prop_assert!(min_pos.gt(zero).unwrap()); + prop_assert!(max_neg.lt(zero).unwrap()); + prop_assert!(min_neg.lt(zero).unwrap()); + + // Verify constants maintain their ordering + prop_assert!(min_pos.lt(max_pos).unwrap()); + prop_assert!(min_neg.lt(max_neg).unwrap()); + prop_assert!(max_neg.lt(zero).unwrap()); + prop_assert!(min_pos.gt(zero).unwrap()); + } +} + +proptest! { + #[test] + /// No arbitrary float exceeds max_positive or is below min_negative. + fn test_constants_edge_cases(float in arb_float()) { + let max_pos = Float::max_positive_value().unwrap(); + let min_pos = Float::min_positive_value().unwrap(); + let max_neg = Float::max_negative_value().unwrap(); + let min_neg = Float::min_negative_value().unwrap(); + + // Constants should always be distinct + prop_assert!(!max_pos.eq(min_pos).unwrap()); + prop_assert!(!max_neg.eq(min_neg).unwrap()); + prop_assert!(!max_pos.eq(max_neg).unwrap()); + prop_assert!(!min_pos.eq(min_neg).unwrap()); + + // Test that constants are at the boundaries + // (Note: We can't test arithmetic operations that would overflow/underflow + // since those would fail, but we can test comparisons) + + // No arbitrary float should be greater than max_pos or less than min_neg + if !float.eq(max_pos).unwrap() { + prop_assert!(!float.gt(max_pos).unwrap()); + } + if !float.eq(min_neg).unwrap() { + prop_assert!(!float.lt(min_neg).unwrap()); + } + } +} diff --git a/crates/tests/src/fuzz_ops.rs b/crates/tests/src/fuzz_ops.rs new file mode 100644 index 00000000..ef320354 --- /dev/null +++ b/crates/tests/src/fuzz_ops.rs @@ -0,0 +1,305 @@ +//! Every operation against f64 over the range f64 represents exactly enough. + +use alloy::primitives::{I256, aliases::I224}; +use proptest::prelude::*; +use rain_math_float::Float; + +/// Convert a Solidity Float to f64 via unpack. +fn sol_to_f64(f: Float) -> Option { + let (coeff, exp) = f.unpack().ok()?; + let c: f64 = i256_to_f64(coeff); + let e: i32 = exp.as_i32(); + Some(c * 10.0_f64.powi(e)) +} + +fn i256_to_f64(v: I256) -> f64 { + if v.is_negative() { + let abs = (!v).wrapping_add(I256::ONE); + -(u256_to_f64(abs.into_raw())) + } else { + u256_to_f64(v.into_raw()) + } +} + +fn u256_to_f64(v: alloy::primitives::U256) -> f64 { + // Convert U256 to f64 via string parsing for accuracy. + v.to_string().parse::().unwrap_or(f64::INFINITY) +} + +// Generate floats in a range where f64 can represent them without +// overflow/underflow. Coefficients up to ~1e15 and exponents -15..15 +// keep values in f64's comfortable range. +prop_compose! { + fn f64_compatible_float()( + coefficient in -10i64.pow(15)..10i64.pow(15), + exponent in -15i32..15i32, + ) -> Float { + Float::pack_lossless( + I224::try_from(coefficient).unwrap(), + exponent, + ).unwrap() + } +} + +/// Check that two f64 values are approximately equal, allowing for +/// f64 rounding errors. Returns true if they're within a relative +/// tolerance of 1e-10 or both are effectively zero. +fn approx_eq(a: f64, b: f64) -> bool { + if a == b { + return true; + } + if a.is_nan() || b.is_nan() { + return false; + } + let max_abs = a.abs().max(b.abs()); + if max_abs < 1e-30 { + return true; + } + ((a - b).abs() / max_abs) < 1e-10 +} + +proptest! { + #[test] + fn fuzz_add( + a in f64_compatible_float(), + b in f64_compatible_float(), + ) { + let sol_result = (a + b).unwrap(); + let a_f64 = sol_to_f64(a).unwrap(); + let b_f64 = sol_to_f64(b).unwrap(); + let expected = a_f64 + b_f64; + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "add: {a_f64} + {b_f64} = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_sub( + a in f64_compatible_float(), + b in f64_compatible_float(), + ) { + let sol_result = (a - b).unwrap(); + let a_f64 = sol_to_f64(a).unwrap(); + let b_f64 = sol_to_f64(b).unwrap(); + let expected = a_f64 - b_f64; + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "sub: {a_f64} - {b_f64} = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_mul( + a in f64_compatible_float(), + b in f64_compatible_float(), + ) { + let sol_result = (a * b).unwrap(); + let a_f64 = sol_to_f64(a).unwrap(); + let b_f64 = sol_to_f64(b).unwrap(); + let expected = a_f64 * b_f64; + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "mul: {a_f64} * {b_f64} = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_div( + a in f64_compatible_float(), + b in f64_compatible_float(), + ) { + let b_f64 = sol_to_f64(b).unwrap(); + // Skip division by zero. + prop_assume!(b_f64.abs() > 1e-30); + + let sol_result = (a / b).unwrap(); + let a_f64 = sol_to_f64(a).unwrap(); + let expected = a_f64 / b_f64; + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "div: {a_f64} / {b_f64} = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_neg(a in f64_compatible_float()) { + let sol_result = (-a).unwrap(); + let a_f64 = sol_to_f64(a).unwrap(); + let expected = -a_f64; + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "neg: -{a_f64} = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_abs(a in f64_compatible_float()) { + let sol_result = a.abs().unwrap(); + let a_f64 = sol_to_f64(a).unwrap(); + let expected = a_f64.abs(); + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "abs: |{a_f64}| = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_inv(a in f64_compatible_float()) { + let a_f64 = sol_to_f64(a).unwrap(); + // Skip values too close to zero. + prop_assume!(a_f64.abs() > 1e-10); + + let sol_result = a.inv().unwrap(); + let expected = 1.0 / a_f64; + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "inv: 1/{a_f64} = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_floor(a in f64_compatible_float()) { + let a_f64 = sol_to_f64(a).unwrap(); + let sol_result = a.floor().unwrap(); + let expected = a_f64.floor(); + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "floor: floor({a_f64}) = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_integer(a in f64_compatible_float()) { + let a_f64 = sol_to_f64(a).unwrap(); + let sol_result = a.integer().unwrap(); + let expected = a_f64.trunc(); + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "integer: trunc({a_f64}) = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_frac( + coefficient in -10i64.pow(10)..10i64.pow(10), + exponent in -5i32..0i32, + ) { + let a = Float::pack_lossless( + I224::try_from(coefficient).unwrap(), + exponent, + ).unwrap(); + let a_f64 = sol_to_f64(a).unwrap(); + let sol_result = a.frac().unwrap(); + let expected = a_f64.fract(); + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + (expected - actual).abs() < 1e-6, + "frac: fract({a_f64}) = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_min( + a in f64_compatible_float(), + b in f64_compatible_float(), + ) { + let sol_result = a.min(b).unwrap(); + let a_f64 = sol_to_f64(a).unwrap(); + let b_f64 = sol_to_f64(b).unwrap(); + let expected = a_f64.min(b_f64); + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "min: min({a_f64}, {b_f64}) = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_max( + a in f64_compatible_float(), + b in f64_compatible_float(), + ) { + let sol_result = a.max(b).unwrap(); + let a_f64 = sol_to_f64(a).unwrap(); + let b_f64 = sol_to_f64(b).unwrap(); + let expected = a_f64.max(b_f64); + let actual = sol_to_f64(sol_result).unwrap(); + prop_assert!( + approx_eq(expected, actual), + "max: max({a_f64}, {b_f64}) = {expected}, sol = {actual}", + ); + } + + #[test] + fn fuzz_is_zero(a in f64_compatible_float()) { + let a_f64 = sol_to_f64(a).unwrap(); + let sol_result = a.is_zero().unwrap(); + let expected = a_f64 == 0.0; + prop_assert!( + sol_result == expected, + "is_zero: is_zero({}) = {}, sol = {}", + a_f64, expected, sol_result + ); + } + + #[test] + fn fuzz_fixed_decimal_round_trip( + coefficient in 0i64..10i64.pow(15), + decimals in 0u8..18u8, + ) { + use alloy::primitives::U256; + let value = U256::from(coefficient as u64); + // Convert to float and back. + let float = Float::from_fixed_decimal(value, decimals); + prop_assume!(float.is_ok()); + let float = float.unwrap(); + let (back, lossless) = float.to_fixed_decimal_lossy(decimals).unwrap(); + if lossless { + prop_assert!( + back == value, + "round-trip failed: {} with {} decimals, got {}", + coefficient, decimals, back + ); + } + } + + #[test] + fn fuzz_comparisons( + a in f64_compatible_float(), + b in f64_compatible_float(), + ) { + let a_f64 = sol_to_f64(a).unwrap(); + let b_f64 = sol_to_f64(b).unwrap(); + + // Only test comparisons when values are far enough apart + // that f64 precision issues don't cause false failures. + let diff = (a_f64 - b_f64).abs(); + let max_abs = a_f64.abs().max(b_f64.abs()); + prop_assume!(diff > max_abs * 1e-10 || diff < 1e-30); + + let sol_lt = a.lt(b).unwrap(); + let sol_gt = a.gt(b).unwrap(); + let sol_eq = a.eq(b).unwrap(); + + if diff < 1e-30 { + // Both effectively zero. + prop_assert!(sol_eq, "eq: {a_f64} == {b_f64} should be true"); + } else if a_f64 < b_f64 { + prop_assert!(sol_lt, "lt: {a_f64} < {b_f64} should be true"); + prop_assert!(!sol_gt, "gt: {a_f64} > {b_f64} should be false"); + } else { + prop_assert!(sol_gt, "gt: {a_f64} > {b_f64} should be true"); + prop_assert!(!sol_lt, "lt: {a_f64} < {b_f64} should be false"); + } + } +} diff --git a/crates/tests/src/lib.rs b/crates/tests/src/lib.rs new file mode 100644 index 00000000..19adad38 --- /dev/null +++ b/crates/tests/src/lib.rs @@ -0,0 +1,13 @@ +//! Tests of the library through the `rain-math-float` bindings, run over +//! `test/concrete/TestDecimalFloat.sol` and `TestDecimalFloatHarness.sol` +//! compiled from this source, and cross-references of the packed constants +//! against values derived here. + +#[cfg(test)] +mod constants; +#[cfg(test)] +mod float; +#[cfg(test)] +mod fuzz_ops; +#[cfg(test)] +mod tables; diff --git a/crates/tests/src/tables.rs b/crates/tests/src/tables.rs new file mode 100644 index 00000000..1d33eefc --- /dev/null +++ b/crates/tests/src/tables.rs @@ -0,0 +1,316 @@ +//! The log tables `LibLogTable` ships, read through the harness, against an +//! independent generation from f64 math. +#![allow(clippy::needless_range_loop)] + +use rain_math_float::tables; + +/// `ALT_TABLE_FLAG` as used in LibLogTable.sol: bit 15 of a uint16. +const ALT_TABLE_FLAG: u16 = 0x8000; + +#[test] +fn alt_table_flag_is_the_library_flag() { + assert_eq!(tables::alt_table_flag().unwrap(), ALT_TABLE_FLAG); +} + +/// Generate the main log table: uint16[10][90]. +/// +/// Standard 4-figure log table layout. Row r (0-89) and column c (0-9) +/// represent the 3-digit mantissa prefix (10+r) and third digit c, so +/// the looked-up number is n = (10+r)*100 + c*10, ranging from 1000 to +/// 9990. The stored value is the fractional part of log10(n) scaled by +/// 10000: round((log10(n) - 3) * 10000). +/// +/// ALT_TABLE_FLAG is set on entries where the small alt table provides +/// different (more precise) mean differences than the regular small table. +fn generate_log_table(small: &[[u8; 10]; 90], small_alt: &[[u8; 10]; 10]) -> [[u16; 10]; 90] { + let mut table = [[0u16; 10]; 90]; + for (row, table_row) in table.iter_mut().enumerate() { + for (col, entry) in table_row.iter_mut().enumerate() { + let n = ((10 + row) * 100 + col * 10) as f64; + let base = ((n.log10() - 3.0) * 10000.0).round() as u16; + let needs_alt = row < 10 && small[row][col] != small_alt[row][col]; + *entry = if needs_alt { + base | ALT_TABLE_FLAG + } else { + base + }; + } + } + table +} + +/// Generate the small log table: uint8[10][90]. +/// +/// Mean differences for the 4th digit. Each entry is the rounded +/// difference in scaled log10 between the 4-digit number and the base +/// 3-digit number for that row. +fn generate_log_table_small() -> [[u8; 10]; 90] { + let mut table = [[0u8; 10]; 90]; + for (row, table_row) in table.iter_mut().enumerate() { + let base_n = (10 + row) * 100; + let base_log = (base_n as f64).log10(); + for (col, entry) in table_row.iter_mut().enumerate() { + let diff = ((base_n + col) as f64).log10() - base_log; + *entry = (diff * 10000.0).round() as u8; + } + } + table +} + +/// Generate the small alt log table: uint8[10][10]. +/// +/// Higher-precision mean differences for the first 10 rows (mantissa +/// 100-199). Uses floor of scaled values then takes the difference. +fn generate_log_table_small_alt() -> [[u8; 10]; 10] { + let mut table = [[0u8; 10]; 10]; + for (row, table_row) in table.iter_mut().enumerate() { + let base_n = (10 + row) * 100; + let base_log = (base_n as f64).log10(); + for (col, entry) in table_row.iter_mut().enumerate() { + let diff = ((base_n + col) as f64).log10() - base_log; + *entry = (diff * 10000.0).round() as u8; + } + } + table +} + +/// Generate the antilog table: uint16[10][100]. +/// +/// The full antilog index range is 0-9999 (ANTILOG_IDX_CARDINALITY). +/// The main table has 1000 entries (100 rows × 10 cols), one per group +/// of 10 consecutive indices. Flattened entry k corresponds to indices +/// k*10 through k*10+9. Value = round(10^(k*10/10000) * 1000). +fn generate_antilog_table() -> [[u16; 10]; 100] { + let mut table = [[0u16; 10]; 100]; + for (row, table_row) in table.iter_mut().enumerate() { + for (col, entry) in table_row.iter_mut().enumerate() { + let k = row * 10 + col; + *entry = (10.0_f64.powf((k * 10) as f64 / 10000.0) * 1000.0).round() as u16; + } + } + table +} + +/// Generate the small antilog table: uint8[10][100]. +/// +/// Indexed by [idx/100][idx%10] where idx is the full index (0-9999). +/// The value is the correction to add to the main table entry. +/// For a given idx: main covers idx rounded down to nearest 10, +/// small adds the sub-10 correction. +/// +/// Value = round(10^(idx/10000) * 1000) - main_table[idx/10] +/// But since many indices share the same [row][col], the table stores +/// a representative value. In practice it's computed for the first +/// occurrence (tens digit = 0). +fn generate_antilog_table_small() -> [[u8; 10]; 100] { + let mut table = [[0u8; 10]; 100]; + for (row, table_row) in table.iter_mut().enumerate() { + for (col, entry) in table_row.iter_mut().enumerate() { + let idx = row * 100 + col; + let main_k = idx / 10; + let main_val = (10.0_f64.powf((main_k * 10) as f64 / 10000.0) * 1000.0).round(); + let exact_val = (10.0_f64.powf(idx as f64 / 10000.0) * 1000.0).round(); + *entry = (exact_val - main_val).round() as u8; + } + } + table +} + +/// Verify the main log table entries are within ±1 of the true value. +/// The Solidity tables are transcribed from a published 4-figure log +/// table reference and may use rounding conventions that differ from +/// IEEE 754 f64, so we check proximity rather than exact equality. +#[test] +fn test_log_table_accuracy() { + let table = tables::log_table_dec().unwrap(); + for row in 0..90 { + for col in 0..10 { + let n = ((10 + row) * 100 + col * 10) as f64; + let expected = ((n.log10() - 3.0) * 10000.0).round() as i32; + let actual = (table[row][col] & !ALT_TABLE_FLAG) as i32; + assert!( + (actual - expected).abs() <= 1, + "log table [{row}][{col}]: n={n}, expected={expected}, actual={actual}, diff={}", + actual - expected + ); + } + } +} + +/// Verify the main antilog table entries are within ±1 of the true value. +#[test] +fn test_antilog_table_accuracy() { + let table = tables::anti_log_table_dec().unwrap(); + for row in 0..100 { + for col in 0..10 { + let k = row * 10 + col; + let expected = (10.0_f64.powf((k * 10) as f64 / 10000.0) * 1000.0).round() as i32; + let actual = table[row][col] as i32; + assert!( + (actual - expected).abs() <= 1, + "antilog table [{row}][{col}]: k={k}, expected={expected}, actual={actual}, diff={}", + actual - expected + ); + } + } +} + +/// Verify that main + small gives a value close to the true log10 +/// for every 4-digit number 1000-9999. +#[test] +fn test_log_lookup_accuracy() { + let main = tables::log_table_dec().unwrap(); + let small = tables::log_table_dec_small().unwrap(); + let small_alt = tables::log_table_dec_small_alt().unwrap(); + for n in 1000..10000_usize { + let row = n / 10 - 100; + let _col = (n / 10) % 10; + let d = n % 10; + let main_row = row / 10; + let main_col = row % 10; + + let main_entry = main[main_row][main_col]; + let main_val = (main_entry & !ALT_TABLE_FLAG) as i32; + let use_alt = main_entry & ALT_TABLE_FLAG != 0; + let small_val = if use_alt { + small_alt[main_row][d] as i32 + } else { + small[main_row][d] as i32 + }; + let table_result = main_val + small_val; + let true_val = ((n as f64).log10() - 3.0) * 10000.0; + + // The lookup should be within 2 of the true value (main has + // ±1 error, small has ±1 error). + assert!( + (table_result as f64 - true_val).abs() < 2.5, + "log lookup for n={n}: table={table_result}, true={true_val:.2}, diff={:.2}", + table_result as f64 - true_val + ); + } +} + +/// Verify that main + small gives a value close to the true antilog +/// for every index 0-9999. +#[test] +fn test_antilog_lookup_accuracy() { + let main = tables::anti_log_table_dec().unwrap(); + let small = tables::anti_log_table_dec_small().unwrap(); + for idx in 0..10000_usize { + let main_k = idx / 10; + let main_row = main_k / 10; + let main_col = main_k % 10; + let main_val = main[main_row][main_col] as i32; + + let small_row = idx / 100; + let small_col = idx % 10; + let small_val = small[small_row][small_col] as i32; + + let table_result = main_val + small_val; + let true_val = 10.0_f64.powf(idx as f64 / 10000.0) * 1000.0; + + assert!( + (table_result as f64 - true_val).abs() < 2.5, + "antilog lookup for idx={idx}: table={table_result}, true={true_val:.2}, diff={:.2}", + table_result as f64 - true_val + ); + } +} + +/// Verify that the main antilog table entries exactly match +/// round(10^(k*10/10000) * 1000). +#[test] +fn test_antilog_table_exact() { + let generated = generate_antilog_table(); + let solidity = tables::anti_log_table_dec().unwrap(); + for row in 0..100 { + for col in 0..10 { + assert_eq!( + generated[row][col], solidity[row][col], + "antilog table mismatch at [{row}][{col}]: generated={}, solidity={}", + generated[row][col], solidity[row][col] + ); + } + } +} + +/// Verify the small log table — generated values are either exact or +/// at most 1 above the Solidity value. The published reference table +/// uses rounding conventions that floor certain values where IEEE 754 +/// round-half-up produces the next integer. The direction is always +/// generated >= solidity. +#[test] +fn test_log_table_small_generation() { + let generated = generate_log_table_small(); + let solidity = tables::log_table_dec_small().unwrap(); + for row in 0..90 { + for col in 0..10 { + let diff = generated[row][col] as i16 - solidity[row][col] as i16; + assert!( + diff.abs() <= 1, + "log small [{row}][{col}]: generated={}, solidity={}, diff={diff}", + generated[row][col], + solidity[row][col] + ); + } + } +} + +/// Verify the small alt log table — allows ±2 because the published +/// table uses interpolation conventions that differ from per-entry +/// floor differences by up to 2 units. +#[test] +fn test_log_table_small_alt_generation() { + let generated = generate_log_table_small_alt(); + let solidity = tables::log_table_dec_small_alt().unwrap(); + for row in 0..10 { + for col in 0..10 { + let diff = generated[row][col] as i16 - solidity[row][col] as i16; + assert!( + diff.abs() <= 3, + "log small alt [{row}][{col}]: generated={}, solidity={}, diff={diff}", + generated[row][col], + solidity[row][col] + ); + } + } +} + +/// Verify the small antilog table — same +1 tolerance. +#[test] +fn test_antilog_table_small_generation() { + let generated = generate_antilog_table_small(); + let solidity = tables::anti_log_table_dec_small().unwrap(); + for row in 0..100 { + for col in 0..10 { + let diff = generated[row][col] as i16 - solidity[row][col] as i16; + assert!( + diff.abs() <= 1, + "antilog small [{row}][{col}]: generated={}, solidity={}, diff={diff}", + generated[row][col], + solidity[row][col] + ); + } + } +} + +/// Verify the main log table — the base values (without ALT flag) +/// match exactly. ALT flags depend on the small table generation +/// so they get +1 tolerance via the ALT flag being set or not. +#[test] +fn test_log_table_generation() { + let small = generate_log_table_small(); + let small_alt = generate_log_table_small_alt(); + let generated = generate_log_table(&small, &small_alt); + let solidity = tables::log_table_dec().unwrap(); + for row in 0..90 { + for col in 0..10 { + let gen_base = generated[row][col] & !ALT_TABLE_FLAG; + let sol_base = solidity[row][col] & !ALT_TABLE_FLAG; + assert_eq!( + gen_base, sol_base, + "log [{row}][{col}] base: generated={gen_base}, solidity={sol_base}", + ); + } + } +} diff --git a/test/abstract/LogTest.sol b/test/abstract/LogTest.sol index 032910ce..4d466d11 100644 --- a/test/abstract/LogTest.sol +++ b/test/abstract/LogTest.sol @@ -5,35 +5,14 @@ pragma solidity =0.8.25; // Re-export console2 here for convenience. // forge-lint: disable-next-line(unused-import) import {Test, console2} from "forge-std-1.16.1/src/Test.sol"; -import {LibDataContract} from "rain-datacontract-0.1.9/src/lib/LibDataContract.sol"; -import {LibLogTable, LOG_TABLE_DISAMBIGUATOR} from "src/lib/table/LibLogTable.sol"; +import {LibTestLogTables} from "test/lib/LibTestLogTables.sol"; abstract contract LogTest is Test { address sTables; - /// Deploy the combined log/anti-log tables data contract at a `create` - /// address and return it, rebuilding the table bytes purely from - /// `LibLogTable` source. The transcendental library functions take the - /// tables-contract address as a parameter, so this self-contained helper is - /// all the pure-math suite needs: no Zoltu-deterministic deploy pin, no - /// frozen `src/generated` snapshot. function logTables() internal returns (address) { if (sTables == address(0)) { - bytes memory tables = abi.encodePacked( - LibLogTable.toBytes(LibLogTable.logTableDec()), - LibLogTable.toBytes(LibLogTable.logTableDecSmall()), - LibLogTable.toBytes(LibLogTable.logTableDecSmallAlt()), - LibLogTable.toBytes(LibLogTable.antiLogTableDec()), - LibLogTable.toBytes(LibLogTable.antiLogTableDecSmall()), - LOG_TABLE_DISAMBIGUATOR - ); - bytes memory creationCode = LibDataContract.contractCreationCode(tables); - address tablesAddress; - assembly ("memory-safe") { - tablesAddress := create(0, add(creationCode, 0x20), mload(creationCode)) - } - assertTrue(tablesAddress != address(0), "Failed to deploy tables"); - sTables = tablesAddress; + sTables = LibTestLogTables.deploy(); } return sTables; } diff --git a/test/concrete/TestDecimalFloat.sol b/test/concrete/TestDecimalFloat.sol new file mode 100644 index 00000000..8d649db6 --- /dev/null +++ b/test/concrete/TestDecimalFloat.sol @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {LibDecimalFloat, Float} from "src/lib/LibDecimalFloat.sol"; +import {LibFormatDecimalFloat} from "src/lib/format/LibFormatDecimalFloat.sol"; +import {LibParseDecimalFloat} from "src/lib/parse/LibParseDecimalFloat.sol"; +import {ScientificMinNotLessThanMax} from "src/error/ErrDecimalFloat.sol"; +import {LibTestLogTables} from "test/lib/LibTestLogTables.sol"; + +/// The `DecimalFloat` ABI over this source, for the Rust bindings' tests. The +/// constructor deploys the log tables, where the deployed concrete requires +/// them at their Zoltu address. +contract TestDecimalFloat { + using LibDecimalFloat for Float; + + // slither-disable-next-line too-many-digits + Float public constant FORMAT_DEFAULT_SCIENTIFIC_MIN = + Float.wrap(0xfffffffc00000000000000000000000000000000000000000000000000000001); + + // slither-disable-next-line too-many-digits + Float public constant FORMAT_DEFAULT_SCIENTIFIC_MAX = + Float.wrap(0x0000000900000000000000000000000000000000000000000000000000000001); + + address immutable I_TABLES; + + constructor() { + I_TABLES = LibTestLogTables.deploy(); + } + + function maxPositiveValue() external pure returns (Float) { + return LibDecimalFloat.FLOAT_MAX_POSITIVE_VALUE; + } + + function minPositiveValue() external pure returns (Float) { + return LibDecimalFloat.FLOAT_MIN_POSITIVE_VALUE; + } + + function maxNegativeValue() external pure returns (Float) { + return LibDecimalFloat.FLOAT_MAX_NEGATIVE_VALUE; + } + + function minNegativeValue() external pure returns (Float) { + return LibDecimalFloat.FLOAT_MIN_NEGATIVE_VALUE; + } + + function zero() external pure returns (Float) { + return LibDecimalFloat.FLOAT_ZERO; + } + + function e() external pure returns (Float) { + return LibDecimalFloat.FLOAT_E; + } + + function parse(string memory str) external pure returns (bytes4, Float) { + (bytes4 errorSelector, Float parsed) = LibParseDecimalFloat.parseDecimalFloat(str); + return (errorSelector, parsed); + } + + function format(Float a, Float scientificMin, Float scientificMax) public pure returns (string memory) { + if (!scientificMin.lt(scientificMax)) { + revert ScientificMinNotLessThanMax(scientificMin, scientificMax); + } + Float absA = a.abs(); + return LibFormatDecimalFloat.toDecimalString(a, absA.lt(scientificMin) || absA.gt(scientificMax)); + } + + function format(Float a, bool scientific) external pure returns (string memory) { + return LibFormatDecimalFloat.toDecimalString(a, scientific); + } + + function format(Float a) external pure returns (string memory) { + return format(a, FORMAT_DEFAULT_SCIENTIFIC_MIN, FORMAT_DEFAULT_SCIENTIFIC_MAX); + } + + function add(Float a, Float b) external pure returns (Float) { + return a.add(b); + } + + function sub(Float a, Float b) external pure returns (Float) { + return a.sub(b); + } + + function minus(Float a) external pure returns (Float) { + return a.minus(); + } + + function abs(Float a) external pure returns (Float) { + return a.abs(); + } + + function mul(Float a, Float b) external pure returns (Float) { + return a.mul(b); + } + + function div(Float a, Float b) external pure returns (Float) { + return a.div(b); + } + + function inv(Float a) external pure returns (Float) { + return a.inv(); + } + + function eq(Float a, Float b) external pure returns (bool) { + return a.eq(b); + } + + function lt(Float a, Float b) external pure returns (bool) { + return a.lt(b); + } + + function gt(Float a, Float b) external pure returns (bool) { + return a.gt(b); + } + + function lte(Float a, Float b) external pure returns (bool) { + return a.lte(b); + } + + function gte(Float a, Float b) external pure returns (bool) { + return a.gte(b); + } + + function integer(Float a) external pure returns (Float) { + return a.integer(); + } + + function frac(Float a) external pure returns (Float) { + return a.frac(); + } + + function floor(Float a) external pure returns (Float) { + return a.floor(); + } + + function ceil(Float a) external pure returns (Float) { + return a.ceil(); + } + + function pow10(Float a) external view returns (Float) { + return a.pow10(I_TABLES); + } + + function log10(Float a) external view returns (Float) { + return a.log10(I_TABLES); + } + + function pow(Float a, Float b) external view returns (Float) { + return a.pow(b, I_TABLES); + } + + function sqrt(Float a) external view returns (Float) { + return a.sqrt(I_TABLES); + } + + function min(Float a, Float b) external pure returns (Float) { + return a.min(b); + } + + function max(Float a, Float b) external pure returns (Float) { + return a.max(b); + } + + function isZero(Float a) external pure returns (bool) { + return a.isZero(); + } + + function fromFixedDecimalLossless(uint256 value, uint8 decimals) external pure returns (Float) { + return LibDecimalFloat.fromFixedDecimalLosslessPacked(value, decimals); + } + + function toFixedDecimalLossless(Float float, uint8 decimals) external pure returns (uint256) { + return LibDecimalFloat.toFixedDecimalLossless(float, decimals); + } + + function fromFixedDecimalLossy(uint256 value, uint8 decimals) external pure returns (Float, bool) { + //slither-disable-next-line unused-return + return LibDecimalFloat.fromFixedDecimalLossyPacked(value, decimals); + } + + function toFixedDecimalLossy(Float float, uint8 decimals) external pure returns (uint256, bool) { + //slither-disable-next-line unused-return + return LibDecimalFloat.toFixedDecimalLossy(float, decimals); + } +} diff --git a/test/concrete/TestDecimalFloatHarness.sol b/test/concrete/TestDecimalFloatHarness.sol new file mode 100644 index 00000000..87913420 --- /dev/null +++ b/test/concrete/TestDecimalFloatHarness.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {LibDecimalFloat, Float} from "src/lib/LibDecimalFloat.sol"; +import {LibLogTable, ALT_TABLE_FLAG} from "src/lib/table/LibLogTable.sol"; + +/// The Rust bindings' `TestDecimalFloat` harness ABI over this source: +/// packing, and the log tables as `LibLogTable` ships them. +contract TestDecimalFloatHarness { + using LibDecimalFloat for Float; + + function packLossless(int224 coefficient, int32 exponent) external pure returns (Float) { + return LibDecimalFloat.packLossless(coefficient, exponent); + } + + function unpack(Float float) external pure returns (int256, int256) { + return LibDecimalFloat.unpack(float); + } + + function altTableFlag() external pure returns (uint16) { + return ALT_TABLE_FLAG; + } + + function logTableDec() external pure returns (uint16[10][90] memory) { + return LibLogTable.logTableDec(); + } + + function logTableDecSmall() external pure returns (uint8[10][90] memory) { + return LibLogTable.logTableDecSmall(); + } + + function logTableDecSmallAlt() external pure returns (uint8[10][10] memory) { + return LibLogTable.logTableDecSmallAlt(); + } + + function antiLogTableDec() external pure returns (uint16[10][100] memory) { + return LibLogTable.antiLogTableDec(); + } + + function antiLogTableDecSmall() external pure returns (uint8[10][100] memory) { + return LibLogTable.antiLogTableDecSmall(); + } +} diff --git a/test/lib/LibTestLogTables.sol b/test/lib/LibTestLogTables.sol new file mode 100644 index 00000000..6bdeac13 --- /dev/null +++ b/test/lib/LibTestLogTables.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {LibDataContract} from "rain-datacontract-0.1.9/src/lib/LibDataContract.sol"; +import {LibLogTable, LOG_TABLE_DISAMBIGUATOR} from "src/lib/table/LibLogTable.sol"; + +error LogTablesNotDeployed(); + +library LibTestLogTables { + /// Deploys the combined log tables from `LibLogTable` source as a data + /// contract at a `create` address and returns it. + function deploy() internal returns (address) { + bytes memory tables = abi.encodePacked( + LibLogTable.toBytes(LibLogTable.logTableDec()), + LibLogTable.toBytes(LibLogTable.logTableDecSmall()), + LibLogTable.toBytes(LibLogTable.logTableDecSmallAlt()), + LibLogTable.toBytes(LibLogTable.antiLogTableDec()), + LibLogTable.toBytes(LibLogTable.antiLogTableDecSmall()), + LOG_TABLE_DISAMBIGUATOR + ); + bytes memory creationCode = LibDataContract.contractCreationCode(tables); + address tablesAddress; + assembly ("memory-safe") { + tablesAddress := create(0, add(creationCode, 0x20), mload(creationCode)) + } + if (tablesAddress == address(0)) { + revert LogTablesNotDeployed(); + } + return tablesAddress; + } +} From b39a8e844c3d2724c2155a960c3754c6bee9eaea Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Mon, 7 Sep 2026 16:27:36 +0000 Subject: [PATCH 4/6] Ignore proptest regression seeds The committed ones were recorded under mutated source during probing. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QyCCzi9WZPhuXcU1hwr2bq --- .gitignore | 1 + crates/tests/proptest-regressions/float.txt | 11 ----------- crates/tests/proptest-regressions/fuzz_ops.txt | 7 ------- 3 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 crates/tests/proptest-regressions/float.txt delete mode 100644 crates/tests/proptest-regressions/fuzz_ops.txt diff --git a/.gitignore b/.gitignore index cd6e7aed..191c52de 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ temp .pre-commit-config.yaml .claude target +proptest-regressions diff --git a/crates/tests/proptest-regressions/float.txt b/crates/tests/proptest-regressions/float.txt deleted file mode 100644 index af82acb8..00000000 --- a/crates/tests/proptest-regressions/float.txt +++ /dev/null @@ -1,11 +0,0 @@ -# Seeds for failure cases proptest has generated in the past. It is -# automatically read and these particular cases re-run before any -# novel cases are generated. -# -# It is recommended to check this file in to source control so that -# everyone who runs the test benefits from these saved cases. -cc f6dbf2daa643e3af6e5ef64882d35c2bbb0c4fb6a3c3af266dc9aa86d9a02109 # shrinks to float = Float(0x0000000000000001000000000000000000000000000000000000000000000000) -cc 2cc26b3c1b4b599834ec3685c77bdd3acafd77455cadfa8dfa4b0be9e713782a # shrinks to a = Float(0x0000000000000000000000000000000000000000000000000000000000000000) -cc 642cb26314dc2fb6c09ab7f626896905e09d18c54629a4e715d1ea5a62e011db # shrinks to a = Float(0x0000000000000000000000000000000000000000000000000000000000000000) -cc 4c7984d448d28df4f7f767c60b599e740b85045c82e164dddcf8ca804dcd6858 # shrinks to float = Float(0xffffffff00000000000000000000000000000000000000000000000000000001) -cc 890df2dbb989cbefae9594af8f895b34638eac35b461fdcb6e6585564a3f6fd6 # shrinks to a = Float(0xffffffff00000000000000000000000000000000000000000000000000000001), b = Float(0x0000000000000000000000000000000000000000000000000000000000000000) diff --git a/crates/tests/proptest-regressions/fuzz_ops.txt b/crates/tests/proptest-regressions/fuzz_ops.txt deleted file mode 100644 index 98d76c1f..00000000 --- a/crates/tests/proptest-regressions/fuzz_ops.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Seeds for failure cases proptest has generated in the past. It is -# automatically read and these particular cases re-run before any -# novel cases are generated. -# -# It is recommended to check this file in to source control so that -# everyone who runs the test benefits from these saved cases. -cc 90fd005104a53dbf42191fdeca18dbab87a6c22e4d33eb305cd81b7d9bf9d290 # shrinks to a = Float(0x0000000000000000000000000000000000000000000000000000000000000001), b = Float(0x0000000000000000000000000000000000000000000000000000000000000000) From 8ee0fbab43d349007539dbf542b043516f16ff1d Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Mon, 7 Sep 2026 16:28:30 +0000 Subject: [PATCH 5/6] Carry the moved tests' proptest regression seeds Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QyCCzi9WZPhuXcU1hwr2bq --- .gitignore | 1 - crates/tests/proptest-regressions/float.txt | 8 ++++++++ crates/tests/proptest-regressions/fuzz_ops.txt | 8 ++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 crates/tests/proptest-regressions/float.txt create mode 100644 crates/tests/proptest-regressions/fuzz_ops.txt diff --git a/.gitignore b/.gitignore index 191c52de..cd6e7aed 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,3 @@ temp .pre-commit-config.yaml .claude target -proptest-regressions diff --git a/crates/tests/proptest-regressions/float.txt b/crates/tests/proptest-regressions/float.txt new file mode 100644 index 00000000..7070cb90 --- /dev/null +++ b/crates/tests/proptest-regressions/float.txt @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 664cbb4a3416dcc12fe1196bdf33bdf3f9e1403c6446f0516dc704da23be5723 # shrinks to a = Float(0x0000000000000000000000000000000000000000000000000000000000000000), b = Float(0xffffffff00000000000000000000000000000000000000000000000000000001) +cc 3fd2457aad2f1f4960353eb70458c7806f645c48898d3d336369b396c6cd13e1 # shrinks to a = Float(0x000000000000000000000000000000000000000000000000534a0c3580000000), b = Float(0x00000000000000000000000000000000000000000000000008e5c21900000000) diff --git a/crates/tests/proptest-regressions/fuzz_ops.txt b/crates/tests/proptest-regressions/fuzz_ops.txt new file mode 100644 index 00000000..6ecefabe --- /dev/null +++ b/crates/tests/proptest-regressions/fuzz_ops.txt @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 285e4d87fcb0e9c1757a0ddf5aa8199fbd17d38208bd0b5ef2288d059eb3934e # shrinks to a = Float(0xffffffff000000000000000000000000000000000000000000009a9939ef8c94) +cc cb8c50af037a017c4a91ac6dede4b4fc2e1372a1de1290ac8fafc546772613d0 # shrinks to a = Float(0xfffffffeffffffffffffffffffffffffffffffffffffffffffffba63064a71d9) From 93238c69d1b67077c5177f47ce2b37a40dd880e0 Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Tue, 8 Sep 2026 06:53:23 +0000 Subject: [PATCH 6/6] Take the review on the Rust tests Force the artifact settings so a shell value cannot redirect the tests, always sync Soldeer before building, drop the near-zero shortcut from the f64 comparison, and require the fixed-decimal round trip to be lossless. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QyCCzi9WZPhuXcU1hwr2bq --- .cargo/config.toml | 9 +++++---- crates/tests/build.rs | 4 +--- crates/tests/src/fuzz_ops.rs | 23 +++++++++++------------ crates/tests/src/tables.rs | 7 ++++--- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 05d39b4f..6376c74a 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,7 @@ # The rain-math-float bindings run over the test concretes compiled from this -# source (crates/tests/build.rs), through their constructors. +# source (crates/tests/build.rs), through their constructors. Forced so a +# value in the shell cannot point the tests elsewhere. [env] -RAIN_MATH_FLOAT_ARTIFACT = { value = "out/TestDecimalFloat.sol/TestDecimalFloat.json", relative = true } -RAIN_MATH_FLOAT_TEST_ARTIFACT = { value = "out/TestDecimalFloatHarness.sol/TestDecimalFloatHarness.json", relative = true } -RAIN_MATH_FLOAT_DEPLOY_MODE = "create" +RAIN_MATH_FLOAT_ARTIFACT = { value = "out/TestDecimalFloat.sol/TestDecimalFloat.json", relative = true, force = true } +RAIN_MATH_FLOAT_TEST_ARTIFACT = { value = "out/TestDecimalFloatHarness.sol/TestDecimalFloatHarness.json", relative = true, force = true } +RAIN_MATH_FLOAT_DEPLOY_MODE = { value = "create", force = true } diff --git a/crates/tests/build.rs b/crates/tests/build.rs index c44e56ce..33124c6c 100644 --- a/crates/tests/build.rs +++ b/crates/tests/build.rs @@ -9,9 +9,7 @@ fn main() { for watched in ["foundry.toml", "soldeer.lock", "src", "test"] { println!("cargo:rerun-if-changed={}", root.join(watched).display()); } - if !root.join("dependencies").is_dir() { - forge(&root, &["soldeer", "install"]); - } + forge(&root, &["soldeer", "install"]); forge(&root, &["build"]); } diff --git a/crates/tests/src/fuzz_ops.rs b/crates/tests/src/fuzz_ops.rs index ef320354..ec288a09 100644 --- a/crates/tests/src/fuzz_ops.rs +++ b/crates/tests/src/fuzz_ops.rs @@ -42,8 +42,7 @@ prop_compose! { } /// Check that two f64 values are approximately equal, allowing for -/// f64 rounding errors. Returns true if they're within a relative -/// tolerance of 1e-10 or both are effectively zero. +/// f64 rounding errors: equal, or within a relative tolerance of 1e-10. fn approx_eq(a: f64, b: f64) -> bool { if a == b { return true; @@ -52,9 +51,6 @@ fn approx_eq(a: f64, b: f64) -> bool { return false; } let max_abs = a.abs().max(b.abs()); - if max_abs < 1e-30 { - return true; - } ((a - b).abs() / max_abs) < 1e-10 } @@ -264,13 +260,16 @@ proptest! { prop_assume!(float.is_ok()); let float = float.unwrap(); let (back, lossless) = float.to_fixed_decimal_lossy(decimals).unwrap(); - if lossless { - prop_assert!( - back == value, - "round-trip failed: {} with {} decimals, got {}", - coefficient, decimals, back - ); - } + prop_assert!( + lossless, + "round-trip lost precision: {} with {} decimals", + coefficient, decimals + ); + prop_assert!( + back == value, + "round-trip failed: {} with {} decimals, got {}", + coefficient, decimals, back + ); } #[test] diff --git a/crates/tests/src/tables.rs b/crates/tests/src/tables.rs index 1d33eefc..6e5c80a3 100644 --- a/crates/tests/src/tables.rs +++ b/crates/tests/src/tables.rs @@ -294,9 +294,10 @@ fn test_antilog_table_small_generation() { } } -/// Verify the main log table — the base values (without ALT flag) -/// match exactly. ALT flags depend on the small table generation -/// so they get +1 tolerance via the ALT flag being set or not. +/// Verify the main log table: the base values (without ALT flag) match +/// exactly. The flags are transcribed from the published table, whose +/// split between the two mean-difference sets varies by row; the lookup +/// test exercises them by following them. #[test] fn test_log_table_generation() { let small = generate_log_table_small();