diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2178d4a..209790a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -58,4 +58,4 @@ jobs: - name: Test run: | - simplex test -v + simplex test --test-threads 4 diff --git a/Cargo.lock b/Cargo.lock index d345b91..0926d0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "arrayvec" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "autocfg" @@ -278,6 +278,18 @@ version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +[[package]] +name = "bitvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -303,6 +315,12 @@ 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" @@ -311,9 +329,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.65" +version = "1.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" dependencies = [ "find-msvc-tools", "jobserver", @@ -383,6 +401,27 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[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 = "cpufeatures" version = "0.2.17" @@ -394,9 +433,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -404,18 +443,24 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" @@ -537,6 +582,18 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + [[package]] name = "foldhash" version = "0.1.5" @@ -549,6 +606,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[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.32" @@ -596,18 +659,6 @@ dependencies = [ "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" @@ -616,7 +667,7 @@ checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", - "r-efi 6.0.0", + "r-efi", ] [[package]] @@ -722,9 +773,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b915661dd01db3f05050265b2477bcc6527b3792388e2749b41623cc592be67d" +checksum = "fe112b004901c62c2faa11f4f75e9864e0cc5af8da71c9115d184a3aa888749f" dependencies = [ "crossbeam-deque", "globset", @@ -736,6 +787,26 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "impl-codec" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d40b9d5e17727407e55028eafc22b2dc68781786e6d7eb8a21103f5058e3a14" +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", +] + [[package]] name = "indexmap" version = "2.14.0" @@ -769,11 +840,11 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] @@ -800,6 +871,21 @@ dependencies = [ "serde_json", ] +[[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.186" @@ -907,6 +993,34 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[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", +] + [[package]] name = "pathdiff" version = "0.2.3" @@ -950,6 +1064,26 @@ dependencies = [ "syn", ] +[[package]] +name = "primitive-types" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721a1da530b5a2633218dc9f75713394c983c352be88d2d7c9ee85e2c4c21794" +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-macro2" version = "1.0.106" @@ -980,15 +1114,15 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.3.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] -name = "r-efi" -version = "6.0.0" +name = "radium" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" @@ -1068,6 +1202,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + [[package]] name = "rustix" version = "0.38.44" @@ -1132,9 +1272,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "same-file" @@ -1308,6 +1448,7 @@ name = "simplicityhl_std" version = "0.1.0" dependencies = [ "anyhow", + "primitive-types", "rand", "smplx-std", ] @@ -1320,9 +1461,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smplx-build" -version = "0.0.7" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f090cc306bc000e1f926d0fbbf92080626530095a3b4541caf8f6b8bedb0a62" +checksum = "55a9a38dc0d803acdeed6217cdf9c1b3ded9220796315a458f47572269abaf2f" dependencies = [ "glob", "globwalk", @@ -1339,9 +1480,9 @@ dependencies = [ [[package]] name = "smplx-macros" -version = "0.0.7" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6758957dde925b558d5453fbf39ca551ee3e0ae04b032686aa5444e695455595" +checksum = "76e1091132a1f5157111920504e403fc8a4eb8a7814a376e4bd4c55a7fb6edff" dependencies = [ "smplx-build", "smplx-test", @@ -1350,9 +1491,9 @@ dependencies = [ [[package]] name = "smplx-regtest" -version = "0.0.7" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9e96c8226c35603c08f37dda2fa319f4d822790c2f0d922d690a952399a4c92" +checksum = "0ccf7e3eade934e890bcee3558af658de46177dbd6a5dd0302bb1a64b7701bbe" dependencies = [ "electrsd", "hex", @@ -1366,9 +1507,9 @@ dependencies = [ [[package]] name = "smplx-sdk" -version = "0.0.7" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68d02d154ff3b7459f86e60dd60edd693a7f60b91ba1ccb29c34be171796fce6" +checksum = "89d06536b493296672867c1a1ea8d67538c233af72624c18694ecb50691fcb74" dependencies = [ "bip39", "bitcoin_hashes", @@ -1386,9 +1527,9 @@ dependencies = [ [[package]] name = "smplx-std" -version = "0.0.7" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d7cde217178eddb3f50572d2d728560388cc74899e38ca9aee0378f3d261db" +checksum = "834fd437c9394610ece857755d5967124a0b97c6837bf1170ae8deed38ba4d32" dependencies = [ "either", "serde", @@ -1400,9 +1541,9 @@ dependencies = [ [[package]] name = "smplx-test" -version = "0.0.7" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200a3f0cf072ffb8df5f841e478d7c46d5649d6d2f0487b5c72a0731d7c882a1" +checksum = "82bf119d89ca2b2ac992377912efe7dd1915e0aa6a193ca5383fb8a3da86594c" dependencies = [ "electrsd", "proc-macro2", @@ -1429,6 +1570,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[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" @@ -1452,6 +1599,12 @@ dependencies = [ "unicode-ident", ] +[[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" @@ -1509,7 +1662,7 @@ dependencies = [ "indexmap", "serde_core", "serde_spanned", - "toml_datetime", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", "winnow 0.7.15", @@ -1524,6 +1677,27 @@ dependencies = [ "serde_core", ] +[[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 = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.3", +] + [[package]] name = "toml_parser" version = "1.1.2+spec-1.1.0" @@ -1545,6 +1719,18 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unicode-ident" version = "1.0.24" @@ -1566,6 +1752,12 @@ 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 = "untrusted" version = "0.9.0" @@ -1600,15 +1792,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasip2" -version = "1.0.4+wasi-0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" -dependencies = [ - "wit-bindgen", -] - [[package]] name = "wasm-bindgen" version = "0.2.126" @@ -1792,27 +1975,33 @@ name = "winnow" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] [[package]] -name = "wit-bindgen" -version = "0.57.1" +name = "wyz" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 01718c7..05cfb7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,8 @@ rust-version = "1.91.0" version = "0.1.0" [dependencies] -smplx-std = "0.0.7" +smplx-std = "0.0.8" anyhow = { version = "1.0.101" } rand = { version = "0.8.6" } +primitive-types = { version = "0.14" } diff --git a/README.md b/README.md index 209b95b..ce9a7b4 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,7 @@ This repository contains the standard library for [SimplicityHL](https://github. ## Installation -> Project currently uses Simplex version `0.0.7`. - -Install `siplexup`, then use it to install the pinned Simplex toolchain: +Install `simplexup`, then use it to install the pinned Simplex toolchain: ```bash curl -L https://smplx.simplicity-lang.org | bash diff --git a/simf/asserts_test.simf b/simf/asserts_test.simf index c09675e..bcaf598 100644 --- a/simf/asserts_test.simf +++ b/simf/asserts_test.simf @@ -1,4 +1,4 @@ -use crate::lib::asserts::{assert_eq_8, assert_eq_16, assert_eq_32, assert_eq_64, assert_eq_256, assert_none_8, assert_none_16, assert_none_32, assert_none_64,assert_none_128, assert_none_256}; +use crate::lib::asserts::{assert_eq_8, assert_eq_16, assert_eq_32, assert_eq_64,assert_eq_128, assert_eq_256, assert_none_8, assert_none_16, assert_none_32, assert_none_64, assert_none_128, assert_none_256}; use crate::helper::if_test_this_function; fn main() { @@ -27,13 +27,14 @@ fn main() { match if_test_this_function(1, fn_idx) { true => { assert_eq_16(unwrap(a_u16), unwrap(b_u16)); }, false => (), }; match if_test_this_function(2, fn_idx) { true => { assert_eq_32(unwrap(a_u32), unwrap(b_u32)); }, false => (), }; match if_test_this_function(3, fn_idx) { true => { assert_eq_64(unwrap(a_u64), unwrap(b_u64)); }, false => (), }; - match if_test_this_function(4, fn_idx) { true => { assert_eq_256(unwrap(a_u256), unwrap(b_u256)); }, false => (), }; + match if_test_this_function(4, fn_idx) { true => { assert_eq_128(unwrap(a_u128), unwrap(b_u128)); }, false => (), }; + match if_test_this_function(5, fn_idx) { true => { assert_eq_256(unwrap(a_u256), unwrap(b_u256)); }, false => (), }; // Assert None - match if_test_this_function(5, fn_idx) { true => { assert_none_8(a_u8); }, false => (), }; - match if_test_this_function(6, fn_idx) { true => { assert_none_16(a_u16); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert_none_32(a_u32); }, false => (), }; - match if_test_this_function(8, fn_idx) { true => { assert_none_64(a_u64); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_none_128(a_u128); }, false => (), }; - match if_test_this_function(10, fn_idx) { true => { assert_none_256(a_u256); }, false => (), }; + match if_test_this_function(6, fn_idx) { true => { assert_none_8(a_u8); }, false => (), }; + match if_test_this_function(7, fn_idx) { true => { assert_none_16(a_u16); }, false => (), }; + match if_test_this_function(8, fn_idx) { true => { assert_none_32(a_u32); }, false => (), }; + match if_test_this_function(9, fn_idx) { true => { assert_none_64(a_u64); }, false => (), }; + match if_test_this_function(10, fn_idx) { true => { assert_none_128(a_u128); }, false => (), }; + match if_test_this_function(11, fn_idx) { true => { assert_none_256(a_u256); }, false => (), }; } diff --git a/simf/helper.simf b/simf/helper.simf index 60ae726..d718091 100644 --- a/simf/helper.simf +++ b/simf/helper.simf @@ -1,3 +1,13 @@ +use crate::lib::logical_operations::not; + pub fn if_test_this_function(index: u8, flag: u8) -> bool { jet::eq_8(index, flag) } + +/// Asserts a result equals the expected bool value. +pub fn assert_bool(result: bool, expected_bool: bool) { + match expected_bool { + true => assert!(result), + false => assert!(not(result)), + } +} \ No newline at end of file diff --git a/simf/lib/asserts.simf b/simf/lib/asserts.simf index e5121d4..6714e6d 100644 --- a/simf/lib/asserts.simf +++ b/simf/lib/asserts.simf @@ -1,3 +1,5 @@ +use crate::lib::u128::{eq_128}; + /// Asserts that two u8 are equal pub fn assert_eq_8(a: u8, b: u8) { assert!(jet::eq_8(a, b)); @@ -18,7 +20,10 @@ pub fn assert_eq_64(a: u64, b: u64) { assert!(jet::eq_64(a, b)); } -// todo: assert_eq_128 +/// Asserts that two u128 are equal +pub fn assert_eq_128(a: u128, b: u128) { + assert!(eq_128(a, b)); +} /// Asserts that two u256 are equal pub fn assert_eq_256(a: u256, b: u256) { diff --git a/simf/lib/u128.simf b/simf/lib/u128.simf new file mode 100644 index 0000000..b5ad44e --- /dev/null +++ b/simf/lib/u128.simf @@ -0,0 +1,429 @@ +use crate::lib::logical_operations::{not, or, and}; +use crate::lib::u64::{safe_add_64, safe_sub_64}; +use crate::lib::u8::safe_sub_8; + +/// Bit logic + +/// Bitwise AND of two 128-bit values +pub fn and_128(a: u128, b: u128) -> u128 { + let (a_high, a_low): (u64, u64) = ::into(a); + let (b_high, b_low): (u64, u64) = ::into(b); + + <(u64, u64)>::into((jet::and_64(a_high, b_high), jet::and_64(a_low, b_low))) +} + +/// Bitwise OR of two 128-bit values +pub fn or_128(a: u128, b: u128) -> u128 { + let (a_high, a_low): (u64, u64) = ::into(a); + let (b_high, b_low): (u64, u64) = ::into(b); + + <(u64, u64)>::into((jet::or_64(a_high, b_high), jet::or_64(a_low, b_low))) +} + +/// Checks if two 128-bit values are equal +pub fn eq_128(a: u128, b: u128) -> bool { + let (a_high, a_low): (u64, u64) = ::into(a); + let (b_high, b_low): (u64, u64) = ::into(b); + + and(jet::eq_64(a_high, b_high), jet::eq_64(a_low, b_low)) +} + +/// Left-shift a 128-bit value by the given amount. Bits are filled with zeroes +pub fn left_shift_128(shift: u8, a: u128) -> u128 { + let (a_high, a_low): (u64, u64) = ::into(a); + + match jet::lt_8(shift, 64) { + true => { + let shifted_bits: u64 = jet::right_shift_64(safe_sub_8(64, shift), a_low); + + let res_high: u64 = jet::or_64(jet::left_shift_64(shift, a_high), shifted_bits); + + <(u64, u64)>::into((res_high, jet::left_shift_64(shift, a_low))) + }, + false => { + let shift: u8 = safe_sub_8(shift, 64); + + <(u64, u64)>::into((jet::left_shift_64(shift, a_low), 0)) + } + } +} + +/// Right-shift a 128-bit value by the given amount. Bits are filled with zeroes +pub fn right_shift_128(shift: u8, a: u128) -> u128 { + let (a_high, a_low): (u64, u64) = ::into(a); + + match jet::lt_8(shift, 64) { + true => { + let shifted_bits: u64 = jet::left_shift_64(safe_sub_8(64, shift), a_high); + + let res_low: u64 = jet::or_64(jet::right_shift_64(shift, a_low), shifted_bits); + + <(u64, u64)>::into((jet::right_shift_64(shift, a_high), res_low)) + }, + false => { + let shift: u8 = safe_sub_8(shift, 64); + + <(u64, u64)>::into((0, jet::right_shift_64(shift, a_high))) + } + } +} + +/// Arithmetic + +/// Checks if an integer is zero +pub fn is_zero_128(a: u128) -> bool { + let (a_high, a_low): (u64, u64) = ::into(a); + + and(jet::is_zero_64(a_high), jet::is_zero_64(a_low)) +} + +/// Checks if an integer is less than another integer +pub fn lt_128(a: u128, b: u128) -> bool { + let (a_high, a_low): (u64, u64) = ::into(a); + let (b_high, b_low): (u64, u64) = ::into(b); + + match jet::lt_64(a_high, b_high) { + true => true, + false => { + match jet::eq_64(a_high, b_high) { + true => jet::lt_64(a_low, b_low), + false => false, + } + } + } +} + +/// Checks if an integer is less than or equal to another integer +pub fn le_128(a: u128, b: u128) -> bool { + let (a_high, a_low): (u64, u64) = ::into(a); + let (b_high, b_low): (u64, u64) = ::into(b); + + match jet::lt_64(a_high, b_high) { + true => true, + false => { + match jet::eq_64(a_high, b_high) { + true => jet::le_64(a_low, b_low), + false => false, + } + } + } +} + +/// Adds two integers and return the carry +pub fn add_128(a: u128, b: u128) -> (bool, u128) { + let (a_high, a_low): (u64, u64) = ::into(a); + let (b_high, b_low): (u64, u64) = ::into(b); + + let (carry_high, sum_high): (bool, u64) = jet::add_64(a_high, b_high); + let (carry_low, sum_low): (bool, u64) = jet::add_64(a_low, b_low); + + match carry_low { + true => { + let (carry, sum_high): (bool, u64) = jet::add_64(sum_high, 1); + let res: u128 = <(u64, u64)>::into((sum_high, sum_low)); + + let final_carry: bool = or(carry, carry_high); + + (final_carry, res) + }, + false => { + let res: u128 = <(u64, u64)>::into((sum_high, sum_low)); + + (carry_high, res) + }, + } +} + +/// Adds the 128-bit integer with the 64-bit integer. Returns a tuple of the sum and the carry +pub fn add_128_64(a: u128, b: u64) -> (bool, u128) { + let (a_high, a_low): (u64, u64) = ::into(a); + + let (carry, res_low): (bool, u64) = jet::add_64(a_low, b); + + match carry { + true => { + let (carry, res_high): (bool, u64) = jet::add_64(a_high, 1); + let res: u128 = <(u64, u64)>::into((res_high, res_low)); + + (carry, res) + }, false => { + (carry, <(u64, u64)>::into((a_high, res_low))) + } + } +} + +/// Returns the sum of two u128 values wrapped in Some, or None if the result overflows u128 +pub fn checked_add_128(a: u128, b: u128) -> Option { + let (carry, sum): (bool, u128) = add_128(a, b); + + match carry { + true => None, + false => Some(sum), + } +} + +/// Returns the sum of two u128 values, panics if the result overflows u128 +pub fn safe_add_128(a: u128, b: u128) -> u128 { + unwrap(checked_add_128(a, b)) +} + +/// Subtracts the second integer from the first integer, and returns the borrow bit +pub fn sub_128(a: u128, b: u128) -> (bool, u128) { + let (a_high, a_low): (u64, u64) = ::into(a); + let (b_high, b_low): (u64, u64) = ::into(b); + + let (borrow_high, diff_high): (bool, u64) = jet::subtract_64(a_high, b_high); + let (borrow_low, diff_low): (bool, u64) = jet::subtract_64(a_low, b_low); + + match borrow_low { + true => { + let (borrow, diff_high): (bool, u64) = jet::subtract_64(diff_high, 1); + let res: u128 = <(u64, u64)>::into((diff_high, diff_low)); + + let final_borrow: bool = or(borrow, borrow_high); + + (final_borrow, res) + }, + false => { + let res: u128 = <(u64, u64)>::into((diff_high, diff_low)); + + (borrow_high, res) + }, + } +} + +/// Returns the difference of two u128 values wrapped in Some, or None if the result overflows u128 +pub fn checked_sub_128(a: u128, b: u128) -> Option { + let (borrow, diff): (bool, u128) = sub_128(a, b); + match borrow { + true => None, + false => Some(diff), + } +} + +/// Returns the difference of two u128 values, panics if the result overflows u128 +pub fn safe_sub_128(a: u128, b: u128) -> u128 { + unwrap(checked_sub_128(a, b)) +} + +/// Multiply two integers. The output is a 256-bit integer +/// The idea is that u128-bit `a` divides into 64-bit `a_high` and `a_low`, +/// so a = a_high * 2^64 + a_low. +/// In the same way, b = b_high * 2^64 + b_low. +/// Therefore, a * b = 2^128 * a_high * b_high + 2^64(a_high * b_low + a_low * b_high) + a_low * b_low. +pub fn mul_128(a: u128, b: u128) -> u256 { + let (a_high, a_low): (u64, u64) = ::into(a); + let (b_high, b_low): (u64, u64) = ::into(b); + + let highest: u128 = jet::multiply_64(a_high, b_high); + let lowest: u128 = jet::multiply_64(a_low, b_low); + let (word_1, word_0): (u64, u64) = ::into(lowest); + let (word_3, word_2): (u64, u64) = ::into(highest); + + let product_1: u128 = jet::multiply_64(a_high, b_low); + let product_2: u128 = jet::multiply_64(b_high, a_low); + let (carry_3, middle): (bool, u128) = add_128(product_1, product_2); + + let word_3: u64 = match carry_3 { + true => safe_add_64(word_3, 1), + false => word_3, + }; + + let (middle_2, middle_1): (u64, u64) = ::into(middle); + + let (carry_2, res_1): (bool, u64) = jet::add_64(word_1, middle_1); + let (carry_3, res_2): (bool, u64) = jet::add_64(word_2, middle_2); + let (carry_3, res_2): (bool, u64) = match carry_2 { + true => { + let (carry, res): (bool, u64) = jet::add_64(res_2, 1); + + (or(carry_3, carry), res) + }, + false => (carry_3, res_2), + }; + + let res_3: u64 = match carry_3 { + true => safe_add_64(word_3, 1), + false => word_3, + }; + + let res_1_0: u128 = <(u64, u64)>::into((res_1, word_0)); + let res_3_2: u128 = <(u64, u64)>::into((res_3, res_2)); + + <(u128, u128)>::into((res_3_2, res_1_0)) +} + +/// Returns the product of two u128 values wrapped in Some, or None if the result overflows u128 +pub fn checked_mul_128(a: u128, b: u128) -> Option { + let result: u256 = mul_128(a, b); + + let (high, low): (u128, u128) = ::into(result); + + match is_zero_128(high) { + true => Some(low), + false => None, + } +} + +/// Returns the product of two u128 values, panics if the result overflows u128 +pub fn safe_mul_128(a: u128, b: u128) -> u128 { + unwrap(checked_mul_128(a, b)) +} + +/// Splits the u256 integer into four u64 integers +pub fn split_256_into_64(a: u256) -> ((u64, u64), (u64, u64)) { + let (high, low): (u128, u128) = ::into(a); + + (::into(high), ::into(low)) +} + +/// Helper function, can be used with jet::div_mod_128_64. +/// Normalizes two u128 values by multiplying both by the same factor, +/// ensuring that the most significant non-zero word of `b` is at least 2^63. +/// +/// If `is_b_u128` is true, expects the upper half of `b` to be non-zero. +/// If `is_b_u128` is false, expects `b` to fit into u64. +/// +/// Division algorithms operate in base 2^64, so the normalization threshold is 2^63. +pub fn normalize_to_threshold(a: u128, b: u128, is_b_u128: bool) -> (u256, u128) { + let threshold: u64 = jet::left_shift_64(63, 1); + + let (b_high, b_low): (u64, u64) = ::into(b); + + let b_highest_word: u64 = match is_b_u128 { + true => b_high, + false => { + assert!(jet::is_zero_64(b_high)); + b_low + } + }; + assert!(not(jet::is_zero_64(b_highest_word))); + + let (norm, remainder): (u64, u64) = jet::div_mod_64(threshold, b_highest_word); + + let norm: u64 = match jet::is_zero_64(remainder) { + true => norm, + false => safe_add_64(norm, 1), + }; + let norm: u128 = <(u64, u64)>::into((0, norm)); + + match jet::lt_64(b_highest_word, threshold) { + true => (mul_128(a, norm), safe_mul_128(b, norm)), + false => (<(u128, u128)>::into((0, a)), b), + } +} + +/// Divides the first u128 integer by the second u128 integer, +/// returns the u64 quotient and the u128 remainder. +/// Implements Algorithm D by Donald Knuth. +/// Requires the upper half of the divisor to be non-zero. +pub fn algorithm_d(dividend: u128, divisor: u128) -> (u64, u128) { + let (norm_dividend, norm_divisor): (u256, u128) = normalize_to_threshold(dividend, divisor, true); + + // normalized dividend fits into 192 bits + let ((_, u2), (u1, u0)): ((u64, u64), (u64, u64)) = split_256_into_64(norm_dividend); + let (v1, v0): (u64, u64) = ::into(norm_divisor); + + let (q_hat, r_hat): (u64, u64) = jet::div_mod_128_64(<(u64, u64)>::into((u2, u1)), v1); + let u0: u128 = <(u64, u64)>::into((0, u0)); + + // correcting estimation, q_hat is off by at most 2 + let q: u64 = match lt_128(safe_add_128(<(u64, u64)>::into((r_hat, 0)), u0), jet::multiply_64(q_hat, v0)) { + true => { + let q_hat: u64 = safe_sub_64(q_hat, 1); + let (carry, r_hat): (bool, u64) = jet::add_64(r_hat, v1); + + match and(not(carry), lt_128(safe_add_128(<(u64, u64)>::into((r_hat, 0)), u0), jet::multiply_64(q_hat, v0))) { + true => safe_sub_64(q_hat, 1), + false => q_hat, + } + }, + false => q_hat, + }; + + let remainder: u128 = safe_sub_128(dividend, safe_mul_128(divisor, <(u64, u64)>::into((0, q)))); + (q, remainder) +} + +/// Divides the 128-bit integer by the 64-bit integer, +/// returns a tuple of the u128 quotient and the u64 remainder +pub fn div_mod_128_64(a: u128, b: u64) -> (u128, u64) { + let (a_high, a_low): (u64, u64) = ::into(a); + + // calculate the upper half of the quotient + let (q_high, remainder): (u64, u64) = jet::div_mod_64(a_high, b); + + // a' = remainder * 2^64 + a_low + let a_prime: u128 = <(u64, u64)>::into((remainder, a_low)); + + // we need to normalize here, because jet::div_mod_128_64 only acceps b >= 2^63 + let (a_normalized, b_normalized): (u256, u128) = normalize_to_threshold(a_prime, <(u64, u64)>::into((0, b)), false); + + // a_normalized fits into u128, because remainder < b and b_normalized fits into u64 + let (_, a_normalized): (u128, u128) = ::into(a_normalized); + let (_, b_normalized): (u64, u64) = ::into(b_normalized); + + // remainder < b, so (remainder * 2^64 + a_low) / b fits into u64 + let (q_low, _): (u64, u64) = jet::div_mod_128_64(a_normalized, b_normalized); // remainder is not valid here due to normalizing + + let (_, remainder): (u64, u64) = ::into(safe_sub_128(a_prime, jet::multiply_64(q_low, b))); + + (<(u64, u64)>::into((q_high, q_low)), remainder) +} + +/// Divides the first integer by the second integer, +/// returns the quotient and the remainder +pub fn div_mod_128(a: u128, b: u128) -> (u128, u128) { + let (a_high, a_low): (u64, u64) = ::into(a); + let (b_high, b_low): (u64, u64) = ::into(b); + + match lt_128(a, b) { + true => (0, a), + false => { + match and(jet::is_zero_64(a_high), jet::is_zero_64(b_high)) { + true => { + // if both a_high and b_high is equal to zero, this narrows down to 64-bit division + let (q, r): (u64, u64) = jet::div_mod_64(a_low, b_low); + (<(u64, u64)>::into((0, q)), <(u64, u64)>::into((0, r))) + }, + false => { + match jet::eq_64(a_high, b_high) { + true => (1, <(u64, u64)>::into((0, safe_sub_64(a_low, b_low)))), + false => { + match jet::is_zero_64(b_high) { + true => { + let (q, r): (u128, u64) = div_mod_128_64(a, b_low); + (q, <(u64, u64)>::into((0, r))) + }, + false => { + let (q, r): (u64, u128) = algorithm_d(a, b); + (<(u64, u64)>::into((0, q)), r) + } + } + } + } + } + } + } + } +} + +/// Divide the first integer by the second integer, returns the quotient +pub fn div_128(a: u128, b: u128) -> u128 { + let (q, _): (u128, u128) = div_mod_128(a, b); + + q +} + +/// Returns the quotient of two u128 values wrapped in Some, or None if the result overflows u128 +pub fn checked_div_128(a: u128, b: u128) -> Option { + match is_zero_128(b) { + true => None, + false => Some(div_128(a, b)), + } +} + +/// Returns the quotient of two u128 values, panics if the result overflows u128 +pub fn safe_div_128(a: u128, b: u128) -> u128 { + unwrap(checked_div_128(a, b)) +} diff --git a/simf/lib/u32.simf b/simf/lib/u32.simf index 909fc56..aad32f5 100644 --- a/simf/lib/u32.simf +++ b/simf/lib/u32.simf @@ -13,7 +13,7 @@ pub fn safe_add_32(a: u32, b: u32) -> u32 { unwrap(checked_add_32(a, b)) } -/// Returns the sum of two u32 values, panics if the result overflows u32 +/// Returns the difference of two u32 values wrapped in Some, or None if the result overflows u32 pub fn checked_sub_32(a: u32, b: u32) -> Option { let (borrow, diff): (bool, u32) = jet::subtract_32(a, b); diff --git a/simf/lib/u64.simf b/simf/lib/u64.simf index 913dbdc..3f6d038 100644 --- a/simf/lib/u64.simf +++ b/simf/lib/u64.simf @@ -13,7 +13,7 @@ pub fn safe_add_64(a: u64, b: u64) -> u64 { unwrap(checked_add_64(a, b)) } -/// Returns the sum of two u64 values, panics if the result overflows u64 +/// Returns the difference of two u64 values wrapped in Some, or None if the result overflows u64 pub fn checked_sub_64(a: u64, b: u64) -> Option { let (borrow, diff): (bool, u64) = jet::subtract_64(a, b); diff --git a/simf/u128_test.simf b/simf/u128_test.simf new file mode 100644 index 0000000..f772705 --- /dev/null +++ b/simf/u128_test.simf @@ -0,0 +1,43 @@ +use crate::lib::u128::{ checked_add_128, safe_add_128, checked_sub_128, safe_sub_128, checked_mul_128, safe_mul_128, checked_div_128, safe_div_128, eq_128 }; +use crate::lib::asserts::{assert_none_128, assert_eq_128}; +use crate::helper::if_test_this_function; + +/// Asserts a `checked_*` result equals the expected Option. +/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single +/// witness value carries both, removing the need for a separate overflow flag. +fn assert_eq_opt(result: Option, expected: Option) { + match expected { + None => assert_none_128(result), + Some(e: u128) => assert_eq_128(unwrap(result), e), + } +} + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u128 = witness::FIRST_ARG; + let b: u128 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + let expected_bool: bool = witness::EXPECTED_BOOL; + let second_expected: u128 = witness::SECOND_EXPECTED; // for cases where the result is a 256 bit value + let third_expected: u128 = witness::THIRD_EXPECTED; // for cases where the result is 256 bit + 128 bit values + + /// Safe functions + + // add + match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_128(a, b), expected); }, false => (), }; + match if_test_this_function(1, fn_idx) { true => { assert!(eq_128(safe_add_128(a, b), unwrap(expected))); }, false => (), }; + + // sub + match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_128(a, b), expected); }, false => (), }; + match if_test_this_function(3, fn_idx) { true => { assert!(eq_128(safe_sub_128(a, b), unwrap(expected))); }, false => (), }; + + // mul + match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_128(a, b), expected); }, false => (), }; + match if_test_this_function(5, fn_idx) { true => { assert!(eq_128(safe_mul_128(a, b), unwrap(expected))); }, false => (), }; + + // div + match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_128(a, b), expected); }, false => (), }; + match if_test_this_function(7, fn_idx) { true => { assert!(eq_128(safe_div_128(a, b), unwrap(expected))); }, false => (), }; +} diff --git a/simf/u128_test_arithmetic.simf b/simf/u128_test_arithmetic.simf new file mode 100644 index 0000000..be793f3 --- /dev/null +++ b/simf/u128_test_arithmetic.simf @@ -0,0 +1,112 @@ +use crate::lib::u128::{ eq_128, is_zero_128, lt_128, le_128, add_128, add_128_64, sub_128, mul_128, split_256_into_64, normalize_to_threshold, algorithm_d, div_mod_128_64, div_mod_128, div_128 }; +use crate::helper::{if_test_this_function, assert_bool}; + +/// Asserts a result equals expected u128 and bool values. +/// Used for functions that return carry or borrow bool value. +fn assert_eq_uint_bool(result: (bool, u128), expected: u128, expected_bool: bool) { + let (bool_res, uint_res): (bool, u128) = result; + + assert_bool(bool_res, expected_bool); + + assert!(eq_128(uint_res, expected)); +} + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u128 = witness::FIRST_ARG; + let b: u128 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + let expected_bool: bool = witness::EXPECTED_BOOL; + let second_expected: u128 = witness::SECOND_EXPECTED; // for cases where the result is a 256 bit value + let third_expected: u128 = witness::THIRD_EXPECTED; // for cases where the result is 256 bit + 128 bit values + + /// Arithmetic + + match if_test_this_function(192, fn_idx) { true => { assert_bool(is_zero_128(a), expected_bool); }, false => (), }; + match if_test_this_function(193, fn_idx) { true => { assert_bool(lt_128(a, b), expected_bool); }, false => (), }; + match if_test_this_function(194, fn_idx) { true => { assert_bool(le_128(a, b), expected_bool); }, false => (), }; + + match if_test_this_function(195, fn_idx) { true => { assert_eq_uint_bool(add_128(a, b), unwrap(expected), expected_bool); }, false => (), }; + match if_test_this_function(196, fn_idx) { true => { let (_, b): (u64, u64) = ::into(b); assert_eq_uint_bool(add_128_64(a, b), unwrap(expected), expected_bool); }, false => (), }; + match if_test_this_function(197, fn_idx) { true => { assert_eq_uint_bool(sub_128(a, b), unwrap(expected), expected_bool); }, false => (), }; + + match if_test_this_function(198, fn_idx) { + true => { + let result: u256 = mul_128(a, b); + + let (result_high, result_low): (u128, u128) = ::into(result); + + assert!(eq_128(result_high, unwrap(expected))); + assert!(eq_128(result_low, second_expected)); + }, + false => (), + }; + + match if_test_this_function(199, fn_idx) { + true => { + let input: u256 = <(u128, u128)>::into((a, b)); + let ((res1, res2), (res3, res4)): ((u64, u64), (u64, u64)) = split_256_into_64(input); + + let (expected1, expected2): (u64, u64) = ::into(unwrap(expected)); + let (expected3, expected4): (u64, u64) = ::into(second_expected); + + assert!(jet::eq_64(res1, expected1)); + assert!(jet::eq_64(res2, expected2)); + assert!(jet::eq_64(res3, expected3)); + assert!(jet::eq_64(res4, expected4)); + }, + false => (), + }; + + match if_test_this_function(200, fn_idx) { + true => { + let (result_a, result_b): (u256, u128) = normalize_to_threshold(a, b, expected_bool); + + let (result_a_high, result_a_low): (u128, u128) = ::into(result_a); + + assert!(eq_128(result_a_high, unwrap(expected))); + assert!(eq_128(result_a_low, second_expected)); + assert!(eq_128(result_b, third_expected)); + }, + false => (), + }; + + match if_test_this_function(201, fn_idx) { + true => { + let (_, expected_q): (u64, u64) = ::into(unwrap(expected)); + + let (q, r): (u64, u128) = algorithm_d(a, b); + + assert!(jet::eq_64(q, expected_q)); + assert!(eq_128(r, second_expected)); + }, + false => (), + }; + + match if_test_this_function(202, fn_idx) { + true => { + let (_, b): (u64, u64) = ::into(b); + let (_, expected_r): (u64, u64) = ::into(second_expected); + + let (q, r): (u128, u64) = div_mod_128_64(a, b); + + assert!(eq_128(q, unwrap(expected))); + assert!(jet::eq_64(r, expected_r)); + }, + false => (), + }; + + match if_test_this_function(203, fn_idx) { + true => { + let (q, r): (u128, u128) = div_mod_128(a, b); + + assert!(eq_128(q, unwrap(expected))); + assert!(eq_128(r, second_expected)); + }, + false => (), + }; + + match if_test_this_function(204, fn_idx) { true => { assert!(eq_128(div_128(a, b), unwrap(expected))); }, false => (), }; +} diff --git a/simf/u128_test_bits.simf b/simf/u128_test_bits.simf new file mode 100644 index 0000000..6682883 --- /dev/null +++ b/simf/u128_test_bits.simf @@ -0,0 +1,36 @@ +use crate::lib::u128::{ and_128, or_128, eq_128, left_shift_128, right_shift_128 }; +use crate::helper::{if_test_this_function, assert_bool}; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u128 = witness::FIRST_ARG; + let b: u128 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + let expected_bool: bool = witness::EXPECTED_BOOL; + + /// Bit logic + + match if_test_this_function(192, fn_idx) { true => { assert!(eq_128(and_128(a, b), unwrap(expected))); }, false => (), }; + match if_test_this_function(193, fn_idx) { true => { assert!(eq_128(or_128(a, b), unwrap(expected))); }, false => (), }; + match if_test_this_function(194, fn_idx) { true => { assert_bool(eq_128(a, b), expected_bool); }, false => (), }; + + match if_test_this_function(195, fn_idx) { + true => { + let (_, a): (u64, u64) = ::into(a); + let shift: u8 = jet::rightmost_64_8(a); + + assert!(eq_128(left_shift_128(shift, b), unwrap(expected))); + }, false => (), + }; + + match if_test_this_function(196, fn_idx) { + true => { + let (_, a): (u64, u64) = ::into(a); + let shift: u8 = jet::rightmost_64_8(a); + + assert!(eq_128(right_shift_128(shift, b), unwrap(expected))); + }, false => (), + }; +} diff --git a/simf/u64_test.simf b/simf/u64_test.simf index 955d2c3..26e129a 100644 --- a/simf/u64_test.simf +++ b/simf/u64_test.simf @@ -19,6 +19,7 @@ fn main() { let b: u64 = witness::SECOND_ARG; let expected: Option = witness::EXPECTED; + // add match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_64(a, b), expected); }, false => (), }; match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_64(safe_add_64(a, b), unwrap(expected))); }, false => (), }; diff --git a/tests/asserts_test.rs b/tests/asserts_test.rs index 5c2e82f..ab8790c 100644 --- a/tests/asserts_test.rs +++ b/tests/asserts_test.rs @@ -16,6 +16,7 @@ enum FunctionToTest { AssertEq16, AssertEq32, AssertEq64, + AssertEq128, AssertEq256, AssertNone8, AssertNone16, @@ -94,6 +95,10 @@ fn build_witness(function: FunctionToTest, same: bool, none: bool) -> AssertsTes let (a, b) = generate_uints_in_one_range(same, 0, u64::MAX as u128); (witness.first_arg_u64, witness.second_arg_u64) = (Some(a as u64), Some(b as u64)); } + FunctionToTest::AssertEq128 => { + let (a, b) = generate_uints_in_one_range(same, 0, u128::MAX); + (witness.first_arg_u128, witness.second_arg_u128) = (Some(a), Some(b)); + } FunctionToTest::AssertEq256 => { let (a, b) = generate_uints_in_one_range(same, 0, u8::MAX as u128); (witness.first_arg_u256, witness.second_arg_u256) = @@ -236,6 +241,28 @@ mod asserts_test { ) } + #[simplex::test] + fn assert_eq_128_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq128, + true, + false, + Expect::Ok, + ) + } + + #[simplex::test] + fn assert_eq_128_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq128, + false, + false, + Expect::AssertFailed, + ) + } + #[simplex::test] fn assert_eq_256_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { run_assert( diff --git a/tests/u128_test.rs b/tests/u128_test.rs new file mode 100644 index 0000000..d64fa28 --- /dev/null +++ b/tests/u128_test.rs @@ -0,0 +1,41 @@ +mod common; + +use common::uint::TestUint; + +use simplicityhl_std::artifacts::u128_test::U128TestProgram; +use simplicityhl_std::artifacts::u128_test::derived_u128_test::{ + U128TestArguments, U128TestWitness, +}; + +// The only per-width code for the common operations. +impl TestUint for u128 { + type Program = U128TestProgram; + type Witness = U128TestWitness; + + const ZERO: u128 = 0; + const ONE: u128 = 1; + const MAX: u128 = u128::MAX; + const HALF_MAX: u128 = u128::MAX / 2; + const MUL_BOUND: u128 = 1 << 64; // 2^(128/2) + + fn program() -> U128TestProgram { + U128TestProgram::new(U128TestArguments {}) + } + + fn witness(op: u8, a: u128, b: u128, expected: Option) -> U128TestWitness { + U128TestWitness { + function_index: op, + first_arg: a, + second_arg: b, + expected, + ..Default::default() + } + } +} + +mod u128_tests { + use super::*; + + // Stamps the 16 `#[simplex::test]` entry points for u128. Logic lives in common::uint. + uint_tests!(u128); +} diff --git a/tests/u128_test_arithmetic.rs b/tests/u128_test_arithmetic.rs new file mode 100644 index 0000000..fdc986c --- /dev/null +++ b/tests/u128_test_arithmetic.rs @@ -0,0 +1,828 @@ +mod common; + +use primitive_types::U256; +use rand::Rng; + +use common::core::{Expect, run}; + +use simplicityhl_std::artifacts::u128_test_arithmetic::U128TestArithmeticProgram; +use simplicityhl_std::artifacts::u128_test_arithmetic::derived_u128_test_arithmetic::{ + U128TestArithmeticArguments, U128TestArithmeticWitness, +}; + +enum FunctionToTest { + IsZero128, + Lt128, + Le128, + Add128, + Add128_64, + Sub128, + Mul128, + Split256Into64, + NormalizeToThreshold, + AlgorithmD, + DivMod128_64, + DivMod128, + Div128, +} + +#[inline] +fn op(o: FunctionToTest) -> u8 { + o as u8 + 192 +} + +const DEFAULT_BOOL: bool = false; +const DEFAULT_EXPECTED: u128 = 0; + +fn program() -> U128TestArithmeticProgram { + U128TestArithmeticProgram::new(U128TestArithmeticArguments {}) +} + +fn build_witness( + function: u8, + a: u128, + b: u128, + expected: Option, + expected_bool: bool, + second_expected: u128, + third_expected: u128, +) -> U128TestArithmeticWitness { + U128TestArithmeticWitness { + function_index: function, + first_arg: a, + second_arg: b, + expected, + expected_bool, + second_expected, + third_expected, + } +} + +fn split_helper(a: U256) -> (u128, u128) { + let a_high = (a >> 128).as_u128(); + let a_low = a.low_u128(); + + (a_high, a_low) +} + +mod u128_tests { + use super::*; + + #[simplex::test] + fn u128_test_is_zero_128_true(context: simplex::TestContext) -> anyhow::Result<()> { + let a = 0; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::IsZero128), + a, + DEFAULT_EXPECTED, + Some(DEFAULT_EXPECTED), + true, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_is_zero_128_false(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u128::MAX); + + run( + &context, + program(), + build_witness( + op(FunctionToTest::IsZero128), + a, + DEFAULT_EXPECTED, + Some(DEFAULT_EXPECTED), + false, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_lt_128_less(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = a + 1; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Lt128), + a, + b, + Some(DEFAULT_EXPECTED), + true, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_lt_128_eq(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = a; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Lt128), + a, + b, + Some(DEFAULT_EXPECTED), + false, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_lt_128_bigger(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u128::MAX); + let b = a - 1; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Lt128), + a, + b, + Some(DEFAULT_EXPECTED), + false, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_le_128_less(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = a + 1; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Le128), + a, + b, + Some(DEFAULT_EXPECTED), + true, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_le_128_eq(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = a; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Le128), + a, + b, + Some(DEFAULT_EXPECTED), + true, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_le_128_bigger(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u128::MAX); + let b = a - 1; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Le128), + a, + b, + Some(DEFAULT_EXPECTED), + false, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_add_128_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX / 2); + let b = rand::thread_rng().gen_range(0..=u128::MAX / 2); + let result = a + b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Add128), + a, + b, + Some(result), + false, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_add_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = u128::MAX; + let b = rand::thread_rng().gen_range(1..=u128::MAX); + let result = b - 1; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Add128), + a, + b, + Some(result), + true, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_add_128_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX / 2); + let b = rand::thread_rng().gen_range(0..=u64::MAX) as u128; + let result = a + b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Add128_64), + a, + b, + Some(result), + false, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_add_128_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = u128::MAX; + let b = rand::thread_rng().gen_range(1..=u64::MAX) as u128; + let result = b - 1; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Add128_64), + a, + b, + Some(result), + true, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_sub_128_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(0..=a); + let result = a - b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Sub128), + a, + b, + Some(result), + false, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_sub_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = u128::MAX; + let result = a + 1; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Sub128), + a, + b, + Some(result), + true, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_mul_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = rand::thread_rng().gen_range(0..u128::MAX); + let result = U256::from(a) * U256::from(b); + + let (result_high, result_low) = split_helper(result); + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Mul128), + a, + b, + Some(result_high), + DEFAULT_BOOL, + result_low, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_split_256_into_64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(0..=u128::MAX); + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Split256Into64), + a, + b, + Some(a), + DEFAULT_BOOL, + b, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_normalize_to_threshold_b_is_u64( + context: simplex::TestContext, + ) -> anyhow::Result<()> { + let threshold = 1u128 << 63; + + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(1..threshold); + + let norm: u128 = threshold.div_ceil(b); + + let result_a = U256::from(a) * U256::from(norm); + let result_b = b * norm; + let (result_a_high, result_a_low) = split_helper(result_a); + + run( + &context, + program(), + build_witness( + op(FunctionToTest::NormalizeToThreshold), + a, + b, + Some(result_a_high), + false, + result_a_low, + result_b, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_normalize_to_threshold_b_is_big_enough_not_normalize( + context: simplex::TestContext, + ) -> anyhow::Result<()> { + let threshold = 1 << 63; + + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(threshold..=u64::MAX as u128); + + run( + &context, + program(), + build_witness( + op(FunctionToTest::NormalizeToThreshold), + a, + b, + Some(0), + false, + a, + b, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_normalize_to_threshold_b_is_u128( + context: simplex::TestContext, + ) -> anyhow::Result<()> { + let threshold = 1u128 << 63; + + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range((u64::MAX as u128) + 1..=u128::MAX); + + let b_high = b >> 64; + + let norm: u128 = threshold.div_ceil(b_high); + + let result_a = U256::from(a) * U256::from(norm); + let result_b = b * norm; + let (result_a_high, result_a_low) = split_helper(result_a); + + run( + &context, + program(), + build_witness( + op(FunctionToTest::NormalizeToThreshold), + a, + b, + Some(result_a_high), + true, + result_a_low, + result_b, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_normalize_to_threshold_b_is_u64_fail( + context: simplex::TestContext, + ) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(u64::MAX as u128..=u128::MAX); + + run( + &context, + program(), + build_witness( + op(FunctionToTest::NormalizeToThreshold), + a, + b, + Some(DEFAULT_EXPECTED), + false, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::AssertFailed, + ) + } + + #[simplex::test] + fn u128_test_normalize_to_threshold_b_is_u128_fail( + context: simplex::TestContext, + ) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(1..=u64::MAX as u128); + + run( + &context, + program(), + build_witness( + op(FunctionToTest::NormalizeToThreshold), + a, + b, + Some(DEFAULT_EXPECTED), + true, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::AssertFailed, + ) + } + + #[simplex::test] + fn u128_test_normalize_to_threshold_b_is_zero_fail( + context: simplex::TestContext, + ) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = 0; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::NormalizeToThreshold), + a, + b, + Some(DEFAULT_EXPECTED), + false, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::AssertFailed, + ) + } + + #[simplex::test] + fn u128_test_algorithm_d(context: simplex::TestContext) -> anyhow::Result<()> { + let b = rand::thread_rng().gen_range(u64::MAX as u128..u128::MAX); + let a = rand::thread_rng().gen_range(b..=u128::MAX); + + let q = a / b; + let r = a - q * b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::AlgorithmD), + a, + b, + Some(q), + DEFAULT_BOOL, + r, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_algorithm_d_fail(context: simplex::TestContext) -> anyhow::Result<()> { + let b = rand::thread_rng().gen_range(1..=u64::MAX as u128); + let a = rand::thread_rng().gen_range(b..=u128::MAX); + + let q = a / b; + let r = a - q * b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::AlgorithmD), + a, + b, + Some(q), + DEFAULT_BOOL, + r, + DEFAULT_EXPECTED, + ), + Expect::AssertFailed, + ) + } + + #[simplex::test] + fn test_div_mod_128_64(context: simplex::TestContext) -> anyhow::Result<()> { + //todo + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(1..=u64::MAX as u128); + + let q = a / b; + let r = a - q * b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::DivMod128_64), + a, + b, + Some(q), + DEFAULT_BOOL, + r, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn test_div_mod_128_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = 0; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::DivMod128_64), + a, + b, + Some(DEFAULT_EXPECTED), + DEFAULT_BOOL, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::AssertFailed, + ) + } + + #[simplex::test] + fn u128_test_div_mod_128_a_less_than_b(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = rand::thread_rng().gen_range(a..=u128::MAX); + + let q = a / b; + let r = a - q * b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::DivMod128), + a, + b, + Some(q), + DEFAULT_BOOL, + r, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_div_mod_128_fits_into_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u64::MAX) as u128; + let b = rand::thread_rng().gen_range(1..=u64::MAX) as u128; + + let q = a / b; + let r = a - q * b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::DivMod128), + a, + b, + Some(q), + DEFAULT_BOOL, + r, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_div_mod_128_q_is_1(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = ((a >> 64u128) << 64u128) + rand::thread_rng().gen_range(0..u64::MAX) as u128; + + let q = a / b; + let r = a - q * b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::DivMod128), + a, + b, + Some(q), + DEFAULT_BOOL, + r, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_div_mod_128_b_is_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let b = rand::thread_rng().gen_range(1..u64::MAX as u128); + let a = rand::thread_rng().gen_range(b..=u128::MAX); + + let q = a / b; + let r = a - q * b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::DivMod128), + a, + b, + Some(q), + DEFAULT_BOOL, + r, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_div_mod_128_b_is_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let b = rand::thread_rng().gen_range(u64::MAX as u128..u128::MAX); + let a = rand::thread_rng().gen_range(b + 1..=u128::MAX); + + let q = a / b; + let r = a - q * b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::DivMod128), + a, + b, + Some(q), + DEFAULT_BOOL, + r, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_div_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(1..=u128::MAX); + let result = a / b; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Div128), + a, + b, + Some(result), + DEFAULT_BOOL, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_div_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = 0; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Div128), + a, + b, + Some(DEFAULT_EXPECTED), + DEFAULT_BOOL, + DEFAULT_EXPECTED, + DEFAULT_EXPECTED, + ), + Expect::AssertFailed, + ) + } +} diff --git a/tests/u128_test_bits.rs b/tests/u128_test_bits.rs new file mode 100644 index 0000000..15a34b4 --- /dev/null +++ b/tests/u128_test_bits.rs @@ -0,0 +1,155 @@ +mod common; + +use rand::Rng; + +use common::core::{Expect, run}; + +use simplicityhl_std::artifacts::u128_test_bits::U128TestBitsProgram; +use simplicityhl_std::artifacts::u128_test_bits::derived_u128_test_bits::{ + U128TestBitsArguments, U128TestBitsWitness, +}; + +enum FunctionToTest { + And128, + Or128, + Eq128, + LeftShift128, + RightShift128, +} + +#[inline] +fn op(o: FunctionToTest) -> u8 { + o as u8 + 192 +} + +const DEFAULT_BOOL: bool = false; +const DEFAULT_EXPECTED: u128 = 0; + +fn program() -> U128TestBitsProgram { + U128TestBitsProgram::new(U128TestBitsArguments {}) +} + +fn build_witness( + function: u8, + a: u128, + b: u128, + expected: Option, + expected_bool: bool, +) -> U128TestBitsWitness { + U128TestBitsWitness { + function_index: function, + first_arg: a, + second_arg: b, + expected, + expected_bool, + } +} + +mod u128_tests { + use super::*; + + #[simplex::test] + fn u128_test_and_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(0..=u128::MAX); + let result = a & b; + + run( + &context, + program(), + build_witness(op(FunctionToTest::And128), a, b, Some(result), DEFAULT_BOOL), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_or_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(0..=u128::MAX); + let result = a | b; + + run( + &context, + program(), + build_witness(op(FunctionToTest::Or128), a, b, Some(result), DEFAULT_BOOL), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_eq_128_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Eq128), + a, + a, + Some(DEFAULT_EXPECTED), + true, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_eq_128_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u128::MAX); + let b = a - 1; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::Eq128), + a, + b, + Some(DEFAULT_EXPECTED), + false, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_left_shift_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=(u8::MAX / 2 + 1) as u128); + let b = rand::thread_rng().gen_range(0..=u128::MAX); + let result = b << a; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::LeftShift128), + a, + b, + Some(result), + DEFAULT_BOOL, + ), + Expect::Ok, + ) + } + + #[simplex::test] + fn u128_test_right_shift_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=(u8::MAX / 2 + 1) as u128); + let b = rand::thread_rng().gen_range(0..=u128::MAX); + let result = b >> a; + + run( + &context, + program(), + build_witness( + op(FunctionToTest::RightShift128), + a, + b, + Some(result), + DEFAULT_BOOL, + ), + Expect::Ok, + ) + } +}