diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..421c13b --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,61 @@ +name: Smplx-lint + +on: + workflow_dispatch: + push: + branches: + - master + pull_request: + branches: + - master + - dev + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + SIMPLEX_VERSION: 0.0.11 + +jobs: + lint: + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + persist-credentials: false + submodules: true + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: "1.91.0" + components: rustfmt, clippy + + - name: Use Rust cache + uses: Swatinem/rust-cache@v2 + + - name: Install simplex-cli + uses: BlockstreamResearch/simplicityhl-toolchain@v0.0.2 + with: + components: simplex@${{ env.SIMPLEX_VERSION }} + + # For building generated files + - name: Generate contract artifacts + shell: bash + run: | + simplex build + + - name: Check formatting + run: | + cargo fmt --all --check + + - name: Run clippy + run: | + cargo clippy --workspace --all-targets --all-features -- -D warnings diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index da161af..bed4e67 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,11 +17,12 @@ concurrency: env: CARGO_TERM_COLOR: always RUST_BACKTRACE: full + SIMPLEX_VERSION: 0.0.11 jobs: simplex-tests: runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 60 permissions: contents: read strategy: @@ -47,7 +48,7 @@ jobs: - name: Install simplex-cli uses: BlockstreamResearch/simplicityhl-toolchain@v0.0.2 with: - components: simplex + components: simplex@${{ env.SIMPLEX_VERSION }} - name: Generate contract artifacts shell: bash @@ -60,4 +61,4 @@ jobs: - name: Test run: | - simplex test --test-threads 4 + simplex test --test-threads 4 -v diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a12e66..6657aa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,19 @@ # Changelog -## [0.0.1] +## [Unreleased] -The initial release with checked arithmetic operations for `u8`, `u16`, `u32`, `u64`, and `u128`; -`OP_RETURN` detection utilities; -implementation of `and`, `or`, `not`, and `xor` binary operators; -basic numeric assertions; -and equality and conversion operators for `secp256k1` points. +- Added `mul_div` functions. +- Organized code into modules. +- Refactored test structure. +- Removed `safe_` prefixes from math functions, so the default versions are overflow-checked. +- Added functions for retrieving and asserting `AssetId` and `Amount`. +- Added functions for retrieving script hashes. + +## [0.1.0] + +Initial release! +- Сhecked arithmetic operations for `u8`, `u16`, `u32`, `u64`, `u128` and `u256`. +- `OP_RETURN` detection utilities. +- Implementation of `and`, `or`, `not`, and `xor` binary operators. +- Basic numeric assertions. +- Equality and conversion operators for `secp256k1` points. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fdee6fd..cc14879 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ When submitting a feature request, please provide as many details as possible fo ## Pull Requests -If you're interested in contributing code to the library, start by [forking the repository](https://github.com/BlockstreamResearch/simplicityhl-std/fork) and submitting a pull request. +If you're interested in contributing code to the library, start by [forking the repository](https://github.com/BlockstreamResearch/simplicityhl-std/fork) and submitting a pull request. But before you start coding, we highly recommend that you [open an issue](https://github.com/BlockstreamResearch/simplicityhl-std/issues/new/choose) first to discuss the changes you want to make. diff --git a/Cargo.lock b/Cargo.lock index 7001e42..97cef9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,6 +82,16 @@ dependencies = [ "object", ] +[[package]] +name = "ariadne" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31beedec3ce83ae6da3a79592b3d8d7afd146a5b15bb9bb940279aced60faa89" +dependencies = [ + "unicode-width", + "yansi", +] + [[package]] name = "arrayvec" version = "0.7.8" @@ -96,9 +106,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.18.0" +version = "1.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce2b2dcc879c3bae0d371e77c99f2238400ef24ec001394befa67b6e543add9e" +checksum = "faac5829c2b74c28f830747e7818ccfb684261b5f48a1118b1e2a13d36dfab13" dependencies = [ "aws-lc-sys", "zeroize", @@ -106,9 +116,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.44.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09fae7be8bb3174e05c6afdb34199e6dc0c7c04ba9fa237b1967adfbde27483" +checksum = "f1622d8446a2d4b2ce0c7eefc73dd43a99779028d5ee5c2dd8073a658ba8a2bc" dependencies = [ "cc", "cmake", @@ -169,7 +179,7 @@ dependencies = [ "bitcoin-io", "bitcoin-units", "bitcoin_hashes", - "hex-conservative 0.2.2", + "hex-conservative 0.2.3", "hex_lit", "secp256k1", "serde", @@ -177,20 +187,20 @@ dependencies = [ [[package]] name = "bitcoin-consensus-encoding" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6712f9c6fd6785b3b270884e57c441c403dc5d7e19ca45368c97c7a1de3000ec" +checksum = "9daa31138eb443d5751b207f3f64154e2bb09cd59960562ccc7a7112be38147f" dependencies = [ "bitcoin-internals", - "hex-conservative 1.2.0", + "hex-conservative 1.3.0", "serde", ] [[package]] name = "bitcoin-internals" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d573f4cf32996a8dce612e4348cece65a241f1882ed594047c9ba348e8869fa5" +checksum = "e8bea3a9f0cfece4564e37cb49a38cc245ca5184719e50d7d0dda3268722c4e2" [[package]] name = "bitcoin-io" @@ -224,7 +234,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bca4c7abb40c8817d77403c880988cfd484f23ab2365726afb2f798363e2c4a2" dependencies = [ "bitcoin-io", - "hex-conservative 0.2.2", + "hex-conservative 0.2.3", "serde", ] @@ -273,9 +283,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "bitvec" @@ -328,9 +338,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.4.3" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" +checksum = "877bf67ac8e52449eb2f9e98a344ea163beb70dd1f9eebe3cc5357dcfeaee4df" dependencies = [ "find-msvc-tools", "jobserver", @@ -340,9 +350,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "chumsky" @@ -360,18 +370,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstream", "anstyle", @@ -381,9 +391,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" [[package]] name = "cmake" @@ -432,9 +442,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -442,18 +452,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.20" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -496,9 +506,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "either" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" dependencies = [ "serde", ] @@ -555,9 +565,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" [[package]] name = "errno" @@ -577,9 +587,9 @@ checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "find-msvc-tools" -version = "0.1.11" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" [[package]] name = "fixed-hash" @@ -700,7 +710,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.13.1", + "bitflags 2.13.2", "ignore", "walkdir", ] @@ -730,18 +740,18 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +checksum = "db3fef046dca3ca91ee1408a8c1b80ab777e80a4d308d1bf4e7adb3fcb047e08" dependencies = [ "arrayvec", ] [[package]] name = "hex-conservative" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35431185f361ccf3ffc58254628af5f1f5d5f28531da2e02e5d6c82bbc282a10" +checksum = "271e0d19bcb473b6675739a2b536076b24a082316cb5199ad918edce10c599e8" dependencies = [ "arrayvec", ] @@ -808,9 +818,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.14.0" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", "hashbrown 0.17.1", @@ -849,9 +859,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.104" +version = "0.3.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" dependencies = [ "cfg-if", "futures-util", @@ -887,9 +897,9 @@ checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" [[package]] name = "libc" -version = "0.2.189" +version = "0.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" [[package]] name = "linux-raw-sys" @@ -905,9 +915,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "log" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "memchr" @@ -1062,9 +1072,9 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "13bee6c73da26345c729282832b60b0363cf3dd9f4bfd81d8551b7a1c889a113" [[package]] name = "pkg-config" @@ -1153,9 +1163,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" dependencies = [ "libc", "rand_chacha", @@ -1241,7 +1251,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.13.1", + "bitflags 2.13.2", "errno", "libc", "linux-raw-sys 0.4.15", @@ -1250,11 +1260,11 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" dependencies = [ - "bitflags 2.13.1", + "bitflags 2.13.2", "errno", "libc", "linux-raw-sys 0.12.1", @@ -1263,9 +1273,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.43" +version = "0.23.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" dependencies = [ "aws-lc-rs", "log", @@ -1287,9 +1297,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.14" +version = "0.103.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0527518605e68109d875e248ea259b6758801cf165e4b2c2733ae3b51f12535a" +checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281" dependencies = [ "aws-lc-rs", "ring", @@ -1335,9 +1345,9 @@ dependencies = [ [[package]] name = "secp256k1-zkp" -version = "0.11.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a44aed3002b5ae975f8624c5df3a949cfbf00479e18778b6058fcd213b76e3" +checksum = "403f6ab6ef5189ded7d11cb384a96a9f871001e50b391a8fcbb310c9ebc2099b" dependencies = [ "bitcoin-private", "rand", @@ -1356,6 +1366,12 @@ dependencies = [ "secp256k1-sys", ] +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.229" @@ -1383,14 +1399,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -1401,9 +1417,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c" dependencies = [ "serde_core", ] @@ -1437,7 +1453,7 @@ dependencies = [ "elements", "getrandom 0.2.17", "ghost-cell", - "hex-conservative 0.2.2", + "hex-conservative 0.2.3", "miniscript", "simplicity-sys", ] @@ -1454,10 +1470,11 @@ dependencies = [ [[package]] name = "simplicityhl" -version = "0.6.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361316795ec753230c421d964ab60940d20d5252c2d39272452528832c9e0ec5" +checksum = "ae77168fa3367d234b11bb3999cbd6e04d7180db0b9e11f83de259528e3b23d1" dependencies = [ + "ariadne", "base64 0.21.7", "chumsky", "clap", @@ -1465,6 +1482,7 @@ dependencies = [ "getrandom 0.2.17", "itertools", "miniscript", + "semver", "serde", "serde_json", "simplicity-lang", @@ -1472,7 +1490,7 @@ dependencies = [ [[package]] name = "simplicityhl-std" -version = "0.0.1" +version = "0.1.0" dependencies = [ "anyhow", "num-bigint", @@ -1491,9 +1509,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smplx-build" -version = "0.0.10" +version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5a566aed019a661983dc6f1e420c6431f1cd47c0e3b2d3fabdeb9de75f0c07" +checksum = "a4e9561b9da1d788d3e777f8a59b085dd13a6fbace5b109f2b0576069f9f36ff" dependencies = [ "glob", "globwalk", @@ -1512,9 +1530,9 @@ dependencies = [ [[package]] name = "smplx-macros" -version = "0.0.10" +version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d68dfea03cfb3282d1c28c9cb80ccb683dc015d1f6ab2f1488806f7e9502fe2" +checksum = "9f802ff11501371c4c822f0ecdbf7e9e65180ccbbb43b55f252c9a00cb849d24" dependencies = [ "smplx-build", "smplx-test", @@ -1523,9 +1541,9 @@ dependencies = [ [[package]] name = "smplx-regtest" -version = "0.0.10" +version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a0c9536049b55eebe96cbbd46c6b51026ae964f7c2e664cb4297af9b36178" +checksum = "881db46f30a472018c26c5f245637a722ccba36a873b845d5e6376e7bd5e1106" dependencies = [ "electrsd", "hex", @@ -1539,9 +1557,9 @@ dependencies = [ [[package]] name = "smplx-sdk" -version = "0.0.10" +version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "700f68a14dbbe1e6b214965470197e12505693f7e0fd82360efb53d5430cb823" +checksum = "98b85112288eccd99ba34bd852681d78c3581a52709eab0ce52a073b9d961d8e" dependencies = [ "bip39", "bitcoin_hashes", @@ -1559,9 +1577,9 @@ dependencies = [ [[package]] name = "smplx-std" -version = "0.0.10" +version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b11221eb218a73f1d9e20c57364905e62351c43feb601dbc64d406137ebd63c" +checksum = "e05855ac57a1b5f737a4bc244ebf5924453957a2066a0bb0fd8df033498386ba" dependencies = [ "either", "serde", @@ -1573,9 +1591,9 @@ dependencies = [ [[package]] name = "smplx-test" -version = "0.0.10" +version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ae375c32c2f220320459710b54bbd7d7289bde0a45daa20cc0193a1999cd98" +checksum = "0a66ea20c2701a90faf10f9a18176058dd7a82222797d5ed6da9c83f0f1ca032" dependencies = [ "electrsd", "proc-macro2", @@ -1633,9 +1651,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -1657,44 +1675,35 @@ dependencies = [ "fastrand", "getrandom 0.4.3", "once_cell", - "rustix 1.1.4", + "rustix 1.1.5", "windows-sys 0.61.2", ] [[package]] name = "thiserror" -version = "2.0.20" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.20" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "tinyvec" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" [[package]] name = "toml" @@ -1722,21 +1731,21 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.25.13+spec-1.1.0" +version = "0.25.17+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" +checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c" dependencies = [ "indexmap", - "toml_datetime 1.1.1+spec-1.1.0", + "toml_datetime 1.1.2+spec-1.1.0", "toml_parser", "toml_writer", "winnow 1.0.4", @@ -1744,18 +1753,18 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.1.3+spec-1.1.0" +version = "1.1.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" dependencies = [ "winnow 1.0.4", ] [[package]] name = "toml_writer" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" +checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" [[package]] name = "typenum" @@ -1765,9 +1774,9 @@ checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "uint" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f9227a75a5a540a464c832ad4a4195dbdbecd8787610a56262721fde6f04f90" +checksum = "2833f28e3adbd1b867292ee4053252ea89ab85e44e5e4701ffead8cada0539fa" dependencies = [ "byteorder", "crunchy", @@ -1777,15 +1786,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "unicode-normalization" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +checksum = "75cd3fb03d5288b3ba9a1ee103ac7e9cbb59f0b03d64f8ddfcc04dd42758a85d" dependencies = [ "tinyvec", ] @@ -1796,6 +1805,12 @@ version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -1838,9 +1853,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" -version = "0.2.127" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" dependencies = [ "cfg-if", "once_cell", @@ -1851,9 +1866,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.127" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1861,31 +1876,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.127" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.127" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" dependencies = [ "unicode-ident", ] [[package]] name = "webpki-roots" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +checksum = "1c1c8e20c8a38fc7d65abfe74eb7280e4aa667e8eec8bc84996d2874810748d9" dependencies = [ "rustls-pki-types", ] @@ -2032,20 +2047,26 @@ dependencies = [ "tap", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "zerocopy" -version = "0.8.56" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.56" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", @@ -2054,9 +2075,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" [[package]] name = "zmij" diff --git a/Cargo.toml b/Cargo.toml index b918f7b..422ac42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simplicityhl-std" -version = "0.0.1" +version = "0.1.0" description = "SimplicityHL Standard Library" edition = "2024" rust-version = "1.91.0" @@ -11,7 +11,7 @@ keywords = ["simplicity", "liquid", "elements", "smart-contracts"] categories = ["cryptography::cryptocurrencies"] [dependencies] -smplx-std = { version = "0.0.10" } +smplx-std = { version = "0.0.12" } [dev-dependencies] anyhow = { version = "1.0.101" } diff --git a/README.md b/README.md index d77c4a0..074f198 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,10 @@ simf/lib ├── u64 │ ├── convert.simf │ │ └── Conversions between `u8`, `u16`, `u32`, `u64` and other uint types. -│ └── math.simf -│ └── Overflow-checked arithmetic and `gt`/`ge` functions. +│ ├── math.simf +│ │ └── Overflow-checked arithmetic and `gt`/`ge` functions. +│ └── mul_div.simf +│ └── Full-precision calculation of `floor(a * b / denominator)`. ├── u128 ├── u256 │ ├── bit.simf @@ -34,8 +36,25 @@ simf/lib │ │ └── Basic comparison operations available as jets for `u8`-`u64` but missing for `u128` and `u256`. │ ├── convert.simf │ │ └── Conversions between `u128`, `u256` and other uint types. -│ └── math.simf -│ └── Carry/borrow arithmetic, multiplication, division, and overflow-checked wrappers. +│ ├── math.simf +│ │ └── Carry/borrow arithmetic, multiplication, division, and overflow-checked wrappers. +│ └── mul_div.simf +│ └── Full-precision calculation of `floor(a * b / denominator)`. +├── utxo +│ ├── asserts +│ │ ├── amount.simf +│ │ │ └── Functions for asserting `Amount` in inputs and outputs. +│ │ ├── asset_id.simf +│ │ │ └── Functions for asserting `AssetId` in inputs and outputs. +│ │ └── asset_id_with_amount.simf +│ │ └── Functions for asserting `Amount` and `AssetId` in inputs and outputs. +│ └── getters +│ ├── amount.simf +│ │ └── Functions for retrieving `Amount` in inputs and outputs. +│ ├── asset_id.simf +│ │ └── Functions for retrieving `AssetId` in inputs and outputs. +│ └── asset_id_with_amount.simf +│ └── Functions for retrieving `Amount` and `AssetId` in inputs and outputs. ├── asserts.simf │ └── Assertion helpers: `assert_eq_*` for uints and `bool`, plus `assert_none_*` for `Option`. ├── binary.simf diff --git a/docs/stdlib.json b/docs/stdlib.json index 8fe6358..dd91cf6 100644 --- a/docs/stdlib.json +++ b/docs/stdlib.json @@ -104,6 +104,363 @@ "output_type": "()", "description": "Assert that two `bool` values are equal.\n\n## Panics\nThe assertion fails." }, + { + "simplicityhl_name": "assert_explicit_amount", + "section": "Amount asserts", + "input_type": "u32, bool, u64", + "output_type": "()", + "description": "Asserts that the explicit amount at the specified input or output index equals the expected `u64` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_amount", + "section": "Amount asserts", + "input_type": "u32, bool, Confidential1", + "output_type": "()", + "description": "Asserts that the confidential amount at the specified input or output index equals the expected `Confidential1` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_input_amount", + "section": "Amount asserts", + "input_type": "u32, u64", + "output_type": "()", + "description": "Asserts that the explicit amount at the specified input index equals the expected `u64` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_input_amount", + "section": "Amount asserts", + "input_type": "u32, Confidential1", + "output_type": "()", + "description": "Asserts that the confidential amount at the specified input index equals the expected `Confidential1` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_output_amount", + "section": "Amount asserts", + "input_type": "u32, u64", + "output_type": "()", + "description": "Asserts that the explicit amount at the specified output index equals the expected `u64` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_output_amount", + "section": "Amount asserts", + "input_type": "u32, Confidential1", + "output_type": "()", + "description": "Asserts that the confidential amount at the specified output index equals the expected `Confidential1` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_current_amount", + "section": "Amount asserts", + "input_type": "u64", + "output_type": "()", + "description": "Asserts that the explicit input amount at the current_index equals the expected `u64` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_current_amount", + "section": "Amount asserts", + "input_type": "Confidential1", + "output_type": "()", + "description": "Asserts that the confidential input amount at the current_index equals the expected `Confidential1` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_asset_id_with_amount", + "section": "AssetId and Amount asserts", + "input_type": "u32, bool, u256, u64", + "output_type": "()", + "description": "Asserts that explicit asset_id and amount at the specified input or output index equal the expected `u256` and `u64` values.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_asset_id_with_amount", + "section": "AssetId and Amount asserts", + "input_type": "u32, bool, Confidential1, Confidential1", + "output_type": "()", + "description": "Asserts that confidential asset_id and amount at the specified input or output index equal the expected `Confidential1` values.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_input_asset_id_with_amount", + "section": "AssetId and Amount asserts", + "input_type": "u32, u256, u64", + "output_type": "()", + "description": "Asserts that explicit asset_id and amount at the specified input index equal the expected `u256` and `u64` values.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_input_asset_id_with_amount", + "section": "AssetId and Amount asserts", + "input_type": "u32, Confidential1, Confidential1", + "output_type": "()", + "description": "Asserts that confidential asset_id and amount at the specified input index equal the expected `Confidential1` values.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_output_asset_id_with_amount", + "section": "AssetId and Amount asserts", + "input_type": "u32, u256, u64", + "output_type": "()", + "description": "Asserts that explicit asset_id and amount at the specified output index equal the expected `u256` and `u64` values.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_output_asset_id_with_amount", + "section": "AssetId and Amount asserts", + "input_type": "u32, Confidential1, Confidential1", + "output_type": "()", + "description": "Asserts that confidential asset_id and amount at the specified output index equal the expected `Confidential1` values.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_current_asset_id_with_amount", + "section": "AssetId and Amount asserts", + "input_type": "u256, u64", + "output_type": "()", + "description": "Asserts that explicit input asset_id and amount at the current_index equal the expected `u256` and `u64` values.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_current_asset_id_with_amount", + "section": "AssetId and Amount asserts", + "input_type": "Confidential1, Confidential1", + "output_type": "()", + "description": "Asserts that confidential input asset_id and amount at the current_index equal the expected `Confidential1` values.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_asset_id", + "section": "AssetId asserts", + "input_type": "u32, bool, u256", + "output_type": "()", + "description": "Asserts that the explicit asset_id at the specified input or output index equals the expected `u256` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_asset_id", + "section": "AssetId asserts", + "input_type": "u32, bool, Confidential1", + "output_type": "()", + "description": "Asserts that the confidential asset_id at the specified input or output index equals the expected `Confidential1` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_input_asset_id", + "section": "AssetId asserts", + "input_type": "u32, u256", + "output_type": "()", + "description": "Asserts that the explicit asset_id at the specified input index equals the expected `u256` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_input_asset_id", + "section": "AssetId asserts", + "input_type": "u32, Confidential1", + "output_type": "()", + "description": "Asserts that the confidential asset_id at the specified input index equals the expected `Confidential1` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_output_asset_id", + "section": "AssetId asserts", + "input_type": "u32, u256", + "output_type": "()", + "description": "Asserts that the explicit asset_id at the specified output index equals the expected `u256` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_output_asset_id", + "section": "AssetId asserts", + "input_type": "u32, Confidential1", + "output_type": "()", + "description": "Asserts that the confidential asset_id at the specified output index equals the expected `Confidential1` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_explicit_current_asset_id", + "section": "AssetId asserts", + "input_type": "u256", + "output_type": "()", + "description": "Asserts that the explicit input asset_id at the current_index equals the expected `u256` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "assert_confidential_current_asset_id", + "section": "AssetId asserts", + "input_type": "Confidential1", + "output_type": "()", + "description": "Asserts that the confidential input asset_id at the current_index equals the expected `Confidential1` value.\n\n## Panics\nThe assertion fails." + }, + { + "simplicityhl_name": "get_explicit_amount", + "section": "Amount getters", + "input_type": "u32, bool", + "output_type": "u64", + "description": "Returns the explicit amount at the specified input or output index.\n\n## Panics\nPanics if the specified input or output does not exist or if its amount is confidential." + }, + { + "simplicityhl_name": "get_confidential_amount", + "section": "Amount getters", + "input_type": "u32, bool", + "output_type": "Confidential1", + "description": "Returns the confidential amount at the specified input or output index.\n\n## Panics\nPanics if the specified input or output does not exist or if its amount is explicit." + }, + { + "simplicityhl_name": "get_explicit_input_amount", + "section": "Amount getters", + "input_type": "u32", + "output_type": "u64", + "description": "Returns the explicit amount at the specified input index.\n\n## Panics\nPanics if the specified input does not exist or if its amount is confidential." + }, + { + "simplicityhl_name": "get_confidential_input_amount", + "section": "Amount getters", + "input_type": "u32", + "output_type": "Confidential1", + "description": "Returns the confidential amount at the specified input index.\n\n## Panics\nPanics if the specified input does not exist or if its amount is explicit." + }, + { + "simplicityhl_name": "get_explicit_output_amount", + "section": "Amount getters", + "input_type": "u32", + "output_type": "u64", + "description": "Returns the explicit amount at the specified output index.\n\n## Panics\nPanics if the specified output does not exist or if its amount is confidential." + }, + { + "simplicityhl_name": "get_confidential_output_amount", + "section": "Amount getters", + "input_type": "u32", + "output_type": "Confidential1", + "description": "Returns the confidential amount at the specified output index.\n\n## Panics\nPanics if the specified output does not exist or if its amount is explicit." + }, + { + "simplicityhl_name": "get_explicit_current_amount", + "section": "Amount getters", + "input_type": "()", + "output_type": "u64", + "description": "Returns the explicit input amount at the current_index.\n\n## Panics\nPanics if amount is confidential." + }, + { + "simplicityhl_name": "get_confidential_current_amount", + "section": "Amount getters", + "input_type": "()", + "output_type": "Confidential1", + "description": "Returns the confidential input amount at the current_index.\n\n## Panics\nPanics if amount is explicit." + }, + { + "simplicityhl_name": "get_explicit_asset_id_with_amount", + "section": "AssetId and Amount getters", + "input_type": "u32, bool", + "output_type": "(u256, u64)", + "description": "Returns explicit asset_id and amount at the specified input or output index.\n\n## Panics\nPanics if the specified input or output does not exist or if its asset_id and amount are confidential." + }, + { + "simplicityhl_name": "get_confidential_asset_id_with_amount", + "section": "AssetId and Amount getters", + "input_type": "u32, bool", + "output_type": "(Confidential1, Confidential1)", + "description": "Returns confidential asset_id and amount at the specified input or output index.\n\n## Panics\nPanics if the specified input or output does not exist or if its asset_id and amount are explicit." + }, + { + "simplicityhl_name": "get_explicit_input_asset_id_with_amount", + "section": "AssetId and Amount getters", + "input_type": "u32", + "output_type": "(u256, u64)", + "description": "Returns explicit asset_id and amount at the specified input index.\n\n## Panics\nPanics if the specified input does not exist or if its asset_id and amount are confidential." + }, + { + "simplicityhl_name": "get_confidential_input_asset_id_with_amount", + "section": "AssetId and Amount getters", + "input_type": "u32", + "output_type": "(Confidential1, Confidential1)", + "description": "Returns confidential asset_id and amount at the specified input index.\n\n## Panics\nPanics if the specified input does not exist or if its asset_id and amount are explicit." + }, + { + "simplicityhl_name": "get_explicit_output_asset_id_with_amount", + "section": "AssetId and Amount getters", + "input_type": "u32", + "output_type": "(u256, u64)", + "description": "Returns explicit asset_id and amount at the specified output index.\n\n## Panics\nPanics if the specified output does not exist or if its asset_id and amount are confidential." + }, + { + "simplicityhl_name": "get_confidential_output_asset_id_with_amount", + "section": "AssetId and Amount getters", + "input_type": "u32", + "output_type": "(Confidential1, Confidential1)", + "description": "Returns confidential asset_id and amount at the specified output index.\n\n## Panics\nPanics if the specified output does not exist or if its asset_id and amount are explicit." + }, + { + "simplicityhl_name": "get_explicit_current_asset_id_with_amount", + "section": "AssetId and Amount getters", + "input_type": "()", + "output_type": "(u256, u64)", + "description": "Returns explicit input asset_id and amount at the current_index.\n\n## Panics\nPanics if asset_id and amount are confidential." + }, + { + "simplicityhl_name": "get_confidential_current_asset_id_with_amount", + "section": "AssetId and Amount getters", + "input_type": "()", + "output_type": "(Confidential1, Confidential1)", + "description": "Returns confidential input asset_id and amount at the current_index.\n\n## Panics\nPanics if asset_id and amount are explicit." + }, + { + "simplicityhl_name": "get_explicit_asset_id", + "section": "AssetId getters", + "input_type": "u32, bool", + "output_type": "u256", + "description": "Returns the explicit asset_id at the specified input or output index.\n\n## Panics\nPanics if the specified input or output does not exist or if its asset_id is confidential." + }, + { + "simplicityhl_name": "get_confidential_asset_id", + "section": "AssetId getters", + "input_type": "u32, bool", + "output_type": "Confidential1", + "description": "Returns the confidential asset_id at the specified input or output index.\n\n## Panics\nPanics if the specified input or output does not exist or if its asset_id is explicit." + }, + { + "simplicityhl_name": "get_explicit_input_asset_id", + "section": "AssetId getters", + "input_type": "u32", + "output_type": "u256", + "description": "Returns the explicit asset_id at the specified input index.\n\n## Panics\nPanics if the specified input does not exist or if its asset_id is confidential." + }, + { + "simplicityhl_name": "get_confidential_input_asset_id", + "section": "AssetId getters", + "input_type": "u32", + "output_type": "Confidential1", + "description": "Returns the confidential asset_id at the specified input index.\n\n## Panics\nPanics if the specified input does not exist or if its asset_id is explicit." + }, + { + "simplicityhl_name": "get_explicit_output_asset_id", + "section": "AssetId getters", + "input_type": "u32", + "output_type": "u256", + "description": "Returns the explicit asset_id at the specified output index.\n\n## Panics\nPanics if the specified output does not exist or if its asset_id is confidential." + }, + { + "simplicityhl_name": "get_confidential_output_asset_id", + "section": "AssetId getters", + "input_type": "u32", + "output_type": "Confidential1", + "description": "Returns the confidential asset_id at the specified output index.\n\n## Panics\nPanics if the specified output does not exist or if its asset_id is explicit." + }, + { + "simplicityhl_name": "get_explicit_current_asset_id", + "section": "AssetId getters", + "input_type": "()", + "output_type": "u256", + "description": "Returns the explicit input asset_id at the current_index.\n\n## Panics\nPanics if asset_id is confidential." + }, + { + "simplicityhl_name": "get_confidential_current_asset_id", + "section": "AssetId getters", + "input_type": "()", + "output_type": "Confidential1", + "description": "Returns the confidential input asset_id at the current_index.\n\n## Panics\nPanics if asset_id is explicit." + }, + { + "simplicityhl_name": "get_script_hash", + "section": "Script hash getters", + "input_type": "u32, bool", + "output_type": "u256", + "description": "Returns the SHA256 hash of the scriptPubKey at the specified input or output.\n\n## Panics\nPanics if the specified input or output does not exist." + }, + { + "simplicityhl_name": "get_input_script_hash", + "section": "Script hash getters", + "input_type": "u32", + "output_type": "u256", + "description": "Returns the SHA256 hash of the scriptPubKey of the input at the given index.\n\n## Panics\nPanics if the specified input does not exist." + }, + { + "simplicityhl_name": "get_output_script_hash", + "section": "Script hash getters", + "input_type": "u32", + "output_type": "u256", + "description": "Returns the SHA256 hash of the scriptPubKey of the output at the given index.\n\n## Panics\nPanics if the specified output does not exist." + }, { "simplicityhl_name": "not", "section": "Binary logic", @@ -329,7 +686,7 @@ "description": "Add two `u8` values. Return `Some` of the sum, or `None` if the result overflows `u8`." }, { - "simplicityhl_name": "safe_add_8", + "simplicityhl_name": "add_8", "section": "`u8` arithmetic", "input_type": "u8, u8", "output_type": "u8", @@ -340,14 +697,14 @@ "section": "`u8` arithmetic", "input_type": "u8, u8", "output_type": "Option", - "description": "Subtract the second `u8` value from the first. Return `Some` of the difference, or `None` if the result would underflow `u8`." + "description": "Subtract the second `u8` value from the first. Return `Some` of the difference, or `None` if the result would overflow `u8`." }, { - "simplicityhl_name": "safe_sub_8", + "simplicityhl_name": "sub_8", "section": "`u8` arithmetic", "input_type": "u8, u8", "output_type": "u8", - "description": "Subtract the second `u8` value from the first.\n\n## Panics\nPanics if the result would underflow `u8`." + "description": "Subtract the second `u8` value from the first.\n\n## Panics\nPanics if the result would overflow `u8`." }, { "simplicityhl_name": "checked_mul_8", @@ -357,7 +714,7 @@ "description": "Multiply two `u8` values. Return `Some` of the product, or `None` if the result overflows `u8`." }, { - "simplicityhl_name": "safe_mul_8", + "simplicityhl_name": "mul_8", "section": "`u8` arithmetic", "input_type": "u8, u8", "output_type": "u8", @@ -371,7 +728,7 @@ "description": "Divide the first `u8` value by the second. Return `Some` of the quotient, or `None` if the divisor is zero." }, { - "simplicityhl_name": "safe_div_8", + "simplicityhl_name": "div_8", "section": "`u8` arithmetic", "input_type": "u8, u8", "output_type": "u8", @@ -391,6 +748,13 @@ "output_type": "bool", "description": "Check if the first `u8` value is greater than or equal to the second." }, + { + "simplicityhl_name": "mul_div_8", + "section": "`u8` arithmetic", + "input_type": "u8, u8, u8", + "output_type": "u8", + "description": "Calculate `floor(a * b / denominator)` with full precision. \n\n## Panics\nPanics if the result overflows a `u8` or if the denominator is zero." + }, { "simplicityhl_name": "u8_to_u16", "section": "`u8` conversions", @@ -448,7 +812,7 @@ "description": "Add two `u16` values. Return `Some` of the sum, or `None` if the result overflows `u16`." }, { - "simplicityhl_name": "safe_add_16", + "simplicityhl_name": "add_16", "section": "`u16` arithmetic", "input_type": "u16, u16", "output_type": "u16", @@ -459,14 +823,14 @@ "section": "`u16` arithmetic", "input_type": "u16, u16", "output_type": "Option", - "description": "Subtract the second `u16` value from the first. Return `Some` of the difference, or `None` if the result would underflow `u16`." + "description": "Subtract the second `u16` value from the first. Return `Some` of the difference, or `None` if the result would overflow `u16`." }, { - "simplicityhl_name": "safe_sub_16", + "simplicityhl_name": "sub_16", "section": "`u16` arithmetic", "input_type": "u16, u16", "output_type": "u16", - "description": "Subtract the second `u16` value from the first.\n\n## Panics\nPanics if the result would underflow `u16`." + "description": "Subtract the second `u16` value from the first.\n\n## Panics\nPanics if the result would overflow `u16`." }, { "simplicityhl_name": "checked_mul_16", @@ -476,7 +840,7 @@ "description": "Multiply two `u16` values. Return `Some` of the product, or `None` if the result overflows `u16`." }, { - "simplicityhl_name": "safe_mul_16", + "simplicityhl_name": "mul_16", "section": "`u16` arithmetic", "input_type": "u16, u16", "output_type": "u16", @@ -490,7 +854,7 @@ "description": "Divide the first `u16` value by the second. Return `Some` of the quotient, or `None` if the divisor is zero." }, { - "simplicityhl_name": "safe_div_16", + "simplicityhl_name": "div_16", "section": "`u16` arithmetic", "input_type": "u16, u16", "output_type": "u16", @@ -510,6 +874,13 @@ "output_type": "bool", "description": "Check if the first `u16` value is greater than or equal to the second." }, + { + "simplicityhl_name": "mul_div_16", + "section": "`u16` arithmetic", + "input_type": "u16, u16, u16", + "output_type": "u16", + "description": "Calculate `floor(a * b / denominator)` with full precision. \n\n## Panics\nPanics if the result overflows a `u16` or if the denominator is zero." + }, { "simplicityhl_name": "u16_to_u32", "section": "`u16` conversions", @@ -567,7 +938,7 @@ "description": "Add two `u32` values. Return `Some` of the sum, or `None` if the result overflows `u32`." }, { - "simplicityhl_name": "safe_add_32", + "simplicityhl_name": "add_32", "section": "`u32` arithmetic", "input_type": "u32, u32", "output_type": "u32", @@ -578,14 +949,14 @@ "section": "`u32` arithmetic", "input_type": "u32, u32", "output_type": "Option", - "description": "Subtract the second `u32` value from the first. Return `Some` of the difference, or `None` if the result would underflow `u32`." + "description": "Subtract the second `u32` value from the first. Return `Some` of the difference, or `None` if the result would overflow `u32`." }, { - "simplicityhl_name": "safe_sub_32", + "simplicityhl_name": "sub_32", "section": "`u32` arithmetic", "input_type": "u32, u32", "output_type": "u32", - "description": "Subtract the second `u32` value from the first.\n\n## Panics\nPanics if the result would underflow `u32`." + "description": "Subtract the second `u32` value from the first.\n\n## Panics\nPanics if the result would overflow `u32`." }, { "simplicityhl_name": "checked_mul_32", @@ -595,7 +966,7 @@ "description": "Multiply two `u32` values. Return `Some` of the product, or `None` if the result overflows `u32`." }, { - "simplicityhl_name": "safe_mul_32", + "simplicityhl_name": "mul_32", "section": "`u32` arithmetic", "input_type": "u32, u32", "output_type": "u32", @@ -609,7 +980,7 @@ "description": "Divide the first `u32` value by the second. Return `Some` of the quotient, or `None` if the divisor is zero." }, { - "simplicityhl_name": "safe_div_32", + "simplicityhl_name": "div_32", "section": "`u32` arithmetic", "input_type": "u32, u32", "output_type": "u32", @@ -629,6 +1000,13 @@ "output_type": "bool", "description": "Check if the first `u32` value is greater than or equal to the second." }, + { + "simplicityhl_name": "mul_div_32", + "section": "`u32` arithmetic", + "input_type": "u32, u32, u32", + "output_type": "u32", + "description": "Calculate `floor(a * b / denominator)` with full precision. \n\n## Panics\nPanics if the result overflows a `u32` or if the denominator is zero." + }, { "simplicityhl_name": "u32_to_u64", "section": "`u32` conversions", @@ -693,7 +1071,7 @@ "description": "Add two `u64` values. Return `Some` of the sum, or `None` if the result overflows `u64`." }, { - "simplicityhl_name": "safe_add_64", + "simplicityhl_name": "add_64", "section": "`u64` arithmetic", "input_type": "u64, u64", "output_type": "u64", @@ -704,14 +1082,14 @@ "section": "`u64` arithmetic", "input_type": "u64, u64", "output_type": "Option", - "description": "Subtract the second `u64` value from the first. Return `Some` of the difference, or `None` if the result would underflow `u64`." + "description": "Subtract the second `u64` value from the first. Return `Some` of the difference, or `None` if the result would overflow `u64`." }, { - "simplicityhl_name": "safe_sub_64", + "simplicityhl_name": "sub_64", "section": "`u64` arithmetic", "input_type": "u64, u64", "output_type": "u64", - "description": "Subtract the second `u64` value from the first.\n\n## Panics\nPanics if the result would underflow `u64`." + "description": "Subtract the second `u64` value from the first.\n\n## Panics\nPanics if the result would overflow `u64`." }, { "simplicityhl_name": "checked_mul_64", @@ -721,7 +1099,7 @@ "description": "Multiply two `u64` values. Return `Some` of the product, or `None` if the result overflows `u64`." }, { - "simplicityhl_name": "safe_mul_64", + "simplicityhl_name": "mul_64", "section": "`u64` arithmetic", "input_type": "u64, u64", "output_type": "u64", @@ -735,7 +1113,7 @@ "description": "Divide the first `u64` value by the second. Return `Some` of the quotient, or `None` if the divisor is zero." }, { - "simplicityhl_name": "safe_div_64", + "simplicityhl_name": "div_64", "section": "`u64` arithmetic", "input_type": "u64, u64", "output_type": "u64", @@ -755,6 +1133,13 @@ "output_type": "bool", "description": "Check if the first `u64` value is greater than or equal to the second." }, + { + "simplicityhl_name": "mul_div_64", + "section": "`u64` arithmetic", + "input_type": "u64, u64, u64", + "output_type": "u64", + "description": "Calculate `floor(a * b / denominator)` with full precision. \n\n## Panics\nPanics if the result overflows a `u64` or if the denominator is zero." + }, { "simplicityhl_name": "u64_to_u128", "section": "`u64` conversions", @@ -819,78 +1204,218 @@ "description": "Narrow a `u64` value to `u32`.\n\n## Panics\nPanics if the value does not fit in `u32`." }, { - "simplicityhl_name": "and_128", - "section": "`u128` bit logic", + "simplicityhl_name": "add_128_carry", + "section": "`u128` arithmetic", "input_type": "u128, u128", - "output_type": "u128", - "description": "Bitwise AND of two `u128` values." + "output_type": "(bool, u128)", + "description": "Add two `u128` values. Return the carry bit and the sum." }, { - "simplicityhl_name": "or_128", - "section": "`u128` bit logic", - "input_type": "u128, u128", - "output_type": "u128", - "description": "Bitwise OR of two `u128` values." + "simplicityhl_name": "add_128_64_carry", + "section": "`u128` arithmetic", + "input_type": "u128, u64", + "output_type": "(bool, u128)", + "description": "Add a `u64` value to a `u128` value. Return the carry bit and the sum." }, { - "simplicityhl_name": "eq_128", - "section": "`u128` bit logic", + "simplicityhl_name": "checked_add_128", + "section": "`u128` arithmetic", "input_type": "u128, u128", - "output_type": "bool", - "description": "Check if two `u128` values are equal." + "output_type": "Option", + "description": "Add two `u128` values. Return `Some` of the sum, or `None` if the result overflows `u128`." }, { - "simplicityhl_name": "left_shift_128", - "section": "`u128` bit logic", - "input_type": "u8, u128", + "simplicityhl_name": "add_128", + "section": "`u128` arithmetic", + "input_type": "u128, u128", "output_type": "u128", - "description": "Left-shift a `u128` value by the given amount. Bits shifted out are discarded; vacated low bits are filled with zeroes." + "description": "Add two `u128` values.\n\n## Panics\nPanics if the result overflows `u128`." }, { - "simplicityhl_name": "right_shift_128", - "section": "`u128` bit logic", - "input_type": "u8, u128", - "output_type": "u128", - "description": "Right-shift a `u128` value by the given amount. Bits shifted out are discarded; vacated high bits are filled with zeroes." + "simplicityhl_name": "sub_128_borrow", + "section": "`u128` arithmetic", + "input_type": "u128, u128", + "output_type": "(bool, u128)", + "description": "Subtract the second `u128` value from the first. Return the borrow bit and the difference." }, { - "simplicityhl_name": "is_zero_128", - "section": "`u128` comparisons", - "input_type": "u128", - "output_type": "bool", - "description": "Check if a `u128` value is zero." + "simplicityhl_name": "checked_sub_128", + "section": "`u128` arithmetic", + "input_type": "u128, u128", + "output_type": "Option", + "description": "Subtract the second `u128` value from the first. Return `Some` of the difference, or `None` if the result would overflow `u128`." }, { - "simplicityhl_name": "lt_128", - "section": "`u128` comparisons", + "simplicityhl_name": "sub_128", + "section": "`u128` arithmetic", "input_type": "u128, u128", - "output_type": "bool", - "description": "Check if the first `u128` value is strictly less than the second." + "output_type": "u128", + "description": "Subtract the second `u128` value from the first.\n\n## Panics\nPanics if the result would overflow `u128`." }, { - "simplicityhl_name": "le_128", - "section": "`u128` comparisons", + "simplicityhl_name": "mul_128_wide", + "section": "`u128` arithmetic", "input_type": "u128, u128", - "output_type": "bool", - "description": "Check if the first `u128` value is less than or equal to the second." + "output_type": "u256", + "description": "Multiply two `u128` values. The full, non-truncated product is returned as a `u256`, so this operation can never overflow." }, { - "simplicityhl_name": "gt_128", - "section": "`u128` comparisons", + "simplicityhl_name": "checked_mul_128", + "section": "`u128` arithmetic", "input_type": "u128, u128", - "output_type": "bool", - "description": "Check if the first `u128` value is strictly greater than the second." + "output_type": "Option", + "description": "Multiply two `u128` values. Return `Some` of the product, or `None` if the result overflows `u128`." }, { - "simplicityhl_name": "ge_128", - "section": "`u128` comparisons", + "simplicityhl_name": "mul_128", + "section": "`u128` arithmetic", "input_type": "u128, u128", - "output_type": "bool", - "description": "Check if the first `u128` value is greater than or equal to the second." + "output_type": "u128", + "description": "Multiply two `u128` values.\n\n## Panics\nPanics if the result overflows `u128`." }, { - "simplicityhl_name": "u128_to_u256", - "section": "`u128` conversions", + "simplicityhl_name": "div_mod_128_64", + "section": "`u128` arithmetic", + "input_type": "u128, u64", + "output_type": "(u128, u64)", + "description": "Divide a `u128` value by a `u64` value, returning the `u128` quotient and the `u64` remainder.\n\n## Panics\nPanics if the divisor is zero." + }, + { + "simplicityhl_name": "div_mod_128", + "section": "`u128` arithmetic", + "input_type": "u128, u128", + "output_type": "(u128, u128)", + "description": "Divide the first `u128` value by the second, returning the quotient and the remainder.\n\n## Panics\nPanics if the divisor is zero." + }, + { + "simplicityhl_name": "div_128", + "section": "`u128` arithmetic", + "input_type": "u128, u128", + "output_type": "u128", + "description": "Divide the first `u128` value by the second, returning the quotient.\n\n## Panics\nPanics if the divisor is zero." + }, + { + "simplicityhl_name": "checked_div_128", + "section": "`u128` arithmetic", + "input_type": "u128, u128", + "output_type": "Option", + "description": "Divide the first `u128` value by the second. Return `Some` of the quotient, or `None` if the divisor is zero." + }, + { + "simplicityhl_name": "full_add_128", + "section": "`u128` arithmetic", + "input_type": "bool, u128, u128", + "output_type": "(bool, u128)", + "description": "Add two `u128` values, taking an incoming carry bit. Return the outgoing carry bit and the sum." + }, + { + "simplicityhl_name": "full_sub_128", + "section": "`u128` arithmetic", + "input_type": "bool, u128, u128", + "output_type": "(bool, u128)", + "description": "Subtract the second `u128` value from the first, taking an incoming borrow bit. Return the outgoing borrow bit and the difference." + }, + { + "simplicityhl_name": "mul_128_64_wide", + "section": "`u128` arithmetic", + "input_type": "u128, u64", + "output_type": "u256", + "description": "Multiply a `u128` value by a `u64` value. The full, non-truncated product is returned as a `u256`, so this operation can never overflow." + }, + { + "simplicityhl_name": "calculate_normalizer_base_64", + "section": "`u128` arithmetic", + "input_type": "u128, bool", + "output_type": "u64", + "description": "Helper for `jet::div_mod_128_64`-based division algorithms. Returns the factor by which `b` should be multiplied so that its most-significant non-zero word is at least `2^63`, as required by those algorithms (which operate in base `2^64`). Set `is_b_u128` to `true` if `b`'s upper 64 bits may be non-zero, or `false` if `b` is known to fit in `u64` (in which case its upper 64 bits must already be zero).\n\n## Panics\nThe assertion fails if `is_b_u128` is `false` but `b`'s upper 64 bits are non-zero, or if `b` is zero." + }, + { + "simplicityhl_name": "estimate_quotient_digit_base_64", + "section": "`u128` arithmetic", + "input_type": "u64, u64, u64, u64, u64", + "output_type": "u64", + "description": "Helper for Algorithm D division. Estimates and corrects the next base-`2^64` quotient digit from the three most-significant dividend words (`u2`, `u1`, `u0`) and the two most-significant divisor words (`v1`, `v0`)." + }, + { + "simplicityhl_name": "mul_div_128", + "section": "`u128` arithmetic", + "input_type": "u128, u128, u128", + "output_type": "u128", + "description": "Calculate `floor(a * b / denominator)` with full precision. \n\n## Panics\nPanics if the result overflows a `u128` or if the denominator is zero." + }, + { + "simplicityhl_name": "and_128", + "section": "`u128` bit logic", + "input_type": "u128, u128", + "output_type": "u128", + "description": "Bitwise AND of two `u128` values." + }, + { + "simplicityhl_name": "or_128", + "section": "`u128` bit logic", + "input_type": "u128, u128", + "output_type": "u128", + "description": "Bitwise OR of two `u128` values." + }, + { + "simplicityhl_name": "eq_128", + "section": "`u128` bit logic", + "input_type": "u128, u128", + "output_type": "bool", + "description": "Check if two `u128` values are equal." + }, + { + "simplicityhl_name": "left_shift_128", + "section": "`u128` bit logic", + "input_type": "u8, u128", + "output_type": "u128", + "description": "Left-shift a `u128` value by the given amount. Bits shifted out are discarded; vacated low bits are filled with zeroes." + }, + { + "simplicityhl_name": "right_shift_128", + "section": "`u128` bit logic", + "input_type": "u8, u128", + "output_type": "u128", + "description": "Right-shift a `u128` value by the given amount. Bits shifted out are discarded; vacated high bits are filled with zeroes." + }, + { + "simplicityhl_name": "is_zero_128", + "section": "`u128` comparisons", + "input_type": "u128", + "output_type": "bool", + "description": "Check if a `u128` value is zero." + }, + { + "simplicityhl_name": "lt_128", + "section": "`u128` comparisons", + "input_type": "u128, u128", + "output_type": "bool", + "description": "Check if the first `u128` value is strictly less than the second." + }, + { + "simplicityhl_name": "le_128", + "section": "`u128` comparisons", + "input_type": "u128, u128", + "output_type": "bool", + "description": "Check if the first `u128` value is less than or equal to the second." + }, + { + "simplicityhl_name": "gt_128", + "section": "`u128` comparisons", + "input_type": "u128, u128", + "output_type": "bool", + "description": "Check if the first `u128` value is strictly greater than the second." + }, + { + "simplicityhl_name": "ge_128", + "section": "`u128` comparisons", + "input_type": "u128, u128", + "output_type": "bool", + "description": "Check if the first `u128` value is greater than or equal to the second." + }, + { + "simplicityhl_name": "u128_to_u256", + "section": "`u128` conversions", "input_type": "u128", "output_type": "u256", "description": "Widen a `u128` value to a `u256` value, zero-extending the high bits." @@ -959,144 +1484,165 @@ "description": "Narrow a `u128` value to `u64`.\n\n## Panics\nPanics if the value does not fit in `u64`." }, { - "simplicityhl_name": "add_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "(bool, u128)", - "description": "Add two `u128` values. Return the carry bit and the sum." + "simplicityhl_name": "add_256_carry", + "section": "`u256` arithmetic", + "input_type": "u256, u256", + "output_type": "(bool, u256)", + "description": "Add two `u256` values. Return the carry bit and the sum." }, { - "simplicityhl_name": "add_128_64", - "section": "`u128` arithmetic", - "input_type": "u128, u64", - "output_type": "(bool, u128)", - "description": "Add a `u64` value to a `u128` value. Return the carry bit and the sum." + "simplicityhl_name": "add_256_128_carry", + "section": "`u256` arithmetic", + "input_type": "u256, u128", + "output_type": "(bool, u256)", + "description": "Add a `u128` value to a `u256` value. Return the carry bit and the sum." }, { - "simplicityhl_name": "checked_add_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "Option", - "description": "Add two `u128` values. Return `Some` of the sum, or `None` if the result overflows `u128`." + "simplicityhl_name": "full_add_256", + "section": "`u256` arithmetic", + "input_type": "bool, u256, u256", + "output_type": "(bool, u256)", + "description": "Add two `u256` values, taking an incoming carry bit. Return the outgoing carry bit and the sum." }, { - "simplicityhl_name": "safe_add_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "u128", - "description": "Add two `u128` values.\n\n## Panics\nPanics if the result overflows `u128`." + "simplicityhl_name": "checked_add_256", + "section": "`u256` arithmetic", + "input_type": "u256, u256", + "output_type": "Option", + "description": "Add two `u256` values. Return `Some` of the sum, or `None` if the result overflows `u256`." }, { - "simplicityhl_name": "sub_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "(bool, u128)", - "description": "Subtract the second `u128` value from the first. Return the borrow bit and the difference." + "simplicityhl_name": "add_256", + "section": "`u256` arithmetic", + "input_type": "u256, u256", + "output_type": "u256", + "description": "Add two `u256` values.\n\n## Panics\nPanics if the result overflows `u256`." }, { - "simplicityhl_name": "checked_sub_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "Option", - "description": "Subtract the second `u128` value from the first. Return `Some` of the difference, or `None` if the result would underflow `u128`." + "simplicityhl_name": "sub_256_borrow", + "section": "`u256` arithmetic", + "input_type": "u256, u256", + "output_type": "(bool, u256)", + "description": "Subtract the second `u256` value from the first. Return the borrow bit and the difference." }, { - "simplicityhl_name": "safe_sub_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "u128", - "description": "Subtract the second `u128` value from the first.\n\n## Panics\nPanics if the result would underflow `u128`." + "simplicityhl_name": "checked_sub_256", + "section": "`u256` arithmetic", + "input_type": "u256, u256", + "output_type": "Option", + "description": "Subtract the second `u256` value from the first. Return `Some` of the difference, or `None` if the result would overflow `u256`." }, { - "simplicityhl_name": "mul_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", + "simplicityhl_name": "sub_256", + "section": "`u256` arithmetic", + "input_type": "u256, u256", "output_type": "u256", - "description": "Multiply two `u128` values. The full, non-truncated product is returned as a `u256`, so this operation can never overflow." + "description": "Subtract the second `u256` value from the first.\n\n## Panics\nPanics if the result would overflow `u256`." }, { - "simplicityhl_name": "checked_mul_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "Option", - "description": "Multiply two `u128` values. Return `Some` of the product, or `None` if the result overflows `u128`." + "simplicityhl_name": "mul_256_wide", + "section": "`u256` arithmetic", + "input_type": "u256, u256", + "output_type": "(u256, u256)", + "description": "Multiply two `u256` values. The full, non-truncated product is returned as a pair of `u256` values, most-significant first, so this operation can never overflow." }, { - "simplicityhl_name": "safe_mul_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "u128", - "description": "Multiply two `u128` values.\n\n## Panics\nPanics if the result overflows `u128`." + "simplicityhl_name": "mul_256_64_wide", + "section": "`u256` arithmetic", + "input_type": "u256, u64", + "output_type": "(u64, u256)", + "description": "Multiply a `u256` value by a `u64` value. The full, non-truncated product is returned as a `u64`/`u256` pair, most-significant first, so this operation can never overflow." }, { - "simplicityhl_name": "div_mod_128_64", - "section": "`u128` arithmetic", - "input_type": "u128, u64", - "output_type": "(u128, u64)", - "description": "Divide a `u128` value by a `u64` value, returning the `u128` quotient and the `u64` remainder.\n\n## Panics\nPanics if the divisor is zero." + "simplicityhl_name": "mul_256_128_wide", + "section": "`u256` arithmetic", + "input_type": "u256, u128", + "output_type": "(u128, u256)", + "description": "Multiply a `u256` value by a `u128` value. The full, non-truncated product is returned as a `u128`/`u256` pair, most-significant first, so this operation can never overflow." }, { - "simplicityhl_name": "div_mod_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "(u128, u128)", - "description": "Divide the first `u128` value by the second, returning the quotient and the remainder.\n\n## Panics\nPanics if the divisor is zero." + "simplicityhl_name": "mul_512_128_wide", + "section": "`u256` arithmetic", + "input_type": "u256, u256, u128", + "output_type": "(u128, u256, u256)", + "description": "Multiply a `u512` value by a `u128` value. The full, non-truncated product is returned as a (`u128`, `u256`, `u256`) tuple, most-significant first, so this operation can never overflow." }, { - "simplicityhl_name": "div_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "u128", - "description": "Divide the first `u128` value by the second, returning the quotient.\n\n## Panics\nPanics if the divisor is zero." + "simplicityhl_name": "checked_mul_256", + "section": "`u256` arithmetic", + "input_type": "u256, u256", + "output_type": "Option", + "description": "Multiply two `u256` values. Return `Some` of the product, or `None` if the result overflows `u256`." }, { - "simplicityhl_name": "checked_div_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", - "output_type": "Option", - "description": "Divide the first `u128` value by the second. Return `Some` of the quotient, or `None` if the divisor is zero." + "simplicityhl_name": "mul_256", + "section": "`u256` arithmetic", + "input_type": "u256, u256", + "output_type": "u256", + "description": "Multiply two `u256` values.\n\n## Panics\nPanics if the result overflows `u256`." }, { - "simplicityhl_name": "safe_div_128", - "section": "`u128` arithmetic", - "input_type": "u128, u128", + "simplicityhl_name": "mul_256_128", + "section": "`u256` arithmetic", + "input_type": "u256, u128", + "output_type": "u256", + "description": "Multiply a `u256` value by a `u128` value.\n\n## Panics\nPanics if the result overflows `u256`." + }, + { + "simplicityhl_name": "calculate_normalizer_base_128", + "section": "`u256` arithmetic", + "input_type": "u256", "output_type": "u128", - "description": "Divide the first `u128` value by the second.\n\n## Panics\nPanics if the divisor is zero." + "description": "Helper for algorithm D division algorithms. Returns the factor by which `b` should be multiplied so that its upper 128 bits are at least `2^127`, as required by those algorithms (which operate in base `2^128`).\n\n## Panics\nThe assertion fails if `b`'s upper 128 bits are zero" }, { - "simplicityhl_name": "full_add_128", - "section": "`u128` arithmetic", - "input_type": "bool, u128, u128", - "output_type": "(bool, u128)", - "description": "Add two `u128` values, taking an incoming carry bit. Return the outgoing carry bit and the sum." + "simplicityhl_name": "div_mod_256_64", + "section": "`u256` arithmetic", + "input_type": "u256, u64", + "output_type": "(u256, u64)", + "description": "Divide a `u256` value by a `u64` value, returning the `u256` quotient and the `u64` remainder.\n\n## Panics\nPanics if the divisor is zero." }, { - "simplicityhl_name": "full_sub_128", - "section": "`u128` arithmetic", - "input_type": "bool, u128, u128", - "output_type": "(bool, u128)", - "description": "Subtract the second `u128` value from the first, taking an incoming borrow bit. Return the outgoing borrow bit and the difference." + "simplicityhl_name": "algorithm_d_256_128", + "section": "`u256` arithmetic", + "input_type": "u256, u128", + "output_type": "(u256, u128)", + "description": "Divide a `u256` value by a `u128` value, returning the `u256` quotient and the `u128` remainder.\n\n## Panics\nPanics if the divisor is zero or if divisor's upper 64 bits are zero." }, { - "simplicityhl_name": "mul_128_64", - "section": "`u128` arithmetic", - "input_type": "u128, u64", + "simplicityhl_name": "div_mod_256_128", + "section": "`u256` arithmetic", + "input_type": "u256, u128", + "output_type": "(u256, u128)", + "description": "Divide a `u256` value by a `u128` value, returning the `u256` quotient and the `u128` remainder.\n\n## Panics\nPanics if the divisor is zero." + }, + { + "simplicityhl_name": "div_mod_256", + "section": "`u256` arithmetic", + "input_type": "u256, u256", + "output_type": "(u256, u256)", + "description": "Divide the first `u256` value by the second, returning the quotient and the remainder.\n\n## Panics\nPanics if the divisor is zero." + }, + { + "simplicityhl_name": "div_256", + "section": "`u256` arithmetic", + "input_type": "u256, u256", "output_type": "u256", - "description": "Multiply a `u128` value by a `u64` value. The full, non-truncated product is returned as a `u256`, so this operation can never overflow." + "description": "Divide the first `u256` value by the second, returning the quotient.\n\n## Panics\nPanics if the divisor is zero." }, { - "simplicityhl_name": "calculate_normalizer_base_64", - "section": "`u128` arithmetic", - "input_type": "u128, bool", - "output_type": "u64", - "description": "Helper for `jet::div_mod_128_64`-based division algorithms. Returns the factor by which `b` should be multiplied so that its most-significant non-zero word is at least `2^63`, as required by those algorithms (which operate in base `2^64`). Set `is_b_u128` to `true` if `b`'s upper 64 bits may be non-zero, or `false` if `b` is known to fit in `u64` (in which case its upper 64 bits must already be zero).\n\n## Panics\nThe assertion fails if `is_b_u128` is `false` but `b`'s upper 64 bits are non-zero, or if `b` is zero." + "simplicityhl_name": "checked_div_256", + "section": "`u256` arithmetic", + "input_type": "u256, u256", + "output_type": "Option", + "description": "Divide the first `u256` value by the second. Return `Some` of the quotient, or `None` if the divisor is zero." }, { - "simplicityhl_name": "estimate_quotient_digit_base_64", - "section": "`u128` arithmetic", - "input_type": "u64, u64, u64, u64, u64", - "output_type": "u64", - "description": "Helper for Algorithm D division. Estimates and corrects the next base-`2^64` quotient digit from the three most-significant dividend words (`u2`, `u1`, `u0`) and the two most-significant divisor words (`v1`, `v0`)." + "simplicityhl_name": "mul_div_256", + "section": "`u256` arithmetic", + "input_type": "u256, u256, u256", + "output_type": "u256", + "description": "Calculate `floor(a * b / denominator)` with full precision. \n\n## Panics\nPanics if the result overflows a `u256` or if the denominator is zero." }, { "simplicityhl_name": "and_256", @@ -1237,131 +1783,5 @@ "input_type": "u256", "output_type": "u128", "description": "Narrow a `u256` value to `u128`.\n\n## Panics\nPanics if the value does not fit in `u128`." - }, - { - "simplicityhl_name": "add_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "(bool, u256)", - "description": "Add two `u256` values. Return the carry bit and the sum." - }, - { - "simplicityhl_name": "add_256_128", - "section": "`u256` arithmetic", - "input_type": "u256, u128", - "output_type": "(bool, u256)", - "description": "Add a `u128` value to a `u256` value. Return the carry bit and the sum." - }, - { - "simplicityhl_name": "checked_add_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "Option", - "description": "Add two `u256` values. Return `Some` of the sum, or `None` if the result overflows `u256`." - }, - { - "simplicityhl_name": "safe_add_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "u256", - "description": "Add two `u256` values.\n\n## Panics\nPanics if the result overflows `u256`." - }, - { - "simplicityhl_name": "sub_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "(bool, u256)", - "description": "Subtract the second `u256` value from the first. Return the borrow bit and the difference." - }, - { - "simplicityhl_name": "checked_sub_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "Option", - "description": "Subtract the second `u256` value from the first. Return `Some` of the difference, or `None` if the result would underflow `u256`." - }, - { - "simplicityhl_name": "safe_sub_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "u256", - "description": "Subtract the second `u256` value from the first.\n\n## Panics\nPanics if the result would underflow `u256`." - }, - { - "simplicityhl_name": "mul_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "(u256, u256)", - "description": "Multiply two `u256` values. The full, non-truncated product is returned as a pair of `u256` values, most-significant first, so this operation can never overflow." - }, - { - "simplicityhl_name": "mul_256_64", - "section": "`u256` arithmetic", - "input_type": "u256, u64", - "output_type": "(u64, u256)", - "description": "Multiply a `u256` value by a `u64` value. The full, non-truncated product is returned as a `u64`/`u256` pair, most-significant first, so this operation can never overflow." - }, - { - "simplicityhl_name": "mul_256_128", - "section": "`u256` arithmetic", - "input_type": "u256, u128", - "output_type": "(u128, u256)", - "description": "Multiply a `u256` value by a `u128` value. The full, non-truncated product is returned as a `u128`/`u256` pair, most-significant first, so this operation can never overflow." - }, - { - "simplicityhl_name": "checked_mul_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "Option", - "description": "Multiply two `u256` values. Return `Some` of the product, or `None` if the result overflows `u256`." - }, - { - "simplicityhl_name": "safe_mul_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "u256", - "description": "Multiply two `u256` values.\n\n## Panics\nPanics if the result overflows `u256`." - }, - { - "simplicityhl_name": "div_mod_256_64", - "section": "`u256` arithmetic", - "input_type": "u256, u64", - "output_type": "(u256, u64)", - "description": "Divide a `u256` value by a `u64` value, returning the `u256` quotient and the `u64` remainder.\n\n## Panics\nPanics if the divisor is zero." - }, - { - "simplicityhl_name": "div_mod_256_128", - "section": "`u256` arithmetic", - "input_type": "u256, u128", - "output_type": "(u256, u128)", - "description": "Divide a `u256` value by a `u128` value, returning the `u256` quotient and the `u128` remainder.\n\n## Panics\nPanics if the divisor is zero." - }, - { - "simplicityhl_name": "div_mod_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "(u256, u256)", - "description": "Divide the first `u256` value by the second, returning the quotient and the remainder.\n\n## Panics\nPanics if the divisor is zero." - }, - { - "simplicityhl_name": "div_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "u256", - "description": "Divide the first `u256` value by the second, returning the quotient.\n\n## Panics\nPanics if the divisor is zero." - }, - { - "simplicityhl_name": "checked_div_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "Option", - "description": "Divide the first `u256` value by the second. Return `Some` of the quotient, or `None` if the divisor is zero." - }, - { - "simplicityhl_name": "safe_div_256", - "section": "`u256` arithmetic", - "input_type": "u256, u256", - "output_type": "u256", - "description": "Divide the first `u256` value by the second.\n\n## Panics\nPanics if the divisor is zero." } -] +] \ No newline at end of file diff --git a/simf/asserts_test.simf b/simf/asserts_test.simf deleted file mode 100644 index 36e1708..0000000 --- a/simf/asserts_test.simf +++ /dev/null @@ -1,62 +0,0 @@ -use crate::lib::asserts::{ - assert_eq_1, - assert_eq_8, - assert_eq_16, - assert_eq_32, - assert_eq_64, - assert_eq_128, - assert_eq_256, - assert_eq_bool, - assert_none_1, - 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() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a_u1: Option = witness::FIRST_ARG_U1; - let b_u1: Option = witness::SECOND_ARG_U1; - - let a_u8: Option = witness::FIRST_ARG_U8; - let b_u8: Option = witness::SECOND_ARG_U8; - - let a_u16: Option = witness::FIRST_ARG_U16; - let b_u16: Option = witness::SECOND_ARG_U16; - - let a_u32: Option = witness::FIRST_ARG_U32; - let b_u32: Option = witness::SECOND_ARG_U32; - - let a_u64: Option = witness::FIRST_ARG_U64; - let b_u64: Option = witness::SECOND_ARG_U64; - - let a_u128: Option = witness::FIRST_ARG_U128; - let b_u128: Option = witness::SECOND_ARG_U128; - - let a_u256: Option = witness::FIRST_ARG_U256; - let b_u256: Option = witness::SECOND_ARG_U256; - - // Assert Eq - match if_test_this_function(0, fn_idx) { true => { assert_eq_1(unwrap(a_u1), unwrap(b_u1)); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_eq_8(unwrap(a_u8), unwrap(b_u8)); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_eq_16(unwrap(a_u16), unwrap(b_u16)); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert_eq_32(unwrap(a_u32), unwrap(b_u32)); }, false => (), }; - match if_test_this_function(4, fn_idx) { true => { assert_eq_64(unwrap(a_u64), unwrap(b_u64)); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert_eq_128(unwrap(a_u128), unwrap(b_u128)); }, false => (), }; - match if_test_this_function(6, fn_idx) { true => { assert_eq_256(unwrap(a_u256), unwrap(b_u256)); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert_eq_bool(::into(unwrap(a_u1)), ::into(unwrap(b_u1))); }, false => (), }; - - // Assert None - match if_test_this_function(8, fn_idx) { true => { assert_none_1(a_u1); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_none_8(a_u8); }, false => (), }; - match if_test_this_function(10, fn_idx) { true => { assert_none_16(a_u16); }, false => (), }; - match if_test_this_function(11, fn_idx) { true => { assert_none_32(a_u32); }, false => (), }; - match if_test_this_function(12, fn_idx) { true => { assert_none_64(a_u64); }, false => (), }; - match if_test_this_function(13, fn_idx) { true => { assert_none_128(a_u128); }, false => (), }; - match if_test_this_function(14, fn_idx) { true => { assert_none_256(a_u256); }, false => (), }; -} diff --git a/simf/binary_test.simf b/simf/binary_test.simf deleted file mode 100644 index ec4ab30..0000000 --- a/simf/binary_test.simf +++ /dev/null @@ -1,21 +0,0 @@ -use crate::lib::binary::{not, or, and, xor}; - -fn main() { - assert!(not(false)); - assert!(not(not(true))); - - assert!(or(true, false)); - assert!(or(false, true)); - assert!(or(true, true)); - assert!(not(or(false, false))); - - assert!(and(true, true)); - assert!(not(and(true, false))); - assert!(not(and(false, true))); - assert!(not(and(false, false))); - - assert!(xor(true, false)); - assert!(xor(false, true)); - assert!(not(xor(true, true))); - assert!(not(xor(false, false))); -} diff --git a/simf/helper.simf b/simf/helper.simf deleted file mode 100644 index 4bfc650..0000000 --- a/simf/helper.simf +++ /dev/null @@ -1,13 +0,0 @@ -use crate::lib::binary::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)), - } -} diff --git a/simf/lib/asserts.simf b/simf/lib/asserts.simf index 1c6ad58..6ab2638 100644 --- a/simf/lib/asserts.simf +++ b/simf/lib/asserts.simf @@ -1,6 +1,6 @@ use crate::lib::u128::bit::eq_128; -/// Asserts that two `u1` are equal +/// Asserts that two u1 are equal pub fn assert_eq_1(a: u1, b: u1) { assert!(jet::eq_1(a, b)) } diff --git a/simf/lib/binary.simf b/simf/lib/binary.simf index 85f67d0..9042811 100644 --- a/simf/lib/binary.simf +++ b/simf/lib/binary.simf @@ -1,19 +1,19 @@ /// Returns the result of the NOT operation on the provided value pub fn not(bit: bool) -> bool { - ::into(jet::complement_1(::into(bit))) + ::into(jet::complement_1(::into(bit))) } /// Returns the result of the OR operation on the provided values pub fn or(a: bool, b: bool) -> bool { - ::into(jet::or_1(::into(a), ::into(b))) + ::into(jet::or_1(::into(a), ::into(b))) } /// Returns the result of the AND operation on the provided values pub fn and(a: bool, b: bool) -> bool { - ::into(jet::and_1(::into(a), ::into(b))) + ::into(jet::and_1(::into(a), ::into(b))) } /// Returns the result of the XOR operation on the provided values pub fn xor(a: bool, b: bool) -> bool { - and(or(a, b), not(and(a, b))) + and(or(a, b), not(and(a, b))) } diff --git a/simf/lib/op_return.simf b/simf/lib/op_return.simf index 2f71087..d6e1d85 100644 --- a/simf/lib/op_return.simf +++ b/simf/lib/op_return.simf @@ -8,5 +8,5 @@ pub fn is_output_op_return(output_index: u32) -> bool { /// Asserts that the specified output is an OP_RETURN (null data) output pub fn assert_output_is_op_return(output_index: u32) { - assert!(is_output_op_return(output_index)); + assert!(is_output_op_return(output_index)); } diff --git a/simf/lib/secp256k1/operations.simf b/simf/lib/secp256k1/operations.simf index 0cfabbe..4a1fe85 100644 --- a/simf/lib/secp256k1/operations.simf +++ b/simf/lib/secp256k1/operations.simf @@ -1,5 +1,5 @@ use crate::lib::binary::and; -use crate::lib::asserts::{assert_eq_1, assert_eq_256}; +use crate::lib::asserts::assert_eq_1; /// Compress an affine point to `(parity, x)`, where `parity = 1` iff `y` is odd. pub fn ge_to_point(p: Ge) -> Point { @@ -12,11 +12,17 @@ pub fn ge_to_point(p: Ge) -> Point { } /// Decompress a `Point` into a Jacobian point with `z = 1`. +/// +/// ## Panics +/// - if `x` is not the x-coordinate of a curve point pub fn point_to_gej(p: Point) -> Gej { (unwrap(jet::decompress(p)), 1) } /// Convert the point into affine coordinates. +/// +/// ## Panics +/// - if `p` is the point at infinity pub fn safe_gej_normalize(p: Gej) -> Ge { unwrap(jet::gej_normalize(p)) } @@ -53,16 +59,25 @@ pub fn ge_eq(a: Ge, b: Ge) -> bool { and(fe_eq(ax, bx), fe_eq(ay, by)) } -/// Check if two points are equal. +/// Compressed point equality, with `x` compared modulo `p`. pub fn point_point_eq(a: Point, b: Point) -> bool { - let (ap, ax): (u1, u256) = a; - let (bp, bx): (u1, u256) = b; - and(jet::eq_256(ax, bx), jet::eq_1(ap, bp)) + let (ap, ax): (u1, Fe) = a; + let (bp, bx): (u1, Fe) = b; + and(fe_eq(ax, bx), jet::eq_1(ap, bp)) } -/// Check if two points represent the same point +/// Check if two points represent the same point. +/// Returns `false` if `a` is off-curve or `p` does not decompress to a curve point. pub fn gej_point_eq(a: Gej, p: Point) -> bool { - jet::gej_ge_equiv(a, unwrap(jet::decompress(p))) + let (parity, x): (u1, Fe) = p; + + // Cheaper than `decompress`: an on-curve `a` with matching `x` and `y` parity is exactly `p`. + let parity_eq: bool = match jet::gej_y_is_odd(a) { + true => jet::eq_1(parity, 1), + false => jet::eq_1(parity, 0), + }; + + and(and(jet::gej_is_on_curve(a), jet::gej_x_equiv(x, a)), parity_eq) } /// Field equality modulo `p`. @@ -79,17 +94,17 @@ pub fn assert_scalar_eq(a: Scalar, b: Scalar) { pub fn assert_ge_eq(a: Ge, b: Ge) { let (ax, ay): (Fe, Fe) = a; let (bx, by): (Fe, Fe) = b; - + assert_fe_eq(ax, bx); assert_fe_eq(ay, by); } -/// Check if two points are equal. +/// Compressed point equality, with `x` compared modulo `p`. pub fn assert_point_eq(a: Point, b: Point) { - let (ap, ax): (u1, u256) = a; - let (bp, bx): (u1, u256) = b; + let (ap, ax): (u1, Fe) = a; + let (bp, bx): (u1, Fe) = b; - assert_eq_256(ax, bx); + assert_fe_eq(ax, bx); assert_eq_1(ap, bp); } @@ -99,11 +114,17 @@ pub fn assert_gej_point_eq(a: Gej, p: Point) { } /// Assert two points represent the same curve point. +/// Both points must be on the curve: `gej_equiv` only rejects `y = -b.y` for a matching `x`. pub fn assert_gej_eq(a: Gej, b: Gej) { + assert!(jet::gej_is_on_curve(a)); + assert!(jet::gej_is_on_curve(b)); assert!(jet::gej_equiv(a, b)); } /// Assert point equal an affine point (no normalize required). +/// Both points must be on the curve: `gej_ge_equiv` only rejects `y = -b.y` for a matching `x`. pub fn assert_gej_ge_eq(a: Gej, b: Ge) { + assert!(jet::gej_is_on_curve(a)); + assert!(jet::ge_is_on_curve(b)); assert!(jet::gej_ge_equiv(a, b)); } diff --git a/simf/lib/u128/bit.simf b/simf/lib/u128/bit.simf index 1e4f0e9..7b8e208 100644 --- a/simf/lib/u128/bit.simf +++ b/simf/lib/u128/bit.simf @@ -35,7 +35,10 @@ pub fn left_shift_128(shift: u8, a: u128) -> u128 { match jet::lt_8(shift, 64) { true => { - let (_, low_to_high_amount): (bool, u8) = jet::subtract_8(64, shift); // shift < 64 + let ( + _, + low_to_high_amount + ): (bool, u8) = jet::subtract_8(64, shift); // shift < 64 let shifted_bits: u64 = jet::right_shift_64(low_to_high_amount, a_low); let res_high: u64 = jet::or_64(jet::left_shift_64(shift, a_high), shifted_bits); @@ -46,9 +49,9 @@ pub fn left_shift_128(shift: u8, a: u128) -> u128 { let (_, shift): (bool, u8) = jet::subtract_8(shift, 64); // shift >= 64 <(u64, u64)>::into((jet::left_shift_64(shift, a_low), 0)) - } + }, } - } + }, } } @@ -61,7 +64,10 @@ pub fn right_shift_128(shift: u8, a: u128) -> u128 { match jet::lt_8(shift, 64) { true => { - let (_, high_to_low_amount): (bool, u8) = jet::subtract_8(64, shift); // shift < 64 + let ( + _, + high_to_low_amount + ): (bool, u8) = jet::subtract_8(64, shift); // shift < 64 let shifted_bits: u64 = jet::left_shift_64(high_to_low_amount, a_high); let res_low: u64 = jet::or_64(jet::right_shift_64(shift, a_low), shifted_bits); @@ -72,8 +78,8 @@ pub fn right_shift_128(shift: u8, a: u128) -> u128 { let (_, shift): (bool, u8) = jet::subtract_8(shift, 64); // shift >= 64 <(u64, u64)>::into((0, jet::right_shift_64(shift, a_high))) - } + }, } - } + }, } } diff --git a/simf/lib/u128/math.simf b/simf/lib/u128/math.simf index 1909850..db0d26b 100644 --- a/simf/lib/u128/math.simf +++ b/simf/lib/u128/math.simf @@ -1,12 +1,15 @@ use crate::lib::binary::{not, or, and}; +use crate::lib::u64::convert::u64_to_u128; + use crate::lib::u128::comparison::{is_zero_128, lt_128}; +use crate::lib::u128::convert::{u128_to_u256, split_u128_into_u64}; /// Arithmetic /// Adds two integers and returns 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); +pub fn add_128_carry(a: u128, b: u128) -> (bool, u128) { + let (a_high, a_low): (u64, u64) = split_u128_into_u64(a); + let (b_high, b_low): (u64, u64) = split_u128_into_u64(b); let (carry_low, sum_low): (bool, u64) = jet::add_64(a_low, b_low); let (carry_high, sum_high): (bool, u64) = jet::full_add_64(carry_low, a_high, b_high); @@ -16,8 +19,8 @@ pub fn add_128(a: u128, b: u128) -> (bool, u128) { } /// Adds the 128-bit integer with the 64-bit integer and returns the carry -pub fn add_128_64(a: u128, b: u64) -> (bool, u128) { - let (a_high, a_low): (u64, u64) = ::into(a); +pub fn add_128_64_carry(a: u128, b: u64) -> (bool, u128) { + let (a_high, a_low): (u64, u64) = split_u128_into_u64(a); let (carry_low, res_low): (bool, u64) = jet::add_64(a_low, b); let (carry_high, res_high): (bool, u64) = jet::full_add_64(carry_low, a_high, 0); @@ -28,8 +31,8 @@ pub fn add_128_64(a: u128, b: u64) -> (bool, u128) { /// Adds two integers. Takes a carry-in and returns a carry-out pub fn full_add_128(carry_in: bool, 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 (a_high, a_low): (u64, u64) = split_u128_into_u64(a); + let (b_high, b_low): (u64, u64) = split_u128_into_u64(b); let (carry_low, sum_low): (bool, u64) = jet::full_add_64(carry_in, a_low, b_low); let (carry_out, sum_high): (bool, u64) = jet::full_add_64(carry_low, a_high, b_high); @@ -40,7 +43,7 @@ pub fn full_add_128(carry_in: bool, a: u128, b: u128) -> (bool, u128) { /// 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); + let (carry, sum): (bool, u128) = add_128_carry(a, b); match carry { true => None, @@ -49,14 +52,14 @@ pub fn checked_add_128(a: u128, b: u128) -> Option { } /// Returns the sum of two u128 values, panics if the result overflows u128 -pub fn safe_add_128(a: u128, b: u128) -> u128 { +pub fn 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); +pub fn sub_128_borrow(a: u128, b: u128) -> (bool, u128) { + let (a_high, a_low): (u64, u64) = split_u128_into_u64(a); + let (b_high, b_low): (u64, u64) = split_u128_into_u64(b); let (borrow_low, diff_low): (bool, u64) = jet::subtract_64(a_low, b_low); let (borrow_high, diff_high): (bool, u64) = jet::full_subtract_64(borrow_low, a_high, b_high); @@ -67,8 +70,8 @@ pub fn sub_128(a: u128, b: u128) -> (bool, u128) { /// Subtracts the second integer from the first integer, takes a borrow-in and returns a borrow-out pub fn full_sub_128(borrow_in: bool, 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 (a_high, a_low): (u64, u64) = split_u128_into_u64(a); + let (b_high, b_low): (u64, u64) = split_u128_into_u64(b); let (borrow_low, diff_low): (bool, u64) = jet::full_subtract_64(borrow_in, a_low, b_low); let (borrow_out, diff_high): (bool, u64) = jet::full_subtract_64(borrow_low, a_high, b_high); @@ -79,7 +82,7 @@ pub fn full_sub_128(borrow_in: bool, a: u128, b: u128) -> (bool, u128) { /// 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); + let (borrow, diff): (bool, u128) = sub_128_borrow(a, b); match borrow { true => None, @@ -88,7 +91,7 @@ pub fn checked_sub_128(a: u128, b: u128) -> Option { } /// Returns the difference of two u128 values, panics if the result overflows u128 -pub fn safe_sub_128(a: u128, b: u128) -> u128 { +pub fn sub_128(a: u128, b: u128) -> u128 { unwrap(checked_sub_128(a, b)) } @@ -97,20 +100,20 @@ pub fn safe_sub_128(a: u128, b: u128) -> u128 { /// 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); +pub fn mul_128_wide(a: u128, b: u128) -> u256 { + let (a_high, a_low): (u64, u64) = split_u128_into_u64(a); + let (b_high, b_low): (u64, u64) = split_u128_into_u64(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 (word_1, word_0): (u64, u64) = split_u128_into_u64(lowest); + let (word_3, word_2): (u64, u64) = split_u128_into_u64(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_3a, middle): (bool, u128) = add_128(product_1, product_2); + let (carry_3a, middle): (bool, u128) = add_128_carry(product_1, product_2); - let (middle_2, middle_1): (u64, u64) = ::into(middle); + let (middle_2, middle_1): (u64, u64) = split_u128_into_u64(middle); // fold the low-side carry directly into the word_2 addition via full_add_64, // then propagate any resulting carry into word_3 @@ -121,7 +124,7 @@ pub fn mul_128(a: u128, b: u128) -> u256 { // either factor is `u64::MAX`, and even in the extreme case where // a == b == u128::MAX, the total product still fits into u256. // Therefore, word_3 + carry_3a + carry_3b can not overflow, and `full_add_64` - // is used instead of `safe_add_64` to avoid the unnecessary overflow check + // is used instead of `add_64` to avoid the unnecessary overflow check let (_, res_3a): (bool, u64) = jet::full_add_64(carry_3a, word_3, 0); let (_, res_3): (bool, u64) = jet::full_add_64(carry_3b, res_3a, 0); @@ -135,18 +138,18 @@ pub fn mul_128(a: u128, b: u128) -> u256 { /// The idea is that u128-bit `a` divides into 64-bit `a_high` and `a_low`, /// so a = a_high * 2^64 + a_low. /// Therefore, a * b = 2^64 * a_high * b + a_low * b. -pub fn mul_128_64(a: u128, b: u64) -> u256 { - let (a_high, a_low): (u64, u64) = ::into(a); +pub fn mul_128_64_wide(a: u128, b: u64) -> u256 { + let (a_high, a_low): (u64, u64) = split_u128_into_u64(a); let highest: u128 = jet::multiply_64(a_high, b); let lowest: u128 = jet::multiply_64(a_low, b); - let (word_1, word_0): (u64, u64) = ::into(lowest); - let (word_3, word_2): (u64, u64) = ::into(highest); + let (word_1, word_0): (u64, u64) = split_u128_into_u64(lowest); + let (word_3, word_2): (u64, u64) = split_u128_into_u64(highest); let (carry_2, res_1): (bool, u64) = jet::add_64(word_1, word_2); // a * b fits into u192, so addition below can not overflow and `full_add_64` - // is used instead of `safe_add_64` to avoid the unnecessary overflow check + // is used instead of `add_64` to avoid the unnecessary overflow check let (_, res_2): (bool, u64) = jet::full_add_64(carry_2, word_3, 0); <(u64, u64, u64, u64)>::into((0, res_2, res_1, word_0)) @@ -154,7 +157,7 @@ pub fn mul_128_64(a: u128, b: u64) -> u256 { /// 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 result: u256 = mul_128_wide(a, b); let (high, low): (u128, u128) = ::into(result); match is_zero_128(high) { @@ -164,24 +167,24 @@ pub fn checked_mul_128(a: u128, b: u128) -> Option { } /// Returns the product of two u128 values, panics if the result overflows u128 -pub fn safe_mul_128(a: u128, b: u128) -> u128 { +pub fn mul_128(a: u128, b: u128) -> u128 { unwrap(checked_mul_128(a, b)) } /// Helper function that can be used with jet::div_mod_128_64 or Algorithm D. /// Returns the normalization factor by which `b` should be multiplied so that /// its most significant non-zero word is greater than or equal to 2^63 -pub fn calculate_normalizer_base_64(b: u128, is_b_u128: bool) -> u64 { +pub fn calculate_normalizer_base_64(b: u128, is_b_u128: bool) -> u64 { // Compile-time constant: 2^63. Avoids a runtime jet::left_shift_64 call let threshold: u64 = 0x8000000000000000; - let (b_high, b_low): (u64, u64) = ::into(b); + let (b_high, b_low): (u64, u64) = split_u128_into_u64(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))); @@ -190,9 +193,12 @@ pub fn calculate_normalizer_base_64(b: u128, is_b_u128: bool) -> u64 { match jet::is_zero_64(remainder) { true => norm, false => { - let (_, norm): (bool, u64) = jet::add_64(norm, 1); // norm <= 2^63, so norm + 1 can not overflow + let ( + _, + norm + ): (bool, u64) = jet::add_64(norm, 1); // norm <= 2^63, so norm + 1 can not overflow norm - } + }, } } @@ -206,11 +212,11 @@ pub fn calculate_normalizer_base_64(b: u128, is_b_u128: bool) -> u64 { /// Division algorithms operate in base 2^64, so the normalization threshold is 2^63 fn normalize_to_threshold_128_63(a: u128, b: u128, is_b_u128: bool) -> (u256, u128, u64) { let norm: u64 = calculate_normalizer_base_64(b, is_b_u128); - let norm_128: u128 = <(u64, u64)>::into((0, norm)); + let norm_128: u128 = u64_to_u128(norm); match jet::eq_64(norm, 1) { - true => (<(u128, u128)>::into((0, a)), b, norm), - false => (mul_128(a, norm_128), safe_mul_128(b, norm_128), norm), + true => (u128_to_u256(a), b, norm), + false => (mul_128_wide(a, norm_128), mul_128(b, norm_128), norm), } } @@ -218,9 +224,13 @@ fn normalize_to_threshold_128_63(a: u128, b: u128, is_b_u128: bool) -> (u256, u1 /// Returns the quotient digit to use in the subsequent multiply-and-subtract step. /// Expects result to fit into u64 pub fn estimate_quotient_digit_base_64(u2: u64, u1: u64, u0: u64, v1: u64, v0: u64) -> u64 { - let (q_hat, r_hat, carry): (u64, u64, bool) = match jet::lt_64(u2, v1) { + let ( + q_hat, + r_hat, + carry + ): (u64, u64, bool) = match jet::lt_64(u2, v1) { true => { - let (q_hat, r_hat) : (u64, u64) =jet::div_mod_128_64(<(u64, u64)>::into((u2, u1)), v1); + let (q_hat, r_hat): (u64, u64) = jet::div_mod_128_64(<(u64, u64)>::into((u2, u1)), v1); (q_hat, r_hat, false) }, false => { @@ -230,7 +240,7 @@ pub fn estimate_quotient_digit_base_64(u2: u64, u1: u64, u0: u64, v1: u64, v0: u let (carry, r_hat): (bool, u64) = jet::add_64(u1, v1); (jet::high_64(), r_hat, carry) - } + }, }; match carry { @@ -242,7 +252,7 @@ pub fn estimate_quotient_digit_base_64(u2: u64, u1: u64, u0: u64, v1: u64, v0: u match lt_128(r_hat_u0, jet::multiply_64(q_hat, v0)) { true => { // can not overflow because r_hat_u0 < q_hat * v0, so q_hat is at least 1 - let (_, q_hat): (bool, u64) = jet::subtract_64(q_hat, 1); + let (_, q_hat): (bool, u64) = jet::subtract_64(q_hat, 1); let (carry, r_hat): (bool, u64) = jet::add_64(r_hat, v1); match carry { @@ -253,18 +263,18 @@ pub fn estimate_quotient_digit_base_64(u2: u64, u1: u64, u0: u64, v1: u64, v0: u match lt_128(r_hat_u0, jet::multiply_64(q_hat, v0)) { true => { // can not overflow because r_hat_u0 < q_hat * v0, so q_hat is at least 1 - let (_, q_hat): (bool, u64) = jet::subtract_64(q_hat, 1); + let (_, q_hat): (bool, u64) = jet::subtract_64(q_hat, 1); q_hat - } + }, false => q_hat, } - } + }, } }, false => q_hat, } - } + }, } } @@ -273,22 +283,27 @@ pub fn estimate_quotient_digit_base_64(u2: u64, u1: u64, u0: u64, v1: u64, v0: u /// Implements Algorithm D by Donald Knuth. /// Requires the upper half of the divisor to be non-zero. fn algorithm_d_128_128(dividend: u128, divisor: u128) -> (u64, u128) { - let (norm_dividend, norm_divisor, _): (u256, u128, u64) = normalize_to_threshold_128_63(dividend, divisor, true); + let ( + norm_dividend, + norm_divisor, + _ + ): (u256, u128, u64) = normalize_to_threshold_128_63(dividend, divisor, true); // normalized dividend fits into 192 bits let (_, u2, u1, u0): (u64, u64, u64, u64) = ::into(norm_dividend); - let (v1, v0): (u64, u64) = ::into(norm_divisor); + let (v1, v0): (u64, u64) = split_u128_into_u64(norm_divisor); let q: u64 = estimate_quotient_digit_base_64(u2, u1, u0, v1, v0); - let remainder: u128 = safe_sub_128(dividend, safe_mul_128(divisor, <(u64, u64)>::into((0, q)))); + let remainder: u128 = sub_128(dividend, mul_128(divisor, u64_to_u128(q))); (q, remainder) } /// Divides the 128-bit integer by the 64-bit integer, -/// returns a tuple of the u128 quotient and the u64 remainder +/// returns a tuple of the u128 quotient and the u64 remainder. +/// Panics if the divisor is zero pub fn div_mod_128_64(a: u128, b: u64) -> (u128, u64) { - let (a_high, a_low): (u64, u64) = ::into(a); + let (a_high, a_low): (u64, u64) = split_u128_into_u64(a); // calculate the upper half of the quotient let (q_high, remainder): (u64, u64) = jet::div_mod_64(a_high, b); @@ -297,11 +312,15 @@ pub fn div_mod_128_64(a: u128, b: u64) -> (u128, u64) { let a_prime: u128 = <(u64, u64)>::into((remainder, a_low)); // we need to normalize here, because jet::div_mod_128_64 only accepts b >= 2^63 - let (a_normalized, b_normalized, norm): (u256, u128, u64) = normalize_to_threshold_128_63(a_prime, <(u64, u64)>::into((0, b)), false); + let ( + a_normalized, + b_normalized, + norm + ): (u256, u128, u64) = normalize_to_threshold_128_63(a_prime, u64_to_u128(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); + let (_, b_normalized): (u64, u64) = split_u128_into_u64(b_normalized); // remainder < b, so (remainder * 2^64 + a_low) / b fits into u64 let (q_low, r_normalized): (u64, u64) = jet::div_mod_128_64(a_normalized, b_normalized); @@ -312,62 +331,60 @@ pub fn div_mod_128_64(a: u128, b: u64) -> (u128, u64) { /// Divides the first integer by the second integer, /// returns the quotient and the remainder +/// Panics if the divisor is zero 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); + assert!(not(is_zero_128(b))); + + let (a_high, a_low): (u64, u64) = split_u128_into_u64(a); + let (b_high, b_low): (u64, u64) = split_u128_into_u64(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 => { + match and(jet::is_zero_64(a_high), jet::is_zero_64(b_high)) { + true => { // if both a_high and b_high are 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))) + (u64_to_u128(q), u64_to_u128(r)) }, false => { match jet::eq_64(a_high, b_high) { true => { // safe: !lt_128(a, b) and a_high == b_high, so a_low >= b_low, - // and the subtraction can not underflow + // and the subtraction can not overflow let (_, diff): (bool, u64) = jet::subtract_64(a_low, b_low); - (1, <(u64, u64)>::into((0, diff))) + (1, u64_to_u128(diff)) + }, + false => match jet::is_zero_64(b_high) { + true => { + let (q, r): (u128, u64) = div_mod_128_64(a, b_low); + (q, u64_to_u128(r)) + }, + false => { + let (q, r): (u64, u128) = algorithm_d_128_128(a, b); + (u64_to_u128(q), r) + }, }, - 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_128_128(a, b); - (<(u64, u64)>::into((0, q)), r) - } - } - } } - } + }, } - } + }, } + } /// Divide the first integer by the second integer, returns the quotient +/// Panics if the divisor is zero 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 +/// Returns the quotient of two u128 values wrapped in Some, or None if b is zero 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/u128/mul_div.simf b/simf/lib/u128/mul_div.simf new file mode 100644 index 0000000..e3dfc1b --- /dev/null +++ b/simf/lib/u128/mul_div.simf @@ -0,0 +1,15 @@ +use crate::lib::u128::math::mul_128_wide; +use crate::lib::u128::convert::u128_to_u256; + +use crate::lib::u256::math::div_256; +use crate::lib::u256::convert::safe_u256_to_u128; + +/// Calculates `floor(a * b / denominator)` with full precision. +/// Panics if the result overflows a u128 or if the denominator is zero +pub fn mul_div_128(a: u128, b: u128, denominator: u128) -> u128 { + let denominator_256: u256 = u128_to_u256(denominator); + + let result_256: u256 = div_256(mul_128_wide(a, b), denominator_256); + + safe_u256_to_u128(result_256) +} diff --git a/simf/lib/u16/math.simf b/simf/lib/u16/math.simf index e146253..ccdb49d 100644 --- a/simf/lib/u16/math.simf +++ b/simf/lib/u16/math.simf @@ -9,14 +9,14 @@ pub fn checked_add_16(a: u16, b: u16) -> Option { } /// Returns the sum of two u16 values, panics if the result overflows u16 -pub fn safe_add_16(a: u16, b: u16) -> u16 { +pub fn add_16(a: u16, b: u16) -> u16 { unwrap(checked_add_16(a, b)) } /// Returns the difference of two u16 values wrapped in Some, or None if the result overflows u16 pub fn checked_sub_16(a: u16, b: u16) -> Option { let (borrow, diff): (bool, u16) = jet::subtract_16(a, b); - + match borrow { true => None, false => Some(diff), @@ -24,7 +24,7 @@ pub fn checked_sub_16(a: u16, b: u16) -> Option { } /// Returns the difference of two u16 values, panics if the result overflows u16 -pub fn safe_sub_16(a: u16, b: u16) -> u16 { +pub fn sub_16(a: u16, b: u16) -> u16 { unwrap(checked_sub_16(a, b)) } @@ -41,11 +41,11 @@ pub fn checked_mul_16(a: u16, b: u16) -> Option { } /// Returns the product of two u16 values, panics if the result overflows u16 -pub fn safe_mul_16(a: u16, b: u16) -> u16 { +pub fn mul_16(a: u16, b: u16) -> u16 { unwrap(checked_mul_16(a, b)) } -/// Returns the quotient of two u16 values wrapped in Some, or None if the result overflows u16 +/// Returns the quotient of two u16 values wrapped in Some, or None if b is zero pub fn checked_div_16(a: u16, b: u16) -> Option { match jet::is_zero_16(b) { true => None, @@ -53,8 +53,8 @@ pub fn checked_div_16(a: u16, b: u16) -> Option { } } -/// Returns the quotient of two u16 values, panics if the result overflows u16 -pub fn safe_div_16(a: u16, b: u16) -> u16 { +/// Returns the quotient of two u16 values, panics if the divisor is zero +pub fn div_16(a: u16, b: u16) -> u16 { unwrap(checked_div_16(a, b)) } diff --git a/simf/lib/u16/mul_div.simf b/simf/lib/u16/mul_div.simf new file mode 100644 index 0000000..0592901 --- /dev/null +++ b/simf/lib/u16/mul_div.simf @@ -0,0 +1,15 @@ +use crate::lib::binary::not; +use crate::lib::u16::convert::u16_to_u32; +use crate::lib::u32::convert::safe_u32_to_u16; + +/// Calculates `floor(a * b / denominator)` with full precision. +/// Panics if the result overflows a u16 or if the denominator is zero +pub fn mul_div_16(a: u16, b: u16, denominator: u16) -> u16 { + assert!(not(jet::is_zero_16(denominator))); + + let denominator_32: u32 = u16_to_u32(denominator); + + let result_32: u32 = jet::divide_32(jet::multiply_16(a, b), denominator_32); + + safe_u32_to_u16(result_32) +} diff --git a/simf/lib/u256/bit.simf b/simf/lib/u256/bit.simf index 2df63a7..372ebbc 100644 --- a/simf/lib/u256/bit.simf +++ b/simf/lib/u256/bit.simf @@ -27,7 +27,10 @@ pub fn left_shift_256(shift: u8, a: u256) -> u256 { match jet::lt_8(shift, 128) { true => { - let (_, low_to_high_amount): (bool, u8) = jet::subtract_8(128, shift); // shift < 128 + let ( + _, + low_to_high_amount + ): (bool, u8) = jet::subtract_8(128, shift); // shift < 128 let shifted_bits: u128 = right_shift_128(low_to_high_amount, a_low); let res_high: u128 = or_128(left_shift_128(shift, a_high), shifted_bits); @@ -38,9 +41,9 @@ pub fn left_shift_256(shift: u8, a: u256) -> u256 { let (_, shift): (bool, u8) = jet::subtract_8(shift, 128); // shift >= 128 <(u128, u128)>::into((left_shift_128(shift, a_low), 0)) - } + }, } - } + }, } } @@ -53,7 +56,10 @@ pub fn right_shift_256(shift: u8, a: u256) -> u256 { match jet::lt_8(shift, 128) { true => { - let (_, high_to_low_amount): (bool, u8) = jet::subtract_8(128, shift); // shift < 128 + let ( + _, + high_to_low_amount + ): (bool, u8) = jet::subtract_8(128, shift); // shift < 128 let shifted_bits: u128 = left_shift_128(high_to_low_amount, a_high); let res_low: u128 = or_128(right_shift_128(shift, a_low), shifted_bits); @@ -64,8 +70,8 @@ pub fn right_shift_256(shift: u8, a: u256) -> u256 { let (_, shift): (bool, u8) = jet::subtract_8(shift, 128); // shift >= 128 <(u128, u128)>::into((0, right_shift_128(shift, a_high))) - } + }, } - } + }, } } diff --git a/simf/lib/u256/math.simf b/simf/lib/u256/math.simf index 12a37f7..3102eea 100644 --- a/simf/lib/u256/math.simf +++ b/simf/lib/u256/math.simf @@ -1,12 +1,14 @@ -use crate::lib::binary::{not, and}; +use crate::lib::binary::{not, and, or}; +use crate::lib::u64::convert::u64_to_u128; + use crate::lib::u128::math::{ - add_128, + add_128_carry, full_add_128, - sub_128, + sub_128_borrow, full_sub_128, + mul_128_wide, + mul_128_64_wide, mul_128, - mul_128_64, - safe_mul_128, calculate_normalizer_base_64, estimate_quotient_digit_base_64, div_mod_128, @@ -14,18 +16,19 @@ use crate::lib::u128::math::{ }; use crate::lib::u128::bit::eq_128; use crate::lib::u128::comparison::{is_zero_128, lt_128}; +use crate::lib::u128::convert::{u128_to_u256, split_u128_into_u64}; -use crate::lib::u256::convert::split_u256_into_u64; use crate::lib::u256::comparison::{is_zero_256, lt_256}; +use crate::lib::u256::convert::{split_u256_into_u64, split_u256_into_u128}; /// Arithmetic /// Adds two integers and returns the carry -pub fn add_256(a: u256, b: u256) -> (bool, u256) { - let (a_high, a_low): (u128, u128) = ::into(a); - let (b_high, b_low): (u128, u128) = ::into(b); +pub fn add_256_carry(a: u256, b: u256) -> (bool, u256) { + let (a_high, a_low): (u128, u128) = split_u256_into_u128(a); + let (b_high, b_low): (u128, u128) = split_u256_into_u128(b); - let (carry_low, sum_low): (bool, u128) = add_128(a_low, b_low); + let (carry_low, sum_low): (bool, u128) = add_128_carry(a_low, b_low); let (carry_high, sum_high): (bool, u128) = full_add_128(carry_low, a_high, b_high); let res: u256 = <(u128, u128)>::into((sum_high, sum_low)); @@ -33,15 +36,27 @@ pub fn add_256(a: u256, b: u256) -> (bool, u256) { } /// Adds the 256-bit integer with the 128-bit integer and returns the carry -pub fn add_256_128(a: u256, b: u128) -> (bool, u256) { - let b: u256 = <(u128, u128)>::into((0, b)); +pub fn add_256_128_carry(a: u256, b: u128) -> (bool, u256) { + let b: u256 = u128_to_u256(b); + + add_256_carry(a, b) +} - add_256(a, b) +/// Adds two integers. Takes a carry-in and returns a carry-out +pub fn full_add_256(carry_in: bool, a: u256, b: u256) -> (bool, u256) { + let (a_high, a_low): (u128, u128) = split_u256_into_u128(a); + let (b_high, b_low): (u128, u128) = split_u256_into_u128(b); + + let (carry_low, sum_low): (bool, u128) = full_add_128(carry_in, a_low, b_low); + let (carry_out, sum_high): (bool, u128) = full_add_128(carry_low, a_high, b_high); + + let res: u256 = <(u128, u128)>::into((sum_high, sum_low)); + (carry_out, res) } /// Returns the sum of two u256 values wrapped in Some, or None if the result overflows u256 pub fn checked_add_256(a: u256, b: u256) -> Option { - let (carry, sum): (bool, u256) = add_256(a, b); + let (carry, sum): (bool, u256) = add_256_carry(a, b); match carry { true => None, @@ -50,16 +65,16 @@ pub fn checked_add_256(a: u256, b: u256) -> Option { } /// Returns the sum of two u256 values, panics if the result overflows u256 -pub fn safe_add_256(a: u256, b: u256) -> u256 { +pub fn add_256(a: u256, b: u256) -> u256 { unwrap(checked_add_256(a, b)) } /// Subtracts the second integer from the first integer, and returns the borrow bit -pub fn sub_256(a: u256, b: u256) -> (bool, u256) { - let (a_high, a_low): (u128, u128) = ::into(a); - let (b_high, b_low): (u128, u128) = ::into(b); +pub fn sub_256_borrow(a: u256, b: u256) -> (bool, u256) { + let (a_high, a_low): (u128, u128) = split_u256_into_u128(a); + let (b_high, b_low): (u128, u128) = split_u256_into_u128(b); - let (borrow_low, diff_low): (bool, u128) = sub_128(a_low, b_low); + let (borrow_low, diff_low): (bool, u128) = sub_128_borrow(a_low, b_low); let (borrow_high, diff_high): (bool, u128) = full_sub_128(borrow_low, a_high, b_high); let res: u256 = <(u128, u128)>::into((diff_high, diff_low)); @@ -68,7 +83,7 @@ pub fn sub_256(a: u256, b: u256) -> (bool, u256) { /// Returns the difference of two u256 values wrapped in Some, or None if the result overflows u256 pub fn checked_sub_256(a: u256, b: u256) -> Option { - let (borrow, diff): (bool, u256) = sub_256(a, b); + let (borrow, diff): (bool, u256) = sub_256_borrow(a, b); match borrow { true => None, @@ -77,7 +92,7 @@ pub fn checked_sub_256(a: u256, b: u256) -> Option { } /// Returns the difference of two u256 values, panics if the result overflows u256 -pub fn safe_sub_256(a: u256, b: u256) -> u256 { +pub fn sub_256(a: u256, b: u256) -> u256 { unwrap(checked_sub_256(a, b)) } @@ -86,31 +101,31 @@ pub fn safe_sub_256(a: u256, b: u256) -> u256 { /// so a = a_high * 2^128 + a_low. /// In the same way, b = b_high * 2^128 + b_low. /// Therefore, a * b = 2^256 * a_high * b_high + 2^128(a_high * b_low + a_low * b_high) + a_low * b_low. -pub fn mul_256(a: u256, b: u256) -> (u256, u256) { - let (a_high, a_low): (u128, u128) = ::into(a); - let (b_high, b_low): (u128, u128) = ::into(b); +pub fn mul_256_wide(a: u256, b: u256) -> (u256, u256) { + let (a_high, a_low): (u128, u128) = split_u256_into_u128(a); + let (b_high, b_low): (u128, u128) = split_u256_into_u128(b); - let highest: u256 = mul_128(a_high, b_high); - let lowest: u256 = mul_128(a_low, b_low); - let (word_1, word_0): (u128, u128) = ::into(lowest); - let (word_3, word_2): (u128, u128) = ::into(highest); + let highest: u256 = mul_128_wide(a_high, b_high); + let lowest: u256 = mul_128_wide(a_low, b_low); + let (word_1, word_0): (u128, u128) = split_u256_into_u128(lowest); + let (word_3, word_2): (u128, u128) = split_u256_into_u128(highest); - let product_1: u256 = mul_128(a_high, b_low); - let product_2: u256 = mul_128(b_high, a_low); - let (carry_3a, middle): (bool, u256) = add_256(product_1, product_2); + let product_1: u256 = mul_128_wide(a_high, b_low); + let product_2: u256 = mul_128_wide(b_high, a_low); + let (carry_3a, middle): (bool, u256) = add_256_carry(product_1, product_2); - let (middle_2, middle_1): (u128, u128) = ::into(middle); + let (middle_2, middle_1): (u128, u128) = split_u256_into_u128(middle); // fold the low-side carry directly into the word_2 addition via full_add_128, // then propagate any resulting carry into word_3 - let (carry_2, res_1): (bool, u128) = add_128(word_1, middle_1); + let (carry_2, res_1): (bool, u128) = add_128_carry(word_1, middle_1); let (carry_3b, res_2): (bool, u128) = full_add_128(carry_2, word_2, middle_2); // `word_3` is the upper half of a_high * b_high. It is at most `u128::MAX - 1` when // either factor is `u128::MAX`, and even in the extreme case where // a == b == u256::MAX, the total product still fits into two u256. // Therefore, word_3 + carry_3a + carry_3b can not overflow, and `full_add_128` - // is used instead of `safe_add_128` to avoid the unnecessary overflow check + // is used instead of `add_128` to avoid the unnecessary overflow check let (_, res_3a): (bool, u128) = full_add_128(carry_3a, word_3, 0); let (_, res_3): (bool, u128) = full_add_128(carry_3b, res_3a, 0); @@ -125,18 +140,18 @@ pub fn mul_256(a: u256, b: u256) -> (u256, u256) { /// The idea is that u256-bit `a` divides into 128-bit `a_high` and `a_low`, /// so a = a_high * 2^128 + a_low, /// a * b = 2^128 * a_high * b + a_low * b -pub fn mul_256_64(a: u256, b: u64) -> (u64, u256) { - let (a_high, a_low): (u128, u128) = ::into(a); +pub fn mul_256_64_wide(a: u256, b: u64) -> (u64, u256) { + let (a_high, a_low): (u128, u128) = split_u256_into_u128(a); - let lowest: u256 = mul_128_64(a_low, b); - let highest: u256 = mul_128_64(a_high, b); + let lowest: u256 = mul_128_64_wide(a_low, b); + let highest: u256 = mul_128_64_wide(a_high, b); - let (word_1, word_0): (u128, u128) = ::into(lowest); - let (word_3, word_2): (u128, u128) = ::into(highest); + let (word_1, word_0): (u128, u128) = split_u256_into_u128(lowest); + let (word_3, word_2): (u128, u128) = split_u256_into_u128(highest); - let (_, word_3): (u64, u64) = ::into(word_3); + let (_, word_3): (u64, u64) = split_u128_into_u64(word_3); - let (carry_2, res_1): (bool, u128) = add_128(word_1, word_2); + let (carry_2, res_1): (bool, u128) = add_128_carry(word_1, word_2); // a * b fits into u320, so addition below can not overflow and // `full_add_64` is used to avoid the unnecessary overflow check let (_, res_2): (bool, u64) = jet::full_add_64(carry_2, word_3, 0); @@ -149,16 +164,16 @@ pub fn mul_256_64(a: u256, b: u64) -> (u64, u256) { /// The idea is that u256-bit `a` divides into 128-bit `a_high` and `a_low`, /// so a = a_high * 2^128 + a_low, /// and a * b = 2^128 * a_high * b + a_low * b -pub fn mul_256_128(a: u256, b: u128) -> (u128, u256) { - let (a_high, a_low): (u128, u128) = ::into(a); +pub fn mul_256_128_wide(a: u256, b: u128) -> (u128, u256) { + let (a_high, a_low): (u128, u128) = split_u256_into_u128(a); - let lowest: u256 = mul_128(a_low, b); - let highest: u256 = mul_128(a_high, b); + let lowest: u256 = mul_128_wide(a_low, b); + let highest: u256 = mul_128_wide(a_high, b); - let (word_1, word_0): (u128, u128) = ::into(lowest); - let (word_3, word_2): (u128, u128) = ::into(highest); + let (word_1, word_0): (u128, u128) = split_u256_into_u128(lowest); + let (word_3, word_2): (u128, u128) = split_u256_into_u128(highest); - let (carry_2, res_1): (bool, u128) = add_128(word_1, word_2); + let (carry_2, res_1): (bool, u128) = add_128_carry(word_1, word_2); // a * b fits into u384, so addition below can not overflow and // `full_add_128` is used to avoid the unnecessary overflow check let (_, res_2): (bool, u128) = full_add_128(carry_2, word_3, 0); @@ -166,9 +181,27 @@ pub fn mul_256_128(a: u256, b: u128) -> (u128, u256) { (res_2, <(u128, u128)>::into((res_1, word_0))) } +/// Multiplies two integers. +/// The output consists of a 128-bit integer and two 256-bit integers. +/// The idea is that 512-bit `a` divides into 256-bit `a_high` and `a_low`, +/// so a = a_high * 2^256 + a_low, +/// and a * b = 2^256 * a_high * b + a_low * b +pub fn mul_512_128_wide(a_high: u256, a_low: u256, b: u128) -> (u128, u256, u256) { + let (word_1, word_0): (u128, u256) = mul_256_128_wide(a_low, b); + let (word_3, word_2): (u128, u256) = mul_256_128_wide(a_high, b); + + let (carry, res_1): (bool, u256) = add_256_128_carry(word_2, word_1); + + // a * b fits into u640, so addition below can not overflow and + // `full_add_128` is used to avoid the unnecessary overflow check + let (_, res_2): (bool, u128) = full_add_128(carry, word_3, 0); + + (res_2, res_1, word_0) +} + /// Returns the product of two u256 values wrapped in Some, or None if the result overflows u256 pub fn checked_mul_256(a: u256, b: u256) -> Option { - let (result_high, result_low): (u256, u256) = mul_256(a, b); + let (result_high, result_low): (u256, u256) = mul_256_wide(a, b); match is_zero_256(result_high) { true => Some(result_low), @@ -177,18 +210,50 @@ pub fn checked_mul_256(a: u256, b: u256) -> Option { } /// Returns the product of two u256 values, panics if the result overflows u256 -pub fn safe_mul_256(a: u256, b: u256) -> u256 { +pub fn mul_256(a: u256, b: u256) -> u256 { unwrap(checked_mul_256(a, b)) } /// Returns the product of u256 and u128 values, panics if the result overflows u256 -fn safe_mul_256_128(a: u256, b: u128) -> u256 { - let (result_high, result_low): (u128, u256) = mul_256_128(a, b); +pub fn mul_256_128(a: u256, b: u128) -> u256 { + let (result_high, result_low): (u128, u256) = mul_256_128_wide(a, b); assert!(is_zero_128(result_high)); result_low } +/// Helper function that can be used with Algorithm D. +/// Returns the normalization factor by which `b` should be multiplied so that +/// its most significant non-zero word is greater than or equal to 2^127 +pub fn calculate_normalizer_base_128(b: u256) -> u128 { + // Compile-time constant: 2^127 + let threshold: u128 = 0x80000000000000000000000000000000; + let (b_high, _): (u128, u128) = split_u256_into_u128(b); + + assert!(not(is_zero_128(b_high))); + + match lt_128(b_high, threshold) { + true => { + let (norm, remainder): (u128, u128) = div_mod_128(threshold, b_high); + + match is_zero_128(remainder) { + true => norm, + false => { + let ( + _, + norm + ): (bool, u128) = add_128_carry( + norm, + 1 + ); // norm <= 2^127, so norm + 1 can not overflow + norm + }, + } + }, + false => 1, + } +} + /// Normalizes the dividend and divisor for Algorithm D by multiplying /// both u256 and u128 by the same factor, ensuring that /// the most significant non-zero word of `b` is at least 2^63. @@ -197,13 +262,13 @@ fn safe_mul_256_128(a: u256, b: u128) -> u256 { /// the normalized `b` and the normalization factor. fn normalize_to_threshold_256_63(a: u256, b: u128, is_b_u128: bool) -> (u64, u256, u128, u64) { let norm: u64 = calculate_normalizer_base_64(b, is_b_u128); - let norm_128: u128 = <(u64, u64)>::into((0, norm)); + let norm_128: u128 = u64_to_u128(norm); match jet::eq_64(norm, 1) { true => (0, a, b, norm), false => { - let (high, low): (u64, u256) = mul_256_64(a, norm); - let b_norm: u128 = safe_mul_128(b, norm_128); + let (high, low): (u64, u256) = mul_256_64_wide(a, norm); + let b_norm: u128 = mul_128(b, norm_128); (high, low, b_norm, norm) }, @@ -215,60 +280,50 @@ fn normalize_to_threshold_256_63(a: u256, b: u128, is_b_u128: bool) -> (u64, u25 /// the most significant non-zero word of `b` is at least 2^127. /// /// The normalized dividend fits into 384 bits and is returned as a -/// `(u128, u256)` pair. The normalized divisor fits into a `u256`. +/// `(u128, u256)` pair. The normalized divisor fits into a u256. fn normalize_to_threshold_256_127(a: u256, b: u256) -> (u128, u256, u256) { - // Compile-time constant: 2^127 - let threshold: u128 = 0x80000000000000000000000000000000; - - let (b_high, _): (u128, u128) = ::into(b); - - assert!(not(is_zero_128(b_high))); - - let (norm, remainder): (u128, u128) = div_mod_128(threshold, b_high); + let norm: u128 = calculate_normalizer_base_128(b); - let norm: u128 = match is_zero_128(remainder) { - true => norm, + match eq_128(norm, 1) { + true => (0, a, b), false => { - let (_, norm): (bool, u128) = add_128(norm, 1); // norm <= 2^127, so norm + 1 can not overflow - norm - } - }; + let (high, low): (u128, u256) = mul_256_128_wide(a, norm); - match lt_128(b_high, threshold) { - true => { - let (high, low): (u128, u256) = mul_256_128(a, norm); - - (high, low, safe_mul_256_128(b, norm)) + (high, low, mul_256_128(b, norm)) }, - false => (0, a, b), } } /// Divides the 256-bit integer by the 64-bit integer, /// returns a tuple of the u256 quotient and the u64 remainder +/// Panics if the divisor is zero pub fn div_mod_256_64(dividend: u256, divisor: u64) -> (u256, u64) { let (u3, u2, u1, u0): (u64, u64, u64, u64) = split_u256_into_u64(dividend); // calculate the upper part of the quotient let (q3, remainder): (u64, u64) = jet::div_mod_64(u3, divisor); - let divisor: u128 = <(u64, u64)>::into((0, divisor)); + let divisor: u128 = u64_to_u128(divisor); let dividend: u256 = <(u64, u64, u64, u64)>::into((remainder, u2, u1, u0)); // normalized dividend fits into 256 bits because remainder < divisor and // divisor * norm fits into u64, so dividend * norm also fits - let (_, norm_dividend_low, norm_divisor, norm): (u64, u256, u128, u64) = - normalize_to_threshold_256_63(dividend, divisor, false); + let ( + _, + norm_dividend_low, + norm_divisor, + norm + ): (u64, u256, u128, u64) = normalize_to_threshold_256_63(dividend, divisor, false); let (u3, u2, u1, u0): (u64, u64, u64, u64) = split_u256_into_u64(norm_dividend_low); - let (_, v0): (u64, u64) = ::into(norm_divisor); + let (_, v0): (u64, u64) = split_u128_into_u64(norm_divisor); - let (q2, remainder): (u64, u64) = jet::div_mod_128_64( <(u64, u64)>::into((u3, u2)), v0); - let (q1, remainder): (u64, u64) = jet::div_mod_128_64( <(u64, u64)>::into((remainder, u1)), v0); - let (q0, remainder): (u64, u64) = jet::div_mod_128_64( <(u64, u64)>::into((remainder, u0)), v0); + let (q2, remainder): (u64, u64) = jet::div_mod_128_64(<(u64, u64)>::into((u3, u2)), v0); + let (q1, remainder): (u64, u64) = jet::div_mod_128_64(<(u64, u64)>::into((remainder, u1)), v0); + let (q0, remainder): (u64, u64) = jet::div_mod_128_64(<(u64, u64)>::into((remainder, u0)), v0); let remainder: u64 = jet::divide_64(remainder, norm); - let q: u256 = <(u64, u64, u64, u64)>::into(( q3, q2, q1, q0)); + let q: u256 = <(u64, u64, u64, u64)>::into((q3, q2, q1, q0)); (q, remainder) } @@ -276,12 +331,12 @@ pub fn div_mod_256_64(dividend: u256, divisor: u64) -> (u256, u64) { /// Multiplies the divisor by the quotient digit and subtracts the result from /// the corresponding dividend limbs. Returns the updated dividend segment, /// which is used by Algorithm D -fn mul_and_sub(q: u64, u2: u64, u1: u64, u0: u64, v: u128) -> (u64, u64) { +fn mul_and_sub_64(q: u64, u2: u64, u1: u64, u0: u64, v: u128) -> (u64, u64) { let u: u256 = <(u64, u64, u64, u64)>::into((0, u2, u1, u0)); - let q_v: u256 = mul_128_64(v, q); + let q_v: u256 = mul_128_64_wide(v, q); - let u_updated: u256 = safe_sub_256(u, q_v); + let u_updated: u256 = sub_256(u, q_v); let (_, _, u1, u0): (u64, u64, u64, u64) = split_u256_into_u64(u_updated); (u1, u0) @@ -291,22 +346,26 @@ fn mul_and_sub(q: u64, u2: u64, u1: u64, u0: u64, v: u128) -> (u64, u64) { /// returns a tuple of the u256 quotient and the u128 remainder. /// Implements Algorithm D by Donald Knuth. /// Requires the upper half of the divisor to be non-zero (divisor >= 2^64) -fn algorithm_d_256_128(dividend: u256, divisor: u128) -> (u256, u128) { - let (u4, norm_dividend_low, norm_divisor, norm): (u64, u256, u128, u64) = - normalize_to_threshold_256_63(dividend, divisor, true); +pub fn algorithm_d_256_128(dividend: u256, divisor: u128) -> (u256, u128) { + let ( + u4, + norm_dividend_low, + norm_divisor, + norm + ): (u64, u256, u128, u64) = normalize_to_threshold_256_63(dividend, divisor, true); // normalized dividend fits into 320 bits let (u3, u2, u1, u0): (u64, u64, u64, u64) = split_u256_into_u64(norm_dividend_low); - let (v1, v0): (u64, u64) = ::into(norm_divisor); + let (v1, v0): (u64, u64) = split_u128_into_u64(norm_divisor); let q2: u64 = estimate_quotient_digit_base_64(u4, u3, u2, v1, v0); - let (u3, u2): (u64, u64) = mul_and_sub(q2, u4, u3, u2, norm_divisor); + let (u3, u2): (u64, u64) = mul_and_sub_64(q2, u4, u3, u2, norm_divisor); let q1: u64 = estimate_quotient_digit_base_64(u3, u2, u1, v1, v0); - let (u2, u1): (u64, u64) = mul_and_sub(q1, u3, u2, u1, norm_divisor); + let (u2, u1): (u64, u64) = mul_and_sub_64(q1, u3, u2, u1, norm_divisor); let q0: u64 = estimate_quotient_digit_base_64(u2, u1, u0, v1, v0); - let (u1, u0): (u64, u64) = mul_and_sub(q0, u2, u1, u0, norm_divisor); + let (u1, u0): (u64, u64) = mul_and_sub_64(q0, u2, u1, u0, norm_divisor); let q: u256 = <(u64, u64, u64, u64)>::into((0, q2, q1, q0)); let (remainder, _): (u128, u64) = div_mod_128_64(<(u64, u64)>::into((u1, u0)), norm); @@ -316,14 +375,15 @@ fn algorithm_d_256_128(dividend: u256, divisor: u128) -> (u256, u128) { /// Divides the 256-bit integer by the 128-bit integer, /// returns a tuple of the u256 quotient and the u128 remainder +/// Panics if the divisor is zero pub fn div_mod_256_128(dividend: u256, divisor: u128) -> (u256, u128) { - let (divisor_high, divisor_low): (u64, u64) = ::into(divisor); + let (divisor_high, divisor_low): (u64, u64) = split_u128_into_u64(divisor); match jet::is_zero_64(divisor_high) { true => { let (q, r): (u256, u64) = div_mod_256_64(dividend, divisor_low); - (q, <(u64, u64)>::into((0, r))) + (q, u64_to_u128(r)) }, false => algorithm_d_256_128(dividend, divisor), } @@ -334,107 +394,108 @@ pub fn div_mod_256_128(dividend: u256, divisor: u128) -> (u256, u128) { /// Implements Algorithm D by Donald Knuth. /// Requires the upper half of the divisor to be non-zero (divisor >= 2^128). fn algorithm_d_256_256(dividend: u256, divisor: u256) -> (u128, u256) { - let (u2, norm_dividend_low, norm_divisor): (u128, u256, u256) = normalize_to_threshold_256_127(dividend, divisor); + let ( + u2, + norm_dividend_low, + norm_divisor + ): (u128, u256, u256) = normalize_to_threshold_256_127(dividend, divisor); - let (u1, u0): (u128, u128) = ::into(norm_dividend_low); - let (v1, v0): (u128, u128) = ::into(norm_divisor); + let (u1, u0): (u128, u128) = split_u256_into_u128(norm_dividend_low); + let (v1, v0): (u128, u128) = split_u256_into_u128(norm_divisor); let (q_hat, r_hat): (u256, u128) = algorithm_d_256_128(<(u128, u128)>::into((u2, u1)), v1); - let( _, q_hat): (u128, u128) = ::into(q_hat); + let (_, q_hat): (u128, u128) = split_u256_into_u128(q_hat); let r_hat_u0: u256 = <(u128, u128)>::into((r_hat, u0)); - let u_hat: u256 = mul_128(q_hat, v0); + let u_hat: u256 = mul_128_wide(q_hat, v0); // correcting estimation: q_hat is off by at most 2. let q: u128 = match lt_256(r_hat_u0, u_hat) { true => { // can not overflow because r_hat_u0 < q_hat * v0, so q_hat is at least 1 - let (_, q_hat): (bool, u128) = sub_128(q_hat, 1); - let (carry, r_hat): (bool, u128) = add_128(r_hat, v1); + let (_, q_hat): (bool, u128) = sub_128_borrow(q_hat, 1); + let (carry, r_hat): (bool, u128) = add_128_carry(r_hat, v1); match carry { true => q_hat, false => { let r_hat_u0: u256 = <(u128, u128)>::into((r_hat, u0)); - let (_, u_hat): (bool, u256) = sub_256(u_hat, <(u128, u128)>::into((0, v0))); + let (_, u_hat): (bool, u256) = sub_256_borrow(u_hat, u128_to_u256(v0)); match lt_256(r_hat_u0, u_hat) { true => { // can not overflow because r_hat_u0 < q_hat * v0, so q_hat is at least 1 - let (_, q_hat): (bool, u128) = sub_128(q_hat, 1); + let (_, q_hat): (bool, u128) = sub_128_borrow(q_hat, 1); q_hat - } + }, false => q_hat, } - } + }, } }, false => q_hat, }; - let remainder: u256 = safe_sub_256(dividend, safe_mul_256_128(divisor, q)); + let remainder: u256 = sub_256(dividend, mul_256_128(divisor, q)); (q, remainder) } /// Divides the first integer by the second integer, /// returns the quotient and the remainder +/// Panics if the divisor is zero pub fn div_mod_256(a: u256, b: u256) -> (u256, u256) { - let (a_high, a_low): (u128, u128) = ::into(a); - let (b_high, b_low): (u128, u128) = ::into(b); + assert!(not(is_zero_256(b))); + + let (a_high, a_low): (u128, u128) = split_u256_into_u128(a); + let (b_high, b_low): (u128, u128) = split_u256_into_u128(b); match lt_256(a, b) { true => (0, a), false => { - match and(is_zero_128(a_high), is_zero_128(b_high)) { - true => { + match and(is_zero_128(a_high), is_zero_128(b_high)) { + true => { // if both a_high and b_high are zero, this narrows down to 128-bit division let (q, r): (u128, u128) = div_mod_128(a_low, b_low); - (<(u128, u128)>::into((0, q)), <(u128, u128)>::into((0, r))) + (u128_to_u256(q), u128_to_u256(r)) }, false => { match eq_128(a_high, b_high) { true => { // safe: !lt_256(a, b) and a_high == b_high, so a_low >= b_low, - // and the subtraction can not underflow - let (_, diff): (bool, u128) = sub_128(a_low, b_low); - (1, <(u128, u128)>::into((0, diff))) + // and the subtraction can not overflow + let (_, diff): (bool, u128) = sub_128_borrow(a_low, b_low); + (1, u128_to_u256(diff)) + }, + false => match is_zero_128(b_high) { + true => { + let (q, r): (u256, u128) = div_mod_256_128(a, b_low); + (q, u128_to_u256(r)) + }, + false => { + let (q, r): (u128, u256) = algorithm_d_256_256(a, b); + (u128_to_u256(q), r) + }, }, - false => { - match is_zero_128(b_high) { - true => { - let (q, r): (u256, u128) = div_mod_256_128(a, b_low); - (q, <(u128, u128)>::into((0, r))) - }, - false => { - let (q, r): (u128, u256) = algorithm_d_256_256(a, b); - (<(u128, u128)>::into((0, q)), r) - } - } - } } - } + }, } - } + }, } } /// Divide the first integer by the second integer, returns the quotient +/// Panics if the divisor is zero pub fn div_256(a: u256, b: u256) -> u256 { let (q, _): (u256, u256) = div_mod_256(a, b); q } -/// Returns the quotient of two u256 values wrapped in Some, or None if the result overflows u256 +/// Returns the quotient of two u256 values wrapped in Some, or None if b is zero pub fn checked_div_256(a: u256, b: u256) -> Option { match is_zero_256(b) { true => None, false => Some(div_256(a, b)), } } - -/// Returns the quotient of two u256 values, panics if the result overflows u256 -pub fn safe_div_256(a: u256, b: u256) -> u256 { - unwrap(checked_div_256(a, b)) -} diff --git a/simf/lib/u256/mul_div.simf b/simf/lib/u256/mul_div.simf new file mode 100644 index 0000000..73a3efa --- /dev/null +++ b/simf/lib/u256/mul_div.simf @@ -0,0 +1,201 @@ +use crate::lib::binary::not; + +use crate::lib::u128::math::{add_128_carry, sub_128_borrow, full_sub_128, mul_128_wide}; +use crate::lib::u128::bit::eq_128; +use crate::lib::u128::comparison::{is_zero_128, lt_128}; + +use crate::lib::u256::math::{ + algorithm_d_256_128, + mul_256_128_wide, + sub_256_borrow, + sub_256, + calculate_normalizer_base_128, + mul_512_128_wide, + mul_256_128, + mul_256_wide, + div_mod_256_128, + div_256 +}; +use crate::lib::u256::convert::split_u256_into_u128; +use crate::lib::u256::comparison::{is_zero_256, lt_256}; + +/// Estimates and corrects the next quotient digit (q_hat) for Algorithm D. +/// Returns the quotient digit to use in the subsequent multiply-and-subtract step. +/// Expects result to fit into u128 +fn estimate_quotient_digit_base_128(u2: u128, u1: u128, u0: u128, v1: u128, v0: u128) -> u128 { + let ( + q_hat, + r_hat, + carry + ): (u128, u128, bool) = match lt_128(u2, v1) { + true => { + let ( + q_hat, + r_hat + ): (u256, u128) = algorithm_d_256_128(<(u128, u128)>::into((u2, u1)), v1); + let ( + _, + q_hat + ): (u128, u128) = split_u256_into_u128( + q_hat + ); // skip the check for optimization. u2 < v1, so q_hat fits into u128 + + (q_hat, r_hat, false) + }, + false => { + // This means u2 == v1, q_hat = 2^128, and r_hat = u1. + // Therefore, we need to decrement q and add v1 to r_hat. + // r_hat = u1 + v1 may overflow u128, which means that the estimate is exact + let (carry, r_hat): (bool, u128) = add_128_carry(u1, v1); + + let u128_max: u128 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + (u128_max, r_hat, carry) + }, + }; + + match carry { + true => q_hat, + false => { + let r_hat_u0: u256 = <(u128, u128)>::into((r_hat, u0)); + + // correcting estimation: q_hat is off by at most 2. + match lt_256(r_hat_u0, mul_128_wide(q_hat, v0)) { + true => { + // can not overflow because r_hat_u0 < q_hat * v0, so q_hat is at least 1 + let (_, q_hat): (bool, u128) = sub_128_borrow(q_hat, 1); + let (carry, r_hat): (bool, u128) = add_128_carry(r_hat, v1); + + match carry { + true => q_hat, + false => { + let r_hat_u0: u256 = <(u128, u128)>::into((r_hat, u0)); + + match lt_256(r_hat_u0, mul_128_wide(q_hat, v0)) { + true => { + // can not overflow because r_hat_u0 < q_hat * v0, so q_hat is at least 1 + let (_, q_hat): (bool, u128) = sub_128_borrow(q_hat, 1); + + q_hat + }, + false => q_hat, + } + }, + } + }, + false => q_hat, + } + }, + } +} + +/// Normalizes the dividend and divisor for Algorithm D by multiplying +/// all values by the same factor, ensuring that +/// the most significant non-zero word of `b` is at least 2^127. +/// +/// The normalized dividend fits into 640 bits and is returned as a +/// `(u128, u256, u256)` tuple. The normalized divisor fits into a u256 +fn normalize_to_threshold_512_127(a_high: u256, a_low: u256, b: u256) -> (u128, u256, u256, u256) { + let norm: u128 = calculate_normalizer_base_128(b); + + match eq_128(norm, 1) { + true => (0, a_high, a_low, b), + false => { + let (a_2, a_1, a_0): (u128, u256, u256) = mul_512_128_wide(a_high, a_low, norm); + + (a_2, a_1, a_0, mul_256_128(b, norm)) + }, + } +} + +/// Multiplies the divisor by the quotient digit and subtracts the result from +/// the corresponding dividend limbs. Returns the updated dividend segment, +/// which is used by Algorithm D +fn mul_and_sub_128(q: u128, u2: u128, u1: u128, u0: u128, v: u256) -> (u128, u128) { + let u1_0: u256 = <(u128, u128)>::into((u1, u0)); + + let (q_v_1, q_v_0): (u128, u256) = mul_256_128_wide(v, q); + + let (borrow_low, u_updated_1_0): (bool, u256) = sub_256_borrow(u1_0, q_v_0); + let (borrow, u_updated_2): (bool, u128) = full_sub_128(borrow_low, u2, q_v_1); + + assert!(not(borrow)); + assert!(is_zero_128(u_updated_2)); + + split_u256_into_u128(u_updated_1_0) +} + +/// Divides a 512-bit integer by a 256-bit integer and returns a u256 quotient. +/// Implements Algorithm D by Donald Knuth. +/// Requires the upper half of the divisor to be non-zero (`divisor >= 2^128`) +/// and the quotient to fit into u256 +fn algorithm_d_512_256(dividend_high: u256, dividend_low: u256, divisor: u256) -> u256 { + let ( + _, + norm_dividend_high, + norm_dividend_low, + norm_divisor + ): (u128, u256, u256, u256) = ( + normalize_to_threshold_512_127(dividend_high, dividend_low, divisor) + ); + + let (u3, u2): (u128, u128) = split_u256_into_u128(norm_dividend_high); + let (u1, u0): (u128, u128) = split_u256_into_u128(norm_dividend_low); + let (v1, v0): (u128, u128) = split_u256_into_u128(norm_divisor); + + let q1: u128 = estimate_quotient_digit_base_128(u3, u2, u1, v1, v0); + let (u2, u1): (u128, u128) = mul_and_sub_128(q1, u3, u2, u1, norm_divisor); + + let q0: u128 = estimate_quotient_digit_base_128(u2, u1, u0, v1, v0); + + <(u128, u128)>::into((q1, q0)) +} + +/// Calculates `floor(a * b / denominator)` with full precision. +/// Panics if the result overflows a u256 or if the denominator is zero +pub fn mul_div_256(a: u256, b: u256, denominator: u256) -> u256 { + assert!(not(is_zero_256(denominator))); + + let (result_high, result_low): (u256, u256) = mul_256_wide(a, b); + + match is_zero_256(result_high) { + true => div_256(result_low, denominator), + false => { + // if result_high >= denominator, result will overflow u256 + assert!(lt_256(result_high, denominator)); + let (denom_high, denom_low): (u128, u128) = split_u256_into_u128(denominator); + + match is_zero_128(denom_high) { + true => { + // result_high < denominator, denominator fits into u128, so result_high fits too. + // split_u256_into_u128 is used instead of safe_u256_to_u128 to avoid the unnecessary check + let (_, result_2): (u128, u128) = split_u256_into_u128(result_high); + let (result_1, result_0): (u128, u128) = split_u256_into_u128(result_low); + + // result_high < denominator, so result_2 < denom_low and q1 fits into u128 + let ( + q1, + r + ): (u256, u128) = div_mod_256_128( + <(u128, u128)>::into((result_2, result_1)), + denom_low + ); + let (_, q1): (u128, u128) = split_u256_into_u128(q1); + + // r < denom_low, so q0 fits into u128 + let ( + q0, + _ + ): (u256, u128) = div_mod_256_128( + <(u128, u128)>::into((r, result_0)), + denom_low + ); + let (_, q0): (u128, u128) = split_u256_into_u128(q0); + + <(u128, u128)>::into((q1, q0)) + }, + false => algorithm_d_512_256(result_high, result_low, denominator), + } + }, + } +} diff --git a/simf/lib/u32/math.simf b/simf/lib/u32/math.simf index e85f5e4..a7d6417 100644 --- a/simf/lib/u32/math.simf +++ b/simf/lib/u32/math.simf @@ -9,7 +9,7 @@ pub fn checked_add_32(a: u32, b: u32) -> Option { } /// Returns the sum of two u32 values, panics if the result overflows u32 -pub fn safe_add_32(a: u32, b: u32) -> u32 { +pub fn add_32(a: u32, b: u32) -> u32 { unwrap(checked_add_32(a, b)) } @@ -24,7 +24,7 @@ pub fn checked_sub_32(a: u32, b: u32) -> Option { } /// Returns the difference of two u32 values, panics if the result overflows u32 -pub fn safe_sub_32(a: u32, b: u32) -> u32 { +pub fn sub_32(a: u32, b: u32) -> u32 { unwrap(checked_sub_32(a, b)) } @@ -41,11 +41,11 @@ pub fn checked_mul_32(a: u32, b: u32) -> Option { } /// Returns the product of two u32 values, panics if the result overflows u32 -pub fn safe_mul_32(a: u32, b: u32) -> u32 { +pub fn mul_32(a: u32, b: u32) -> u32 { unwrap(checked_mul_32(a, b)) } -/// Returns the quotient of two u32 values wrapped in Some, or None if the result overflows u32 +/// Returns the quotient of two u32 values wrapped in Some, or None if b is zero pub fn checked_div_32(a: u32, b: u32) -> Option { match jet::is_zero_32(b) { true => None, @@ -53,8 +53,8 @@ pub fn checked_div_32(a: u32, b: u32) -> Option { } } -/// Returns the quotient of two u32 values, panics if the result overflows u32 -pub fn safe_div_32(a: u32, b: u32) -> u32 { +/// Returns the quotient of two u32 values, panics if the divisor is zero +pub fn div_32(a: u32, b: u32) -> u32 { unwrap(checked_div_32(a, b)) } diff --git a/simf/lib/u32/mul_div.simf b/simf/lib/u32/mul_div.simf new file mode 100644 index 0000000..5cd972c --- /dev/null +++ b/simf/lib/u32/mul_div.simf @@ -0,0 +1,15 @@ +use crate::lib::binary::not; +use crate::lib::u32::convert::u32_to_u64; +use crate::lib::u64::convert::safe_u64_to_u32; + +/// Calculates `floor(a * b / denominator)` with full precision. +/// Panics if the result overflows a u32 or if the denominator is zero +pub fn mul_div_32(a: u32, b: u32, denominator: u32) -> u32 { + assert!(not(jet::is_zero_32(denominator))); + + let denominator_64: u64 = u32_to_u64(denominator); + + let result_64: u64 = jet::divide_64(jet::multiply_32(a, b), denominator_64); + + safe_u64_to_u32(result_64) +} diff --git a/simf/lib/u64/math.simf b/simf/lib/u64/math.simf index 77fc4aa..93c11eb 100644 --- a/simf/lib/u64/math.simf +++ b/simf/lib/u64/math.simf @@ -9,7 +9,7 @@ pub fn checked_add_64(a: u64, b: u64) -> Option { } /// Returns the sum of two u64 values, panics if the result overflows u64 -pub fn safe_add_64(a: u64, b: u64) -> u64 { +pub fn add_64(a: u64, b: u64) -> u64 { unwrap(checked_add_64(a, b)) } @@ -24,14 +24,14 @@ pub fn checked_sub_64(a: u64, b: u64) -> Option { } /// Returns the difference of two u64 values, panics if the result overflows u64 -pub fn safe_sub_64(a: u64, b: u64) -> u64 { +pub fn sub_64(a: u64, b: u64) -> u64 { unwrap(checked_sub_64(a, b)) } /// Returns the product of two u64 values wrapped in Some, or None if the result overflows u64 pub fn checked_mul_64(a: u64, b: u64) -> Option { let result: u128 = jet::multiply_64(a, b); - + let (high, low): (u64, u64) = ::into(result); match jet::is_zero_64(high) { @@ -41,11 +41,11 @@ pub fn checked_mul_64(a: u64, b: u64) -> Option { } /// Returns the product of two u64 values, panics if the result overflows u64 -pub fn safe_mul_64(a: u64, b: u64) -> u64 { +pub fn mul_64(a: u64, b: u64) -> u64 { unwrap(checked_mul_64(a, b)) } -/// Returns the quotient of two u64 values wrapped in Some, or None if the result overflows u64 +/// Returns the quotient of two u64 values wrapped in Some, or None if b is zero pub fn checked_div_64(a: u64, b: u64) -> Option { match jet::is_zero_64(b) { true => None, @@ -53,8 +53,8 @@ pub fn checked_div_64(a: u64, b: u64) -> Option { } } -/// Returns the quotient of two u64 values, panics if the result overflows u64 -pub fn safe_div_64(a: u64, b: u64) -> u64 { +/// Returns the quotient of two u64 values, panics if the divisor is zero +pub fn div_64(a: u64, b: u64) -> u64 { unwrap(checked_div_64(a, b)) } diff --git a/simf/lib/u64/mul_div.simf b/simf/lib/u64/mul_div.simf new file mode 100644 index 0000000..ed061c5 --- /dev/null +++ b/simf/lib/u64/mul_div.simf @@ -0,0 +1,13 @@ +use crate::lib::u64::convert::u64_to_u128; +use crate::lib::u128::convert::safe_u128_to_u64; +use crate::lib::u128::math::div_128; + +/// Calculates `floor(a * b / denominator)` with full precision. +/// Panics if the result overflows a u64 or if the denominator is zero +pub fn mul_div_64(a: u64, b: u64, denominator: u64) -> u64 { + let denominator_128: u128 = u64_to_u128(denominator); + + let result_128: u128 = div_128(jet::multiply_64(a, b), denominator_128); + + safe_u128_to_u64(result_128) +} diff --git a/simf/lib/u8/math.simf b/simf/lib/u8/math.simf index 9d50464..b942cd1 100644 --- a/simf/lib/u8/math.simf +++ b/simf/lib/u8/math.simf @@ -9,7 +9,7 @@ pub fn checked_add_8(a: u8, b: u8) -> Option { } /// Returns the sum of two u8 values, panics if the result overflows u8 -pub fn safe_add_8(a: u8, b: u8) -> u8 { +pub fn add_8(a: u8, b: u8) -> u8 { unwrap(checked_add_8(a, b)) } @@ -24,7 +24,7 @@ pub fn checked_sub_8(a: u8, b: u8) -> Option { } /// Returns the difference of two u8 values, panics if the result overflows u8 -pub fn safe_sub_8(a: u8, b: u8) -> u8 { +pub fn sub_8(a: u8, b: u8) -> u8 { unwrap(checked_sub_8(a, b)) } @@ -41,11 +41,11 @@ pub fn checked_mul_8(a: u8, b: u8) -> Option { } /// Returns the product of two u8 values, panics if the result overflows u8 -pub fn safe_mul_8(a: u8, b: u8) -> u8 { +pub fn mul_8(a: u8, b: u8) -> u8 { unwrap(checked_mul_8(a, b)) } -/// Returns the quotient of two u8 values wrapped in Some, or None if the result overflows u8 +/// Returns the quotient of two u8 values wrapped in Some, or None if b is zero pub fn checked_div_8(a: u8, b: u8) -> Option { match jet::is_zero_8(b) { true => None, @@ -53,8 +53,8 @@ pub fn checked_div_8(a: u8, b: u8) -> Option { } } -/// Returns the quotient of two u8 values, panics if the result overflows u8 -pub fn safe_div_8(a: u8, b: u8) -> u8 { +/// Returns the quotient of two u8 values, panics if the divisor is zero +pub fn div_8(a: u8, b: u8) -> u8 { unwrap(checked_div_8(a, b)) } diff --git a/simf/lib/u8/mul_div.simf b/simf/lib/u8/mul_div.simf new file mode 100644 index 0000000..c25dc35 --- /dev/null +++ b/simf/lib/u8/mul_div.simf @@ -0,0 +1,15 @@ +use crate::lib::binary::not; +use crate::lib::u8::convert::u8_to_u16; +use crate::lib::u16::convert::safe_u16_to_u8; + +/// Calculates `floor(a * b / denominator)` with full precision. +/// Panics if the result overflows a u8 or if the denominator is zero +pub fn mul_div_8(a: u8, b: u8, denominator: u8) -> u8 { + assert!(not(jet::is_zero_8(denominator))); + + let denominator_16: u16 = u8_to_u16(denominator); + + let result_16: u16 = jet::divide_16(jet::multiply_8(a, b), denominator_16); + + safe_u16_to_u8(result_16) +} diff --git a/simf/lib/utxo/asserts/amount.simf b/simf/lib/utxo/asserts/amount.simf new file mode 100644 index 0000000..ffc390b --- /dev/null +++ b/simf/lib/utxo/asserts/amount.simf @@ -0,0 +1,81 @@ +use crate::lib::utxo::getters::amount::{ + get_explicit_amount, + get_confidential_amount, + get_explicit_input_amount, + get_confidential_input_amount, + get_explicit_output_amount, + get_confidential_output_amount, + get_explicit_current_amount, + get_confidential_current_amount +}; +use crate::lib::asserts::{assert_eq_1, assert_eq_64, assert_eq_256}; + +/// Asserts that the explicit amount at the specified input or output equals the expected u64 value +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly. +pub fn assert_explicit_amount(index: u32, is_input_index: bool, expected: u64) { + let amount: u64 = get_explicit_amount(index, is_input_index); + + assert_eq_64(amount, expected); +} + +/// Asserts that the confidential amount at the specified input or output equals the expected Confidential1 value +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly. +pub fn assert_confidential_amount(index: u32, is_input_index: bool, expected: Confidential1) { + let (parity_bit, amount): Confidential1 = get_confidential_amount(index, is_input_index); + let (expected_parity_bit, expected_amount): Confidential1 = expected; + + assert_eq_1(parity_bit, expected_parity_bit); + assert_eq_256(amount, expected_amount); +} + +/// Asserts that the explicit amount at the specified input equals the expected u64 value +pub fn assert_explicit_input_amount(index: u32, expected: u64) { + let amount: u64 = get_explicit_input_amount(index); + + assert_eq_64(amount, expected); +} + +/// Asserts that the confidential amount at the specified input equals the expected Confidential1 value +pub fn assert_confidential_input_amount(index: u32, expected: Confidential1) { + let (parity_bit, amount): Confidential1 = get_confidential_input_amount(index); + let (expected_parity_bit, expected_amount): Confidential1 = expected; + + assert_eq_1(parity_bit, expected_parity_bit); + assert_eq_256(amount, expected_amount); +} + +/// Asserts that the explicit amount at the specified output equals the expected u64 value +pub fn assert_explicit_output_amount(index: u32, expected: u64) { + let amount: u64 = get_explicit_output_amount(index); + + assert_eq_64(amount, expected); +} + +/// Asserts that the confidential amount at the specified output equals the expected Confidential1 value +pub fn assert_confidential_output_amount(index: u32, expected: Confidential1) { + let (parity_bit, amount): Confidential1 = get_confidential_output_amount(index); + let (expected_parity_bit, expected_amount): Confidential1 = expected; + + assert_eq_1(parity_bit, expected_parity_bit); + assert_eq_256(amount, expected_amount); +} + +/// Asserts that the explicit input amount at the current_index equals the expected u64 value +pub fn assert_explicit_current_amount(expected: u64) { + let amount: u64 = get_explicit_current_amount(); + + assert_eq_64(amount, expected); +} + +/// Asserts that the confidential input amount at the current_index equals the expected Confidential1 value +pub fn assert_confidential_current_amount(expected: Confidential1) { + let (parity_bit, amount): Confidential1 = get_confidential_current_amount(); + let (expected_parity_bit, expected_amount): Confidential1 = expected; + + assert_eq_1(parity_bit, expected_parity_bit); + assert_eq_256(amount, expected_amount); +} diff --git a/simf/lib/utxo/asserts/asset_id.simf b/simf/lib/utxo/asserts/asset_id.simf new file mode 100644 index 0000000..1e1d702 --- /dev/null +++ b/simf/lib/utxo/asserts/asset_id.simf @@ -0,0 +1,81 @@ +use crate::lib::utxo::getters::asset_id::{ + get_explicit_asset_id, + get_confidential_asset_id, + get_explicit_input_asset_id, + get_confidential_input_asset_id, + get_explicit_output_asset_id, + get_confidential_output_asset_id, + get_explicit_current_asset_id, + get_confidential_current_asset_id +}; +use crate::lib::asserts::{assert_eq_1, assert_eq_256}; + +/// Asserts that the explicit asset_id at the specified input or output equals the expected u256 value +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly. +pub fn assert_explicit_asset_id(index: u32, is_input_index: bool, expected: u256) { + let asset_id: u256 = get_explicit_asset_id(index, is_input_index); + + assert_eq_256(asset_id, expected); +} + +/// Asserts that the confidential asset_id at the specified input or output equals the expected Confidential1 value +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly. +pub fn assert_confidential_asset_id(index: u32, is_input_index: bool, expected: Confidential1) { + let (parity_bit, asset_id): Confidential1 = get_confidential_asset_id(index, is_input_index); + let (expected_parity_bit, expected_asset_id): Confidential1 = expected; + + assert_eq_1(parity_bit, expected_parity_bit); + assert_eq_256(asset_id, expected_asset_id); +} + +/// Asserts that the explicit asset_id at the specified input equals the expected u256 value +pub fn assert_explicit_input_asset_id(index: u32, expected: u256) { + let asset_id: u256 = get_explicit_input_asset_id(index); + + assert_eq_256(asset_id, expected); +} + +/// Asserts that the confidential asset_id at the specified input equals the expected Confidential1 value +pub fn assert_confidential_input_asset_id(index: u32, expected: Confidential1) { + let (parity_bit, asset_id): Confidential1 = get_confidential_input_asset_id(index); + let (expected_parity_bit, expected_asset_id): Confidential1 = expected; + + assert_eq_1(parity_bit, expected_parity_bit); + assert_eq_256(asset_id, expected_asset_id); +} + +/// Asserts that the explicit asset_id at the specified output equals the expected u256 value +pub fn assert_explicit_output_asset_id(index: u32, expected: u256) { + let asset_id: u256 = get_explicit_output_asset_id(index); + + assert_eq_256(asset_id, expected); +} + +/// Asserts that the confidential asset_id at the specified output equals the expected Confidential1 value +pub fn assert_confidential_output_asset_id(index: u32, expected: Confidential1) { + let (parity_bit, asset_id): Confidential1 = get_confidential_output_asset_id(index); + let (expected_parity_bit, expected_asset_id): Confidential1 = expected; + + assert_eq_1(parity_bit, expected_parity_bit); + assert_eq_256(asset_id, expected_asset_id); +} + +/// Asserts that the explicit input asset_id at the current_index equals the expected u256 value +pub fn assert_explicit_current_asset_id(expected: u256) { + let asset_id: u256 = get_explicit_current_asset_id(); + + assert_eq_256(asset_id, expected); +} + +/// Asserts that the confidential input asset_id at the current_index equals the expected Confidential1 value +pub fn assert_confidential_current_asset_id(expected: Confidential1) { + let (parity_bit, asset_id): Confidential1 = get_confidential_current_asset_id(); + let (expected_parity_bit, expected_asset_id): Confidential1 = expected; + + assert_eq_1(parity_bit, expected_parity_bit); + assert_eq_256(asset_id, expected_asset_id); +} diff --git a/simf/lib/utxo/asserts/asset_id_with_amount.simf b/simf/lib/utxo/asserts/asset_id_with_amount.simf new file mode 100644 index 0000000..f577748 --- /dev/null +++ b/simf/lib/utxo/asserts/asset_id_with_amount.simf @@ -0,0 +1,165 @@ +use crate::lib::utxo::getters::asset_id_with_amount::{ + get_explicit_asset_id_with_amount, + get_confidential_asset_id_with_amount, + get_explicit_input_asset_id_with_amount, + get_confidential_input_asset_id_with_amount, + get_explicit_output_asset_id_with_amount, + get_confidential_output_asset_id_with_amount, + get_explicit_current_asset_id_with_amount, + get_confidential_current_asset_id_with_amount +}; +use crate::lib::asserts::{assert_eq_1, assert_eq_64, assert_eq_256}; + +/// Asserts that the explicit asset_id and amount at the specified input or output equal the expected u256 and u64 values +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly. +pub fn assert_explicit_asset_id_with_amount( + index: u32, + is_input_index: bool, + expected_asset_id: u256, + expected_amount: u64 +) { + let (asset_id, amount): (u256, u64) = get_explicit_asset_id_with_amount(index, is_input_index); + + assert_eq_256(asset_id, expected_asset_id); + assert_eq_64(amount, expected_amount); +} + +/// Asserts that the confidential asset_id and amount at the specified input or output equal the expected Confidential1 values +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly. +pub fn assert_confidential_asset_id_with_amount( + index: u32, + is_input_index: bool, + expected_asset_id: Confidential1, + expected_amount: Confidential1 +) { + let ( + asset_id, + amount + ): (Confidential1, Confidential1) = get_confidential_asset_id_with_amount( + index, + is_input_index + ); + + /// asset_id + let (asset_id_parity_bit, asset_id): Confidential1 = asset_id; + let (expected_asset_id_parity_bit, expected_asset_id): Confidential1 = expected_asset_id; + // amount + let (amount_parity_bit, amount): Confidential1 = amount; + let (expected_amount_parity_bit, expected_amount): Confidential1 = expected_amount; + // asset_id + assert_eq_1(asset_id_parity_bit, expected_asset_id_parity_bit); + assert_eq_256(asset_id, expected_asset_id); + // amount + assert_eq_1(amount_parity_bit, expected_amount_parity_bit); + assert_eq_256(amount, expected_amount); +} + +/// Asserts that the explicit asset_id and amount at the specified input equal the expected u256 and u64 values +pub fn assert_explicit_input_asset_id_with_amount( + index: u32, + expected_asset_id: u256, + expected_amount: u64 +) { + let (asset_id, amount): (u256, u64) = get_explicit_input_asset_id_with_amount(index); + + assert_eq_256(asset_id, expected_asset_id); + assert_eq_64(amount, expected_amount); +} + +/// Asserts that the confidential asset_id and amount at the specified input equal the expected Confidential1 values +pub fn assert_confidential_input_asset_id_with_amount( + index: u32, + expected_asset_id: Confidential1, + expected_amount: Confidential1 +) { + let ( + asset_id, + amount + ): (Confidential1, Confidential1) = get_confidential_input_asset_id_with_amount(index); + + // asset_id + let (asset_id_parity_bit, asset_id): Confidential1 = asset_id; + let (expected_asset_id_parity_bit, expected_asset_id): Confidential1 = expected_asset_id; + // amount + let (amount_parity_bit, amount): Confidential1 = amount; + let (expected_amount_parity_bit, expected_amount): Confidential1 = expected_amount; + // asset_id + assert_eq_1(asset_id_parity_bit, expected_asset_id_parity_bit); + assert_eq_256(asset_id, expected_asset_id); + // amount + assert_eq_1(amount_parity_bit, expected_amount_parity_bit); + assert_eq_256(amount, expected_amount); +} + +/// Asserts that the explicit asset_id and amount at the specified output equal the expected u256 and u64 values +pub fn assert_explicit_output_asset_id_with_amount( + index: u32, + expected_asset_id: u256, + expected_amount: u64 +) { + let (asset_id, amount): (u256, u64) = get_explicit_output_asset_id_with_amount(index); + + assert_eq_256(asset_id, expected_asset_id); + assert_eq_64(amount, expected_amount); +} + +/// Asserts that the confidential asset_id and amount at the specified output equal the expected Confidential1 values +pub fn assert_confidential_output_asset_id_with_amount( + index: u32, + expected_asset_id: Confidential1, + expected_amount: Confidential1 +) { + let ( + asset_id, + amount + ): (Confidential1, Confidential1) = get_confidential_output_asset_id_with_amount(index); + + // asset_id + let (asset_id_parity_bit, asset_id): Confidential1 = asset_id; + let (expected_asset_id_parity_bit, expected_asset_id): Confidential1 = expected_asset_id; + // amount + let (amount_parity_bit, amount): Confidential1 = amount; + let (expected_amount_parity_bit, expected_amount): Confidential1 = expected_amount; + // asset_id + assert_eq_1(asset_id_parity_bit, expected_asset_id_parity_bit); + assert_eq_256(asset_id, expected_asset_id); + // amount + assert_eq_1(amount_parity_bit, expected_amount_parity_bit); + assert_eq_256(amount, expected_amount); +} + +/// Asserts that the explicit input asset_id and amount at the current_index equal the expected u256 and u64 values +pub fn assert_explicit_current_asset_id_with_amount(expected_asset_id: u256, expected_amount: u64) { + let (asset_id, amount): (u256, u64) = get_explicit_current_asset_id_with_amount(); + + assert_eq_256(asset_id, expected_asset_id); + assert_eq_64(amount, expected_amount); +} + +/// Asserts that the confidential input asset_id and amount at the current_index equal the expected Confidential1 values +pub fn assert_confidential_current_asset_id_with_amount( + expected_asset_id: Confidential1, + expected_amount: Confidential1 +) { + let ( + asset_id, + amount + ): (Confidential1, Confidential1) = get_confidential_current_asset_id_with_amount(); + + // asset_id + let (asset_id_parity_bit, asset_id): Confidential1 = asset_id; + let (expected_asset_id_parity_bit, expected_asset_id): Confidential1 = expected_asset_id; + // amount + let (amount_parity_bit, amount): Confidential1 = amount; + let (expected_amount_parity_bit, expected_amount): Confidential1 = expected_amount; + // asset_id + assert_eq_1(asset_id_parity_bit, expected_asset_id_parity_bit); + assert_eq_256(asset_id, expected_asset_id); + // amount + assert_eq_1(amount_parity_bit, expected_amount_parity_bit); + assert_eq_256(amount, expected_amount); +} diff --git a/simf/lib/utxo/getters/amount.simf b/simf/lib/utxo/getters/amount.simf new file mode 100644 index 0000000..4901fe0 --- /dev/null +++ b/simf/lib/utxo/getters/amount.simf @@ -0,0 +1,88 @@ +/// Functions for retrieving Amount +/// +/// If you need both `Amount` and `AssetId`, it is recommended to use the corresponding +/// function from the `asset_id_with_amount` file, because all `get_amount` functions +/// also return the `AssetId`. Using `get_amount` and `get_asset_id` together results +/// in unnecessary overhead. + +/// Returns the explicit amount at the specified input or output. +/// Panics if the specified input or output does not exist or if its amount is confidential. +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly +pub fn get_explicit_amount(index: u32, is_input_index: bool) -> u64 { + let ( + _, + amount + ): (Asset1, Amount1) = match is_input_index { + true => unwrap(jet::input_amount(index)), + false => unwrap(jet::output_amount(index)), + }; + + unwrap_right::<(u1, u256)>(amount) +} + +/// Returns the confidential amount at the specified input or output. +/// Panics if the specified input or output does not exist or if its amount is explicit. +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly +pub fn get_confidential_amount(index: u32, is_input_index: bool) -> Confidential1 { + let ( + _, + amount + ): (Asset1, Amount1) = match is_input_index { + true => unwrap(jet::input_amount(index)), + false => unwrap(jet::output_amount(index)), + }; + + unwrap_left::(amount) +} + +/// Returns the explicit amount at the specified input. +/// Panics if the specified input does not exist or if its amount is confidential +pub fn get_explicit_input_amount(index: u32) -> u64 { + let (_, amount): (Asset1, Amount1) = unwrap(jet::input_amount(index)); + + unwrap_right::<(u1, u256)>(amount) +} + +/// Returns the confidential amount at the specified input. +/// Panics if the specified input does not exist or if its amount is explicit +pub fn get_confidential_input_amount(index: u32) -> Confidential1 { + let (_, amount): (Asset1, Amount1) = unwrap(jet::input_amount(index)); + + unwrap_left::(amount) +} + +/// Returns the explicit amount at the specified output. +/// Panics if the specified output does not exist or if its amount is confidential +pub fn get_explicit_output_amount(index: u32) -> u64 { + let (_, amount): (Asset1, Amount1) = unwrap(jet::output_amount(index)); + + unwrap_right::<(u1, u256)>(amount) +} + +/// Returns the confidential amount at the specified output. +/// Panics if the specified output does not exist or if its amount is explicit +pub fn get_confidential_output_amount(index: u32) -> Confidential1 { + let (_, amount): (Asset1, Amount1) = unwrap(jet::output_amount(index)); + + unwrap_left::(amount) +} + +/// Returns the explicit input amount at the current_index. +/// Panics if amount is confidential +pub fn get_explicit_current_amount() -> u64 { + let (_, amount): (Asset1, Amount1) = jet::current_amount(); + + unwrap_right::<(u1, u256)>(amount) +} + +/// Returns the confidential input amount at the current_index. +/// Panics if amount is explicit +pub fn get_confidential_current_amount() -> Confidential1 { + let (_, amount): (Asset1, Amount1) = jet::current_amount(); + + unwrap_left::(amount) +} diff --git a/simf/lib/utxo/getters/asset_id.simf b/simf/lib/utxo/getters/asset_id.simf new file mode 100644 index 0000000..b172992 --- /dev/null +++ b/simf/lib/utxo/getters/asset_id.simf @@ -0,0 +1,77 @@ +/// Functions for retrieving AssetId + +/// Returns the explicit asset_id at the specified input or output. +/// Panics if the specified input or output does not exist or if its asset_id is confidential. +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly. +pub fn get_explicit_asset_id(index: u32, is_input_index: bool) -> u256 { + let asset: Asset1 = match is_input_index { + true => unwrap(jet::input_asset(index)), + false => unwrap(jet::output_asset(index)), + }; + + unwrap_right::<(u1, u256)>(asset) +} + +/// Returns the confidential asset_id at the specified input or output. +/// Panics if the specified input or output does not exist or if its asset_id is explicit +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly. +pub fn get_confidential_asset_id(index: u32, is_input_index: bool) -> Confidential1 { + let asset: Asset1 = match is_input_index { + true => unwrap(jet::input_asset(index)), + false => unwrap(jet::output_asset(index)), + }; + + unwrap_left::(asset) +} + +/// Returns the explicit asset_id at the specified input. +/// Panics if the specified input does not exist or if its asset_id is confidential +pub fn get_explicit_input_asset_id(index: u32) -> u256 { + let asset: Asset1 = unwrap(jet::input_asset(index)); + + unwrap_right::<(u1, u256)>(asset) +} + +/// Returns the confidential asset_id at the specified input. +/// Panics if the specified input does not exist or if its asset_id is explicit +pub fn get_confidential_input_asset_id(index: u32) -> Confidential1 { + let asset: Asset1 = unwrap(jet::input_asset(index)); + + unwrap_left::(asset) +} + +/// Returns the explicit asset_id at the specified output. +/// Panics if the specified output does not exist or if its asset_id is confidential +pub fn get_explicit_output_asset_id(index: u32) -> u256 { + let asset: Asset1 = unwrap(jet::output_asset(index)); + + unwrap_right::<(u1, u256)>(asset) +} + +/// Returns the confidential asset_id at the specified output. +/// Panics if the specified output does not exist or if its asset_id is explicit +pub fn get_confidential_output_asset_id(index: u32) -> Confidential1 { + let asset: Asset1 = unwrap(jet::output_asset(index)); + + unwrap_left::(asset) +} + +/// Returns the explicit input asset_id at the current_index. +/// Panics if asset_id is confidential +pub fn get_explicit_current_asset_id() -> u256 { + let asset: Asset1 = jet::current_asset(); + + unwrap_right::<(u1, u256)>(asset) +} + +/// Returns the confidential input asset_id at the current_index. +/// Panics if asset_id is explicit +pub fn get_confidential_current_asset_id() -> Confidential1 { + let asset: Asset1 = jet::current_asset(); + + unwrap_left::(asset) +} diff --git a/simf/lib/utxo/getters/asset_id_with_amount.simf b/simf/lib/utxo/getters/asset_id_with_amount.simf new file mode 100644 index 0000000..df6d141 --- /dev/null +++ b/simf/lib/utxo/getters/asset_id_with_amount.simf @@ -0,0 +1,86 @@ +/// Functions for retrieving an `AssetId` along with an `Amount` + +/// Returns explicit asset_id and amount at the specified input or output. +/// Panics if the specified input or output does not exist or if its asset_id and amount are confidential. +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly. +pub fn get_explicit_asset_id_with_amount(index: u32, is_input_index: bool) -> (u256, u64) { + let ( + asset, + amount + ): (Asset1, Amount1) = match is_input_index { + true => unwrap(jet::input_amount(index)), + false => unwrap(jet::output_amount(index)), + }; + + (unwrap_right::<(u1, u256)>(asset), unwrap_right::<(u1, u256)>(amount)) +} + +/// Returns confidential asset_id and amount at the specified input or output. +/// Panics if the specified input or output does not exist or if its asset_id and amount are explicit. +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly. +pub fn get_confidential_asset_id_with_amount( + index: u32, + is_input_index: bool +) -> (Confidential1, Confidential1) { + let ( + asset, + amount + ): (Asset1, Amount1) = match is_input_index { + true => unwrap(jet::input_amount(index)), + false => unwrap(jet::output_amount(index)), + }; + + (unwrap_left::(asset), unwrap_left::(amount)) +} + +/// Returns explicit asset_id and amount at the specified input. +/// Panics if the specified input does not exist or if its asset_id and amount are confidential +pub fn get_explicit_input_asset_id_with_amount(index: u32) -> (u256, u64) { + let (asset, amount): (Asset1, Amount1) = unwrap(jet::input_amount(index)); + + (unwrap_right::<(u1, u256)>(asset), unwrap_right::<(u1, u256)>(amount)) +} + +/// Returns confidential asset_id and amount at the specified input. +/// Panics if the specified input does not exist or if its asset_id and amount are explicit +pub fn get_confidential_input_asset_id_with_amount(index: u32) -> (Confidential1, Confidential1) { + let (asset, amount): (Asset1, Amount1) = unwrap(jet::input_amount(index)); + + (unwrap_left::(asset), unwrap_left::(amount)) +} + +/// Returns explicit asset_id and amount at the specified output. +/// Panics if the specified output does not exist or if its asset_id and amount are confidential +pub fn get_explicit_output_asset_id_with_amount(index: u32) -> (u256, u64) { + let (asset, amount): (Asset1, Amount1) = unwrap(jet::output_amount(index)); + + (unwrap_right::<(u1, u256)>(asset), unwrap_right::<(u1, u256)>(amount)) +} + +/// Returns confidential asset_id and amount at the specified output. +/// Panics if the specified output does not exist or if its asset_id and amount are explicit +pub fn get_confidential_output_asset_id_with_amount(index: u32) -> (Confidential1, Confidential1) { + let (asset, amount): (Asset1, Amount1) = unwrap(jet::output_amount(index)); + + (unwrap_left::(asset), unwrap_left::(amount)) +} + +/// Returns explicit input asset_id and amount at the current_index. +/// Panics if asset_id and amount are confidential +pub fn get_explicit_current_asset_id_with_amount() -> (u256, u64) { + let (asset, amount): (Asset1, Amount1) = jet::current_amount(); + + (unwrap_right::<(u1, u256)>(asset), unwrap_right::<(u1, u256)>(amount)) +} + +/// Returns confidential input asset_id and amount at the current_index. +/// Panics if asset_id and amount are explicit +pub fn get_confidential_current_asset_id_with_amount() -> (Confidential1, Confidential1) { + let (asset, amount): (Asset1, Amount1) = jet::current_amount(); + + (unwrap_left::(asset), unwrap_left::(amount)) +} diff --git a/simf/lib/utxo/getters/script_hash.simf b/simf/lib/utxo/getters/script_hash.simf new file mode 100644 index 0000000..c3732f3 --- /dev/null +++ b/simf/lib/utxo/getters/script_hash.simf @@ -0,0 +1,25 @@ +/// Returns the SHA256 hash of the scriptPubKey of the UTXO at the specified input or output. +/// Panics if the specified input or output does not exist. +/// +/// Warning: using this incurs the overhead, and should be used only when the input/output selection +/// needs to be determined at runtime; otherwise, use the input- or output- specific getter directly +pub fn get_script_hash(index: u32, is_input_index: bool) -> u256 { + let script_hash: Option = match is_input_index { + true => jet::input_script_hash(index), + false => jet::output_script_hash(index), + }; + + unwrap(script_hash) +} + +/// Returns the SHA256 hash of the scriptPubKey of the UTXO of the input at the given index. +/// Panics if the specified input does not exist +pub fn get_input_script_hash(index: u32) -> u256 { + unwrap(jet::input_script_hash(index)) +} + +/// Returns the SHA256 hash of the scriptPubKey of the UTXO of the output at the given index. +/// Panics if the specified output does not exist +pub fn get_output_script_hash(index: u32) -> u256 { + unwrap(jet::output_script_hash(index)) +} diff --git a/simf/op_return_test.simf b/simf/op_return_test.simf deleted file mode 100644 index d847d8e..0000000 --- a/simf/op_return_test.simf +++ /dev/null @@ -1,12 +0,0 @@ -use crate::lib::op_return::{is_output_op_return, assert_output_is_op_return}; -use crate::helper::{if_test_this_function, assert_bool}; - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let index: u32 = witness::INDEX; - let expected: bool = witness::EXPECTED; - - match if_test_this_function(0, fn_idx) { true => { assert_bool(is_output_op_return(index), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_output_is_op_return(index); }, false => (), }; -} diff --git a/simf/secp256k1_operations_test.simf b/simf/secp256k1_operations_test.simf deleted file mode 100644 index 991eae8..0000000 --- a/simf/secp256k1_operations_test.simf +++ /dev/null @@ -1,35 +0,0 @@ -use crate::lib::secp256k1::operations::{ - ge_to_point, point_to_gej, fe_sub, scalar_sub, gej_sub, - fe_eq, scalar_eq, ge_eq, gej_point_eq, safe_gej_normalize, - assert_fe_eq, assert_scalar_eq, assert_ge_eq, assert_point_eq, assert_gej_point_eq, assert_gej_eq -}; -use crate::helper::if_test_this_function; - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - // Interpreted as Fe or Scalar depending on the function index - let uint_a: u256 = witness::FIRST_UINT; - let uint_b: u256 = witness::SECOND_UINT; - let ge_a: Ge = witness::FIRST_GE; - let ge_b: Ge = witness::SECOND_GE; - let gej_a: Gej = witness::FIRST_GEJ; - let gej_b: Gej = witness::SECOND_GEJ; - let point_a: Point = witness::FIRST_POINT; - - let exp_uint: u256 = witness::EXPECTED_UINT; - let exp_ge: Ge = witness::EXPECTED_GE; - let exp_gej: Gej = witness::EXPECTED_GEJ; - let exp_point: Point = witness::EXPECTED_POINT; - - match if_test_this_function(0, fn_idx) { true => { assert_point_eq(ge_to_point(ge_a), exp_point); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_gej_point_eq(point_to_gej(point_a), exp_point); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_fe_eq(fe_sub(uint_a, uint_b), exp_uint); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert_scalar_eq(scalar_sub(uint_a, uint_b), exp_uint); }, false => (), }; - match if_test_this_function(4, fn_idx) { true => { assert_gej_eq(gej_sub(gej_a, gej_b), exp_gej); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert!(fe_eq(uint_a, uint_b)); }, false => (), }; - match if_test_this_function(6, fn_idx) { true => { assert!(scalar_eq(uint_a, uint_b)); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert!(ge_eq(ge_a, ge_b)); }, false => (), }; - match if_test_this_function(8, fn_idx) { true => { assert!(gej_point_eq(gej_a, point_a)); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_ge_eq(safe_gej_normalize(gej_a), exp_ge); }, false => (), }; -} diff --git a/simf/tests/asserts.simf b/simf/tests/asserts.simf new file mode 100644 index 0000000..75e771a --- /dev/null +++ b/simf/tests/asserts.simf @@ -0,0 +1,138 @@ +use crate::lib::asserts::{ + assert_eq_1, + assert_eq_8, + assert_eq_16, + assert_eq_32, + assert_eq_64, + assert_eq_128, + assert_eq_256, + assert_eq_bool, + assert_none_1, + assert_none_8, + assert_none_16, + assert_none_32, + assert_none_64, + assert_none_128, + assert_none_256 +}; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a_u1: Option = witness::FIRST_ARG_U1; + let b_u1: Option = witness::SECOND_ARG_U1; + + let a_u8: Option = witness::FIRST_ARG_U8; + let b_u8: Option = witness::SECOND_ARG_U8; + + let a_u16: Option = witness::FIRST_ARG_U16; + let b_u16: Option = witness::SECOND_ARG_U16; + + let a_u32: Option = witness::FIRST_ARG_U32; + let b_u32: Option = witness::SECOND_ARG_U32; + + let a_u64: Option = witness::FIRST_ARG_U64; + let b_u64: Option = witness::SECOND_ARG_U64; + + let a_u128: Option = witness::FIRST_ARG_U128; + let b_u128: Option = witness::SECOND_ARG_U128; + + let a_u256: Option = witness::FIRST_ARG_U256; + let b_u256: Option = witness::SECOND_ARG_U256; + + // Assert Eq + match is_selected(0, fn_idx) { + true => { + assert_eq_1(unwrap(a_u1), unwrap(b_u1)); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_eq_8(unwrap(a_u8), unwrap(b_u8)); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_eq_16(unwrap(a_u16), unwrap(b_u16)); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert_eq_32(unwrap(a_u32), unwrap(b_u32)); + }, + false => (), + }; + match is_selected(4, fn_idx) { + true => { + assert_eq_64(unwrap(a_u64), unwrap(b_u64)); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert_eq_128(unwrap(a_u128), unwrap(b_u128)); + }, + false => (), + }; + match is_selected(6, fn_idx) { + true => { + assert_eq_256(unwrap(a_u256), unwrap(b_u256)); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert_eq_bool(::into(unwrap(a_u1)), ::into(unwrap(b_u1))); + }, + false => (), + }; + + // Assert None + match is_selected(8, fn_idx) { + true => { + assert_none_1(a_u1); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_none_8(a_u8); + }, + false => (), + }; + match is_selected(10, fn_idx) { + true => { + assert_none_16(a_u16); + }, + false => (), + }; + match is_selected(11, fn_idx) { + true => { + assert_none_32(a_u32); + }, + false => (), + }; + match is_selected(12, fn_idx) { + true => { + assert_none_64(a_u64); + }, + false => (), + }; + match is_selected(13, fn_idx) { + true => { + assert_none_128(a_u128); + }, + false => (), + }; + match is_selected(14, fn_idx) { + true => { + assert_none_256(a_u256); + }, + false => (), + }; +} diff --git a/simf/tests/binary.simf b/simf/tests/binary.simf new file mode 100644 index 0000000..e348d91 --- /dev/null +++ b/simf/tests/binary.simf @@ -0,0 +1,21 @@ +use crate::lib::binary::{not, or, and, xor}; + +fn main() { + assert!(not(false)); + assert!(not(not(true))); + + assert!(or(true, false)); + assert!(or(false, true)); + assert!(or(true, true)); + assert!(not(or(false, false))); + + assert!(and(true, true)); + assert!(not(and(true, false))); + assert!(not(and(false, true))); + assert!(not(and(false, false))); + + assert!(xor(true, false)); + assert!(xor(false, true)); + assert!(not(xor(true, true))); + assert!(not(xor(false, false))); +} diff --git a/simf/tests/mock.simf b/simf/tests/mock.simf new file mode 100644 index 0000000..e71fdf5 --- /dev/null +++ b/simf/tests/mock.simf @@ -0,0 +1 @@ +fn main() {} \ No newline at end of file diff --git a/simf/tests/op_return.simf b/simf/tests/op_return.simf new file mode 100644 index 0000000..d30a1d0 --- /dev/null +++ b/simf/tests/op_return.simf @@ -0,0 +1,24 @@ +use crate::lib::op_return::{is_output_op_return, assert_output_is_op_return}; + +use crate::tests::support::dispatch::is_selected; +use crate::tests::support::expect::assert_bool; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let index: u32 = witness::INDEX; + let expected: bool = witness::EXPECTED; + + match is_selected(0, fn_idx) { + true => { + assert_bool(is_output_op_return(index), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_output_is_op_return(index); + }, + false => (), + }; +} diff --git a/simf/tests/secp256k1/operations.simf b/simf/tests/secp256k1/operations.simf new file mode 100644 index 0000000..8e7485d --- /dev/null +++ b/simf/tests/secp256k1/operations.simf @@ -0,0 +1,98 @@ +use crate::lib::secp256k1::operations::{ + ge_to_point, + point_to_gej, + fe_sub, + scalar_sub, + gej_sub, + fe_eq, + scalar_eq, + ge_eq, + gej_point_eq, + safe_gej_normalize, + assert_fe_eq, + assert_scalar_eq, + assert_ge_eq, + assert_point_eq, + assert_gej_point_eq, + assert_gej_eq +}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + // Interpreted as Fe or Scalar depending on the function index + let uint_a: u256 = witness::FIRST_UINT; + let uint_b: u256 = witness::SECOND_UINT; + let ge_a: Ge = witness::FIRST_GE; + let ge_b: Ge = witness::SECOND_GE; + let gej_a: Gej = witness::FIRST_GEJ; + let gej_b: Gej = witness::SECOND_GEJ; + let point_a: Point = witness::FIRST_POINT; + + let exp_uint: u256 = witness::EXPECTED_UINT; + let exp_ge: Ge = witness::EXPECTED_GE; + let exp_gej: Gej = witness::EXPECTED_GEJ; + let exp_point: Point = witness::EXPECTED_POINT; + + match is_selected(0, fn_idx) { + true => { + assert_point_eq(ge_to_point(ge_a), exp_point); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_gej_point_eq(point_to_gej(point_a), exp_point); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_fe_eq(fe_sub(uint_a, uint_b), exp_uint); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert_scalar_eq(scalar_sub(uint_a, uint_b), exp_uint); + }, + false => (), + }; + match is_selected(4, fn_idx) { + true => { + assert_gej_eq(gej_sub(gej_a, gej_b), exp_gej); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert!(fe_eq(uint_a, uint_b)); + }, + false => (), + }; + match is_selected(6, fn_idx) { + true => { + assert!(scalar_eq(uint_a, uint_b)); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert!(ge_eq(ge_a, ge_b)); + }, + false => (), + }; + match is_selected(8, fn_idx) { + true => { + assert!(gej_point_eq(gej_a, point_a)); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_ge_eq(safe_gej_normalize(gej_a), exp_ge); + }, + false => (), + }; +} diff --git a/simf/tests/support/dispatch.simf b/simf/tests/support/dispatch.simf new file mode 100644 index 0000000..721d949 --- /dev/null +++ b/simf/tests/support/dispatch.simf @@ -0,0 +1,6 @@ +/// Indices `0..192` belong to the operations shared by all unsigned widths and +/// stay in lockstep with `CommonOp` on the Rust side. `192..256` are free for +/// operations specific to a single width. +pub fn is_selected(index: u8, fn_idx: u8) -> bool { + jet::eq_8(index, fn_idx) +} diff --git a/simf/tests/support/expect.simf b/simf/tests/support/expect.simf new file mode 100644 index 0000000..73b0365 --- /dev/null +++ b/simf/tests/support/expect.simf @@ -0,0 +1,136 @@ +//! Assertions shared by the test programs. +//! +//! SimplicityHL has no generics, so each family is written once per width and +//! named with that width's suffix, exactly like `crate::lib::asserts`. + +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::lib::binary::not; +use crate::lib::u128::bit::eq_128; + +/// 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)), + } +} + +/// 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. +pub fn assert_eq_opt_8(result: Option, expected: Option) { + match expected { + Some(e: u8) => assert_eq_8(unwrap(result), e), + None => assert_none_8(result), + } +} + +pub fn assert_eq_opt_16(result: Option, expected: Option) { + match expected { + Some(e: u16) => assert_eq_16(unwrap(result), e), + None => assert_none_16(result), + } +} + +pub fn assert_eq_opt_32(result: Option, expected: Option) { + match expected { + Some(e: u32) => assert_eq_32(unwrap(result), e), + None => assert_none_32(result), + } +} + +pub fn assert_eq_opt_64(result: Option, expected: Option) { + match expected { + Some(e: u64) => assert_eq_64(unwrap(result), e), + None => assert_none_64(result), + } +} + +pub fn assert_eq_opt_128(result: Option, expected: Option) { + match expected { + Some(e: u128) => assert_eq_128(unwrap(result), e), + None => assert_none_128(result), + } +} + +pub fn assert_eq_opt_256(result: Option, expected: Option) { + match expected { + Some(e: u256) => assert_eq_256(unwrap(result), e), + None => assert_none_256(result), + } +} + +/// Asserts a result equals the expected bool value. +/// `None` encodes `false`, and `Some(_)` encodes `true`. +pub fn assert_bool_by_opt_8(result: bool, expected: Option) { + match expected { + Some(_: u8) => assert!(result), + None => assert!(not(result)), + } +} + +pub fn assert_bool_by_opt_16(result: bool, expected: Option) { + match expected { + Some(_: u16) => assert!(result), + None => assert!(not(result)), + } +} + +pub fn assert_bool_by_opt_32(result: bool, expected: Option) { + match expected { + Some(_: u32) => assert!(result), + None => assert!(not(result)), + } +} + +pub fn assert_bool_by_opt_64(result: bool, expected: Option) { + match expected { + Some(_: u64) => assert!(result), + None => assert!(not(result)), + } +} + +pub fn assert_bool_by_opt_128(result: bool, expected: Option) { + match expected { + Some(_: u128) => assert!(result), + None => assert!(not(result)), + } +} + +pub fn assert_bool_by_opt_256(result: bool, expected: Option) { + match expected { + Some(_: u256) => assert!(result), + None => assert!(not(result)), + } +} + +/// Asserts a `(carry, value)` result equals the expected pair. Used by the +/// primitives that return an out-of-band carry or borrow alongside the result. +pub fn assert_eq_uint_bool_128(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)); +} + +pub fn assert_eq_uint_bool_256(result: (bool, u256), expected: u256, expected_bool: bool) { + let (bool_res, uint_res): (bool, u256) = result; + + assert_bool(bool_res, expected_bool); + + assert_eq_256(uint_res, expected); +} diff --git a/simf/u1_convert_test.simf b/simf/tests/u1/convert.simf similarity index 83% rename from simf/u1_convert_test.simf rename to simf/tests/u1/convert.simf index 8263efc..a1df432 100644 --- a/simf/u1_convert_test.simf +++ b/simf/tests/u1/convert.simf @@ -7,7 +7,6 @@ use crate::lib::u1::convert::{ u1_to_u256, u1_to_bool }; -use crate::lib::u128::bit::eq_128; use crate::lib::asserts::{ assert_eq_bool, assert_eq_8, @@ -17,7 +16,8 @@ use crate::lib::asserts::{ assert_eq_128, assert_eq_256 }; -use crate::helper::if_test_this_function; + +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -26,7 +26,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); @@ -37,7 +37,7 @@ fn main() { false => (), }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); @@ -47,7 +47,7 @@ fn main() { false => (), }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, expected): (u32, u32) = ::into(expected); @@ -57,7 +57,7 @@ fn main() { false => (), }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); @@ -66,7 +66,7 @@ fn main() { false => (), }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); @@ -75,14 +75,14 @@ fn main() { false => (), }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { assert_eq_256(u1_to_u256(a), expected); }, false => (), }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let expected_bool: bool = jet::eq_256(expected, 1); assert_eq_bool(u1_to_bool(a), expected_bool); diff --git a/simf/u128_test_bits.simf b/simf/tests/u128/bit.simf similarity index 51% rename from simf/u128_test_bits.simf rename to simf/tests/u128/bit.simf index b3ea239..60ac37f 100644 --- a/simf/u128_test_bits.simf +++ b/simf/tests/u128/bit.simf @@ -1,5 +1,7 @@ use crate::lib::u128::bit::{and_128, or_128, eq_128, left_shift_128, right_shift_128}; -use crate::helper::{if_test_this_function, assert_bool}; + +use crate::tests::support::dispatch::is_selected; +use crate::tests::support::expect::assert_bool; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -12,25 +14,42 @@ fn main() { /// Bit logic - match if_test_this_function(0, fn_idx) { true => { assert!(eq_128(and_128(a, b), unwrap(expected))); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert!(eq_128(or_128(a, b), unwrap(expected))); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_bool(eq_128(a, b), expected_bool); }, false => (), }; + match is_selected(0, fn_idx) { + true => { + assert!(eq_128(and_128(a, b), unwrap(expected))); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert!(eq_128(or_128(a, b), unwrap(expected))); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_bool(eq_128(a, b), expected_bool); + }, + false => (), + }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, 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 => (), + assert!(eq_128(left_shift_128(shift, b), unwrap(expected))); + }, + false => (), }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, 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 => (), + assert!(eq_128(right_shift_128(shift, b), unwrap(expected))); + }, + false => (), }; } diff --git a/simf/tests/u128/comparison.simf b/simf/tests/u128/comparison.simf new file mode 100644 index 0000000..9a30979 --- /dev/null +++ b/simf/tests/u128/comparison.simf @@ -0,0 +1,33 @@ +use crate::lib::u128::comparison::{is_zero_128, lt_128, le_128}; + +use crate::tests::support::dispatch::is_selected; +use crate::tests::support::expect::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_bool: bool = witness::EXPECTED_BOOL; + + /// Comparison operations + + match is_selected(0, fn_idx) { + true => { + assert_bool(is_zero_128(a), expected_bool); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_bool(lt_128(a, b), expected_bool); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_bool(le_128(a, b), expected_bool); + }, + false => (), + }; +} diff --git a/simf/u128_convert_test.simf b/simf/tests/u128/convert.simf similarity index 92% rename from simf/u128_convert_test.simf rename to simf/tests/u128/convert.simf index 0d70dcf..eff41e7 100644 --- a/simf/u128_convert_test.simf +++ b/simf/tests/u128/convert.simf @@ -18,7 +18,8 @@ use crate::lib::asserts::{ assert_eq_64, assert_eq_256 }; -use crate::helper::if_test_this_function; + +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -27,14 +28,14 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { assert_eq_256(u128_to_u256(a), expected); }, false => {}, }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let ( a15, @@ -121,7 +122,7 @@ fn main() { false => {}, }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let ( a7, @@ -161,7 +162,7 @@ fn main() { false => {}, }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (a3, a2, a1, a0): (u32, u32, u32, u32) = split_u128_into_u32(a); @@ -177,7 +178,7 @@ fn main() { false => {}, }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (a1, a0): (u64, u64) = split_u128_into_u64(a); @@ -189,7 +190,7 @@ fn main() { false => {}, }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); @@ -199,7 +200,7 @@ fn main() { false => {}, }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u8 = jet::rightmost_64_8(expected); @@ -209,7 +210,7 @@ fn main() { false => {}, }; - match if_test_this_function(7, fn_idx) { + match is_selected(7, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u16 = jet::rightmost_64_16(expected); @@ -219,7 +220,7 @@ fn main() { false => {}, }; - match if_test_this_function(8, fn_idx) { + match is_selected(8, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u32 = jet::rightmost_64_32(expected); @@ -229,7 +230,7 @@ fn main() { false => {}, }; - match if_test_this_function(9, fn_idx) { + match is_selected(9, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); diff --git a/simf/tests/u128/math/api.simf b/simf/tests/u128/math/api.simf new file mode 100644 index 0000000..5cf1585 --- /dev/null +++ b/simf/tests/u128/math/api.simf @@ -0,0 +1,95 @@ +use crate::lib::u128::math::{ + checked_add_128, + add_128, + checked_sub_128, + sub_128, + checked_mul_128, + mul_128, + checked_div_128, + div_128 +}; +use crate::lib::u128::comparison::{gt_128, ge_128}; +use crate::lib::asserts::assert_eq_128; + +use crate::tests::support::expect::{assert_bool_by_opt_128, assert_eq_opt_128}; +use crate::tests::support::dispatch::is_selected; + +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; + + /// Safe functions + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_128(checked_add_128(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_eq_128(add_128(a, b), unwrap(expected)); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_128(checked_sub_128(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert_eq_128(sub_128(a, b), unwrap(expected)); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_128(checked_mul_128(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert_eq_128(mul_128(a, b), unwrap(expected)); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_128(checked_div_128(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert_eq_128(div_128(a, b), unwrap(expected)); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_128(gt_128(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_128(ge_128(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/tests/u128/math/primitives.simf b/simf/tests/u128/math/primitives.simf new file mode 100644 index 0000000..e8edb36 --- /dev/null +++ b/simf/tests/u128/math/primitives.simf @@ -0,0 +1,145 @@ +use crate::lib::u128::math::{ + add_128_carry, + add_128_64_carry, + full_add_128, + sub_128_borrow, + full_sub_128, + mul_128_wide, + mul_128_64_wide, + calculate_normalizer_base_64, + estimate_quotient_digit_base_64, + div_mod_128_64, + div_mod_128 +}; +use crate::lib::u128::bit::eq_128; + +use crate::tests::support::expect::assert_eq_uint_bool_128; +use crate::tests::support::dispatch::is_selected; + +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 + + /// Arithmetic + + match is_selected(0, fn_idx) { + true => { + assert_eq_uint_bool_128(add_128_carry(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + let (_, b): (u64, u64) = ::into(b); + assert_eq_uint_bool_128(add_128_64_carry(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_eq_uint_bool_128( + full_add_128(eq_128(second_expected, 1), a, b), + unwrap(expected), + expected_bool + ); + }, + false => (), + }; + + match is_selected(3, fn_idx) { + true => { + assert_eq_uint_bool_128(sub_128_borrow(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; + match is_selected(4, fn_idx) { + true => { + assert_eq_uint_bool_128( + full_sub_128(eq_128(second_expected, 1), a, b), + unwrap(expected), + expected_bool + ); + }, + false => (), + }; + + match is_selected(5, fn_idx) { + true => { + let result: u256 = mul_128_wide(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 is_selected(6, fn_idx) { + true => { + let (_, b): (u64, u64) = ::into(b); + let result: u256 = mul_128_64_wide(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 is_selected(7, fn_idx) { + true => { + let norm: u64 = calculate_normalizer_base_64(b, expected_bool); + + let (_, expected_norm): (u64, u64) = ::into(unwrap(expected)); + + assert!(jet::eq_64(norm, expected_norm)); + }, + false => (), + }; + + match is_selected(8, fn_idx) { + true => { + let (_, u2): (u64, u64) = ::into(a); + let (u1, u0): (u64, u64) = ::into(b); + let (v1, v0): (u64, u64) = ::into(second_expected); + + let q: u64 = estimate_quotient_digit_base_64(u2, u1, u0, v1, v0); + + let (_, expected_q): (u64, u64) = ::into(unwrap(expected)); + + assert!(jet::eq_64(q, expected_q)); + }, + false => (), + }; + + match is_selected(9, 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 is_selected(10, 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 => (), + }; +} diff --git a/simf/tests/u128/mul_div.simf b/simf/tests/u128/mul_div.simf new file mode 100644 index 0000000..689305b --- /dev/null +++ b/simf/tests/u128/mul_div.simf @@ -0,0 +1,21 @@ +use crate::lib::u128::mul_div::mul_div_128; +use crate::lib::asserts::assert_eq_128; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u128 = witness::FIRST_ARG; + let b: u128 = witness::SECOND_ARG; + let c: u128 = witness::THIRD_ARG; + + let expected: Option = witness::EXPECTED; + + match is_selected(0, fn_idx) { + true => { + assert_eq_128(mul_div_128(a, b, c), unwrap(expected)); + }, + false => (), + }; +} diff --git a/simf/u16_convert_test.simf b/simf/tests/u16/convert.simf similarity index 84% rename from simf/u16_convert_test.simf rename to simf/tests/u16/convert.simf index 847d4f3..b0ddae5 100644 --- a/simf/u16_convert_test.simf +++ b/simf/tests/u16/convert.simf @@ -7,7 +7,6 @@ use crate::lib::u16::convert::{ safe_u16_to_u1, safe_u16_to_u8 }; -use crate::lib::u128::bit::eq_128; use crate::lib::asserts::{ assert_eq_1, assert_eq_8, @@ -16,7 +15,8 @@ use crate::lib::asserts::{ assert_eq_128, assert_eq_256 }; -use crate::helper::if_test_this_function; + +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -25,7 +25,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, expected): (u32, u32) = ::into(expected); @@ -35,7 +35,7 @@ fn main() { false => {}, }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); @@ -44,7 +44,7 @@ fn main() { false => {}, }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); @@ -53,14 +53,14 @@ fn main() { false => {}, }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { assert_eq_256(u16_to_u256(a), expected); }, false => {}, }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (a1, a0): (u8, u8) = split_u16_into_u8(a); @@ -74,7 +74,7 @@ fn main() { false => {}, }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); @@ -84,7 +84,7 @@ fn main() { false => {}, }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u8 = jet::rightmost_64_8(expected); diff --git a/simf/tests/u16/math.simf b/simf/tests/u16/math.simf new file mode 100644 index 0000000..4736d91 --- /dev/null +++ b/simf/tests/u16/math.simf @@ -0,0 +1,93 @@ +use crate::lib::u16::math::{ + checked_add_16, + add_16, + checked_sub_16, + sub_16, + checked_mul_16, + mul_16, + checked_div_16, + div_16, + gt_16, + ge_16 +}; + +use crate::tests::support::expect::{assert_bool_by_opt_16, assert_eq_opt_16}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u16 = witness::FIRST_ARG; + let b: u16 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_16(checked_add_16(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert!(jet::eq_16(add_16(a, b), unwrap(expected))); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_16(checked_sub_16(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert!(jet::eq_16(sub_16(a, b), unwrap(expected))); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_16(checked_mul_16(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert!(jet::eq_16(mul_16(a, b), unwrap(expected))); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_16(checked_div_16(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert!(jet::eq_16(div_16(a, b), unwrap(expected))); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_16(gt_16(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_16(ge_16(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/tests/u16/mul_div.simf b/simf/tests/u16/mul_div.simf new file mode 100644 index 0000000..80e7e0c --- /dev/null +++ b/simf/tests/u16/mul_div.simf @@ -0,0 +1,21 @@ +use crate::lib::u16::mul_div::mul_div_16; +use crate::lib::asserts::assert_eq_16; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u16 = witness::FIRST_ARG; + let b: u16 = witness::SECOND_ARG; + let c: u16 = witness::THIRD_ARG; + + let expected: Option = witness::EXPECTED; + + match is_selected(0, fn_idx) { + true => { + assert_eq_16(mul_div_16(a, b, c), unwrap(expected)); + }, + false => (), + }; +} diff --git a/simf/u256_test_bits.simf b/simf/tests/u256/bit.simf similarity index 62% rename from simf/u256_test_bits.simf rename to simf/tests/u256/bit.simf index 797c0e8..42075b5 100644 --- a/simf/u256_test_bits.simf +++ b/simf/tests/u256/bit.simf @@ -1,7 +1,8 @@ use crate::lib::u256::bit::{and_256, or_256, left_shift_256, right_shift_256}; use crate::lib::u256::convert::split_u256_into_u64; use crate::lib::asserts::assert_eq_256; -use crate::helper::if_test_this_function; + +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -12,24 +13,36 @@ fn main() { /// Bit logic - match if_test_this_function(0, fn_idx) { true => { assert_eq_256(and_256(a, b), unwrap(expected)); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_eq_256(or_256(a, b), unwrap(expected)); }, false => (), }; + match is_selected(0, fn_idx) { + true => { + assert_eq_256(and_256(a, b), unwrap(expected)); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_eq_256(or_256(a, b), unwrap(expected)); + }, + false => (), + }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, _, _, a): (u64, u64, u64, u64) = split_u256_into_u64(a); let shift: u8 = jet::rightmost_64_8(a); - assert_eq_256(left_shift_256(shift, b), unwrap(expected)); - }, false => (), + assert_eq_256(left_shift_256(shift, b), unwrap(expected)); + }, + false => (), }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (_, _, _, a): (u64, u64, u64, u64) = split_u256_into_u64(a); let shift: u8 = jet::rightmost_64_8(a); - assert_eq_256(right_shift_256(shift, b), unwrap(expected)); - }, false => (), + assert_eq_256(right_shift_256(shift, b), unwrap(expected)); + }, + false => (), }; } diff --git a/simf/tests/u256/comparison.simf b/simf/tests/u256/comparison.simf new file mode 100644 index 0000000..86cf498 --- /dev/null +++ b/simf/tests/u256/comparison.simf @@ -0,0 +1,33 @@ +use crate::lib::u256::comparison::{is_zero_256, lt_256, le_256}; + +use crate::tests::support::dispatch::is_selected; +use crate::tests::support::expect::assert_bool; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u256 = witness::FIRST_ARG; + let b: u256 = witness::SECOND_ARG; + let expected_bool: bool = witness::EXPECTED_BOOL; + + /// Comparison operations + + match is_selected(0, fn_idx) { + true => { + assert_bool(is_zero_256(a), expected_bool); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_bool(lt_256(a, b), expected_bool); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_bool(le_256(a, b), expected_bool); + }, + false => (), + }; +} diff --git a/simf/u256_convert_test.simf b/simf/tests/u256/convert.simf similarity index 95% rename from simf/u256_convert_test.simf rename to simf/tests/u256/convert.simf index fe659dd..46791dd 100644 --- a/simf/u256_convert_test.simf +++ b/simf/tests/u256/convert.simf @@ -19,7 +19,8 @@ use crate::lib::asserts::{ assert_eq_64, assert_eq_128 }; -use crate::helper::if_test_this_function; + +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -28,7 +29,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let ( a31, @@ -185,7 +186,7 @@ fn main() { false => {}, }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let ( a15, @@ -275,7 +276,7 @@ fn main() { false => {}, }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let ( a7, @@ -315,7 +316,7 @@ fn main() { false => {}, }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (a3, a2, a1, a0): (u64, u64, u64, u64) = split_u256_into_u64(a); @@ -334,7 +335,7 @@ fn main() { false => {}, }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (a1, a0): (u128, u128) = split_u256_into_u128(a); @@ -346,7 +347,7 @@ fn main() { false => {}, }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); @@ -356,7 +357,7 @@ fn main() { false => {}, }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u8 = jet::rightmost_64_8(expected); @@ -366,7 +367,7 @@ fn main() { false => {}, }; - match if_test_this_function(7, fn_idx) { + match is_selected(7, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u16 = jet::rightmost_64_16(expected); @@ -376,7 +377,7 @@ fn main() { false => {}, }; - match if_test_this_function(8, fn_idx) { + match is_selected(8, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u32 = jet::rightmost_64_32(expected); @@ -386,7 +387,7 @@ fn main() { false => {}, }; - match if_test_this_function(9, fn_idx) { + match is_selected(9, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); @@ -395,7 +396,7 @@ fn main() { false => {}, }; - match if_test_this_function(10, fn_idx) { + match is_selected(10, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); diff --git a/simf/tests/u256/math/add.simf b/simf/tests/u256/math/add.simf new file mode 100644 index 0000000..7ba03e8 --- /dev/null +++ b/simf/tests/u256/math/add.simf @@ -0,0 +1,38 @@ +use crate::lib::u256::math::{add_256_carry, add_256_128_carry, full_add_256}; + +use crate::tests::support::expect::assert_eq_uint_bool_256; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u256 = witness::FIRST_ARG; + let b: u256 = witness::SECOND_ARG; + let carry_in: bool = witness::THIRD_ARG; + let expected: Option = witness::EXPECTED; + let expected_bool: bool = witness::EXPECTED_BOOL; + + /// Arithmetic + + match is_selected(0, fn_idx) { + true => { + assert_eq_uint_bool_256(add_256_carry(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; + + match is_selected(1, fn_idx) { + true => { + let (_, b): (u128, u128) = ::into(b); + assert_eq_uint_bool_256(add_256_128_carry(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; + + match is_selected(2, fn_idx) { + true => { + assert_eq_uint_bool_256(full_add_256(carry_in, a, b), unwrap(expected), expected_bool); + }, + false => (), + }; +} diff --git a/simf/tests/u256/math/api.simf b/simf/tests/u256/math/api.simf new file mode 100644 index 0000000..7de1362 --- /dev/null +++ b/simf/tests/u256/math/api.simf @@ -0,0 +1,95 @@ +use crate::lib::u256::math::{ + checked_add_256, + add_256, + checked_sub_256, + sub_256, + checked_mul_256, + mul_256, + checked_div_256, + div_256 +}; +use crate::lib::u256::comparison::{gt_256, ge_256}; +use crate::lib::asserts::assert_eq_256; + +use crate::tests::support::expect::{assert_bool_by_opt_256, assert_eq_opt_256}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u256 = witness::FIRST_ARG; + let b: u256 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + /// Safe functions + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_256(checked_add_256(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_eq_256(add_256(a, b), unwrap(expected)); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_256(checked_sub_256(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert_eq_256(sub_256(a, b), unwrap(expected)); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_256(checked_mul_256(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert_eq_256(mul_256(a, b), unwrap(expected)); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_256(checked_div_256(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert_eq_256(div_256(a, b), unwrap(expected)); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_256(gt_256(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_256(ge_256(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/tests/u256/math/div.simf b/simf/tests/u256/math/div.simf new file mode 100644 index 0000000..2ae56b8 --- /dev/null +++ b/simf/tests/u256/math/div.simf @@ -0,0 +1,83 @@ +use crate::lib::u256::math::{ + calculate_normalizer_base_128, + div_mod_256_64, + algorithm_d_256_128, + div_mod_256_128, + div_mod_256 +}; +use crate::lib::u256::convert::split_u256_into_u64; +use crate::lib::asserts::{assert_eq_128, assert_eq_256}; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u256 = witness::FIRST_ARG; + let b: u256 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + let second_expected: u256 = witness::SECOND_EXPECTED; + + /// Arithmetic + + match is_selected(0, fn_idx) { + true => { + let result: u128 = calculate_normalizer_base_128(a); + + let (_, expected_r): (u128, u128) = ::into(unwrap(expected)); + + assert_eq_128(result, expected_r); + }, + false => (), + }; + + match is_selected(1, fn_idx) { + true => { + let (_, _, _, b): (u64, u64, u64, u64) = split_u256_into_u64(b); + let (_, _, _, expected_r): (u64, u64, u64, u64) = split_u256_into_u64(second_expected); + + let (q, r): (u256, u64) = div_mod_256_64(a, b); + + assert_eq_256(q, unwrap(expected)); + assert!(jet::eq_64(r, expected_r)); + }, + false => (), + }; + + match is_selected(2, fn_idx) { + true => { + let (_, b): (u128, u128) = ::into(b); + let (_, expected_r): (u128, u128) = ::into(second_expected); + + let (q, r): (u256, u128) = algorithm_d_256_128(a, b); + + assert_eq_256(q, unwrap(expected)); + assert_eq_128(r, expected_r); + }, + false => (), + }; + + match is_selected(3, fn_idx) { + true => { + let (_, b): (u128, u128) = ::into(b); + let (_, expected_r): (u128, u128) = ::into(second_expected); + + let (q, r): (u256, u128) = div_mod_256_128(a, b); + + assert_eq_256(q, unwrap(expected)); + assert_eq_128(r, expected_r); + }, + false => (), + }; + + match is_selected(4, fn_idx) { + true => { + let (q, r): (u256, u256) = div_mod_256(a, b); + + assert_eq_256(q, unwrap(expected)); + assert_eq_256(r, second_expected); + }, + false => (), + }; +} diff --git a/simf/u256_test_sub_mul.simf b/simf/tests/u256/math/sub_mul.simf similarity index 51% rename from simf/u256_test_sub_mul.simf rename to simf/tests/u256/math/sub_mul.simf index aa6b673..2d47842 100644 --- a/simf/u256_test_sub_mul.simf +++ b/simf/tests/u256/math/sub_mul.simf @@ -1,35 +1,41 @@ -use crate::lib::u256::math::{sub_256, mul_256, mul_256_64, mul_256_128}; +use crate::lib::u256::math::{ + sub_256_borrow, + mul_256_wide, + mul_256_64_wide, + mul_256_128_wide, + mul_512_128_wide, + mul_256_128 +}; use crate::lib::u256::convert::split_u256_into_u64; use crate::lib::asserts::{assert_eq_64, assert_eq_128, assert_eq_256}; -use crate::helper::{if_test_this_function, assert_bool}; -/// Asserts a result equals expected u256 and bool values. -/// Used for functions that return carry or borrow bool value. -fn assert_eq_uint_bool(result: (bool, u256), expected: u256, expected_bool: bool) { - let (bool_res, uint_res): (bool, u256) = result; - - assert_bool(bool_res, expected_bool); - - assert_eq_256(uint_res, expected); -} +use crate::tests::support::expect::assert_eq_uint_bool_256; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; let a: u256 = witness::FIRST_ARG; let b: u256 = witness::SECOND_ARG; + let c: u128 = witness::THIRD_ARG; let expected: Option = witness::EXPECTED; let expected_bool: bool = witness::EXPECTED_BOOL; let second_expected: u256 = witness::SECOND_EXPECTED; + let third_expected: u256 = witness::THIRD_EXPECTED; /// Arithmetic - match if_test_this_function(0, fn_idx) { true => { assert_eq_uint_bool(sub_256(a, b), unwrap(expected), expected_bool); }, false => (), }; + match is_selected(0, fn_idx) { + true => { + assert_eq_uint_bool_256(sub_256_borrow(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { - let (result_high, result_low): (u256, u256) = mul_256(a, b); + let (result_high, result_low): (u256, u256) = mul_256_wide(a, b); assert_eq_256(result_high, unwrap(expected)); assert_eq_256(result_low, second_expected); @@ -37,12 +43,12 @@ fn main() { false => (), }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, _, _, b): (u64, u64, u64, u64) = split_u256_into_u64(b); let (_, _, _, expected): (u64, u64, u64, u64) = split_u256_into_u64(unwrap(expected)); - let (result_high, result_low): (u64, u256) = mul_256_64(a, b); + let (result_high, result_low): (u64, u256) = mul_256_64_wide(a, b); assert_eq_64(result_high, expected); assert_eq_256(result_low, second_expected); @@ -50,16 +56,39 @@ fn main() { false => (), }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (_, b): (u128, u128) = ::into(b); let (_, expected): (u128, u128) = ::into(unwrap(expected)); - let (result_high, result_low): (u128, u256) = mul_256_128(a, b); + let (result_high, result_low): (u128, u256) = mul_256_128_wide(a, b); assert_eq_128(result_high, expected); assert_eq_256(result_low, second_expected); }, false => (), }; + + match is_selected(4, fn_idx) { + true => { + let (result_2, result_1, result_0): (u128, u256, u256) = mul_512_128_wide(a, b, c); + + let (_, expected): (u128, u128) = ::into(unwrap(expected)); + + assert_eq_128(result_2, expected); + assert_eq_256(result_1, second_expected); + assert_eq_256(result_0, third_expected); + }, + false => (), + }; + + match is_selected(5, fn_idx) { + true => { + let (_, b): (u128, u128) = ::into(b); + let result: u256 = mul_256_128(a, b); + + assert_eq_256(result, unwrap(expected)); + }, + false => (), + }; } diff --git a/simf/tests/u256/mul_div.simf b/simf/tests/u256/mul_div.simf new file mode 100644 index 0000000..6ce1f52 --- /dev/null +++ b/simf/tests/u256/mul_div.simf @@ -0,0 +1,21 @@ +use crate::lib::u256::mul_div::mul_div_256; +use crate::lib::asserts::assert_eq_256; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u256 = witness::FIRST_ARG; + let b: u256 = witness::SECOND_ARG; + let c: u256 = witness::THIRD_ARG; + + let expected: Option = witness::EXPECTED; + + match is_selected(0, fn_idx) { + true => { + assert_eq_256(mul_div_256(a, b, c), unwrap(expected)); + }, + false => (), + }; +} diff --git a/simf/u32_convert_test.simf b/simf/tests/u32/convert.simf similarity index 86% rename from simf/u32_convert_test.simf rename to simf/tests/u32/convert.simf index 658cc58..9e409db 100644 --- a/simf/u32_convert_test.simf +++ b/simf/tests/u32/convert.simf @@ -8,7 +8,6 @@ use crate::lib::u32::convert::{ safe_u32_to_u8, safe_u32_to_u16 }; -use crate::lib::u128::bit::eq_128; use crate::lib::asserts::{ assert_eq_1, assert_eq_8, @@ -17,7 +16,8 @@ use crate::lib::asserts::{ assert_eq_128, assert_eq_256 }; -use crate::helper::if_test_this_function; + +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -26,7 +26,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); @@ -35,7 +35,7 @@ fn main() { false => {}, }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); @@ -44,14 +44,14 @@ fn main() { false => {}, }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { assert_eq_256(u32_to_u256(a), expected); }, false => {}, }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (a3, a2, a1, a0): (u8, u8, u8, u8) = split_u32_into_u8(a); @@ -72,7 +72,7 @@ fn main() { false => {}, }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (a1, a0): (u16, u16) = split_u32_into_u16(a); @@ -86,7 +86,7 @@ fn main() { false => {}, }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); @@ -96,7 +96,7 @@ fn main() { false => {}, }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u8 = jet::rightmost_64_8(expected); @@ -106,7 +106,7 @@ fn main() { false => {}, }; - match if_test_this_function(7, fn_idx) { + match is_selected(7, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u16 = jet::rightmost_64_16(expected); diff --git a/simf/tests/u32/math.simf b/simf/tests/u32/math.simf new file mode 100644 index 0000000..103b12a --- /dev/null +++ b/simf/tests/u32/math.simf @@ -0,0 +1,93 @@ +use crate::lib::u32::math::{ + checked_add_32, + add_32, + checked_sub_32, + sub_32, + checked_mul_32, + mul_32, + checked_div_32, + div_32, + gt_32, + ge_32 +}; + +use crate::tests::support::expect::{assert_bool_by_opt_32, assert_eq_opt_32}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u32 = witness::FIRST_ARG; + let b: u32 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_32(checked_add_32(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert!(jet::eq_32(add_32(a, b), unwrap(expected))); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_32(checked_sub_32(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert!(jet::eq_32(sub_32(a, b), unwrap(expected))); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_32(checked_mul_32(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert!(jet::eq_32(mul_32(a, b), unwrap(expected))); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_32(checked_div_32(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert!(jet::eq_32(div_32(a, b), unwrap(expected))); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_32(gt_32(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_32(ge_32(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/tests/u32/mul_div.simf b/simf/tests/u32/mul_div.simf new file mode 100644 index 0000000..167302e --- /dev/null +++ b/simf/tests/u32/mul_div.simf @@ -0,0 +1,21 @@ +use crate::lib::u32::mul_div::mul_div_32; +use crate::lib::asserts::assert_eq_32; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u32 = witness::FIRST_ARG; + let b: u32 = witness::SECOND_ARG; + let c: u32 = witness::THIRD_ARG; + + let expected: Option = witness::EXPECTED; + + match is_selected(0, fn_idx) { + true => { + assert_eq_32(mul_div_32(a, b, c), unwrap(expected)); + }, + false => (), + }; +} diff --git a/simf/u64_convert_test.simf b/simf/tests/u64/convert.simf similarity index 89% rename from simf/u64_convert_test.simf rename to simf/tests/u64/convert.simf index 00d651e..0606bd4 100644 --- a/simf/u64_convert_test.simf +++ b/simf/tests/u64/convert.simf @@ -17,7 +17,8 @@ use crate::lib::asserts::{ assert_eq_128, assert_eq_256 }; -use crate::helper::if_test_this_function; + +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -26,7 +27,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); @@ -35,14 +36,14 @@ fn main() { false => {}, }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { assert_eq_256(u64_to_u256(a), expected); }, false => {}, }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let ( a7, @@ -79,7 +80,7 @@ fn main() { false => {}, }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (a3, a2, a1, a0): (u16, u16, u16, u16) = split_u64_into_u16(a); @@ -99,7 +100,7 @@ fn main() { false => {}, }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (a1, a0): (u32, u32) = split_u64_into_u32(a); @@ -112,7 +113,7 @@ fn main() { false => {}, }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); @@ -122,7 +123,7 @@ fn main() { false => {}, }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u8 = jet::rightmost_64_8(expected); @@ -132,7 +133,7 @@ fn main() { false => {}, }; - match if_test_this_function(7, fn_idx) { + match is_selected(7, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u16 = jet::rightmost_64_16(expected); @@ -142,7 +143,7 @@ fn main() { false => {}, }; - match if_test_this_function(8, fn_idx) { + match is_selected(8, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u32 = jet::rightmost_64_32(expected); diff --git a/simf/tests/u64/math.simf b/simf/tests/u64/math.simf new file mode 100644 index 0000000..6f5f510 --- /dev/null +++ b/simf/tests/u64/math.simf @@ -0,0 +1,93 @@ +use crate::lib::u64::math::{ + checked_add_64, + add_64, + checked_sub_64, + sub_64, + checked_mul_64, + mul_64, + checked_div_64, + div_64, + gt_64, + ge_64 +}; + +use crate::tests::support::expect::{assert_bool_by_opt_64, assert_eq_opt_64}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u64 = witness::FIRST_ARG; + let b: u64 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_64(checked_add_64(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert!(jet::eq_64(add_64(a, b), unwrap(expected))); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_64(checked_sub_64(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert!(jet::eq_64(sub_64(a, b), unwrap(expected))); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_64(checked_mul_64(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert!(jet::eq_64(mul_64(a, b), unwrap(expected))); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_64(checked_div_64(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert!(jet::eq_64(div_64(a, b), unwrap(expected))); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_64(gt_64(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_64(ge_64(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/tests/u64/mul_div.simf b/simf/tests/u64/mul_div.simf new file mode 100644 index 0000000..ea660c8 --- /dev/null +++ b/simf/tests/u64/mul_div.simf @@ -0,0 +1,21 @@ +use crate::lib::u64::mul_div::mul_div_64; +use crate::lib::asserts::assert_eq_64; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u64 = witness::FIRST_ARG; + let b: u64 = witness::SECOND_ARG; + let c: u64 = witness::THIRD_ARG; + + let expected: Option = witness::EXPECTED; + + match is_selected(0, fn_idx) { + true => { + assert_eq_64(mul_div_64(a, b, c), unwrap(expected)); + }, + false => (), + }; +} diff --git a/simf/u8_convert_test.simf b/simf/tests/u8/convert.simf similarity index 87% rename from simf/u8_convert_test.simf rename to simf/tests/u8/convert.simf index 2256638..91d8d51 100644 --- a/simf/u8_convert_test.simf +++ b/simf/tests/u8/convert.simf @@ -7,7 +7,6 @@ use crate::lib::u8::convert::{ split_u8_into_u1, safe_u8_to_u1 }; -use crate::lib::u128::bit::eq_128; use crate::lib::asserts::{ assert_eq_1, assert_eq_16, @@ -16,7 +15,8 @@ use crate::lib::asserts::{ assert_eq_128, assert_eq_256 }; -use crate::helper::if_test_this_function; + +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -25,7 +25,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); @@ -35,7 +35,7 @@ fn main() { false => (), }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, expected): (u32, u32) = ::into(expected); @@ -45,7 +45,7 @@ fn main() { false => (), }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); @@ -54,7 +54,7 @@ fn main() { false => (), }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); @@ -63,14 +63,14 @@ fn main() { false => (), }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { assert_eq_256(u8_to_u256(a), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let ( a7, @@ -108,7 +108,7 @@ fn main() { false => (), }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); diff --git a/simf/tests/u8/math.simf b/simf/tests/u8/math.simf new file mode 100644 index 0000000..9e3eace --- /dev/null +++ b/simf/tests/u8/math.simf @@ -0,0 +1,93 @@ +use crate::lib::u8::math::{ + checked_add_8, + add_8, + checked_sub_8, + sub_8, + checked_mul_8, + mul_8, + checked_div_8, + div_8, + gt_8, + ge_8 +}; + +use crate::tests::support::expect::{assert_bool_by_opt_8, assert_eq_opt_8}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u8 = witness::FIRST_ARG; + let b: u8 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_8(checked_add_8(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert!(jet::eq_8(add_8(a, b), unwrap(expected))); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_8(checked_sub_8(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert!(jet::eq_8(sub_8(a, b), unwrap(expected))); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_8(checked_mul_8(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert!(jet::eq_8(mul_8(a, b), unwrap(expected))); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_8(checked_div_8(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert!(jet::eq_8(div_8(a, b), unwrap(expected))); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_8(gt_8(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_8(ge_8(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/tests/u8/mul_div.simf b/simf/tests/u8/mul_div.simf new file mode 100644 index 0000000..45be7ec --- /dev/null +++ b/simf/tests/u8/mul_div.simf @@ -0,0 +1,21 @@ +use crate::lib::u8::mul_div::mul_div_8; +use crate::lib::asserts::assert_eq_8; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u8 = witness::FIRST_ARG; + let b: u8 = witness::SECOND_ARG; + let c: u8 = witness::THIRD_ARG; + + let expected: Option = witness::EXPECTED; + + match is_selected(0, fn_idx) { + true => { + assert_eq_8(mul_div_8(a, b, c), unwrap(expected)); + }, + false => (), + }; +} diff --git a/simf/tests/utxo/asserts/amount.simf b/simf/tests/utxo/asserts/amount.simf new file mode 100644 index 0000000..c9532e8 --- /dev/null +++ b/simf/tests/utxo/asserts/amount.simf @@ -0,0 +1,81 @@ +use crate::lib::utxo::asserts::amount::{ + assert_explicit_amount, + assert_confidential_amount, + assert_explicit_input_amount, + assert_confidential_input_amount, + assert_explicit_output_amount, + assert_confidential_output_amount, + assert_explicit_current_amount, + assert_confidential_current_amount +}; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let index: u32 = witness::INDEX; + let is_input_index: bool = witness::IS_INPUT_INDEX; + + let expected_amount: u64 = witness::EXPECTED; + let expected_parity: u1 = witness::EXPECTED_PARITY; + let expected_confidential_amount: u256 = witness::EXPECTED_CONF; + + let expected_confidential: Confidential1 = (expected_parity, expected_confidential_amount); + + match is_selected(0, fn_idx) { + true => { + assert_explicit_amount(index, is_input_index, expected_amount); + }, + false => (), + }; + + match is_selected(1, fn_idx) { + true => { + assert_confidential_amount(index, is_input_index, expected_confidential); + }, + false => (), + }; + + match is_selected(2, fn_idx) { + true => { + assert_explicit_input_amount(index, expected_amount); + }, + false => (), + }; + + match is_selected(3, fn_idx) { + true => { + assert_confidential_input_amount(index, expected_confidential); + }, + false => (), + }; + + match is_selected(4, fn_idx) { + true => { + assert_explicit_output_amount(index, expected_amount); + }, + false => (), + }; + + match is_selected(5, fn_idx) { + true => { + assert_confidential_output_amount(index, expected_confidential); + }, + false => (), + }; + + match is_selected(6, fn_idx) { + true => { + assert_explicit_current_amount(expected_amount); + }, + false => (), + }; + + match is_selected(7, fn_idx) { + true => { + assert_confidential_current_amount(expected_confidential); + }, + false => (), + }; +} diff --git a/simf/tests/utxo/asserts/asset_id.simf b/simf/tests/utxo/asserts/asset_id.simf new file mode 100644 index 0000000..f770118 --- /dev/null +++ b/simf/tests/utxo/asserts/asset_id.simf @@ -0,0 +1,81 @@ +use crate::lib::utxo::asserts::asset_id::{ + assert_explicit_asset_id, + assert_confidential_asset_id, + assert_explicit_input_asset_id, + assert_confidential_input_asset_id, + assert_explicit_output_asset_id, + assert_confidential_output_asset_id, + assert_explicit_current_asset_id, + assert_confidential_current_asset_id +}; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let index: u32 = witness::INDEX; + let is_input_index: bool = witness::IS_INPUT_INDEX; + + let expected_asset_id: u256 = witness::EXPECTED; + let expected_parity: u1 = witness::EXPECTED_PARITY; + let expected_confidential_asset_id: u256 = witness::EXPECTED_CONF; + + let expected_confidential: Confidential1 = (expected_parity, expected_confidential_asset_id); + + match is_selected(0, fn_idx) { + true => { + assert_explicit_asset_id(index, is_input_index, expected_asset_id); + }, + false => (), + }; + + match is_selected(1, fn_idx) { + true => { + assert_confidential_asset_id(index, is_input_index, expected_confidential); + }, + false => (), + }; + + match is_selected(2, fn_idx) { + true => { + assert_explicit_input_asset_id(index, expected_asset_id); + }, + false => (), + }; + + match is_selected(3, fn_idx) { + true => { + assert_confidential_input_asset_id(index, expected_confidential); + }, + false => (), + }; + + match is_selected(4, fn_idx) { + true => { + assert_explicit_output_asset_id(index, expected_asset_id); + }, + false => (), + }; + + match is_selected(5, fn_idx) { + true => { + assert_confidential_output_asset_id(index, expected_confidential); + }, + false => (), + }; + + match is_selected(6, fn_idx) { + true => { + assert_explicit_current_asset_id(expected_asset_id); + }, + false => (), + }; + + match is_selected(7, fn_idx) { + true => { + assert_confidential_current_asset_id(expected_confidential); + }, + false => (), + }; +} diff --git a/simf/tests/utxo/asserts/asset_id_with_amount.simf b/simf/tests/utxo/asserts/asset_id_with_amount.simf new file mode 100644 index 0000000..7fb2caa --- /dev/null +++ b/simf/tests/utxo/asserts/asset_id_with_amount.simf @@ -0,0 +1,114 @@ +use crate::lib::utxo::asserts::asset_id_with_amount::{ + assert_explicit_asset_id_with_amount, + assert_confidential_asset_id_with_amount, + assert_explicit_input_asset_id_with_amount, + assert_confidential_input_asset_id_with_amount, + assert_explicit_output_asset_id_with_amount, + assert_confidential_output_asset_id_with_amount, + assert_explicit_current_asset_id_with_amount, + assert_confidential_current_asset_id_with_amount +}; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let index: u32 = witness::INDEX; + let is_input_index: bool = witness::IS_INPUT_INDEX; + + let expected_asset_id: u256 = witness::EXPECTED_ASSET; + let expected_asset_parity: u1 = witness::EXPECTED_ASSET_PARITY; + let expected_confidential_asset_id: u256 = witness::EXPECTED_CONF_ASSET; + + let expected_confidential_asset_id: Confidential1 = ( + expected_asset_parity, + expected_confidential_asset_id + ); + + let expected_amount: u64 = witness::EXPECTED_AMOUNT; + let expected_amount_parity: u1 = witness::EXPECTED_AMOUNT_PARITY; + let expected_confidential_amount: u256 = witness::EXPECTED_CONF_AMOUNT; + + let expected_confidential_amount: Confidential1 = ( + expected_amount_parity, + expected_confidential_amount + ); + + match is_selected(0, fn_idx) { + true => { + assert_explicit_asset_id_with_amount( + index, + is_input_index, + expected_asset_id, + expected_amount + ); + }, + false => (), + }; + + match is_selected(1, fn_idx) { + true => { + assert_confidential_asset_id_with_amount( + index, + is_input_index, + expected_confidential_asset_id, + expected_confidential_amount + ); + }, + false => (), + }; + + match is_selected(2, fn_idx) { + true => { + assert_explicit_input_asset_id_with_amount(index, expected_asset_id, expected_amount); + }, + false => (), + }; + + match is_selected(3, fn_idx) { + true => { + assert_confidential_input_asset_id_with_amount( + index, + expected_confidential_asset_id, + expected_confidential_amount + ); + }, + false => (), + }; + + match is_selected(4, fn_idx) { + true => { + assert_explicit_output_asset_id_with_amount(index, expected_asset_id, expected_amount); + }, + false => (), + }; + + match is_selected(5, fn_idx) { + true => { + assert_confidential_output_asset_id_with_amount( + index, + expected_confidential_asset_id, + expected_confidential_amount + ); + }, + false => (), + }; + + match is_selected(6, fn_idx) { + true => { + assert_explicit_current_asset_id_with_amount(expected_asset_id, expected_amount); + }, + false => (), + }; + + match is_selected(7, fn_idx) { + true => { + assert_confidential_current_asset_id_with_amount( + expected_confidential_asset_id, + expected_confidential_amount + ); + }, + false => (), + }; +} diff --git a/simf/tests/utxo/getters/amount.simf b/simf/tests/utxo/getters/amount.simf new file mode 100644 index 0000000..08b6b0a --- /dev/null +++ b/simf/tests/utxo/getters/amount.simf @@ -0,0 +1,104 @@ +use crate::lib::utxo::getters::amount::{ + get_explicit_amount, + get_confidential_amount, + get_explicit_input_amount, + get_confidential_input_amount, + get_explicit_output_amount, + get_confidential_output_amount, + get_explicit_current_amount, + get_confidential_current_amount +}; +use crate::lib::asserts::{assert_eq_1, assert_eq_64, assert_eq_256}; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let index: u32 = witness::INDEX; + let is_input_index: bool = witness::IS_INPUT_INDEX; + + let expected_amount: u64 = witness::EXPECTED; + let expected_parity: u1 = witness::EXPECTED_PARITY; + let expected_confidential_amount: u256 = witness::EXPECTED_CONF; + + match is_selected(0, fn_idx) { + true => { + assert_eq_64(get_explicit_amount(index, is_input_index), expected_amount); + }, + false => (), + }; + + match is_selected(1, fn_idx) { + true => { + let ( + parity_bit, + confidential_amount + ): Confidential1 = get_confidential_amount(index, is_input_index); + + assert_eq_1(parity_bit,expected_parity); + assert_eq_256(confidential_amount, expected_confidential_amount); + }, + false => (), + }; + + match is_selected(2, fn_idx) { + true => { + assert_eq_64(get_explicit_input_amount(index), expected_amount); + }, + false => (), + }; + + match is_selected(3, fn_idx) { + true => { + let ( + parity_bit, + confidential_amount + ): Confidential1 = get_confidential_input_amount(index); + + assert_eq_1(parity_bit,expected_parity); + assert_eq_256(confidential_amount, expected_confidential_amount); + }, + false => (), + }; + + match is_selected(4, fn_idx) { + true => { + assert_eq_64(get_explicit_output_amount(index), expected_amount); + }, + false => (), + }; + + match is_selected(5, fn_idx) { + true => { + let ( + parity_bit, + confidential_amount + ): Confidential1 = get_confidential_output_amount(index); + + assert_eq_1(parity_bit,expected_parity); + assert_eq_256(confidential_amount, expected_confidential_amount); + }, + false => (), + }; + + match is_selected(6, fn_idx) { + true => { + assert_eq_64(get_explicit_current_amount(), expected_amount); + }, + false => (), + }; + + match is_selected(7, fn_idx) { + true => { + let ( + parity_bit, + confidential_amount + ): Confidential1 = get_confidential_current_amount(); + + assert_eq_1(parity_bit,expected_parity); + assert_eq_256(confidential_amount, expected_confidential_amount); + }, + false => (), + }; +} diff --git a/simf/tests/utxo/getters/asset_id.simf b/simf/tests/utxo/getters/asset_id.simf new file mode 100644 index 0000000..1655758 --- /dev/null +++ b/simf/tests/utxo/getters/asset_id.simf @@ -0,0 +1,104 @@ +use crate::lib::utxo::getters::asset_id::{ + get_explicit_asset_id, + get_confidential_asset_id, + get_explicit_input_asset_id, + get_confidential_input_asset_id, + get_explicit_output_asset_id, + get_confidential_output_asset_id, + get_explicit_current_asset_id, + get_confidential_current_asset_id +}; +use crate::lib::asserts::{assert_eq_1, assert_eq_256}; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let index: u32 = witness::INDEX; + let is_input_index: bool = witness::IS_INPUT_INDEX; + + let expected_asset_id: u256 = witness::EXPECTED; + let expected_parity: u1 = witness::EXPECTED_PARITY; + let expected_confidential_asset_id: u256 = witness::EXPECTED_CONF; + + match is_selected(0, fn_idx) { + true => { + assert_eq_256(get_explicit_asset_id(index, is_input_index), expected_asset_id); + }, + false => (), + }; + + match is_selected(1, fn_idx) { + true => { + let ( + parity_bit, + confidential_asset_id + ): Confidential1 = get_confidential_asset_id(index, is_input_index); + + assert_eq_1(parity_bit, expected_parity); + assert_eq_256(confidential_asset_id, expected_confidential_asset_id); + }, + false => (), + }; + + match is_selected(2, fn_idx) { + true => { + assert_eq_256(get_explicit_input_asset_id(index), expected_asset_id); + }, + false => (), + }; + + match is_selected(3, fn_idx) { + true => { + let ( + parity_bit, + confidential_asset_id + ): Confidential1 = get_confidential_input_asset_id(index); + + assert_eq_1(parity_bit, expected_parity); + assert_eq_256(confidential_asset_id, expected_confidential_asset_id); + }, + false => (), + }; + + match is_selected(4, fn_idx) { + true => { + assert_eq_256(get_explicit_output_asset_id(index), expected_asset_id); + }, + false => (), + }; + + match is_selected(5, fn_idx) { + true => { + let ( + parity_bit, + confidential_asset_id + ): Confidential1 = get_confidential_output_asset_id(index); + + assert_eq_1(parity_bit, expected_parity); + assert_eq_256(confidential_asset_id, expected_confidential_asset_id); + }, + false => (), + }; + + match is_selected(6, fn_idx) { + true => { + assert_eq_256(get_explicit_current_asset_id(), expected_asset_id); + }, + false => (), + }; + + match is_selected(7, fn_idx) { + true => { + let ( + parity_bit, + confidential_asset_id + ): Confidential1 = get_confidential_current_asset_id(); + + assert_eq_1(parity_bit, expected_parity); + assert_eq_256(confidential_asset_id, expected_confidential_asset_id); + }, + false => (), + }; +} diff --git a/simf/tests/utxo/getters/asset_id_with_amount.simf b/simf/tests/utxo/getters/asset_id_with_amount.simf new file mode 100644 index 0000000..298b265 --- /dev/null +++ b/simf/tests/utxo/getters/asset_id_with_amount.simf @@ -0,0 +1,162 @@ +use crate::lib::utxo::getters::asset_id_with_amount::{ + get_explicit_asset_id_with_amount, + get_confidential_asset_id_with_amount, + get_explicit_input_asset_id_with_amount, + get_confidential_input_asset_id_with_amount, + get_explicit_output_asset_id_with_amount, + get_confidential_output_asset_id_with_amount, + get_explicit_current_asset_id_with_amount, + get_confidential_current_asset_id_with_amount +}; +use crate::lib::asserts::{assert_eq_1, assert_eq_64, assert_eq_256}; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let index: u32 = witness::INDEX; + let is_input_index: bool = witness::IS_INPUT_INDEX; + + let expected_asset_id: u256 = witness::EXPECTED_ASSET; + let expected_asset_parity: u1 = witness::EXPECTED_ASSET_PARITY; + let expected_confidential_asset_id: u256 = witness::EXPECTED_CONF_ASSET; + + let expected_amount: u64 = witness::EXPECTED_AMOUNT; + let expected_amount_parity: u1 = witness::EXPECTED_AMOUNT_PARITY; + let expected_confidential_amount: u256 = witness::EXPECTED_CONF_AMOUNT; + + match is_selected(0, fn_idx) { + true => { + let ( + asset_id, + amount + ): (u256, u64) = get_explicit_asset_id_with_amount(index, is_input_index); + + assert_eq_256(asset_id, expected_asset_id); + assert_eq_64(amount, expected_amount); + }, + false => (), + }; + + match is_selected(1, fn_idx) { + true => { + let ( + ( + parity_bit_asset_id, + confidential_asset_id + ), + ( + parity_bit_amount, + confidential_amount + ) + ): (Confidential1, Confidential1) = get_confidential_asset_id_with_amount( + index, + is_input_index + ); + + assert_eq_1(parity_bit_asset_id, expected_asset_parity); + assert_eq_256(confidential_asset_id, expected_confidential_asset_id); + + assert_eq_1(parity_bit_amount, expected_amount_parity); + assert_eq_256(confidential_amount, expected_confidential_amount); + }, + false => (), + }; + + match is_selected(2, fn_idx) { + true => { + let (asset_id, amount): (u256, u64) = get_explicit_input_asset_id_with_amount(index); + + assert_eq_256(asset_id, expected_asset_id); + assert_eq_64(amount, expected_amount); + }, + false => (), + }; + + match is_selected(3, fn_idx) { + true => { + let ( + ( + parity_bit_asset_id, + confidential_asset_id + ), + ( + parity_bit_amount, + confidential_amount + ) + ): (Confidential1, Confidential1) = get_confidential_input_asset_id_with_amount(index); + + assert_eq_1(parity_bit_asset_id, expected_asset_parity); + assert_eq_256(confidential_asset_id, expected_confidential_asset_id); + + assert_eq_1(parity_bit_amount, expected_amount_parity); + assert_eq_256(confidential_amount, expected_confidential_amount); + }, + false => (), + }; + + match is_selected(4, fn_idx) { + true => { + let (asset_id, amount): (u256, u64) = get_explicit_output_asset_id_with_amount(index); + + assert_eq_256(asset_id, expected_asset_id); + assert_eq_64(amount, expected_amount); + }, + false => (), + }; + + match is_selected(5, fn_idx) { + true => { + let ( + ( + parity_bit_asset_id, + confidential_asset_id + ), + ( + parity_bit_amount, + confidential_amount + ) + ): (Confidential1, Confidential1) = get_confidential_output_asset_id_with_amount(index); + + assert_eq_1(parity_bit_asset_id, expected_asset_parity); + assert_eq_256(confidential_asset_id, expected_confidential_asset_id); + + assert_eq_1(parity_bit_amount, expected_amount_parity); + assert_eq_256(confidential_amount, expected_confidential_amount); + }, + false => (), + }; + + match is_selected(6, fn_idx) { + true => { + let (asset_id, amount): (u256, u64) = get_explicit_current_asset_id_with_amount(); + + assert_eq_256(asset_id, expected_asset_id); + assert_eq_64(amount, expected_amount); + }, + false => (), + }; + + match is_selected(7, fn_idx) { + true => { + let ( + ( + parity_bit_asset_id, + confidential_asset_id + ), + ( + parity_bit_amount, + confidential_amount + ) + ): (Confidential1, Confidential1) = get_confidential_current_asset_id_with_amount(); + + assert_eq_1(parity_bit_asset_id, expected_asset_parity); + assert_eq_256(confidential_asset_id, expected_confidential_asset_id); + + assert_eq_1(parity_bit_amount, expected_amount_parity); + assert_eq_256(confidential_amount, expected_confidential_amount); + }, + false => (), + }; +} diff --git a/simf/tests/utxo/getters/script_hash.simf b/simf/tests/utxo/getters/script_hash.simf new file mode 100644 index 0000000..68aff1c --- /dev/null +++ b/simf/tests/utxo/getters/script_hash.simf @@ -0,0 +1,38 @@ +use crate::lib::utxo::getters::script_hash::{ + get_script_hash, + get_input_script_hash, + get_output_script_hash +}; +use crate::lib::asserts::assert_eq_256; + +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let index: u32 = witness::INDEX; + let is_input_index: bool = witness::IS_INPUT_INDEX; + + let expected_hash: u256 = witness::EXPECTED; + + match is_selected(0, fn_idx) { + true => { + assert_eq_256(get_script_hash(index, is_input_index), expected_hash); + }, + false => (), + }; + + match is_selected(1, fn_idx) { + true => { + assert_eq_256(get_input_script_hash(index), expected_hash); + }, + false => (), + }; + + match is_selected(2, fn_idx) { + true => { + assert_eq_256(get_output_script_hash(index), expected_hash); + }, + false => (), + }; +} diff --git a/simf/u128_basic_math_test.simf b/simf/u128_basic_math_test.simf deleted file mode 100644 index 17d5992..0000000 --- a/simf/u128_basic_math_test.simf +++ /dev/null @@ -1,122 +0,0 @@ -use crate::lib::u128::math::{ - add_128, - add_128_64, - full_add_128, - sub_128, - full_sub_128, - mul_128, - mul_128_64, - calculate_normalizer_base_64, - estimate_quotient_digit_base_64, - div_mod_128_64, - div_mod_128, - div_128 -}; -use crate::lib::u128::bit::eq_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 - - /// Arithmetic - - match if_test_this_function(0, fn_idx) { true => { assert_eq_uint_bool(add_128(a, b), unwrap(expected), expected_bool); }, false => (), }; - match if_test_this_function(1, 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(2, fn_idx) { true => { assert_eq_uint_bool(full_add_128(eq_128(second_expected, 1), a, b), unwrap(expected), expected_bool); }, false => (), }; - - match if_test_this_function(3, fn_idx) { true => { assert_eq_uint_bool(sub_128(a, b), unwrap(expected), expected_bool); }, false => (), }; - match if_test_this_function(4, fn_idx) { true => { assert_eq_uint_bool(full_sub_128(eq_128(second_expected, 1), a, b), unwrap(expected), expected_bool); }, false => (), }; - - match if_test_this_function(5, 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(6, fn_idx) { - true => { - let (_, b): (u64, u64) = ::into(b); - let result: u256 = mul_128_64(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(7, fn_idx) { - true => { - let norm: u64 = calculate_normalizer_base_64(b, expected_bool); - - let (_, expected_norm): (u64, u64) = ::into(unwrap(expected)); - - assert!(jet::eq_64(norm, expected_norm)); - }, - false => (), - }; - - match if_test_this_function(8, fn_idx) { - true => { - let (_, u2): (u64, u64) = ::into(a); - let (u1, u0): (u64, u64) = ::into(b); - let (v1, v0): (u64, u64) = ::into(second_expected); - - let q: u64 = estimate_quotient_digit_base_64(u2, u1, u0, v1, v0); - - let (_, expected_q): (u64, u64) = ::into(unwrap(expected)); - - assert!(jet::eq_64(q, expected_q)); - }, - false => (), - }; - - match if_test_this_function(9, 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(10, 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(11, fn_idx) { true => { assert!(eq_128(div_128(a, b), unwrap(expected))); }, false => (), }; -} diff --git a/simf/u128_math_test.simf b/simf/u128_math_test.simf deleted file mode 100644 index 1c73009..0000000 --- a/simf/u128_math_test.simf +++ /dev/null @@ -1,63 +0,0 @@ -use crate::lib::u128::math::{ - checked_add_128, - safe_add_128, - checked_sub_128, - safe_sub_128, - checked_mul_128, - safe_mul_128, - checked_div_128, - safe_div_128 -}; -use crate::lib::u128::comparison::{gt_128, ge_128}; -use crate::lib::asserts::{assert_none_128, assert_eq_128}; -use crate::lib::binary::not; -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 { - Some(e: u128) => assert_eq_128(unwrap(result), e), - None => assert_none_128(result), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u128) => assert!(result), - None => assert!(not(result)), - } -} - -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; - - /// 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 => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_128(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_128(a, b), expected); }, false => (), }; -} diff --git a/simf/u128_test_compare.simf b/simf/u128_test_compare.simf deleted file mode 100644 index e9badb1..0000000 --- a/simf/u128_test_compare.simf +++ /dev/null @@ -1,20 +0,0 @@ -use crate::lib::u128::comparison::{ - is_zero_128, - lt_128, - le_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_bool: bool = witness::EXPECTED_BOOL; - - /// Comparison operations - - match if_test_this_function(0, fn_idx) { true => { assert_bool(is_zero_128(a), expected_bool); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_bool(lt_128(a, b), expected_bool); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_bool(le_128(a, b), expected_bool); }, false => (), }; -} diff --git a/simf/u16_math_test.simf b/simf/u16_math_test.simf deleted file mode 100644 index bc7aece..0000000 --- a/simf/u16_math_test.simf +++ /dev/null @@ -1,51 +0,0 @@ -use crate::lib::u16::math::{checked_add_16, safe_add_16, checked_sub_16, safe_sub_16, checked_mul_16, safe_mul_16, checked_div_16, safe_div_16, gt_16, ge_16}; -use crate::lib::asserts::{assert_none_16, assert_eq_16}; -use crate::lib::binary::not; -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_16(result), - Some(e: u16) => assert_eq_16(unwrap(result), e), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u16) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u16 = witness::FIRST_ARG; - let b: u16 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - // add - match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_16(a, b), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_16(safe_add_16(a, b), unwrap(expected))); }, false => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_16(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_16(safe_sub_16(a, b), unwrap(expected))); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_16(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_16(safe_mul_16(a, b), unwrap(expected))); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_16(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_16(safe_div_16(a, b), unwrap(expected))); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_16(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_16(a, b), expected); }, false => (), }; -} diff --git a/simf/u256_math_test.simf b/simf/u256_math_test.simf deleted file mode 100644 index 9bc8930..0000000 --- a/simf/u256_math_test.simf +++ /dev/null @@ -1,63 +0,0 @@ -use crate::lib::u256::math::{ - checked_add_256, - safe_add_256, - checked_sub_256, - safe_sub_256, - checked_mul_256, - safe_mul_256, - checked_div_256, - safe_div_256 -}; -use crate::lib::u256::comparison::{gt_256, ge_256}; -use crate::lib::asserts::{assert_none_256, assert_eq_256}; -use crate::lib::binary::not; -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 { - Some(e: u256) => assert_eq_256(unwrap(result), e), - None => assert_none_256(result), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u256) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u256 = witness::FIRST_ARG; - let b: u256 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - /// Safe functions - - // add - match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_256(a, b), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => {assert_eq_256(safe_add_256(a, b), unwrap(expected)); }, false => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_256(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => {assert_eq_256(safe_sub_256(a, b), unwrap(expected)); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_256(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => {assert_eq_256(safe_mul_256(a, b), unwrap(expected)); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_256(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => {assert_eq_256(safe_div_256(a, b), unwrap(expected)); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_256(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_256(a, b), expected); }, false => (), }; -} diff --git a/simf/u256_test_add.simf b/simf/u256_test_add.simf deleted file mode 100644 index 1c06f46..0000000 --- a/simf/u256_test_add.simf +++ /dev/null @@ -1,27 +0,0 @@ -use crate::lib::u256::math::{add_256, add_256_128}; -use crate::lib::asserts::assert_eq_256; -use crate::helper::{if_test_this_function, assert_bool}; - -/// Asserts a result equals expected u256 and bool values. -/// Used for functions that return carry or borrow bool value. -fn assert_eq_uint_bool(result: (bool, u256), expected: u256, expected_bool: bool) { - let (bool_res, uint_res): (bool, u256) = result; - - assert_bool(bool_res, expected_bool); - - assert_eq_256(uint_res, expected); -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u256 = witness::FIRST_ARG; - let b: u256 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - let expected_bool: bool = witness::EXPECTED_BOOL; - - /// Arithmetic - - match if_test_this_function(0, fn_idx) { true => { assert_eq_uint_bool(add_256(a, b), unwrap(expected), expected_bool); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { let (_, b): (u128, u128) = ::into(b); assert_eq_uint_bool(add_256_128(a, b), unwrap(expected), expected_bool); }, false => (), }; -} diff --git a/simf/u256_test_compare.simf b/simf/u256_test_compare.simf deleted file mode 100644 index 5192369..0000000 --- a/simf/u256_test_compare.simf +++ /dev/null @@ -1,16 +0,0 @@ -use crate::lib::u256::comparison::{is_zero_256, lt_256, le_256}; -use crate::helper::{if_test_this_function, assert_bool}; - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u256 = witness::FIRST_ARG; - let b: u256 = witness::SECOND_ARG; - let expected_bool: bool = witness::EXPECTED_BOOL; - - /// Comparison operations - - match if_test_this_function(0, fn_idx) { true => { assert_bool(is_zero_256(a), expected_bool); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_bool(lt_256(a, b), expected_bool); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_bool(le_256(a, b), expected_bool); }, false => (), }; -} diff --git a/simf/u256_test_div.simf b/simf/u256_test_div.simf deleted file mode 100644 index 7c895b2..0000000 --- a/simf/u256_test_div.simf +++ /dev/null @@ -1,54 +0,0 @@ -use crate::lib::u256::math::{div_mod_256_64, div_mod_256_128, div_mod_256, div_256}; -use crate::lib::u256::convert::split_u256_into_u64; -use crate::lib::asserts::{assert_eq_128, assert_eq_256}; -use crate::helper::if_test_this_function; - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u256 = witness::FIRST_ARG; - let b: u256 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - let second_expected: u256 = witness::SECOND_EXPECTED; - - /// Arithmetic - - match if_test_this_function(0, fn_idx) { - true => { - let (_, _, _, b): (u64, u64, u64, u64) = split_u256_into_u64(b); - let (_, _, _, expected_r): (u64, u64, u64, u64) = split_u256_into_u64(second_expected); - - let (q, r): (u256, u64) = div_mod_256_64(a, b); - - assert_eq_256(q, unwrap(expected)); - assert!(jet::eq_64(r, expected_r)); - }, - false => (), - }; - - match if_test_this_function(1, fn_idx) { - true => { - let (_, b): (u128, u128) = ::into(b); - let (_, expected_r): (u128, u128) = ::into(second_expected); - - let (q, r): (u256, u128) = div_mod_256_128(a, b); - - assert_eq_256(q, unwrap(expected)); - assert_eq_128(r, expected_r); - }, - false => (), - }; - - match if_test_this_function(2, fn_idx) { - true => { - let (q, r): (u256, u256) = div_mod_256(a, b); - - assert_eq_256(q, unwrap(expected)); - assert_eq_256(r, second_expected); - }, - false => (), - }; - - match if_test_this_function(3, fn_idx) { true => { assert_eq_256(div_256(a, b), unwrap(expected)); }, false => (), }; -} diff --git a/simf/u32_math_test.simf b/simf/u32_math_test.simf deleted file mode 100644 index 0d8274e..0000000 --- a/simf/u32_math_test.simf +++ /dev/null @@ -1,51 +0,0 @@ -use crate::lib::u32::math::{checked_add_32, safe_add_32, checked_sub_32, safe_sub_32, checked_mul_32, safe_mul_32, checked_div_32, safe_div_32, gt_32, ge_32}; -use crate::lib::asserts::{assert_none_32, assert_eq_32}; -use crate::lib::binary::not; -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_32(result), - Some(e: u32) => assert_eq_32(unwrap(result), e), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u32) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u32 = witness::FIRST_ARG; - let b: u32 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - // add - match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_32(a, b), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_32(safe_add_32(a, b), unwrap(expected))); }, false => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_32(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_32(safe_sub_32(a, b), unwrap(expected))); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_32(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_32(safe_mul_32(a, b), unwrap(expected))); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_32(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_32(safe_div_32(a, b), unwrap(expected))); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_32(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_32(a, b), expected); }, false => (), }; -} diff --git a/simf/u64_math_test.simf b/simf/u64_math_test.simf deleted file mode 100644 index 0866a57..0000000 --- a/simf/u64_math_test.simf +++ /dev/null @@ -1,62 +0,0 @@ -use crate::lib::u64::math::{ - checked_add_64, - safe_add_64, - checked_sub_64, - safe_sub_64, - checked_mul_64, - safe_mul_64, - checked_div_64, - safe_div_64, - gt_64, - ge_64 -}; -use crate::lib::asserts::{assert_none_64, assert_eq_64}; -use crate::lib::binary::not; -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 { - Some(e: u64) => assert_eq_64(unwrap(result), e), - None => assert_none_64(result), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u64) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u64 = witness::FIRST_ARG; - 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 => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_64(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_64(safe_sub_64(a, b), unwrap(expected))); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_64(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_64(safe_mul_64(a, b), unwrap(expected))); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_64(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_64(safe_div_64(a, b), unwrap(expected))); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_64(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_64(a, b), expected); }, false => (), }; -} diff --git a/simf/u8_math_test.simf b/simf/u8_math_test.simf deleted file mode 100644 index d8c4f44..0000000 --- a/simf/u8_math_test.simf +++ /dev/null @@ -1,62 +0,0 @@ -use crate::lib::u8::math::{ - checked_add_8, - safe_add_8, - checked_sub_8, - safe_sub_8, - checked_mul_8, - safe_mul_8, - checked_div_8, - safe_div_8, - gt_8, - ge_8 -}; -use crate::lib::asserts::{assert_none_8, assert_eq_8}; -use crate::lib::binary::not; -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 { - Some(e: u8) => assert_eq_8(unwrap(result), e), - None => assert_none_8(result), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u8) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u8 = witness::FIRST_ARG; - let b: u8 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - // add - match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_8(a, b), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_8(safe_add_8(a, b), unwrap(expected))); }, false => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_8(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_8(safe_sub_8(a, b), unwrap(expected))); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_8(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_8(safe_mul_8(a, b), unwrap(expected))); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_8(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_8(safe_div_8(a, b), unwrap(expected))); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_8(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_8(a, b), expected); }, false => (), }; -} diff --git a/tests/asserts_test.rs b/tests/asserts_test.rs deleted file mode 100644 index 94fcee0..0000000 --- a/tests/asserts_test.rs +++ /dev/null @@ -1,499 +0,0 @@ -mod common; - -use rand::Rng; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::asserts_test::AssertsTestProgram; -use simplicityhl_std::artifacts::asserts_test::derived_asserts_test::{ - AssertsTestArguments, AssertsTestWitness, -}; - -// Dispatch indices — must match the `if_test_this_function(N, ..)` arms in -// simf/asserts_test.simf. -enum FunctionToTest { - AssertEq1, - AssertEq8, - AssertEq16, - AssertEq32, - AssertEq64, - AssertEq128, - AssertEq256, - AssertEqBool, - - AssertNone1, - AssertNone8, - AssertNone16, - AssertNone32, - AssertNone64, - AssertNone128, - AssertNone256, -} - -const DEFAULT_SOME_U8: Option = Some(0); -const DEFAULT_SOME_U16: Option = Some(0); -const DEFAULT_SOME_U32: Option = Some(0); -const DEFAULT_SOME_U64: Option = Some(0); -const DEFAULT_SOME_U128: Option = Some(0); -const DEFAULT_SOME_U256: Option<[u8; 32]> = Some([0; 32]); - -fn program() -> AssertsTestProgram { - AssertsTestProgram::new(&AssertsTestArguments {}) -} - -/// Returns two values in `[min, max]` that are equal when `same`, distinct otherwise. -pub fn generate_uints_in_one_range(same: bool, min_val: u128, max_val: u128) -> (u128, u128) { - let some_u = rand::thread_rng().gen_range(min_val..=max_val); - - if same { - return (some_u, some_u); - } - - assert!( - min_val != max_val, - "cannot generate distinct values in a single-value range" - ); - - let mut other_u = rand::thread_rng().gen_range(min_val..=max_val); - - while other_u == some_u { - other_u = rand::thread_rng().gen_range(min_val..=max_val); - } - - (some_u, other_u) -} - -/// Builds the witness for one assert call. `same` controls the two `assert_eq` -/// args; `none` makes the single `assert_none` arg `None`. -fn build_witness(function: FunctionToTest, same: bool, none: bool) -> AssertsTestWitness { - let mut witness = AssertsTestWitness { - function_index: 0, - first_arg_u1: DEFAULT_SOME_U8, // u1 in Simplicity is represented as u8 - second_arg_u1: DEFAULT_SOME_U8, - first_arg_u8: DEFAULT_SOME_U8, - second_arg_u8: DEFAULT_SOME_U8, - first_arg_u16: DEFAULT_SOME_U16, - second_arg_u16: DEFAULT_SOME_U16, - first_arg_u32: DEFAULT_SOME_U32, - second_arg_u32: DEFAULT_SOME_U32, - first_arg_u64: DEFAULT_SOME_U64, - second_arg_u64: DEFAULT_SOME_U64, - first_arg_u128: DEFAULT_SOME_U128, - second_arg_u128: DEFAULT_SOME_U128, - first_arg_u256: DEFAULT_SOME_U256, - second_arg_u256: DEFAULT_SOME_U256, - }; - - match function { - FunctionToTest::AssertEq1 => { - let (a, b) = generate_uints_in_one_range(same, 0, 1u128); - (witness.first_arg_u1, witness.second_arg_u1) = (Some(a as u8), Some(b as u8)); - } - FunctionToTest::AssertEq8 => { - let (a, b) = generate_uints_in_one_range(same, 0, u8::MAX as u128); - (witness.first_arg_u8, witness.second_arg_u8) = (Some(a as u8), Some(b as u8)); - } - FunctionToTest::AssertEq16 => { - let (a, b) = generate_uints_in_one_range(same, 0, u16::MAX as u128); - (witness.first_arg_u16, witness.second_arg_u16) = (Some(a as u16), Some(b as u16)); - } - FunctionToTest::AssertEq32 => { - let (a, b) = generate_uints_in_one_range(same, 0, u32::MAX as u128); - (witness.first_arg_u32, witness.second_arg_u32) = (Some(a as u32), Some(b as u32)); - } - FunctionToTest::AssertEq64 => { - 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) = - (Some([a as u8; 32]), Some([b as u8; 32])); - } - FunctionToTest::AssertEqBool => { - let (a, b) = generate_uints_in_one_range(same, 0, 1u128); - (witness.first_arg_u1, witness.second_arg_u1) = (Some(a as u8), Some(b as u8)); - } - FunctionToTest::AssertNone1 => { - if none { - witness.first_arg_u1 = None; - } - } - FunctionToTest::AssertNone8 => { - if none { - witness.first_arg_u8 = None; - } - } - FunctionToTest::AssertNone16 => { - if none { - witness.first_arg_u16 = None; - } - } - FunctionToTest::AssertNone32 => { - if none { - witness.first_arg_u32 = None; - } - } - FunctionToTest::AssertNone64 => { - if none { - witness.first_arg_u64 = None; - } - } - FunctionToTest::AssertNone128 => { - if none { - witness.first_arg_u128 = None; - } - } - FunctionToTest::AssertNone256 => { - if none { - witness.first_arg_u256 = None; - } - } - } - - witness.function_index = function as u8; - witness -} - -fn run_assert( - context: &simplex::TestContext, - function: FunctionToTest, - same: bool, - none: bool, - expect: Expect, -) -> anyhow::Result<()> { - run( - context, - program(), - build_witness(function, same, none), - expect, - ) -} - -mod asserts_test { - use super::*; - - // ---------- assert_eq: happy = equal args, unhappy = distinct args ---------- - #[simplex::test] - fn assert_eq_1_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert(&context, FunctionToTest::AssertEq1, true, false, Expect::Ok) - } - - #[simplex::test] - fn assert_eq_1_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq1, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_8_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert(&context, FunctionToTest::AssertEq8, true, false, Expect::Ok) - } - - #[simplex::test] - fn assert_eq_8_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq8, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_16_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq16, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_16_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq16, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_32_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq32, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_32_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq32, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_64_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq64, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_64_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq64, - false, - false, - Expect::AssertFailed, - ) - } - - #[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( - &context, - FunctionToTest::AssertEq256, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_256_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq256, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_bool_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEqBool, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_bool_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEqBool, - false, - false, - Expect::AssertFailed, - ) - } - - // ---------- assert_none: happy = None arg, unhappy = Some arg ---------- - #[simplex::test] - fn assert_none_1_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone1, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_1_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone1, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_8_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone8, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_8_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone8, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_16_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone16, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_16_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone16, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_32_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone32, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_32_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone32, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_64_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone64, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_64_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone64, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_128_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone128, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_128_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone128, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_256_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone256, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_256_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone256, - false, - false, - Expect::AssertFailed, - ) - } -} diff --git a/tests/binary_test.rs b/tests/binary_test.rs deleted file mode 100644 index 2da001e..0000000 --- a/tests/binary_test.rs +++ /dev/null @@ -1,18 +0,0 @@ -mod common; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::binary_test::BinaryTestProgram; -use simplicityhl_std::artifacts::binary_test::derived_binary_test::{ - BinaryTestArguments, BinaryTestWitness, -}; - -mod binary_tests { - use super::*; - - #[simplex::test] - fn binary_test(context: simplex::TestContext) -> anyhow::Result<()> { - let program = BinaryTestProgram::new(&BinaryTestArguments {}); - run(&context, program, BinaryTestWitness {}, Expect::Ok) - } -} diff --git a/tests/common/core.rs b/tests/common/core.rs deleted file mode 100644 index ada5e42..0000000 --- a/tests/common/core.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Each `tests/*.rs` is a separate crate that mounts this module but uses only -// part of it, so per-crate dead-code analysis would warn about the rest. -#![allow(dead_code)] - -use simplex::program::{Program, WitnessTrait}; -use simplex::simplicityhl::elements::Script; -use simplex::transaction::{ - FinalTransaction, PartialInput, PartialOutput, ProgramInput, RequiredSignature, -}; - -#[derive(Clone, Copy)] -pub enum Expect { - /// The spend succeeds. - Ok, - /// A failed `assert!` in the contract. - AssertFailed, - /// Execution reached a pruned branch (e.g. `unwrap(None)`, a `safe_*` overflow). - PrunedBranch, -} - -impl Expect { - /// The exact broadcast error message for a failing expectation (`None` for `Ok`). - fn error_message(self) -> Option<&'static str> { - match self { - Expect::Ok => None, - Expect::AssertFailed => Some("Failed to prune program: Jet failed during execution"), - Expect::PrunedBranch => { - Some("Failed to prune program: Execution reached a pruned branch") - } - } - } -} - -/// Send sats to the program's script so it has a UTXO to spend. -pub fn fund( - context: &simplex::TestContext, - program: &impl AsRef, -) -> anyhow::Result