diff --git a/Cargo.lock b/Cargo.lock index 947026a587..f5274e0506 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,20 +4,17 @@ version = 4 [[package]] name = "acir" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acir_field", "base64 0.22.1", - "bincode 2.0.1", "brillig", - "color-eyre", "flate2", - "noir_protobuf", + "noirc_span", + "num-bigint", + "num-traits", "num_enum", - "prost", - "prost-build", - "protoc-prebuilt", "rmp-serde", "serde", "serde-big-array", @@ -28,8 +25,8 @@ dependencies = [ [[package]] name = "acir_field" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "ark-bn254", "ark-ff 0.5.0", @@ -42,14 +39,14 @@ dependencies = [ [[package]] name = "acvm" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acir", "acvm_blackbox_solver", "brillig_vm", - "fxhash", "indexmap 2.13.0", + "rustc-hash", "serde", "thiserror 1.0.69", "tracing", @@ -57,31 +54,22 @@ dependencies = [ [[package]] name = "acvm_blackbox_solver" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acir", + "aes 0.8.4", "blake2", "blake3", - "k256", - "keccak", - "libaes", + "cbc", + "k256 0.14.0-rc.9", + "keccak 0.2.0-rc.0", "log", - "num-bigint", - "p256", - "sha2", + "p256 0.14.0-rc.9", + "sha2 0.11.0", "thiserror 1.0.69", ] -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -105,7 +93,7 @@ checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", "cipher 0.3.0", - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", ] @@ -117,7 +105,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher 0.4.4", - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] @@ -128,7 +116,7 @@ checksum = "04097e08a47d9ad181c2e1f4a5fabc9ae06ce8839a333ba9a949bcb0d31fd2a3" dependencies = [ "cipher 0.5.1", "cpubits", - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] @@ -189,7 +177,7 @@ dependencies = [ "c-kzg", "derive_more", "either", - "k256", + "k256 0.13.4", "once_cell", "rand 0.8.5", "secp256k1", @@ -283,7 +271,7 @@ dependencies = [ "either", "serde", "serde_with", - "sha2", + "sha2 0.10.9", "thiserror 2.0.18", ] @@ -368,7 +356,7 @@ dependencies = [ "hashbrown 0.16.1", "indexmap 2.13.0", "itoa", - "k256", + "k256 0.13.4", "keccak-asm", "paste", "proptest", @@ -455,8 +443,8 @@ dependencies = [ "async-trait", "auto_impl", "either", - "elliptic-curve", - "k256", + "elliptic-curve 0.13.8", + "k256 0.13.4", "thiserror 2.0.18", ] @@ -471,7 +459,7 @@ dependencies = [ "alloy-primitives", "alloy-signer", "async-trait", - "k256", + "k256 0.13.4", "rand 0.8.5", "thiserror 2.0.18", ] @@ -1354,18 +1342,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" [[package]] -name = "backtrace" -version = "0.3.76" +name = "barretenberg-rs" +version = "4.2.0-aztecnr-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +checksum = "c244bbd116be1c35671e9285671c34b90a2af64e895c60cc622109f5f7545b30" dependencies = [ - "addr2line", - "cfg-if", + "hex", "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", + "rmp", + "rmp-serde", + "rmpv", + "serde", + "thiserror 1.0.69", ] [[package]] @@ -1374,6 +1362,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base16ct" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" + [[package]] name = "base64" version = "0.21.7" @@ -1402,19 +1396,6 @@ version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" -[[package]] -name = "bb" -version = "1.0.0-nightly.20250723" -source = "git+https://github.com/zkmopro/noir-rs?tag=v1.0.0-beta.8#234fefbd95fbb9a7cffd57c7c19cf63e4cf1d732" -dependencies = [ - "cc", - "chkstk_stub", - "num-bigint", - "thiserror 1.0.69", - "tracing", - "tracing-subscriber", -] - [[package]] name = "bcs" version = "0.1.6" @@ -1449,26 +1430,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bincode" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" -dependencies = [ - "bincode_derive", - "serde", - "unty", -] - -[[package]] -name = "bincode_derive" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" -dependencies = [ - "virtue", -] - [[package]] name = "bindgen" version = "0.71.1" @@ -1550,11 +1511,11 @@ dependencies = [ [[package]] name = "blake2" -version = "0.10.6" +version = "0.11.0-rc.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +checksum = "061f1a09225e328e1ffbb378d2d49923c0ca5fee19fb5ac1cc9c1e9d52b93690" dependencies = [ - "digest 0.10.7", + "digest 0.11.2", ] [[package]] @@ -1568,7 +1529,7 @@ dependencies = [ "cc", "cfg-if", "constant_time_eq", - "cpufeatures", + "cpufeatures 0.2.17", "rayon-core", "serde", ] @@ -1582,6 +1543,24 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + [[package]] name = "blocking" version = "1.6.2" @@ -1609,8 +1588,8 @@ dependencies = [ [[package]] name = "bn254_blackbox_solver" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acir", "acvm_blackbox_solver", @@ -1619,8 +1598,6 @@ dependencies = [ "ark-ff 0.5.0", "ark-grumpkin", "hex", - "lazy_static", - "num-bigint", ] [[package]] @@ -1673,8 +1650,8 @@ dependencies = [ [[package]] name = "brillig" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acir_field", "serde", @@ -1682,8 +1659,8 @@ dependencies = [ [[package]] name = "brillig_vm" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acir", "acvm_blackbox_solver", @@ -1796,6 +1773,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "cc" version = "1.2.56" @@ -1841,15 +1827,6 @@ dependencies = [ "serde_with", ] -[[package]] -name = "chkstk_stub" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "047f6ab2f3b9bcaf23b593d1580898e4244d27eadf1a1fae99212ee5735d3d1c" -dependencies = [ - "cc", -] - [[package]] name = "chromiumoxide" version = "0.7.0" @@ -2045,9 +2022,15 @@ source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a83 dependencies = [ "bytemuck", "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", ] +[[package]] +name = "cmov" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" + [[package]] name = "codespan" version = "0.11.1" @@ -2069,33 +2052,6 @@ dependencies = [ "unicode-width 0.1.14", ] -[[package]] -name = "color-eyre" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - [[package]] name = "colorchoice" version = "1.0.4" @@ -2141,7 +2097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "531185e432bb31db1ecda541e9e7ab21468d4d844ad7505e0546a49b4945d49b" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "proptest", "serde_core", ] @@ -2152,6 +2108,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "const_format" version = "0.2.35" @@ -2234,6 +2196,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -2348,6 +2319,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a0d26b245348befa0c121944541476763dcc46ede886c88f9d12e1697d27c3" +dependencies = [ + "cpubits", + "ctutils", + "getrandom 0.4.2", + "hybrid-array", + "num-traits", + "rand_core 0.10.1", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.7" @@ -2364,7 +2351,9 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" dependencies = [ + "getrandom 0.4.2", "hybrid-array", + "rand_core 0.10.1", ] [[package]] @@ -2406,6 +2395,16 @@ dependencies = [ "cipher 0.4.4", ] +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", + "subtle", +] + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -2413,7 +2412,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", "fiat-crypto", "rand_core 0.6.4", @@ -2598,7 +2597,7 @@ checksum = "7902cd1dde9e8ffc953428933f37f9b943dc123265709220cded6277946cadf7" dependencies = [ "anyhow", "az", - "bincode 1.3.3", + "bincode", "bit-set", "bit-vec", "bytes", @@ -2706,8 +2705,19 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", - "pem-rfc7468", + "const-oid 0.9.6", + "pem-rfc7468 0.7.0", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "const-oid 0.10.2", + "pem-rfc7468 1.0.0", "zeroize", ] @@ -2869,12 +2879,24 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", + "block-buffer 0.10.4", + "const-oid 0.9.6", "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", + "const-oid 0.10.2", + "crypto-common 0.2.1", + "ctutils", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -2916,13 +2938,28 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der", + "der 0.7.10", "digest 0.10.7", - "elliptic-curve", - "rfc6979", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", "serdect", - "signature", - "spki", + "signature 2.2.0", + "spki 0.7.3", +] + +[[package]] +name = "ecdsa" +version = "0.17.0-rc.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4bf51f0534ed6e59a0f2f26272b64ba55c470133f8424c2adfd1c4d59d9988" +dependencies = [ + "der 0.8.0", + "digest 0.11.2", + "elliptic-curve 0.14.0-rc.31", + "rfc6979 0.5.0-rc.5", + "signature 3.0.0-rc.10", + "spki 0.8.0", + "zeroize", ] [[package]] @@ -2952,22 +2989,44 @@ version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "base16ct", - "crypto-bigint", + "base16ct 0.2.0", + "crypto-bigint 0.5.5", "digest 0.10.7", "ff", "generic-array", "group", "hkdf", - "pem-rfc7468", - "pkcs8", + "pem-rfc7468 0.7.0", + "pkcs8 0.10.2", "rand_core 0.6.4", - "sec1", + "sec1 0.7.3", "serdect", "subtle", "zeroize", ] +[[package]] +name = "elliptic-curve" +version = "0.14.0-rc.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b148a81cede8f4023248f980cffdf7611c46f2add469c6980e815b7c5b764ba5" +dependencies = [ + "base16ct 1.0.0", + "crypto-bigint 0.7.3", + "crypto-common 0.2.1", + "digest 0.11.2", + "hybrid-array", + "once_cell", + "pem-rfc7468 1.0.0", + "pkcs8 0.11.0-rc.11", + "rand_core 0.10.1", + "rustcrypto-ff", + "rustcrypto-group", + "sec1 0.8.1", + "subtle", + "zeroize", +] + [[package]] name = "encode_unicode" version = "1.0.0" @@ -3062,16 +3121,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - [[package]] name = "fastrand" version = "2.3.0" @@ -3152,8 +3201,8 @@ dependencies = [ [[package]] name = "fm" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "codespan-reporting", "iter-extended", @@ -3335,15 +3384,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -3391,6 +3431,7 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] @@ -3415,12 +3456,6 @@ dependencies = [ "polyval 0.6.2", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "glob" version = "0.3.3" @@ -3603,7 +3638,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", ] [[package]] @@ -3615,6 +3650,15 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.2", +] + [[package]] name = "home" version = "0.5.12" @@ -3699,7 +3743,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1" dependencies = [ "serde", + "subtle", "typenum", + "zeroize", ] [[package]] @@ -3739,7 +3785,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.6", + "webpki-roots", ] [[package]] @@ -3947,12 +3993,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "indenter" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" - [[package]] name = "indexmap" version = "1.9.3" @@ -3995,6 +4035,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ + "block-padding", "generic-array", ] @@ -4063,8 +4104,8 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "iter-extended" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" [[package]] name = "itertools" @@ -4171,12 +4212,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", - "ecdsa", - "elliptic-curve", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", "once_cell", "serdect", - "sha2", - "signature", + "sha2 0.10.9", + "signature 2.2.0", +] + +[[package]] +name = "k256" +version = "0.14.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b382cbfd43caf55991a93850ce538aa1aa67bb264af367d22dfe7937c4e997d" +dependencies = [ + "cpubits", + "ecdsa 0.17.0-rc.17", + "elliptic-curve 0.14.0-rc.31", + "sha2 0.11.0", + "signature 3.0.0-rc.10", ] [[package]] @@ -4185,7 +4239,16 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", +] + +[[package]] +name = "keccak" +version = "0.2.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d546793a04a1d3049bd192856f804cfe96356e2cf36b54b4e575155babe9f41" +dependencies = [ + "cpufeatures 0.2.17", ] [[package]] @@ -4219,12 +4282,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" -[[package]] -name = "libaes" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82903360c009b816f5ab72a9b68158c27c301ee2c3f20655b55c5e589e7d3bb7" - [[package]] name = "libc" version = "0.2.183" @@ -4392,7 +4449,7 @@ name = "mpz-circuits-core" version = "0.1.0-alpha.5" source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5" dependencies = [ - "bincode 1.3.3", + "bincode", "itybity 0.3.1", "once_cell", "rand 0.9.2", @@ -4407,7 +4464,7 @@ name = "mpz-circuits-data" version = "0.1.0-alpha.5" source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5" dependencies = [ - "bincode 1.3.3", + "bincode", "mpz-circuits-core", "once_cell", ] @@ -4773,23 +4830,19 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "multimap" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" - [[package]] name = "nargo" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acvm", + "brillig", "fm", "iter-extended", "jsonrpsee", "noir_greybox_fuzzer", "noirc_abi", + "noirc_artifacts", "noirc_driver", "noirc_errors", "noirc_frontend", @@ -4811,22 +4864,20 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "noir" -version = "1.0.0-beta.8-3" -source = "git+https://github.com/zkmopro/noir-rs?tag=v1.0.0-beta.8#234fefbd95fbb9a7cffd57c7c19cf63e4cf1d732" +version = "1.0.0-beta.19" +source = "git+https://github.com/zkmopro/noir-rs?tag=v1.0.0-beta.19#0e4fdc9fc0cb383fcada7d3864dd2424f137316b" dependencies = [ - "acir", "acvm", "acvm_blackbox_solver", + "barretenberg-rs", "base64 0.22.1", - "base64ct", - "bb", - "bincode 1.3.3", + "bincode", "bn254_blackbox_solver", "clap", "flate2", "hex", + "keccak 0.2.0-rc.0", "nargo", - "proptest", "reqwest", "serde", "serde_json", @@ -4837,8 +4888,8 @@ dependencies = [ [[package]] name = "noir_greybox_fuzzer" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acvm", "build-data", @@ -4847,27 +4898,18 @@ dependencies = [ "noirc_artifacts", "num-traits", "proptest", - "rand 0.8.5", - "rand_xorshift", + "rand 0.9.2", + "rand_xorshift 0.4.0", "rayon", "sha256", "termcolor", "walkdir", ] -[[package]] -name = "noir_protobuf" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" -dependencies = [ - "color-eyre", - "prost", -] - [[package]] name = "noirc_abi" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acvm", "iter-extended", @@ -4882,83 +4924,85 @@ dependencies = [ [[package]] name = "noirc_arena" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" [[package]] name = "noirc_artifacts" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ + "acir", "acvm", + "base64 0.22.1", "codespan-reporting", + "flate2", "fm", "noirc_abi", - "noirc_driver", "noirc_errors", "noirc_printable_type", "serde", + "serde_json", + "thiserror 1.0.69", + "tracing", ] [[package]] name = "noirc_driver" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acvm", "build-data", "clap", "fm", - "fxhash", "iter-extended", "noirc_abi", + "noirc_artifacts", "noirc_errors", "noirc_evaluator", "noirc_frontend", "rust-embed", - "serde", + "rustc-hash", "tracing", ] [[package]] name = "noirc_errors" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ - "acvm", - "base64 0.22.1", - "codespan", "codespan-reporting", - "flate2", "fm", - "fxhash", - "noirc_printable_type", + "noirc_span", + "rustc-hash", "serde", - "serde_json", - "tracing", ] [[package]] name = "noirc_evaluator" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acvm", "bn254_blackbox_solver", "cfg-if", "chrono", "fm", - "fxhash", "im", + "indexmap 2.13.0", "iter-extended", + "noirc_artifacts", "noirc_errors", "noirc_frontend", "noirc_printable_type", "num-bigint", "num-integer", "num-traits", - "petgraph 0.8.3", + "petgraph", "rayon", + "rustc-hash", + "rustc-stable-hash", "serde", "serde_json", "serde_with", @@ -4970,22 +5014,22 @@ dependencies = [ [[package]] name = "noirc_frontend" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acvm", "bn254_blackbox_solver", "cfg-if", "fm", - "fxhash", "im", "iter-extended", "noirc_arena", + "noirc_artifacts", "noirc_errors", "noirc_printable_type", "num-bigint", "num-traits", - "petgraph 0.8.3", + "petgraph", "rangemap", "rustc-hash", "serde", @@ -5000,8 +5044,8 @@ dependencies = [ [[package]] name = "noirc_printable_type" -version = "1.0.0-beta.8" -source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" dependencies = [ "acvm", "iter-extended", @@ -5009,6 +5053,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "noirc_span" +version = "1.0.0-beta.19" +source = "git+https://github.com/noir-lang/noir.git?rev=v1.0.0-beta.19#74d6be658e1ad252f87943292ba09bdd4da80bd4" +dependencies = [ + "codespan", + "serde", +] + [[package]] name = "nom" version = "7.1.3" @@ -5131,15 +5184,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -5180,23 +5224,30 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" -[[package]] -name = "owo-colors" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" - [[package]] name = "p256" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", "serdect", - "sha2", + "sha2 0.10.9", +] + +[[package]] +name = "p256" +version = "0.14.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b97e3bf0465157ae90975ff52dbeb1362ba618924878c9f74c25baa27a65f9a" +dependencies = [ + "ecdsa 0.17.0-rc.17", + "elliptic-curve 0.14.0-rc.31", + "primefield", + "primeorder 0.14.0-rc.9", + "sha2 0.11.0", ] [[package]] @@ -5271,6 +5322,15 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pem-rfc7468" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -5317,17 +5377,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" dependencies = [ "pest", - "sha2", -] - -[[package]] -name = "petgraph" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" -dependencies = [ - "fixedbitset", - "indexmap 2.13.0", + "sha2 0.10.9", ] [[package]] @@ -5401,8 +5451,18 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", - "spki", + "der 0.7.10", + "spki 0.7.3", +] + +[[package]] +name = "pkcs8" +version = "0.11.0-rc.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12922b6296c06eb741b02d7b5161e3aaa22864af38dfa025a1a3ba3f68c84577" +dependencies = [ + "der 0.8.0", + "spki 0.8.0", ] [[package]] @@ -5460,7 +5520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", "universal-hash 0.4.0", ] @@ -5472,7 +5532,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", "universal-hash 0.5.1", ] @@ -5527,16 +5587,39 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "primefield" +version = "0.14.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b52e6ee42db392378a95622b463c9740631171d1efce43fa445a569c1600cb6" +dependencies = [ + "crypto-bigint 0.7.3", + "crypto-common 0.2.1", + "rand_core 0.10.1", + "rustcrypto-ff", + "subtle", + "zeroize", +] + [[package]] name = "primeorder" version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "elliptic-curve", + "elliptic-curve 0.13.8", "serdect", ] +[[package]] +name = "primeorder" +version = "0.14.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0556580e42c19833f5d232aca11a7687a503ee41f937b54f5ae1d50fc2a6a36a" +dependencies = [ + "elliptic-curve 0.14.0-rc.31", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -5624,75 +5707,13 @@ dependencies = [ "num-traits", "rand 0.8.5", "rand_chacha 0.3.1", - "rand_xorshift", + "rand_xorshift 0.3.0", "regex-syntax", "rusty-fork", "tempfile", "unarray", ] -[[package]] -name = "prost" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" -dependencies = [ - "heck 0.5.0", - "itertools 0.14.0", - "log", - "multimap", - "once_cell", - "petgraph 0.7.1", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.117", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "prost-types" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" -dependencies = [ - "prost", -] - -[[package]] -name = "protoc-prebuilt" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d85d4641fe3b8c6e853dfd09fe35379bc6b6e66bd692ac29ed4f7087de69ed5" -dependencies = [ - "ureq", - "zip", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -5853,6 +5874,12 @@ dependencies = [ "serde", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "rand_xorshift" version = "0.3.0" @@ -5862,6 +5889,15 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + [[package]] name = "rand_xoshiro" version = "0.6.0" @@ -6010,7 +6046,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.6", + "webpki-roots", ] [[package]] @@ -6028,7 +6064,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac", + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "rfc6979" +version = "0.5.0-rc.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a3127ee32baec36af75b4107082d9bd823501ec14a4e016be4b6b37faa74ae" +dependencies = [ + "hmac 0.13.0", "subtle", ] @@ -6090,13 +6136,22 @@ dependencies = [ "serde", ] +[[package]] +name = "rmpv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a4e1d4b9b938a26d2996af33229f0ca0956c652c1375067f0b45291c1df8417" +dependencies = [ + "rmp", +] + [[package]] name = "rs_merkle" version = "1.4.2" source = "git+https://github.com/tlsnotary/rs-merkle.git?rev=85f3e82#85f3e827451e18c21f110068b4322fb99d2f0a8c" dependencies = [ "serde", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -6189,7 +6244,7 @@ version = "8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" dependencies = [ - "sha2", + "sha2 0.10.9", "walkdir", ] @@ -6209,12 +6264,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "rustc-demangle" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -6227,6 +6276,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustc-stable-hash" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "781442f29170c5c93b7185ad559492601acdc71d5bb0706f5868094f45cfcd08" + [[package]] name = "rustc_version" version = "0.3.3" @@ -6245,6 +6300,27 @@ dependencies = [ "semver 1.0.27", ] +[[package]] +name = "rustcrypto-ff" +version = "0.14.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd2a8adb347447693cd2ba0d218c4b66c62da9b0a5672b17b981e4291ec65ff6" +dependencies = [ + "rand_core 0.10.1", + "subtle", +] + +[[package]] +name = "rustcrypto-group" +version = "0.14.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "369f9b61aa45933c062c9f6b5c3c50ab710687eca83dd3802653b140b43f85ed" +dependencies = [ + "rand_core 0.10.1", + "rustcrypto-ff", + "subtle", +] + [[package]] name = "rustix" version = "0.38.44" @@ -6302,7 +6378,6 @@ version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ - "log", "once_cell", "ring 0.17.14", "rustls-pki-types", @@ -6478,15 +6553,29 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "base16ct", - "der", + "base16ct 0.2.0", + "der 0.7.10", "generic-array", - "pkcs8", + "pkcs8 0.10.2", "serdect", "subtle", "zeroize", ] +[[package]] +name = "sec1" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d" +dependencies = [ + "base16ct 1.0.0", + "ctutils", + "der 0.8.0", + "hybrid-array", + "subtle", + "zeroize", +] + [[package]] name = "secp256k1" version = "0.30.0" @@ -6709,7 +6798,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" dependencies = [ - "base16ct", + "base16ct 0.2.0", "serde", ] @@ -6719,7 +6808,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96005f01d74e0866a7c27bc47e6051e286339df96c5ab10dd0ee833043a0fbd5" dependencies = [ - "bincode 1.3.3", + "bincode", "bytes", "futures-channel", "futures-core", @@ -6738,7 +6827,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -6749,10 +6838,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.2", +] + [[package]] name = "sha256" version = "1.6.0" @@ -6762,7 +6862,7 @@ dependencies = [ "async-trait", "bytes", "hex", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -6772,7 +6872,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest 0.10.7", - "keccak", + "keccak 0.1.6", ] [[package]] @@ -6858,6 +6958,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "3.0.0-rc.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f1880df446116126965eeec169136b2e0251dba37c6223bcc819569550edea3" +dependencies = [ + "digest 0.11.2", + "rand_core 0.10.1", +] + [[package]] name = "simd-adler32" version = "0.3.8" @@ -6968,7 +7078,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.10", +] + +[[package]] +name = "spki" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" +dependencies = [ + "base64ct", + "der 0.8.0", ] [[package]] @@ -7368,7 +7488,7 @@ dependencies = [ "tracing", "tracing-subscriber", "web-spawn", - "webpki-roots 1.0.6", + "webpki-roots", ] [[package]] @@ -7380,9 +7500,9 @@ dependencies = [ "alloy-signer-local", "bcs", "blake3", - "k256", + "k256 0.13.4", "opaque-debug", - "p256", + "p256 0.13.2", "rand 0.9.2", "rand06-compat", "rangeset", @@ -7419,7 +7539,7 @@ dependencies = [ "aead", "aes-gcm", "bimap", - "bincode 1.3.3", + "bincode", "blake3", "generic-array", "hex", @@ -7434,7 +7554,7 @@ dependencies = [ "rustls-pki-types", "rustls-webpki 0.103.9", "serde", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "tiny-keccak", "tlsn-attestation", @@ -7443,7 +7563,7 @@ dependencies = [ "tlsn-tls-core", "web-time 0.2.4", "webpki-root-certs", - "webpki-roots 1.0.6", + "webpki-roots", "zeroize", ] @@ -7474,7 +7594,7 @@ name = "tlsn-examples" version = "0.0.0" dependencies = [ "anyhow", - "bincode 1.3.3", + "bincode", "chrono", "clap", "futures", @@ -7482,7 +7602,7 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "k256", + "k256 0.13.4", "noir", "serde", "serde_json", @@ -7606,7 +7726,7 @@ dependencies = [ "mpz-vm-core", "rand 0.9.2", "ring 0.17.14", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "tokio", "tracing", @@ -7628,7 +7748,7 @@ dependencies = [ "mpz-ot", "mpz-share-conversion", "mpz-vm-core", - "p256", + "p256 0.13.2", "rand 0.9.2", "rand06-compat", "rand_core 0.9.5", @@ -7663,7 +7783,7 @@ dependencies = [ "mpz-share-conversion", "mpz-vm-core", "opaque-debug", - "p256", + "p256 0.13.2", "pin-project-lite", "rand 0.9.2", "rand_chacha 0.9.0", @@ -7764,10 +7884,10 @@ dependencies = [ "digest 0.10.7", "env_logger", "futures", - "hmac", + "hmac 0.12.1", "log", "mpz-common", - "p256", + "p256 0.13.2", "rand 0.9.2", "rand06-compat", "ring 0.17.14", @@ -7776,13 +7896,13 @@ dependencies = [ "rustls-pki-types", "rustls-webpki 0.103.9", "sct", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "tlsn-core", "tlsn-tls-core", "tokio", "web-time 0.2.4", - "webpki-roots 1.0.6", + "webpki-roots", ] [[package]] @@ -7790,7 +7910,7 @@ name = "tlsn-tls-core" version = "0.1.0-alpha.15-pre" dependencies = [ "futures", - "hmac", + "hmac 0.12.1", "rand 0.9.2", "ring 0.17.14", "rustls-pemfile", @@ -7798,7 +7918,7 @@ dependencies = [ "rustls-webpki 0.103.9", "sct", "serde", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "tracing", "web-time 0.2.4", @@ -8097,16 +8217,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-error" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" -dependencies = [ - "tracing", - "tracing-subscriber", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -8289,27 +8399,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "unty" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" - -[[package]] -name = "ureq" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" -dependencies = [ - "base64 0.22.1", - "log", - "once_cell", - "rustls 0.23.37", - "rustls-pki-types", - "url", - "webpki-roots 0.26.11", -] - [[package]] name = "url" version = "2.5.8" @@ -8400,12 +8489,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "virtue" -version = "0.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" - [[package]] name = "vsimd" version = "0.8.0" @@ -8641,15 +8724,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.6", -] - [[package]] name = "webpki-roots" version = "1.0.6" @@ -9297,18 +9371,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "byteorder", - "crc32fast", - "crossbeam-utils", - "flate2", -] - [[package]] name = "zmij" version = "1.0.21" diff --git a/crates/examples/Cargo.toml b/crates/examples/Cargo.toml index ec1d4b5846..eda6d18c00 100644 --- a/crates/examples/Cargo.toml +++ b/crates/examples/Cargo.toml @@ -38,7 +38,7 @@ tokio = { workspace = true, features = [ tokio-util = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } -noir = { git = "https://github.com/zkmopro/noir-rs", tag = "v1.0.0-beta.8", features = [ +noir = { git = "https://github.com/zkmopro/noir-rs", tag = "v1.0.0-beta.19", features = [ "barretenberg", ] } diff --git a/crates/examples/basic_zk/README.md b/crates/examples/basic_zk/README.md index f9b44e6fb6..a0d37b07fd 100644 --- a/crates/examples/basic_zk/README.md +++ b/crates/examples/basic_zk/README.md @@ -124,11 +124,13 @@ basic_zk/ We use [Mopro's `noir_rs`](https://zkmopro.org/docs/crates/noir-rs/) for ZK proof generation. The **circuit is pre-compiled and ready to use**. You don't need to install Noir tools to run the example. But if you want to change or test the circuit in isolation, you can use the following instructions. -Before you proceed, we recommend to double check that your Noir tooling matches the versions used in Mopro's `noir_rs`: +Before you proceed, we recommend to double check that your Noir tooling matches the version used in Mopro's `noir_rs`: ```sh -# Install correct Noir and BB versions (important for compatibility!) -noirup --version 1.0.0-beta.8 -bbup -v 1.0.0-nightly.20250723 +# Install the matching Noir compiler version +noirup --version 1.0.0-beta.19 + +# Optional: install a compatible barretenberg CLI for manual proving/verifying. +bbup ``` If you don't have `noirup` and `bbup` installed yet, check [Noir's Quick Start](https://noir-lang.org/docs/getting_started/quick_start). diff --git a/crates/examples/basic_zk/noir/Nargo.toml b/crates/examples/basic_zk/noir/Nargo.toml index 0c237f5fcb..59a039ed8d 100644 --- a/crates/examples/basic_zk/noir/Nargo.toml +++ b/crates/examples/basic_zk/noir/Nargo.toml @@ -4,5 +4,5 @@ type = "bin" authors = [""] [dependencies] -sha256 = { tag = "v0.1.5", git = "https://github.com/noir-lang/sha256" } -date = { tag = "v0.5.4", git = "https://github.com/madztheo/noir-date.git" } +sha256 = { tag = "v0.3.0", git = "https://github.com/noir-lang/sha256" } +date = { tag = "v0.5.6", git = "https://github.com/madztheo/noir-date.git" } diff --git a/crates/examples/basic_zk/noir/src/main.nr b/crates/examples/basic_zk/noir/src/main.nr index 9549e73586..b5ad27bca9 100644 --- a/crates/examples/basic_zk/noir/src/main.nr +++ b/crates/examples/basic_zk/noir/src/main.nr @@ -1,4 +1,4 @@ -use dep::date::Date; +use date::Date; fn main( // Public inputs diff --git a/crates/examples/basic_zk/noir/target/noir.json b/crates/examples/basic_zk/noir/target/noir.json index 03217d89f2..3393b2e4ea 100644 --- a/crates/examples/basic_zk/noir/target/noir.json +++ b/crates/examples/basic_zk/noir/target/noir.json @@ -1 +1 @@ -{"noir_version":"1.0.0-beta.8+ba05d729b9753aa5ce2b076c1dd4795edb173f68","hash":"4238770051219268338","abi":{"parameters":[{"name":"proof_date","type":{"kind":"struct","path":"date::date::Date","fields":[{"name":"day","type":{"kind":"integer","sign":"unsigned","width":8}},{"name":"month","type":{"kind":"integer","sign":"unsigned","width":8}},{"name":"year","type":{"kind":"integer","sign":"unsigned","width":32}}]},"visibility":"public"},{"name":"committed_hash","type":{"kind":"array","length":32,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"public"},{"name":"date_of_birth","type":{"kind":"string","length":10},"visibility":"private"},{"name":"blinder","type":{"kind":"array","length":16,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"}],"return_type":null,"error_types":{"2920182694213909827":{"error_kind":"string","string":"attempt to subtract with overflow"},"5019202896831570965":{"error_kind":"string","string":"attempt to add with overflow"},"6668324276689745315":{"error_kind":"string","string":"Field failed to decompose into specified 4 limbs"},"7233212735005103307":{"error_kind":"string","string":"attempt to multiply with overflow"},"14225679739041873922":{"error_kind":"string","string":"Index out of bounds"},"14514982005979867414":{"error_kind":"string","string":"attempt to bit-shift with overflow"},"17843811134343075018":{"error_kind":"string","string":"Stack too deep"}}},"bytecode":"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","debug_symbols":"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","file_map":{"5":{"source":"use crate::meta::derive_via;\n\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { $crate::cmp::Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for u1 {\n fn eq(self, other: u1) -> bool {\n self == other\n }\n}\n\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\nimpl Eq for (A, B)\nwhere\n A: Eq,\n B: Eq,\n{\n fn eq(self, other: (A, B)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1)\n }\n}\n\nimpl Eq for (A, B, C)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n{\n fn eq(self, other: (A, B, C)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2)\n }\n}\n\nimpl Eq for (A, B, C, D)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n{\n fn eq(self, other: (A, B, C, D)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3)\n }\n}\n\nimpl Eq for (A, B, C, D, E)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n E: Eq,\n{\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n self.0.eq(other.0)\n & self.1.eq(other.1)\n & self.2.eq(other.2)\n & self.3.eq(other.3)\n & self.4.eq(other.4)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::cmp::Ord };\n let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == $crate::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = $crate::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let mut result = self.len().cmp(other.len());\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for (A, B)\nwhere\n A: Ord,\n B: Ord,\n{\n fn cmp(self, other: (A, B)) -> Ordering {\n let result = self.0.cmp(other.0);\n\n if result != Ordering::equal() {\n result\n } else {\n self.1.cmp(other.1)\n }\n }\n}\n\nimpl Ord for (A, B, C)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n{\n fn cmp(self, other: (A, B, C)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n{\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D, E)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n E: Ord,\n{\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n if result == Ordering::equal() {\n result = self.4.cmp(other.4);\n }\n\n result\n }\n}\n\n// Compares and returns the maximum of two values.\n//\n// Returns the second argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::max(1, 2), 2);\n// assert_eq(cmp::max(2, 2), 2);\n// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n// Compares and returns the minimum of two values.\n//\n// Returns the first argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::min(1, 2), 1);\n// assert_eq(cmp::min(2, 2), 2);\n// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use crate::cmp::{max, min};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0_u64, 1), 0);\n assert_eq(min(0_u64, 0), 0);\n assert_eq(min(1_u64, 1), 1);\n assert_eq(min(255_u8, 0), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0_u64, 1), 1);\n assert_eq(max(0_u64, 0), 0);\n assert_eq(max(1_u64, 1), 1);\n assert_eq(max(255_u8, 0), 255);\n }\n}\n","path":"std/cmp.nr"},"18":{"source":"pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array.\n /// This slice will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits(self: Self) -> [u1; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i] == 1);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits(self: Self) -> [u1; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i] == 1);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [u1; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1.\n pub fn sgn0(self) -> u1 {\n self as u1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array.\n/// This slice will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits(value: Field) -> [u1; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits(value: Field) -> [u1; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [u1] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [u1] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime};\n use super::field_less_than;\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [u1; 8] = field.to_be_bits();\n assert_eq(bits, [0, 0, 0, 0, 0, 0, 1, 0]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [u1; 8] = field.to_le_bits();\n assert_eq(bits, [0, 1, 0, 0, 0, 0, 0, 0]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(f\"radix must be greater than 1\");\n }\n }\n\n // TODO: Update this test to account for the Brillig restriction that the radix must be greater than 2\n //#[test]\n //fn test_to_le_radix_brillig_1() {\n // // this test should only fail in constrained mode\n // if runtime::is_unconstrained() {\n // let field = 1;\n // let out: [u8; 8] = field.to_le_radix(1);\n // crate::println(out);\n // let expected = [0; 8];\n // assert(out == expected, \"unexpected result\");\n // }\n //}\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(f\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(f\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n // TODO: Update this test to account for the Brillig restriction that the radix must be less than 512\n //#[test]\n //fn test_to_le_radix_brillig_512() {\n // // this test should only fail in constrained mode\n // if runtime::is_unconstrained() {\n // let field = 1;\n // let out: [u8; 8] = field.to_le_radix(512);\n // let mut expected = [0; 8];\n // expected[0] = 1;\n // assert(out == expected, \"unexpected result\");\n // }\n //}\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n}\n","path":"std/field/mod.nr"},"22":{"source":"pub mod hash;\npub mod aes128;\npub mod array;\npub mod slice;\npub mod ecdsa_secp256k1;\npub mod ecdsa_secp256r1;\npub mod embedded_curve_ops;\npub mod field;\npub mod collections;\npub mod compat;\npub mod convert;\npub mod option;\npub mod string;\npub mod test;\npub mod cmp;\npub mod ops;\npub mod default;\npub mod prelude;\npub mod runtime;\npub mod meta;\npub mod append;\npub mod mem;\npub mod panic;\npub mod hint;\n\nuse convert::AsPrimitive;\n\n// Oracle calls are required to be wrapped in an unconstrained function\n// Thus, the only argument to the `println` oracle is expected to always be an ident\n#[oracle(print)]\nunconstrained fn print_oracle(with_newline: bool, input: T) {}\n\nunconstrained fn print_unconstrained(with_newline: bool, input: T) {\n print_oracle(with_newline, input);\n}\n\npub fn println(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(true, input);\n }\n}\n\npub fn print(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(false, input);\n }\n}\n\npub fn verify_proof(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n) {\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, 0);\n}\n\npub fn verify_proof_with_type(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {\n if !crate::runtime::is_unconstrained() {\n crate::assert_constant(proof_type);\n }\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\n}\n\n#[foreign(recursive_aggregation)]\nfn verify_proof_internal(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {}\n\n// Asserts that the given value is known at compile-time.\n// Useful for debugging for-loop bounds.\n#[builtin(assert_constant)]\npub fn assert_constant(x: T) {}\n\n// Asserts that the given value is both true and known at compile-time.\n// The message can be a string, a format string, or any value, as long as it is known at compile-time\n#[builtin(static_assert)]\npub fn static_assert(predicate: bool, message: T) {}\n\n#[deprecated(\"wrapping operations should be done with the Wrapping traits. E.g: x.wrapping_add(y)\")]\npub fn wrapping_add(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n AsPrimitive::as_(x.as_() + y.as_())\n}\n#[deprecated(\"wrapping operations should be done with the Wrapping traits. E.g: x.wrapping_sub(y)\")]\npub fn wrapping_sub(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n //340282366920938463463374607431768211456 is 2^128, it is used to avoid underflow\n AsPrimitive::as_(x.as_() + 340282366920938463463374607431768211456 - y.as_())\n}\n#[deprecated(\"wrapping operations should be done with the Wrapping traits. E.g: x.wrapping_mul(y)\")]\npub fn wrapping_mul(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n AsPrimitive::as_(x.as_() * y.as_())\n}\n\n#[builtin(as_witness)]\npub fn as_witness(x: Field) {}\n\nmod tests {\n use super::ops::arith::WrappingMul;\n\n #[test(should_fail_with = \"custom message\")]\n fn test_static_assert_custom_message() {\n super::static_assert(1 == 2, \"custom message\");\n }\n\n #[test]\n fn test_wrapping_mul() {\n let zero: u128 = 0;\n let one: u128 = 1;\n let two_pow_64: u128 = 0x10000000000000000;\n let u128_max: u128 = 0xffffffffffffffffffffffffffffffff;\n\n // 1*0==0\n assert_eq(zero, zero.wrapping_mul(one));\n\n // 0*1==0\n assert_eq(zero, one.wrapping_mul(zero));\n\n // 1*1==1\n assert_eq(one, one.wrapping_mul(one));\n\n // 0 * ( 1 << 64 ) == 0\n assert_eq(zero, zero.wrapping_mul(two_pow_64));\n\n // ( 1 << 64 ) * 0 == 0\n assert_eq(zero, two_pow_64.wrapping_mul(zero));\n\n // 1 * ( 1 << 64 ) == 1 << 64\n assert_eq(two_pow_64, two_pow_64.wrapping_mul(one));\n\n // ( 1 << 64 ) * 1 == 1 << 64\n assert_eq(two_pow_64, one.wrapping_mul(two_pow_64));\n\n // ( 1 << 64 ) * ( 1 << 64 ) == 1 << 64\n assert_eq(zero, two_pow_64.wrapping_mul(two_pow_64));\n // -1 * -1 == 1\n assert_eq(one, u128_max.wrapping_mul(u128_max));\n }\n}\n","path":"std/lib.nr"},"50":{"source":"use dep::date::Date;\n\nfn main(\n // Public inputs\n proof_date: pub date::Date, // \"2025-08-29\"\n committed_hash: pub [u8; 32], // Hash of (blinder || dob string)\n // Private inputs\n date_of_birth: str<10>, // \"1985-03-12\"\n blinder: [u8; 16], // Random 16-byte blinder\n) {\n let is_18 = check_18(date_of_birth, proof_date);\n\n let correct_hash = check_hash(date_of_birth, blinder, committed_hash);\n\n assert(correct_hash);\n assert(is_18);\n}\n\nfn check_18(date_of_birth: str<10>, proof_date: date::Date) -> bool {\n let dob = parse_birth_date(date_of_birth);\n let is_18 = dob.add_years(18).lt(proof_date);\n println(f\"Is 18? {is_18}\");\n is_18\n}\n\nfn check_hash(date_of_birth: str<10>, blinder: [u8; 16], committed_hash: [u8; 32]) -> bool {\n let hash_input: [u8; 26] = make_hash_input(date_of_birth, blinder);\n let computed_hash = sha256::sha256_var(hash_input, 26);\n let correct_hash = computed_hash == committed_hash;\n println(f\"Correct hash? {correct_hash}\");\n correct_hash\n}\n\nfn make_hash_input(dob: str<10>, blinder: [u8; 16]) -> [u8; 26] {\n let mut input: [u8; 26] = [0; 26];\n for i in 0..10 {\n input[i] = dob.as_bytes()[i];\n }\n for i in 0..16 {\n input[10 + i] = blinder[i];\n }\n input\n}\n\npub fn parse_birth_date(birth_date: str<10>) -> date::Date {\n let date: [u8; 10] = birth_date.as_bytes();\n let date_str: str<8> =\n [date[0], date[1], date[2], date[3], date[5], date[6], date[8], date[9]].as_str_unchecked();\n Date::from_str_long_year(date_str)\n}\n\n#[test]\nfn test_max_is_over_18() {\n // Private input\n let date_of_birth = \"1985-03-12\";\n let blinder = [120, 80, 62, 10, 76, 60, 130, 98, 147, 161, 139, 126, 27, 236, 36, 56];\n\n // Public input\n let proof_date = date::Date { year: 2025, month: 9, day: 2 };\n let committed_hash = [\n 229, 118, 202, 216, 213, 230, 125, 163, 48, 178, 118, 225, 84, 7, 140, 63, 173, 255, 163,\n 208, 163, 3, 63, 204, 37, 120, 254, 246, 202, 116, 122, 145,\n ];\n\n main(proof_date, committed_hash, date_of_birth, blinder);\n}\n\n#[test(should_fail)]\nfn test_under_18() {\n // Private input\n let date_of_birth = \"2010-08-01\";\n let blinder = [160, 23, 57, 158, 141, 195, 155, 132, 109, 242, 48, 220, 70, 217, 229, 189];\n\n // Public input\n let proof_date = date::Date { year: 2025, month: 8, day: 29 };\n let committed_hash = [\n 16, 132, 194, 62, 232, 90, 157, 153, 4, 231, 1, 54, 226, 3, 87, 174, 129, 177, 80, 69, 37,\n 222, 209, 91, 168, 156, 9, 109, 108, 144, 168, 109,\n ];\n\n main(proof_date, committed_hash, date_of_birth, blinder);\n}\n","path":"/Users/heeckhau/tlsnotary/tlsn/crates/examples/interactive_zk/noir/src/main.nr"},"51":{"source":"use std::cmp::Eq;\nuse std::println;\n\nglobal UNIX_EPOCH_YEAR: u32 = 1970;\nglobal SECONDS_IN_DAY: u32 = 86400;\n\npub struct Date {\n pub day: u8,\n pub month: u8,\n pub year: u32,\n}\n\nfn get_number_from_utf8_code(code: u8) -> u8 {\n assert(code >= 48 & code <= 57);\n code - 48\n}\n\nfn number_to_utf8_code(number: u8) -> u8 {\n assert(number >= 0 & number <= 9);\n number + 48\n}\n\nimpl Date {\n pub fn new(year: u32, month: u8, day: u8) -> Self {\n assert(month >= 1 & month <= 12);\n assert(day >= 1 & day <= 31);\n let date = Self { day: day, month: month, year: year };\n assert(day <= date.get_days_in_month(month));\n date\n }\n\n pub fn from_bytes_short_year(date: [u8; 6], threshold_date: Date) -> Self {\n let firstYearDigit = get_number_from_utf8_code(date[0]);\n let secondYearDigit = get_number_from_utf8_code(date[1]);\n\n let mut year: u32 = firstYearDigit as u32 * 10 + secondYearDigit as u32;\n\n let firstMonthDigit = get_number_from_utf8_code(date[2]);\n let secondMonthDigit = get_number_from_utf8_code(date[3]);\n\n let month = firstMonthDigit * 10 + secondMonthDigit;\n\n let firstDayDigit = get_number_from_utf8_code(date[4]);\n let secondDayDigit = get_number_from_utf8_code(date[5]);\n\n let day = firstDayDigit * 10 + secondDayDigit;\n\n let mut currentYear: u32 = threshold_date.year % 100;\n\n // This way we have a smooth 100 years period according to a threshold year\n // Taking the current year as threshold year (for birthdates for example)\n // if the current year is 2023, then 24 will be interpreted as 1924\n // while 22 will be interpreted as 2022\n // A bit problematic for people over 100 years old\n if year <= currentYear {\n year += 2000;\n } else {\n year += 1900;\n }\n\n Self { day: day, month: month, year: year }\n }\n\n pub fn from_bytes_long_year(date: [u8; 8]) -> Self {\n let firstYearDigit = get_number_from_utf8_code(date[0]);\n let secondYearDigit = get_number_from_utf8_code(date[1]);\n let thirdYearDigit = get_number_from_utf8_code(date[2]);\n let fourthYearDigit = get_number_from_utf8_code(date[3]);\n\n let year: u32 = firstYearDigit as u32 * 1000\n + secondYearDigit as u32 * 100\n + thirdYearDigit as u32 * 10\n + fourthYearDigit as u32;\n\n let firstMonthDigit = get_number_from_utf8_code(date[4]);\n let secondMonthDigit = get_number_from_utf8_code(date[5]);\n\n let month = firstMonthDigit * 10 + secondMonthDigit;\n\n let firstDayDigit = get_number_from_utf8_code(date[6]);\n let secondDayDigit = get_number_from_utf8_code(date[7]);\n\n let day = firstDayDigit * 10 + secondDayDigit;\n\n Self { day: day, month: month, year: year }\n }\n\n pub fn from_str_short_year(date: str<6>, threshold_date: Date) -> Self {\n let date_bytes = date.as_bytes();\n Date::from_bytes_short_year(date_bytes, threshold_date)\n }\n\n pub fn from_str_long_year(date: str<8>) -> Self {\n let date_bytes = date.as_bytes();\n Date::from_bytes_long_year(date_bytes)\n }\n\n fn count_leap_years_since_epoch(year: u32, epoch_year: u32) -> u32 {\n let y = year - 1;\n let leaps_up_to_y = y / 4 - y / 100 + y / 400;\n let leaps_up_to_epoch_year =\n (epoch_year - 1) / 4 - (epoch_year - 1) / 100 + (epoch_year - 1) / 400;\n leaps_up_to_y - leaps_up_to_epoch_year\n }\n\n fn days_since_epoch(year: u32, epoch_year: u32) -> u32 {\n 365 * (year - epoch_year) + Date::count_leap_years_since_epoch(year, epoch_year)\n }\n\n fn estimate_start_day_and_year(days: u32, epoch_year: u32) -> (u32, u32) {\n let first_guess_year = epoch_year + days / 365;\n\n let days_lower_bound = if first_guess_year > epoch_year {\n Date::days_since_epoch(first_guess_year - 1, epoch_year)\n } else {\n 0\n };\n let day_guess = Date::days_since_epoch(first_guess_year, epoch_year);\n let days_upper_bound = Date::days_since_epoch(first_guess_year + 1, epoch_year);\n\n let use_lower_bound = (days >= days_lower_bound) & (days < day_guess);\n let use_upper_bound = days >= days_upper_bound;\n\n let mut best_year = first_guess_year;\n let mut best_start_day = day_guess;\n\n best_year = if use_lower_bound {\n first_guess_year - 1\n } else {\n best_year\n };\n best_start_day = if use_lower_bound {\n days_lower_bound\n } else {\n best_start_day\n };\n\n best_year = if use_upper_bound {\n first_guess_year + 1\n } else {\n best_year\n };\n best_start_day = if use_upper_bound {\n days_upper_bound\n } else {\n best_start_day\n };\n\n (best_year, best_start_day)\n }\n\n pub fn from_timestamp_with_epoch(timestamp: u64, epoch_year: u32) -> Self {\n let days = timestamp / SECONDS_IN_DAY as u64;\n let (year, year_start_day) = Date::estimate_start_day_and_year(days as u32, epoch_year);\n let day_of_year = days as u32 - year_start_day;\n\n let is_leap = Date::is_leap_year(Date::new(year, 1, 1));\n\n let days_at_month_start: [u32; 13] = if is_leap {\n [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]\n } else {\n [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]\n };\n\n let mut month: u32 = 1;\n for i in 0..12 {\n let advance = day_of_year >= days_at_month_start[i + 1];\n month = if advance { month + 1 } else { month };\n }\n\n let day: u32 = day_of_year - days_at_month_start[(month - 1) as u32] + 1;\n Date::new(year, month as u8, day as u8)\n }\n\n pub fn from_timestamp(timestamp: u64) -> Self {\n Date::from_timestamp_with_epoch(timestamp, UNIX_EPOCH_YEAR)\n }\n\n pub fn get_duration_in_days(self: Self, other: Self, absolute: bool) -> i64 {\n let mut duration_years = self.get_duration_between_years(other);\n let mut duration_months = self.get_duration_between_months(other);\n let mut duration_days = self.day as i64 - other.day as i64;\n if (self.year < other.year) {\n if (other.is_leap_year() & other.month > 2 & self.month > 2) {\n duration_days -= 1;\n }\n } else if (self.year > other.year) {\n if (self.is_leap_year() & self.month > 2 & other.month > 2) {\n duration_days += 1;\n }\n }\n let totalDuration: i64 = duration_years + duration_months + duration_days;\n\n if (totalDuration < 0) & absolute {\n -1 * totalDuration\n } else {\n totalDuration\n }\n }\n\n pub fn gt(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) > 0\n }\n\n pub fn lt(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) < 0\n }\n\n pub fn eq(self: Self, other: Self) -> bool {\n (self.day == other.day) & (self.month == other.month) & (self.year == other.year)\n }\n\n pub fn ne(self: Self, other: Self) -> bool {\n !self.eq(other)\n }\n\n pub fn gte(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) >= 0\n }\n\n pub fn lte(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) <= 0\n }\n\n pub fn println(self: Self) {\n let year = self.year;\n let month = self.month;\n let day = self.day;\n // Let's write the date in the YYYY-MM-DD format\n // since people don't agree on which format is best\n // between MM/DD/YYYY and DD/MM/YYYY\n if (month < 10) & (day < 10) {\n println(f\"Date: {year}-0{month}-0{day}\");\n } else if month < 10 {\n println(f\"Date: {year}-0{month}-{day}\");\n } else if day < 10 {\n println(f\"Date: {year}-{month}-0{day}\");\n } else {\n println(f\"Date: {year}-{month}-{day}\");\n }\n }\n\n pub fn to_bytes(self: Self) -> [u8; 8] {\n let mut date: [u8; 8] = [0; 8];\n\n let firstYearDigit = self.year / 1000;\n let secondYearDigit = (self.year - firstYearDigit * 1000) / 100;\n let thirdYearDigit = (self.year - firstYearDigit * 1000 - secondYearDigit * 100) / 10;\n let fourthYearDigit =\n self.year - firstYearDigit * 1000 - secondYearDigit * 100 - thirdYearDigit * 10;\n\n date[0] = number_to_utf8_code(firstYearDigit as u8);\n date[1] = number_to_utf8_code(secondYearDigit as u8);\n date[2] = number_to_utf8_code(thirdYearDigit as u8);\n date[3] = number_to_utf8_code(fourthYearDigit as u8);\n\n let firstMonthDigit = self.month / 10;\n let secondMonthDigit = self.month - firstMonthDigit * 10;\n\n date[4] = number_to_utf8_code(firstMonthDigit as u8);\n date[5] = number_to_utf8_code(secondMonthDigit as u8);\n\n let firstDayDigit = self.day / 10;\n let secondDayDigit = self.day - firstDayDigit * 10;\n\n date[6] = number_to_utf8_code(firstDayDigit as u8);\n date[7] = number_to_utf8_code(secondDayDigit as u8);\n\n date\n }\n\n pub fn to_string(self: Self) -> str<8> {\n let date_bytes = self.to_bytes();\n date_bytes.as_str_unchecked()\n }\n\n pub fn to_timestamp_with_epoch(self: Self, epoch_year: u32) -> u32 {\n let days = self.get_duration_in_days(Date::new(epoch_year, 1, 1), true);\n days as u32 * SECONDS_IN_DAY\n }\n\n pub fn to_timestamp(self: Self) -> u32 {\n self.to_timestamp_with_epoch(UNIX_EPOCH_YEAR)\n }\n\n pub fn is_leap_year(self: Self) -> bool {\n ((self.year % 4 == 0) & (self.year % 100 != 0)) | (self.year % 400 == 0)\n }\n\n pub fn leap_year_count(year: u32) -> i32 {\n (year / 4) as i32 - (year / 100) as i32 + (year / 400) as i32\n }\n\n pub fn get_days_in_month(self: Self, month: u8) -> u8 {\n assert(month >= 1 & month <= 12);\n if month == 2 {\n if self.is_leap_year() {\n 29\n } else {\n 28\n }\n } else {\n if (month == 1)\n | (month == 3)\n | (month == 5)\n | (month == 7)\n | (month == 8)\n | (month == 10)\n | (month == 12) {\n 31\n } else {\n 30\n }\n }\n }\n\n pub fn get_duration_between_months(self: Self, other: Self) -> i64 {\n assert(self.month >= 1 & self.month <= 12);\n assert(other.month >= 1 & other.month <= 12);\n let mut duration: i64 = 0;\n if (self.month < other.month) {\n for month in 1..13 {\n if month >= self.month & month < other.month {\n duration -= other.get_days_in_month(month) as i64;\n }\n }\n } else {\n for month in 1..13 {\n if month >= other.month & month < self.month {\n duration += self.get_days_in_month(month) as i64;\n }\n }\n }\n duration\n }\n\n pub fn get_duration_between_years(self: Self, other: Self) -> i64 {\n let mut duration: i64 = 0;\n if (self.year < other.year) {\n let mut leap_year_count: i32 =\n Date::leap_year_count(other.year - 1) - Date::leap_year_count(self.year);\n if self.is_leap_year() {\n leap_year_count += 1;\n }\n duration -= leap_year_count as i64 * 366;\n duration -=\n (other.year as i64 - self.year as i64 - leap_year_count as i64) as i64 * 365;\n } else if (self.year > other.year) {\n let mut leap_year_count: i32 =\n Date::leap_year_count(self.year - 1) - Date::leap_year_count(other.year);\n if other.is_leap_year() {\n leap_year_count += 1;\n }\n duration += leap_year_count as i64 * 366;\n duration +=\n (self.year as i64 - other.year as i64 - leap_year_count as i64) as i64 * 365;\n }\n duration\n }\n\n pub fn add_years(self: Self, years: u32) -> Self {\n Self { day: self.day, month: self.month, year: self.year + years }\n }\n\n pub fn sub_years(self: Self, years: u32) -> Self {\n Self { day: self.day, month: self.month, year: self.year - years }\n }\n\n pub fn add_months(self: Self, months: u32) -> Self {\n let mut newMonth = self.month as u32 + months;\n let mut newYear = self.year;\n let yearToAdd = (newMonth - 1) / 12;\n if newMonth > 12 {\n newYear += yearToAdd as u32;\n newMonth -= 12 * yearToAdd;\n }\n Self { day: self.day, month: newMonth as u8, year: newYear }\n }\n\n pub fn sub_months(self: Self, months: u32) -> Self {\n let mut newMonth = self.month as i32 - months as i32;\n let mut newYear = self.year;\n if newMonth < 1 {\n let yearToSub = ((newMonth as i32 - 12 as i32) * -1) / 12;\n newYear -= yearToSub as u32;\n newMonth += 12 * yearToSub;\n }\n Self { day: self.day, month: newMonth as u8, year: newYear }\n }\n\n pub fn add_days(self: Self, days: u32) -> Self {\n let mut newDay = self.day as u32 + days;\n let mut newMonth = self.month as u32;\n let mut newYear = self.year;\n let mut date = Self { day: newDay as u8, month: newMonth as u8, year: newYear };\n if newDay > self.get_days_in_month(self.month) as u32 {\n let max_months = (newDay / 30) + 1;\n let bound = self.month as u64 + max_months as u64;\n for _ in self.month as u64..bound as u64 {\n let days_in_month = date.get_days_in_month(newMonth as u8) as u32;\n if newDay > days_in_month {\n newDay -= days_in_month;\n newMonth += 1;\n if newMonth > 12 {\n newYear += 1;\n newMonth = 1;\n }\n // We need to mutate the date object inside the loop\n // so we can use get_days_in_month properly\n date.day = newDay as u8;\n date.year = newYear;\n date.month = newMonth as u8;\n }\n }\n }\n date\n }\n\n // Performance could be improved\n pub fn sub_days(self: Self, days: u32) -> Self {\n let mut newDay = self.day as i32 - days as i32;\n let mut newMonth = self.month as i32;\n let mut newYear = self.year;\n let mut date = Self { day: newDay as u8, month: newMonth as u8, year: newYear };\n if newDay < 1 {\n let max_months = (self.day as u32 + days) / 30 + 1;\n let bound = self.month as u64 + max_months as u64;\n for _ in self.month as u64..bound as u64 {\n let days_in_month = date.get_days_in_month(newMonth as u8) as i32;\n if newDay < 1 {\n newDay += days_in_month;\n newMonth -= 1;\n if newMonth < 1 {\n newYear -= 1;\n newMonth = 12;\n }\n // We need to mutate the date object inside the loop\n // so we can use get_days_in_month properly\n date.day = newDay as u8;\n date.year = newYear;\n date.month = newMonth as u8;\n }\n }\n }\n date\n }\n}\n\nimpl Eq for Date {\n fn eq(self: Self, other: Self) -> bool {\n self.eq(other)\n }\n}\n","path":"/Users/heeckhau/nargo/github.com/madztheo/noir-date.git/v0.5.4/src/date.nr"},"62":{"source":"use std::hash::sha256_compression;\nuse std::runtime::is_unconstrained;\n\nuse constants::{\n BLOCK_BYTE_PTR, BLOCK_SIZE, HASH, INITIAL_STATE, INT_BLOCK, INT_BLOCK_SIZE, INT_SIZE,\n INT_SIZE_PTR, MSG_BLOCK, MSG_SIZE_PTR, STATE, TWO_POW_16, TWO_POW_24, TWO_POW_32, TWO_POW_8,\n};\n\npub(crate) mod constants;\nmod tests;\n\n// Implementation of SHA-256 mapping a byte array of variable length to\n// 32 bytes.\n\n// Deprecated in favour of `sha256_var`\n// docs:start:sha256\npub fn sha256(input: [u8; N]) -> HASH\n// docs:end:sha256\n{\n digest(input)\n}\n\n// SHA-256 hash function\n#[no_predicates]\npub fn digest(msg: [u8; N]) -> HASH {\n sha256_var(msg, N as u64)\n}\n\n// Variable size SHA-256 hash\npub fn sha256_var(msg: [u8; N], message_size: u64) -> HASH {\n let message_size = message_size as u32;\n assert(message_size <= N);\n\n if std::runtime::is_unconstrained() {\n // Safety: SHA256 is running as an unconstrained function.\n unsafe {\n __sha256_var(msg, message_size)\n }\n } else {\n let (mut h, mut msg_block, mut msg_byte_ptr) =\n process_full_blocks(msg, message_size, INITIAL_STATE);\n\n finalize_sha256_blocks(msg, message_size, N, h, msg_block, msg_byte_ptr)\n }\n}\n\npub(crate) unconstrained fn __sha_var(\n msg: [u8; N],\n message_size: u32,\n initial_state: STATE,\n) -> HASH {\n let num_full_blocks = message_size / BLOCK_SIZE;\n // Intermediate hash, starting with the canonical initial value\n let mut h: STATE = initial_state;\n // Pointer into msg_block on a 64 byte scale\n for i in 0..num_full_blocks {\n let (msg_block, _) = build_msg_block(msg, message_size, BLOCK_SIZE * i);\n h = sha256_compression(msg_block, h);\n }\n\n // Handle setup of the final msg block.\n // This case is only hit if the msg is less than the block size,\n // or our message cannot be evenly split into blocks.\n\n finalize_last_sha256_block(h, message_size, msg)\n}\n\n// Helper function to finalize the message block with padding and length\npub(crate) unconstrained fn finalize_last_sha256_block(\n mut h: STATE,\n message_size: u32,\n msg: [u8; N],\n) -> HASH {\n let modulo = message_size % BLOCK_SIZE;\n let (mut msg_block, mut msg_byte_ptr): (INT_BLOCK, u32) = if modulo != 0 {\n let num_full_blocks = message_size / BLOCK_SIZE;\n let msg_start = BLOCK_SIZE * num_full_blocks;\n let (new_msg_block, new_msg_byte_ptr) = build_msg_block(msg, message_size, msg_start);\n (new_msg_block, new_msg_byte_ptr)\n } else {\n // If we had modulo == 0 then it means the last block was full,\n // and we can reset the pointer to zero to overwrite it.\n ([0; INT_BLOCK_SIZE], 0)\n };\n\n // Pad the rest such that we have a [u32; 2] block at the end representing the length\n // of the message, and a block of 1 0 ... 0 following the message (i.e. [1 << 7, 0, ..., 0]).\n // Here we rely on the fact that everything beyond the available input is set to 0.\n let index = msg_byte_ptr / INT_SIZE;\n msg_block[index] = set_item_byte_then_zeros(msg_block[index], msg_byte_ptr, 1 << 7);\n\n // If we don't have room to write the size, compress the block and reset it.\n let (h, mut msg_byte_ptr): (STATE, u32) = if msg_byte_ptr >= MSG_SIZE_PTR {\n // `attach_len_to_msg_block` will zero out everything after the `msg_byte_ptr`.\n (sha256_compression(msg_block, h), 0)\n } else {\n (h, msg_byte_ptr + 1)\n };\n msg_block = attach_len_to_msg_block(msg_block, msg_byte_ptr, message_size);\n\n hash_final_block(msg_block, h)\n}\n\n// Variable size SHA-256 hash\nunconstrained fn __sha256_var(msg: [u8; N], message_size: u32) -> HASH {\n __sha_var(msg, message_size, INITIAL_STATE)\n}\n\npub(crate) fn process_full_blocks(\n msg: [u8; N],\n message_size: u32,\n mut h: STATE,\n) -> (STATE, MSG_BLOCK, u32) {\n let mut msg_block: MSG_BLOCK = [0; INT_BLOCK_SIZE];\n let mut msg_byte_ptr = 0;\n let num_blocks = N / BLOCK_SIZE;\n for i in 0..num_blocks {\n let msg_start = BLOCK_SIZE * i;\n let (new_msg_block, new_msg_byte_ptr) =\n // Safety: separate verification function\n unsafe { build_msg_block(msg, message_size, msg_start) };\n\n if msg_start < message_size {\n msg_block = new_msg_block;\n }\n\n // Verify the block we are compressing was appropriately constructed\n let new_msg_byte_ptr = verify_msg_block(msg, message_size, msg_block, msg_start);\n if msg_start < message_size {\n msg_byte_ptr = new_msg_byte_ptr;\n }\n\n // If the block is filled, compress it.\n // An un-filled block is handled after this loop.\n if (msg_start < message_size) & (msg_byte_ptr == BLOCK_SIZE) {\n h = sha256_compression(msg_block, h);\n }\n }\n (h, msg_block, msg_byte_ptr)\n}\n\n// Take `BLOCK_SIZE` number of bytes from `msg` starting at `msg_start`.\n// Returns the block and the length that has been copied rather than padded with zeros.\npub(crate) unconstrained fn build_msg_block(\n msg: [u8; N],\n message_size: u32,\n msg_start: u32,\n) -> (MSG_BLOCK, BLOCK_BYTE_PTR) {\n let mut msg_block: MSG_BLOCK = [0; INT_BLOCK_SIZE];\n\n // We insert `BLOCK_SIZE` bytes (or up to the end of the message)\n let block_input = if message_size < msg_start {\n // This function is sometimes called with `msg_start` past the end of the message.\n // In this case we return an empty block and zero pointer to signal that the result should be ignored.\n 0\n } else if message_size < msg_start + BLOCK_SIZE {\n message_size - msg_start\n } else {\n BLOCK_SIZE\n };\n\n // Figure out the number of items in the int array that we have to pack.\n // e.g. if the input is [0,1,2,3,4,5] then we need to pack it as 2 items: [0123, 4500]\n let int_input = (block_input + INT_SIZE - 1) / INT_SIZE;\n\n for i in 0..int_input {\n let mut msg_item: u32 = 0;\n // Always construct the integer as 4 bytes, even if it means going beyond the input.\n for j in 0..INT_SIZE {\n let k = i * INT_SIZE + j;\n let msg_byte = if k < block_input {\n msg[msg_start + k]\n } else {\n 0\n };\n msg_item = lshift8(msg_item, 1) + msg_byte as u32;\n }\n msg_block[i] = msg_item;\n }\n\n // Returning the index as if it was a 64 byte array.\n // We have to project it down to 16 items and bit shifting to get a byte back if we need it.\n (msg_block, block_input)\n}\n\n// Verify the block we are compressing was appropriately constructed by `build_msg_block`\n// and matches the input data. Returns the index of the first unset item.\n// If `message_size` is less than `msg_start` then this is called with the old non-empty block;\n// in that case we can skip verification, ie. no need to check that everything is zero.\nfn verify_msg_block(\n msg: [u8; N],\n message_size: u32,\n msg_block: MSG_BLOCK,\n msg_start: u32,\n) -> BLOCK_BYTE_PTR {\n let mut msg_byte_ptr = 0;\n let mut msg_end = msg_start + BLOCK_SIZE;\n if msg_end > N {\n msg_end = N;\n }\n // We might have to go beyond the input to pad the fields.\n if msg_end % INT_SIZE != 0 {\n msg_end = msg_end + INT_SIZE - msg_end % INT_SIZE;\n }\n\n // Reconstructed packed item.\n let mut msg_item: u32 = 0;\n\n // Inclusive at the end so that we can compare the last item.\n let mut i: u32 = 0;\n for k in msg_start..=msg_end {\n if k % INT_SIZE == 0 {\n // If we consumed some input we can compare against the block.\n if (msg_start < message_size) & (k > msg_start) {\n assert_eq(msg_block[i], msg_item as u32);\n i = i + 1;\n msg_item = 0;\n }\n }\n // Shift the accumulator\n msg_item = lshift8(msg_item, 1);\n // If we have input to consume, add it at the rightmost position.\n if k < message_size & k < msg_end {\n msg_item = msg_item + msg[k] as u32;\n msg_byte_ptr = msg_byte_ptr + 1;\n }\n }\n\n msg_byte_ptr\n}\n\n// Verify the block we are compressing was appropriately padded with zeros by `build_msg_block`.\n// This is only relevant for the last, potentially partially filled block.\nfn verify_msg_block_padding(msg_block: MSG_BLOCK, msg_byte_ptr: BLOCK_BYTE_PTR) {\n // Check all the way to the end of the block.\n verify_msg_block_zeros(msg_block, msg_byte_ptr, INT_BLOCK_SIZE);\n}\n\n// Verify that a region of ints in the message block are (partially) zeroed,\n// up to an (exclusive) maximum which can either be the end of the block\n// or just where the size is to be written.\nfn verify_msg_block_zeros(\n msg_block: MSG_BLOCK,\n mut msg_byte_ptr: BLOCK_BYTE_PTR,\n max_int_byte_ptr: u32,\n) {\n // This variable is used to get around the compiler under-constrained check giving a warning.\n // We want to check against a constant zero, but if it does not come from the circuit inputs\n // or return values the compiler check will issue a warning.\n let zero = msg_block[0] - msg_block[0];\n\n // First integer which is supposed to be (partially) zero.\n let mut int_byte_ptr = msg_byte_ptr / INT_SIZE;\n\n // Check partial zeros.\n let modulo = msg_byte_ptr % INT_SIZE;\n if modulo != 0 {\n let zeros = INT_SIZE - modulo;\n let mask = if zeros == 3 {\n TWO_POW_24\n } else if zeros == 2 {\n TWO_POW_16\n } else {\n TWO_POW_8\n };\n assert_eq(msg_block[int_byte_ptr] % mask, zero);\n int_byte_ptr = int_byte_ptr + 1;\n }\n\n // Check the rest of the items.\n for i in 0..max_int_byte_ptr {\n if i >= int_byte_ptr {\n assert_eq(msg_block[i], zero);\n }\n }\n}\n\n// Verify that up to the byte pointer the two blocks are equal.\n// At the byte pointer the new block can be partially zeroed.\nfn verify_msg_block_equals_last(\n msg_block: MSG_BLOCK,\n last_block: MSG_BLOCK,\n mut msg_byte_ptr: BLOCK_BYTE_PTR,\n) {\n // msg_byte_ptr is the position at which they are no longer have to be the same.\n // First integer which is supposed to be (partially) zero contains that pointer.\n let mut int_byte_ptr = msg_byte_ptr / INT_SIZE;\n\n // Check partial zeros.\n let modulo = msg_byte_ptr % INT_SIZE;\n if modulo != 0 {\n // Reconstruct the partially zero item from the last block.\n let last_field = last_block[int_byte_ptr];\n let mut msg_item: u32 = 0;\n // Reset to where they are still equal.\n msg_byte_ptr = msg_byte_ptr - modulo;\n for i in 0..INT_SIZE {\n msg_item = lshift8(msg_item, 1);\n if i < modulo {\n msg_item = msg_item + get_item_byte(last_field, msg_byte_ptr) as u32;\n msg_byte_ptr = msg_byte_ptr + 1;\n }\n }\n assert_eq(msg_block[int_byte_ptr], msg_item);\n }\n\n for i in 0..INT_SIZE_PTR {\n if i < int_byte_ptr {\n assert_eq(msg_block[i], last_block[i]);\n }\n }\n}\n\n// Set the rightmost `zeros` number of bytes to 0.\n#[inline_always]\nfn set_item_zeros(item: u32, zeros: u8) -> u32 {\n lshift8(rshift8(item, zeros), zeros)\n}\n\n// Replace one byte in the item with a value, and set everything after it to zero.\nfn set_item_byte_then_zeros(msg_item: u32, msg_byte_ptr: BLOCK_BYTE_PTR, msg_byte: u8) -> u32 {\n let zeros = INT_SIZE - msg_byte_ptr % INT_SIZE;\n let zeroed_item = set_item_zeros(msg_item, zeros as u8);\n let new_item = byte_into_item(msg_byte, msg_byte_ptr);\n zeroed_item + new_item\n}\n\n// Get a byte of a message item according to its overall position in the `BLOCK_SIZE` space.\nfn get_item_byte(mut msg_item: u32, msg_byte_ptr: BLOCK_BYTE_PTR) -> u8 {\n // How many times do we have to shift to the right to get to the position we want?\n let max_shifts = INT_SIZE - 1;\n let shifts = max_shifts - msg_byte_ptr % INT_SIZE;\n msg_item = rshift8(msg_item, shifts as u8);\n // At this point the byte we want is in the rightmost position.\n msg_item as u8\n}\n\n// Project a byte into a position in a field based on the overall block pointer.\n// For example putting 1 into pointer 5 would be 100, because overall we would\n// have [____, 0100] with indexes [0123,4567].\n#[inline_always]\nfn byte_into_item(msg_byte: u8, msg_byte_ptr: BLOCK_BYTE_PTR) -> u32 {\n let mut msg_item = msg_byte as u32;\n // How many times do we have to shift to the left to get to the position we want?\n let max_shifts = INT_SIZE - 1;\n let shifts = max_shifts - msg_byte_ptr % INT_SIZE;\n lshift8(msg_item, shifts as u8)\n}\n\n// Construct a field out of 4 bytes.\n#[inline_always]\nfn make_item(b0: u8, b1: u8, b2: u8, b3: u8) -> u32 {\n let mut item = b0 as u32;\n item = lshift8(item, 1) + b1 as u32;\n item = lshift8(item, 1) + b2 as u32;\n item = lshift8(item, 1) + b3 as u32;\n item\n}\n\n// Shift by 8 bits to the left between 0 and 4 times.\n// Checks `is_unconstrained()` to just use a bitshift if we're running in an unconstrained context,\n// otherwise multiplies by 256.\n#[inline_always]\nfn lshift8(item: u32, shifts: u8) -> u32 {\n if is_unconstrained() {\n // Brillig wouldn't shift 0<<4 without overflow.\n if shifts >= 4 {\n 0\n } else {\n item << (8 * shifts)\n }\n } else {\n // We can do a for loop up to INT_SIZE or an if-else.\n if shifts == 0 {\n item\n } else if shifts == 1 {\n item * TWO_POW_8\n } else if shifts == 2 {\n item * TWO_POW_16\n } else if shifts == 3 {\n item * TWO_POW_24\n } else {\n // Doesn't make sense, but it's most likely called on 0 anyway.\n 0\n }\n }\n}\n\n// Shift by 8 bits to the right between 0 and 4 times.\n// Checks `is_unconstrained()` to just use a bitshift if we're running in an unconstrained context,\n// otherwise divides by 256.\n#[inline_always]\nfn rshift8(item: u32, shifts: u8) -> u32 {\n if is_unconstrained() {\n item >> (8 * shifts)\n } else {\n // Division wouldn't work on `Field`.\n if shifts == 0 {\n item\n } else if shifts == 1 {\n item / TWO_POW_8\n } else if shifts == 2 {\n item / TWO_POW_16\n } else if shifts == 3 {\n item / TWO_POW_24\n } else {\n 0\n }\n }\n}\n\n// Zero out all bytes between the end of the message and where the length is appended,\n// then write the length into the last 8 bytes of the block.\nunconstrained fn attach_len_to_msg_block(\n mut msg_block: MSG_BLOCK,\n mut msg_byte_ptr: BLOCK_BYTE_PTR,\n message_size: u32,\n) -> MSG_BLOCK {\n // We assume that `msg_byte_ptr` is less than 57 because if not then it is reset to zero before calling this function.\n // In any case, fill blocks up with zeros until the last 64 bits (i.e. until msg_byte_ptr = 56).\n // There can be one item which has to be partially zeroed.\n let modulo = msg_byte_ptr % INT_SIZE;\n if modulo != 0 {\n // Index of the block in which we find the item we need to partially zero.\n let i = msg_byte_ptr / INT_SIZE;\n let zeros = INT_SIZE - modulo;\n msg_block[i] = set_item_zeros(msg_block[i], zeros as u8);\n msg_byte_ptr = msg_byte_ptr + zeros;\n }\n\n // The rest can be zeroed without bit shifting anything.\n for i in (msg_byte_ptr / INT_SIZE)..INT_SIZE_PTR {\n msg_block[i] = 0;\n }\n\n // Set the last two 4 byte ints as the first/second half of the 8 bytes of the length.\n let len = 8 * message_size;\n let len_bytes: [u8; 8] = (len as Field).to_be_bytes();\n msg_block[INT_SIZE_PTR] = (len_bytes[0] as u32) << 24\n | (len_bytes[1] as u32) << 16\n | (len_bytes[2] as u32) << 8\n | (len_bytes[3] as u32);\n\n msg_block[INT_SIZE_PTR + 1] = (len_bytes[4] as u32) << 24\n | (len_bytes[5] as u32) << 16\n | (len_bytes[6] as u32) << 8\n | (len_bytes[7] as u32);\n\n msg_block\n}\n\n// Verify that the message length was correctly written by `attach_len_to_msg_block`,\n// and that everything between the byte pointer and the size pointer was zeroed,\n// and that everything before the byte pointer was untouched.\nfn verify_msg_len(\n msg_block: MSG_BLOCK,\n last_block: MSG_BLOCK,\n msg_byte_ptr: BLOCK_BYTE_PTR,\n message_size: u32,\n) {\n // Check zeros up to the size pointer.\n verify_msg_block_zeros(msg_block, msg_byte_ptr, INT_SIZE_PTR);\n\n // Check that up to the pointer we match the last block.\n verify_msg_block_equals_last(msg_block, last_block, msg_byte_ptr);\n\n // We verify the message length was inserted correctly by reversing the byte decomposition.\n std::static_assert(\n INT_SIZE_PTR + 2 == INT_BLOCK_SIZE,\n \"INT_SIZE_PTR + 2 must equal INT_BLOCK_SIZE\",\n );\n let reconstructed_len_hi = msg_block[INT_SIZE_PTR] as Field;\n let reconstructed_len_lo = msg_block[INT_SIZE_PTR + 1] as Field;\n\n let reconstructed_len: Field =\n reconstructed_len_hi * TWO_POW_32 as Field + reconstructed_len_lo;\n let len = 8 * (message_size as Field);\n assert_eq(reconstructed_len, len);\n}\n\n// Perform the final compression, then transform the `STATE` into `HASH`.\nfn hash_final_block(msg_block: MSG_BLOCK, mut state: STATE) -> HASH {\n let mut out_h: HASH = [0; 32]; // Digest as sequence of bytes\n // Hash final padded block\n state = sha256_compression(msg_block, state);\n\n // Return final hash as byte array\n for j in 0..8 {\n let h_bytes: [u8; 4] = (state[j] as Field).to_be_bytes();\n for k in 0..4 {\n out_h[4 * j + k] = h_bytes[k];\n }\n }\n\n out_h\n}\n\npub(crate) fn finalize_sha256_blocks(\n msg: [u8; N],\n message_size: u32,\n total_len: u32,\n mut h: STATE,\n mut msg_block: MSG_BLOCK,\n mut msg_byte_ptr: u32,\n) -> HASH {\n let modulo = total_len % BLOCK_SIZE;\n // Handle setup of the final msg block.\n // This case is only hit if the msg is less than the block size,\n // or our message cannot be evenly split into blocks.\n if modulo != 0 {\n let num_blocks = total_len / BLOCK_SIZE;\n let msg_start = BLOCK_SIZE * num_blocks;\n let (new_msg_block, new_msg_byte_ptr) =\n // Safety: separate verification function\n unsafe { build_msg_block(msg, message_size, msg_start) };\n\n if msg_start < message_size {\n msg_block = new_msg_block;\n }\n\n let new_msg_byte_ptr = verify_msg_block(msg, message_size, msg_block, msg_start);\n if msg_start < message_size {\n msg_byte_ptr = new_msg_byte_ptr;\n verify_msg_block_padding(msg_block, msg_byte_ptr);\n }\n }\n\n // If we had modulo == 0 then it means the last block was full,\n // and we can reset the pointer to zero to overwrite it.\n if msg_byte_ptr == BLOCK_SIZE {\n msg_byte_ptr = 0;\n }\n\n // Pad the rest such that we have a [u32; 2] block at the end representing the length\n // of the message, and a block of 1 0 ... 0 following the message (i.e. [1 << 7, 0, ..., 0]).\n // Here we rely on the fact that everything beyond the available input is set to 0.\n let index = msg_byte_ptr / INT_SIZE;\n msg_block[index] = set_item_byte_then_zeros(msg_block[index], msg_byte_ptr, 1 << 7);\n\n msg_byte_ptr = msg_byte_ptr + 1;\n let last_block = msg_block;\n\n // If we don't have room to write the size, compress the block and reset it.\n if msg_byte_ptr > MSG_SIZE_PTR {\n h = sha256_compression(msg_block, h);\n\n // `attach_len_to_msg_block` will zero out everything after the `msg_byte_ptr`.\n msg_byte_ptr = 0;\n }\n\n // Safety: separate verification function\n msg_block = unsafe { attach_len_to_msg_block(msg_block, msg_byte_ptr, message_size) };\n\n verify_msg_len(msg_block, last_block, msg_byte_ptr, message_size);\n\n hash_final_block(msg_block, h)\n}\n\n/**\n * Given some state of a partially computed sha256 hash and part of the preimage, continue hashing\n * @notice used for complex/ recursive offloading of post-partial hashing\n *\n * @param N - the maximum length of the message to hash\n * @param h - the intermediate hash state\n * @param msg - the preimage to hash\n * @param message_size - the actual length of the preimage to hash\n * @return the intermediate hash state after compressing in msg to h\n */\npub fn partial_sha256_var_interstitial(\n mut h: [u32; 8],\n msg: [u8; N],\n message_size: u32,\n) -> [u32; 8] {\n assert(message_size % BLOCK_SIZE == 0, \"Message size must be a multiple of the block size\");\n if std::runtime::is_unconstrained() {\n // Safety: running as an unconstrained function\n unsafe {\n __sha_partial_var_interstitial(h, msg, message_size)\n }\n } else {\n let (mut h, _, _) = process_full_blocks(msg, message_size, h);\n\n h\n }\n}\n\n/**\n * Given some state of a partially computed sha256 hash and remaining preimage, complete the hash\n * @notice used for traditional partial hashing\n *\n * @param N - the maximum length of the message to hash\n * @param h - the intermediate hash state\n * @param msg - the remaining preimage to hash\n * @param message_size - the size of the current chunk\n * @param real_message_size - the total size of the original preimage\n * @return finalized sha256 hash\n */\npub fn partial_sha256_var_end(\n mut h: [u32; 8],\n msg: [u8; N],\n message_size: u32,\n real_message_size: u32,\n) -> [u8; 32] {\n assert(message_size % BLOCK_SIZE == 0, \"Message size must be a multiple of the block size\");\n if std::runtime::is_unconstrained() {\n // Safety: running as an unconstrained function\n unsafe {\n h = __sha_partial_var_interstitial(h, msg, message_size);\n\n // Handle setup of the final msg block.\n // This case is only hit if the msg is less than the block size,\n // or our message cannot be evenly split into blocks.\n\n finalize_last_sha256_block(h, real_message_size, msg)\n }\n } else {\n let (mut h, mut msg_block, mut msg_byte_ptr) = process_full_blocks(msg, message_size, h);\n finalize_sha256_blocks(msg, real_message_size, N, h, msg_block, msg_byte_ptr)\n }\n}\n\nunconstrained fn __sha_partial_var_interstitial(\n mut h: [u32; 8],\n msg: [u8; N],\n message_size: u32,\n) -> [u32; 8] {\n let num_full_blocks = message_size / BLOCK_SIZE;\n // Intermediate hash, starting with the canonical initial value\n // Pointer into msg_block on a 64 byte scale\n for i in 0..num_full_blocks {\n let (msg_block, _) = build_msg_block(msg, message_size, BLOCK_SIZE * i);\n h = sha256_compression(msg_block, h);\n }\n h\n}\n\nmod equivalence_test {\n\n #[test]\n fn test_implementations_agree(msg: [u8; 100], message_size: u64) {\n let message_size = message_size % 100;\n // Safety: test function\n let unconstrained_sha = unsafe { super::__sha256_var(msg, message_size as u32) };\n let sha = super::sha256_var(msg, message_size);\n assert_eq(sha, unconstrained_sha);\n }\n}\n","path":"/Users/heeckhau/nargo/github.com/noir-lang/sha256/v0.1.5/src/sha256.nr"}},"names":["main"],"brillig_names":["print_unconstrained","build_msg_block","attach_len_to_msg_block","print_unconstrained","directive_integer_quotient","directive_invert","directive_to_radix"]} \ No newline at end of file +{"noir_version":"1.0.0-beta.19+74d6be658e1ad252f87943292ba09bdd4da80bd4","hash":"18153235887826690717","abi":{"parameters":[{"name":"proof_date","type":{"kind":"struct","path":"date::date::Date","fields":[{"name":"day","type":{"kind":"integer","sign":"unsigned","width":8}},{"name":"month","type":{"kind":"integer","sign":"unsigned","width":8}},{"name":"year","type":{"kind":"integer","sign":"unsigned","width":32}}]},"visibility":"public"},{"name":"committed_hash","type":{"kind":"array","length":32,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"public"},{"name":"date_of_birth","type":{"kind":"string","length":10},"visibility":"private"},{"name":"blinder","type":{"kind":"array","length":16,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"}],"return_type":null,"error_types":{"361444214588792908":{"error_kind":"string","string":"attempt to multiply with overflow"},"1998584279744703196":{"error_kind":"string","string":"attempt to subtract with overflow"},"11019205087382408538":{"error_kind":"string","string":"Field failed to decompose into specified 4 limbs"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"15764276373176857197":{"error_kind":"string","string":"Stack too deep"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"}}},"bytecode":"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","debug_symbols":"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","file_map":{"5":{"source":"use crate::meta::derive_via;\n\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { $crate::cmp::Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for u1 {\n fn eq(self, other: u1) -> bool {\n self == other\n }\n}\n\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n if result {\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\nimpl Eq for (A, B)\nwhere\n A: Eq,\n B: Eq,\n{\n fn eq(self, other: (A, B)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1)\n }\n}\n\nimpl Eq for (A, B, C)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n{\n fn eq(self, other: (A, B, C)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2)\n }\n}\n\nimpl Eq for (A, B, C, D)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n{\n fn eq(self, other: (A, B, C, D)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3)\n }\n}\n\nimpl Eq for (A, B, C, D, E)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n E: Eq,\n{\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n self.0.eq(other.0)\n & self.1.eq(other.1)\n & self.2.eq(other.2)\n & self.3.eq(other.3)\n & self.4.eq(other.4)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::cmp::Ord };\n let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == $crate::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = $crate::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let self_len = self.len();\n let other_len = other.len();\n let min_len = if self_len < other_len {\n self_len\n } else {\n other_len\n };\n\n let mut result = Ordering::equal();\n for i in 0..min_len {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n\n if result != Ordering::equal() {\n result\n } else {\n self_len.cmp(other_len)\n }\n }\n}\n\nimpl Ord for (A, B)\nwhere\n A: Ord,\n B: Ord,\n{\n fn cmp(self, other: (A, B)) -> Ordering {\n let result = self.0.cmp(other.0);\n\n if result != Ordering::equal() {\n result\n } else {\n self.1.cmp(other.1)\n }\n }\n}\n\nimpl Ord for (A, B, C)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n{\n fn cmp(self, other: (A, B, C)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n{\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D, E)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n E: Ord,\n{\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n if result == Ordering::equal() {\n result = self.4.cmp(other.4);\n }\n\n result\n }\n}\n\n// Compares and returns the maximum of two values.\n//\n// Returns the second argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::max(1, 2), 2);\n// assert_eq(cmp::max(2, 2), 2);\n// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n// Compares and returns the minimum of two values.\n//\n// Returns the first argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::min(1, 2), 1);\n// assert_eq(cmp::min(2, 2), 2);\n// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use super::{Eq, max, min, Ord};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0_u64, 1), 0);\n assert_eq(min(0_u64, 0), 0);\n assert_eq(min(1_u64, 1), 1);\n assert_eq(min(255_u8, 0), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0_u64, 1), 1);\n assert_eq(max(0_u64, 0), 0);\n assert_eq(max(1_u64, 1), 1);\n assert_eq(max(255_u8, 0), 255);\n }\n\n #[test]\n fn correctly_handles_unequal_length_vectors() {\n let vector_1 = [0, 1, 2, 3].as_vector();\n let vector_2 = [0, 1, 2].as_vector();\n assert(!vector_1.eq(vector_2));\n }\n\n #[test]\n fn lexicographic_ordering_for_vectors() {\n assert(\n [2_u32].as_vector().cmp([1_u32, 1_u32, 1_u32].as_vector())\n == super::Ordering::greater(),\n );\n assert(\n [1_u32, 2_u32].as_vector().cmp([1_u32, 2_u32, 3_u32].as_vector())\n == super::Ordering::less(),\n );\n }\n}\n","path":"std/cmp.nr"},"18":{"source":"pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits(self: Self) -> [u1; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i] == 1);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits(self: Self) -> [u1; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i] == 1);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [u1; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1.\n pub fn sgn0(self) -> u1 {\n self as u1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits(value: Field) -> [u1; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits(value: Field) -> [u1; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [u1] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [u1] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime, static_assert};\n use super::{\n field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,\n };\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [u1; 8] = field.to_be_bits();\n assert_eq(bits, [0, 0, 0, 0, 0, 0, 1, 0]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [u1; 8] = field.to_le_bits();\n assert_eq(bits, [0, 1, 0, 0, 0, 0, 0, 0]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n // Updated test to account for Brillig restriction that radix must be greater than 2\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_brillig_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 1;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n\n #[test]\n unconstrained fn test_large_field_values_unconstrained() {\n let large_field = 0xffffffffffffffff;\n\n let bits: [u1; 64] = large_field.to_le_bits();\n assert_eq(bits[0], 1);\n\n let bytes: [u8; 8] = large_field.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_field);\n\n let radix_bytes: [u8; 8] = large_field.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);\n }\n\n #[test]\n fn test_large_field_values() {\n let large_val = 0xffffffffffffffff;\n\n let bits: [u1; 64] = large_val.to_le_bits();\n assert_eq(bits[0], 1);\n\n let bytes: [u8; 8] = large_val.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_val);\n\n let radix_bytes: [u8; 8] = large_val.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);\n }\n\n #[test]\n fn test_decomposition_edge_cases() {\n let zero_bits: [u1; 8] = 0.to_le_bits();\n assert_eq(zero_bits, [0; 8]);\n\n let zero_bytes: [u8; 8] = 0.to_le_bytes();\n assert_eq(zero_bytes, [0; 8]);\n\n let one_bits: [u1; 8] = 1.to_le_bits();\n let expected: [u1; 8] = [1, 0, 0, 0, 0, 0, 0, 0];\n assert_eq(one_bits, expected);\n\n let pow2_bits: [u1; 8] = 4.to_le_bits();\n let expected: [u1; 8] = [0, 0, 1, 0, 0, 0, 0, 0];\n assert_eq(pow2_bits, expected);\n }\n\n #[test]\n fn test_pow_32() {\n assert_eq(2.pow_32(3), 8);\n assert_eq(3.pow_32(2), 9);\n assert_eq(5.pow_32(0), 1);\n assert_eq(7.pow_32(1), 7);\n\n assert_eq(2.pow_32(10), 1024);\n\n assert_eq(0.pow_32(5), 0);\n assert_eq(0.pow_32(0), 1);\n\n assert_eq(1.pow_32(100), 1);\n }\n\n #[test]\n fn test_sgn0() {\n assert_eq(0.sgn0(), 0);\n assert_eq(2.sgn0(), 0);\n assert_eq(4.sgn0(), 0);\n assert_eq(100.sgn0(), 0);\n\n assert_eq(1.sgn0(), 1);\n assert_eq(3.sgn0(), 1);\n assert_eq(5.sgn0(), 1);\n assert_eq(101.sgn0(), 1);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 8 limbs\")]\n fn test_bit_decomposition_overflow() {\n // 8 bits can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u1; 8] = large_val.to_le_bits();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 4 limbs\")]\n fn test_byte_decomposition_overflow() {\n // 4 bytes can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u8; 4] = large_val.to_le_bytes();\n }\n\n #[test]\n fn test_to_from_be_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_minus_1_bytes[32 - 1] > 0);\n p_minus_1_bytes[32 - 1] -= 1;\n\n let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_plus_1_bytes[32 - 1] < 255);\n p_plus_1_bytes[32 - 1] += 1;\n\n let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 BE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();\n assert_eq(p_plus_1_converted_bytes[32 - 1], 1);\n p_plus_1_converted_bytes[32 - 1] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_be_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_be_bytes().len(), 32);\n let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 BE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_be_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n #[test]\n fn test_to_from_le_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_minus_1_bytes[0] > 0);\n p_minus_1_bytes[0] -= 1;\n\n let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_plus_1_bytes[0] < 255);\n p_plus_1_bytes[0] += 1;\n\n let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 LE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();\n assert_eq(p_plus_1_converted_bytes[0], 1);\n p_plus_1_converted_bytes[0] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_le_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_le_bytes().len(), 32);\n let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 LE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_le_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n /// Convert a little endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_le_bits(bits: [u1; N]) -> Field {\n static_assert(\n N <= modulus_le_bits().len(),\n \"N must be less than or equal to modulus_le_bits().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n /// Convert a big endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_be_bits(bits: [u1; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[N - 1 - i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n #[test]\n fn test_to_from_be_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)\n let mut p_minus_1_bits: [u1; 254] = modulus_be_bits().as_array();\n assert(p_minus_1_bits[254 - 1] > 0);\n p_minus_1_bits[254 - 1] -= 1;\n\n let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [u1; 254] = p_minus_1.to_be_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 BE bits for (modulus + 4)\n let mut p_plus_4_bits: [u1; 254] = modulus_be_bits().as_array();\n assert(p_plus_4_bits[254 - 3] < 1);\n p_plus_4_bits[254 - 3] += 1;\n\n let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 BE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [u1; 254] = p_plus_4.to_be_bits();\n assert_eq(p_plus_4_converted_bits[254 - 3], 1);\n p_plus_4_converted_bits[254 - 3] = 0;\n assert_eq(p_plus_4_converted_bits, [0; 254]);\n\n // checking that Field::from_be_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_be_bits().len(), 254);\n let p = from_be_bits::<254>(modulus_be_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 BE bytes produces 254 zeroes\n let p_bits: [u1; 254] = 0.to_be_bits();\n assert_eq(p_bits, [0; 254]);\n }\n }\n\n #[test]\n fn test_to_from_le_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)\n let mut p_minus_1_bits: [u1; 254] = modulus_le_bits().as_array();\n assert(p_minus_1_bits[0] > 0);\n p_minus_1_bits[0] -= 1;\n\n let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [u1; 254] = p_minus_1.to_le_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 LE bits for (modulus + 4)\n let mut p_plus_4_bits: [u1; 254] = modulus_le_bits().as_array();\n assert(p_plus_4_bits[2] < 1);\n p_plus_4_bits[2] += 1;\n\n let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 LE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [u1; 254] = p_plus_4.to_le_bits();\n assert_eq(p_plus_4_converted_bits[2], 1);\n p_plus_4_converted_bits[2] = 0;\n assert_eq(p_plus_4_converted_bits, [0; 254]);\n\n // checking that Field::from_le_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_le_bits().len(), 254);\n let p = from_le_bits::<254>(modulus_le_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 LE bytes produces 254 zeroes\n let p_bits: [u1; 254] = 0.to_le_bits();\n assert_eq(p_bits, [0; 254]);\n }\n }\n}\n","path":"std/field/mod.nr"},"22":{"source":"pub mod hash;\npub mod aes128;\npub mod array;\npub mod vector;\npub mod ecdsa_secp256k1;\npub mod ecdsa_secp256r1;\npub mod embedded_curve_ops;\npub mod field;\npub mod collections;\npub mod compat;\npub mod convert;\npub mod option;\npub mod string;\npub mod test;\npub mod cmp;\npub mod ops;\npub mod default;\npub mod prelude;\npub mod runtime;\npub mod meta;\npub mod append;\npub mod mem;\npub mod panic;\npub mod hint;\n\nmod primitive_docs;\n\n// Oracle calls are required to be wrapped in an unconstrained function\n// Thus, the only argument to the `println` oracle is expected to always be an ident\n#[oracle(print)]\nunconstrained fn print_oracle(with_newline: bool, input: T) {}\n\nunconstrained fn print_unconstrained(with_newline: bool, input: T) {\n print_oracle(with_newline, input);\n}\n\npub fn println(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(true, input);\n }\n}\n\npub fn print(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(false, input);\n }\n}\n\n/// Asserts the validity of the provided proof and public inputs against the provided verification key and hash.\n///\n/// The ACVM cannot determine whether the provided proof is valid during execution as this requires knowledge of\n/// the backend against which the program is being proven. However if an invalid proof if submitted, the program may\n/// fail to prove or the backend may generate a proof which will subsequently fail to verify.\n///\n/// # Important Note\n///\n/// If you are not developing your own backend such as [Barretenberg](https://github.com/AztecProtocol/barretenberg)\n/// you probably shouldn't need to interact with this function directly. It's easier and safer to use a verification\n/// library which is published by the developers of the backend which will document or enforce any safety requirements.\n///\n/// If you use this directly, you're liable to introduce underconstrainedness bugs and *your circuit will be insecure*.\n///\n/// # Arguments\n/// - verification_key: The verification key of the circuit to be verified.\n/// - proof: The proof to be verified.\n/// - public_inputs: The public inputs associated with `proof`\n/// - key_hash: The hash of `verification_key` of the form expected by the backend.\n/// - proof_type: An identifier for the proving scheme used to generate the proof to be verified. This allows\n/// for a single backend to support verifying multiple proving schemes.\n///\n/// # Constraining `key_hash`\n///\n/// The Noir compiler does not by itself constrain that `key_hash` is a valid hash of `verification_key`.\n/// This is because different backends may differ in how they hash their verification keys.\n/// It is then the responsibility of either the noir developer (by explicitly hashing the verification key\n/// in the correct manner) or by the proving system itself internally asserting the correctness of `key_hash`.\npub fn verify_proof_with_type(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {\n if !crate::runtime::is_unconstrained() {\n crate::assert_constant(proof_type);\n }\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\n}\n\n#[foreign(recursive_aggregation)]\nfn verify_proof_internal(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {}\n\n// Asserts that the given value is known at compile-time.\n// Useful for debugging for-loop bounds.\n#[builtin(assert_constant)]\npub fn assert_constant(x: T) {}\n\n// Asserts that the given value is both true and known at compile-time.\n// The message can be a string, a format string, or any value, as long as it is known at compile-time\n#[builtin(static_assert)]\npub fn static_assert(predicate: bool, message: T) {}\n\n#[builtin(as_witness)]\npub fn as_witness(x: Field) {}\n","path":"std/lib.nr"},"51":{"source":"use date::Date;\n\nfn main(\n // Public inputs\n proof_date: pub date::Date, // \"2025-08-29\"\n committed_hash: pub [u8; 32], // Hash of (blinder || dob string)\n // Private inputs\n date_of_birth: str<10>, // \"1985-03-12\"\n blinder: [u8; 16], // Random 16-byte blinder\n) {\n let is_18 = check_18(date_of_birth, proof_date);\n\n let correct_hash = check_hash(date_of_birth, blinder, committed_hash);\n\n assert(correct_hash);\n assert(is_18);\n}\n\nfn check_18(date_of_birth: str<10>, proof_date: date::Date) -> bool {\n let dob = parse_birth_date(date_of_birth);\n let is_18 = dob.add_years(18).lt(proof_date);\n println(f\"Is 18? {is_18}\");\n is_18\n}\n\nfn check_hash(date_of_birth: str<10>, blinder: [u8; 16], committed_hash: [u8; 32]) -> bool {\n let hash_input: [u8; 26] = make_hash_input(date_of_birth, blinder);\n let computed_hash = sha256::sha256_var(hash_input, 26);\n let correct_hash = computed_hash == committed_hash;\n println(f\"Correct hash? {correct_hash}\");\n correct_hash\n}\n\nfn make_hash_input(dob: str<10>, blinder: [u8; 16]) -> [u8; 26] {\n let mut input: [u8; 26] = [0; 26];\n for i in 0..10 {\n input[i] = dob.as_bytes()[i];\n }\n for i in 0..16 {\n input[10 + i] = blinder[i];\n }\n input\n}\n\npub fn parse_birth_date(birth_date: str<10>) -> date::Date {\n let date: [u8; 10] = birth_date.as_bytes();\n let date_str: str<8> =\n [date[0], date[1], date[2], date[3], date[5], date[6], date[8], date[9]].as_str_unchecked();\n Date::from_str_long_year(date_str)\n}\n\n#[test]\nfn test_max_is_over_18() {\n // Private input\n let date_of_birth = \"1985-03-12\";\n let blinder = [120, 80, 62, 10, 76, 60, 130, 98, 147, 161, 139, 126, 27, 236, 36, 56];\n\n // Public input\n let proof_date = date::Date { year: 2025, month: 9, day: 2 };\n let committed_hash = [\n 229, 118, 202, 216, 213, 230, 125, 163, 48, 178, 118, 225, 84, 7, 140, 63, 173, 255, 163,\n 208, 163, 3, 63, 204, 37, 120, 254, 246, 202, 116, 122, 145,\n ];\n\n main(proof_date, committed_hash, date_of_birth, blinder);\n}\n\n#[test(should_fail)]\nfn test_under_18() {\n // Private input\n let date_of_birth = \"2010-08-01\";\n let blinder = [160, 23, 57, 158, 141, 195, 155, 132, 109, 242, 48, 220, 70, 217, 229, 189];\n\n // Public input\n let proof_date = date::Date { year: 2025, month: 8, day: 29 };\n let committed_hash = [\n 16, 132, 194, 62, 232, 90, 157, 153, 4, 231, 1, 54, 226, 3, 87, 174, 129, 177, 80, 69, 37,\n 222, 209, 91, 168, 156, 9, 109, 108, 144, 168, 109,\n ];\n\n main(proof_date, committed_hash, date_of_birth, blinder);\n}\n","path":"/home/heeckhau/tlsnotary/tlsn/crates/examples/basic_zk/noir/src/main.nr"},"52":{"source":"use std::cmp::Eq;\nuse std::println;\n\nglobal UNIX_EPOCH_YEAR: u32 = 1970;\nglobal SECONDS_IN_DAY: u32 = 86400;\n\npub struct Date {\n pub day: u8,\n pub month: u8,\n pub year: u32,\n}\n\nfn get_number_from_utf8_code(code: u8) -> u8 {\n assert(code >= 48 & code <= 57);\n code - 48\n}\n\nfn number_to_utf8_code(number: u8) -> u8 {\n assert(number >= 0 & number <= 9);\n number + 48\n}\n\nimpl Date {\n pub fn new(year: u32, month: u8, day: u8) -> Self {\n assert(month >= 1 & month <= 12);\n assert(day >= 1 & day <= 31);\n let date = Self { day: day, month: month, year: year };\n assert(day <= date.get_days_in_month(month));\n date\n }\n\n pub fn from_bytes_short_year(date: [u8; 6], threshold_date: Date) -> Self {\n let firstYearDigit = get_number_from_utf8_code(date[0]);\n let secondYearDigit = get_number_from_utf8_code(date[1]);\n\n let mut year: u32 = firstYearDigit as u32 * 10 + secondYearDigit as u32;\n\n let firstMonthDigit = get_number_from_utf8_code(date[2]);\n let secondMonthDigit = get_number_from_utf8_code(date[3]);\n\n let month = firstMonthDigit * 10 + secondMonthDigit;\n\n let firstDayDigit = get_number_from_utf8_code(date[4]);\n let secondDayDigit = get_number_from_utf8_code(date[5]);\n\n let day = firstDayDigit * 10 + secondDayDigit;\n\n let mut currentYear: u32 = threshold_date.year % 100;\n\n // This way we have a smooth 100 years period according to a threshold year\n // Taking the current year as threshold year (for birthdates for example)\n // if the current year is 2023, then 24 will be interpreted as 1924\n // while 22 will be interpreted as 2022\n // A bit problematic for people over 100 years old\n if year <= currentYear {\n year += 2000;\n } else {\n year += 1900;\n }\n\n Self { day: day, month: month, year: year }\n }\n\n pub fn from_bytes_long_year(date: [u8; 8]) -> Self {\n let firstYearDigit = get_number_from_utf8_code(date[0]);\n let secondYearDigit = get_number_from_utf8_code(date[1]);\n let thirdYearDigit = get_number_from_utf8_code(date[2]);\n let fourthYearDigit = get_number_from_utf8_code(date[3]);\n\n let year: u32 = firstYearDigit as u32 * 1000\n + secondYearDigit as u32 * 100\n + thirdYearDigit as u32 * 10\n + fourthYearDigit as u32;\n\n let firstMonthDigit = get_number_from_utf8_code(date[4]);\n let secondMonthDigit = get_number_from_utf8_code(date[5]);\n\n let month = firstMonthDigit * 10 + secondMonthDigit;\n\n let firstDayDigit = get_number_from_utf8_code(date[6]);\n let secondDayDigit = get_number_from_utf8_code(date[7]);\n\n let day = firstDayDigit * 10 + secondDayDigit;\n\n Self { day: day, month: month, year: year }\n }\n\n pub fn from_str_short_year(date: str<6>, threshold_date: Date) -> Self {\n let date_bytes = date.as_bytes();\n Date::from_bytes_short_year(date_bytes, threshold_date)\n }\n\n pub fn from_str_long_year(date: str<8>) -> Self {\n let date_bytes = date.as_bytes();\n Date::from_bytes_long_year(date_bytes)\n }\n\n fn count_leap_years_since_epoch(year: u32, epoch_year: u32) -> u32 {\n let y = year - 1;\n let leaps_up_to_y = y / 4 - y / 100 + y / 400;\n let leaps_up_to_epoch_year =\n (epoch_year - 1) / 4 - (epoch_year - 1) / 100 + (epoch_year - 1) / 400;\n leaps_up_to_y - leaps_up_to_epoch_year\n }\n\n fn days_since_epoch(year: u32, epoch_year: u32) -> u64 {\n 365 * (year as u64 - epoch_year as u64)\n + Date::count_leap_years_since_epoch(year, epoch_year) as u64\n }\n\n fn estimate_start_day_and_year(days: u64, epoch_year: u32) -> (u32, u64) {\n let first_guess_year = (epoch_year as u64 + days / 365) as u32;\n\n let days_lower_bound = if first_guess_year > epoch_year {\n Date::days_since_epoch(first_guess_year - 1, epoch_year)\n } else {\n 0\n };\n let day_guess = Date::days_since_epoch(first_guess_year, epoch_year);\n let days_upper_bound = Date::days_since_epoch(first_guess_year + 1, epoch_year);\n\n let use_lower_bound = (days >= days_lower_bound) & (days < day_guess);\n let use_upper_bound = days >= days_upper_bound;\n\n let mut best_year = first_guess_year;\n let mut best_start_day = day_guess;\n\n best_year = if use_lower_bound {\n first_guess_year - 1\n } else {\n best_year\n };\n best_start_day = if use_lower_bound {\n days_lower_bound\n } else {\n best_start_day\n };\n\n best_year = if use_upper_bound {\n first_guess_year + 1\n } else {\n best_year\n };\n best_start_day = if use_upper_bound {\n days_upper_bound\n } else {\n best_start_day\n };\n\n (best_year, best_start_day)\n }\n\n pub fn from_timestamp_with_epoch(timestamp: u64, epoch_year: u32) -> Self {\n let days = timestamp / SECONDS_IN_DAY as u64;\n let (year, year_start_day) = Date::estimate_start_day_and_year(days, epoch_year);\n let day_of_year = (days - year_start_day) as u32;\n\n let is_leap = Date::is_leap_year(Date::new(year, 1, 1));\n\n let days_at_month_start: [u32; 13] = if is_leap {\n [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]\n } else {\n [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]\n };\n\n let mut month: u32 = 1;\n for i in 0..12 {\n let advance = day_of_year >= days_at_month_start[i + 1];\n month = if advance { month + 1 } else { month };\n }\n\n let day: u32 = day_of_year - days_at_month_start[(month - 1) as u32] + 1;\n Date::new(year, month as u8, day as u8)\n }\n\n pub fn from_timestamp(timestamp: u64) -> Self {\n Date::from_timestamp_with_epoch(timestamp, UNIX_EPOCH_YEAR)\n }\n\n pub fn get_duration_in_days(self: Self, other: Self, absolute: bool) -> i64 {\n let mut duration_years = self.get_duration_between_years(other);\n let mut duration_months = self.get_duration_between_months(other);\n let mut duration_days = self.day as i64 - other.day as i64;\n if (self.year < other.year) {\n if (other.is_leap_year() & other.month > 2 & self.month > 2) {\n duration_days -= 1;\n }\n } else if (self.year > other.year) {\n if (self.is_leap_year() & self.month > 2 & other.month > 2) {\n duration_days += 1;\n }\n }\n let totalDuration: i64 = duration_years + duration_months + duration_days;\n\n if (totalDuration < 0) & absolute {\n -1 * totalDuration\n } else {\n totalDuration\n }\n }\n\n pub fn gt(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) > 0\n }\n\n pub fn lt(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) < 0\n }\n\n pub fn eq(self: Self, other: Self) -> bool {\n (self.day == other.day) & (self.month == other.month) & (self.year == other.year)\n }\n\n pub fn ne(self: Self, other: Self) -> bool {\n !self.eq(other)\n }\n\n pub fn gte(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) >= 0\n }\n\n pub fn lte(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) <= 0\n }\n\n pub fn println(self: Self) {\n let year = self.year;\n let month = self.month;\n let day = self.day;\n // Let's write the date in the YYYY-MM-DD format\n // since people don't agree on which format is best\n // between MM/DD/YYYY and DD/MM/YYYY\n if (month < 10) & (day < 10) {\n println(f\"Date: {year}-0{month}-0{day}\");\n } else if month < 10 {\n println(f\"Date: {year}-0{month}-{day}\");\n } else if day < 10 {\n println(f\"Date: {year}-{month}-0{day}\");\n } else {\n println(f\"Date: {year}-{month}-{day}\");\n }\n }\n\n pub fn to_bytes(self: Self) -> [u8; 8] {\n let mut date: [u8; 8] = [0; 8];\n\n let firstYearDigit = self.year / 1000;\n let secondYearDigit = (self.year - firstYearDigit * 1000) / 100;\n let thirdYearDigit = (self.year - firstYearDigit * 1000 - secondYearDigit * 100) / 10;\n let fourthYearDigit =\n self.year - firstYearDigit * 1000 - secondYearDigit * 100 - thirdYearDigit * 10;\n\n date[0] = number_to_utf8_code(firstYearDigit as u8);\n date[1] = number_to_utf8_code(secondYearDigit as u8);\n date[2] = number_to_utf8_code(thirdYearDigit as u8);\n date[3] = number_to_utf8_code(fourthYearDigit as u8);\n\n let firstMonthDigit = self.month / 10;\n let secondMonthDigit = self.month - firstMonthDigit * 10;\n\n date[4] = number_to_utf8_code(firstMonthDigit as u8);\n date[5] = number_to_utf8_code(secondMonthDigit as u8);\n\n let firstDayDigit = self.day / 10;\n let secondDayDigit = self.day - firstDayDigit * 10;\n\n date[6] = number_to_utf8_code(firstDayDigit as u8);\n date[7] = number_to_utf8_code(secondDayDigit as u8);\n\n date\n }\n\n pub fn to_string(self: Self) -> str<8> {\n let date_bytes = self.to_bytes();\n date_bytes.as_str_unchecked()\n }\n\n pub fn to_timestamp_with_epoch(self: Self, epoch_year: u32) -> u64 {\n let days = self.get_duration_in_days(Date::new(epoch_year, 1, 1), true);\n days as u64 * SECONDS_IN_DAY as u64\n }\n\n pub fn to_timestamp(self: Self) -> u64 {\n self.to_timestamp_with_epoch(UNIX_EPOCH_YEAR)\n }\n\n pub fn is_leap_year(self: Self) -> bool {\n ((self.year % 4 == 0) & (self.year % 100 != 0)) | (self.year % 400 == 0)\n }\n\n pub fn leap_year_count(year: u32) -> i32 {\n (year / 4) as i32 - (year / 100) as i32 + (year / 400) as i32\n }\n\n pub fn get_days_in_month(self: Self, month: u8) -> u8 {\n assert(month >= 1 & month <= 12);\n if month == 2 {\n if self.is_leap_year() {\n 29\n } else {\n 28\n }\n } else {\n if (month == 1)\n | (month == 3)\n | (month == 5)\n | (month == 7)\n | (month == 8)\n | (month == 10)\n | (month == 12) {\n 31\n } else {\n 30\n }\n }\n }\n\n pub fn get_duration_between_months(self: Self, other: Self) -> i64 {\n assert(self.month >= 1 & self.month <= 12);\n assert(other.month >= 1 & other.month <= 12);\n let mut duration: i64 = 0;\n if (self.month < other.month) {\n for month in 1..13 {\n if month >= self.month & month < other.month {\n duration -= other.get_days_in_month(month) as i64;\n }\n }\n } else {\n for month in 1..13 {\n if month >= other.month & month < self.month {\n duration += self.get_days_in_month(month) as i64;\n }\n }\n }\n duration\n }\n\n pub fn get_duration_between_years(self: Self, other: Self) -> i64 {\n let mut duration: i64 = 0;\n if (self.year < other.year) {\n let mut leap_year_count: i32 =\n Date::leap_year_count(other.year - 1) - Date::leap_year_count(self.year);\n if self.is_leap_year() {\n leap_year_count += 1;\n }\n duration -= leap_year_count as i64 * 366;\n duration -=\n (other.year as i64 - self.year as i64 - leap_year_count as i64) as i64 * 365;\n } else if (self.year > other.year) {\n let mut leap_year_count: i32 =\n Date::leap_year_count(self.year - 1) - Date::leap_year_count(other.year);\n if other.is_leap_year() {\n leap_year_count += 1;\n }\n duration += leap_year_count as i64 * 366;\n duration +=\n (self.year as i64 - other.year as i64 - leap_year_count as i64) as i64 * 365;\n }\n duration\n }\n\n fn check_for_leap_year_adjustment(year: u32, month: u8, day: u8) -> Self {\n let needs_adjustment = (month == 2) & (day == 29) & !Date::new(year, 1, 1).is_leap_year();\n if needs_adjustment {\n Self { day: 1, month: 3, year: year }\n } else {\n Self { day: day, month: month, year: year }\n }\n }\n\n fn to_days_since_year_one(self: Self) -> u64 {\n // Calculate days from years\n let y: u64 = self.year as u64 - 1;\n let days_from_years = y * 365;\n\n // Calculate leap years up to (year - 1)\n let leap_years = y / 4 - y / 100 + y / 400;\n\n // Get day of year for current date\n let is_leap = self.is_leap_year();\n let days_at_month_start: [u32; 13] = if is_leap {\n [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]\n } else {\n [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]\n };\n\n let day_of_year = days_at_month_start[(self.month - 1) as u32] + (self.day - 1) as u32;\n\n days_from_years + leap_years + day_of_year as u64\n }\n\n fn from_days_since_year_one(days: u64) -> Self {\n let first_guess_year = (1 + days / 365) as u32;\n\n // Calculate days at the start of each candidate year\n let days_lower_bound = if first_guess_year > 1 {\n Date::days_since_epoch(first_guess_year - 1, 1)\n } else {\n 0\n };\n let day_guess = Date::days_since_epoch(first_guess_year, 1);\n let days_upper_bound = Date::days_since_epoch(first_guess_year + 1, 1);\n\n // Determine which year the days fall into\n let use_lower_bound = (days >= days_lower_bound) & (days < day_guess);\n let use_upper_bound = days >= days_upper_bound;\n\n let mut best_year = first_guess_year;\n let mut best_start_day = day_guess;\n\n best_year = if use_lower_bound {\n first_guess_year - 1\n } else {\n best_year\n };\n best_start_day = if use_lower_bound {\n days_lower_bound\n } else {\n best_start_day\n };\n\n best_year = if use_upper_bound {\n first_guess_year + 1\n } else {\n best_year\n };\n best_start_day = if use_upper_bound {\n days_upper_bound\n } else {\n best_start_day\n };\n\n // Calculate day of year\n let day_of_year = (days - best_start_day) as u32;\n\n // Determine month and day from day of year\n let is_leap = Date::is_leap_year(Date::new(best_year, 1, 1));\n let days_at_month_start: [u32; 13] = if is_leap {\n [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]\n } else {\n [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]\n };\n\n let mut month: u32 = 1;\n for i in 0..12 {\n let advance = day_of_year >= days_at_month_start[i + 1];\n month = if advance { month + 1 } else { month };\n }\n\n let day = day_of_year - days_at_month_start[(month - 1) as u32] + 1;\n Date::new(best_year, month as u8, day as u8)\n }\n\n pub fn add_years(self: Self, years: u32) -> Self {\n let mut newYear = self.year + years;\n let mut newMonth = self.month;\n let mut newDay = self.day;\n Self::check_for_leap_year_adjustment(newYear, newMonth, newDay)\n }\n\n pub fn sub_years(self: Self, years: u32) -> Self {\n let mut newYear = self.year - years;\n let mut newMonth = self.month;\n let mut newDay = self.day;\n Self::check_for_leap_year_adjustment(newYear, newMonth, newDay)\n }\n\n pub fn add_months(self: Self, months: u32) -> Self {\n let mut newMonth = self.month as u32 + months;\n let mut newYear = self.year;\n let mut newDay = self.day;\n let yearToAdd = (newMonth - 1) / 12;\n if newMonth > 12 {\n newYear += yearToAdd as u32;\n newMonth -= 12 * yearToAdd;\n }\n if newDay > self.get_days_in_month(newMonth as u8) {\n newDay = self.get_days_in_month(newMonth as u8);\n }\n Self::check_for_leap_year_adjustment(newYear, newMonth as u8, newDay)\n }\n\n pub fn sub_months(self: Self, months: u32) -> Self {\n let mut newMonth = self.month as i32 - months as i32;\n let mut newYear = self.year;\n let mut newDay = self.day;\n if newMonth < 1 {\n let yearToSub = ((newMonth as i32 - 12 as i32) * -1) / 12;\n newYear -= yearToSub as u32;\n newMonth += 12 * yearToSub;\n }\n if newDay > self.get_days_in_month(newMonth as u8) {\n newDay = self.get_days_in_month(newMonth as u8);\n }\n Self::check_for_leap_year_adjustment(newYear, newMonth as u8, newDay)\n }\n\n pub fn add_days(self: Self, days: u64) -> Self {\n // Convert current date to days since year 1\n let current_days = self.to_days_since_year_one();\n\n // Add the desired number of days\n let new_total_days = current_days + days;\n\n // Convert back to a date\n Date::from_days_since_year_one(new_total_days)\n }\n\n pub fn sub_days(self: Self, days: u64) -> Self {\n // Convert current date to days since year 1\n let current_days = self.to_days_since_year_one();\n\n // Ensure we don't go below year 1\n assert(current_days >= days, \"Cannot subtract more days than have passed since year 1\");\n\n // Subtract the desired number of days\n let new_total_days = current_days - days;\n\n // Convert back to a date\n Date::from_days_since_year_one(new_total_days)\n }\n}\n\nimpl Eq for Date {\n fn eq(self: Self, other: Self) -> bool {\n self.eq(other)\n }\n}\n","path":"/home/heeckhau/nargo/github.com/madztheo/noir-date.git/v0.5.6/src/date.nr"},"65":{"source":"use std::hash::sha256_compression;\nuse std::runtime::is_unconstrained;\n\nuse constants::{\n BLOCK_BYTE_PTR, BLOCK_SIZE, HASH, INITIAL_STATE, INT_BLOCK_SIZE, INT_SIZE, INT_SIZE_PTR,\n MSG_BLOCK, MSG_SIZE_PTR, STATE, TWO_POW_16, TWO_POW_24, TWO_POW_32, TWO_POW_8,\n};\n\npub(crate) mod constants;\nmod tests;\nmod oracle_tests;\n\n// Implementation of SHA-256 mapping a byte array of variable length to\n// 32 bytes.\n\n// Deprecated in favour of `sha256_var`\n// docs:start:sha256\npub fn sha256(input: [u8; N]) -> HASH\n// docs:end:sha256\n{\n digest(input)\n}\n\n// SHA-256 hash function\n#[no_predicates]\npub fn digest(msg: [u8; N]) -> HASH {\n sha256_var(msg, N)\n}\n\n// Variable size SHA-256 hash\npub fn sha256_var(msg: [u8; N], message_size: u32) -> HASH {\n assert(message_size <= N);\n\n let (h, msg_block) = process_full_blocks(msg, message_size, INITIAL_STATE);\n\n finalize_sha256_blocks(message_size, h, msg_block)\n}\n\n/// Returns the first partially filled message block along with the internal state prior to its compression.\npub(crate) fn process_full_blocks(\n msg: [u8; N],\n message_size: u32,\n initial_state: STATE,\n) -> (STATE, MSG_BLOCK) {\n if std::runtime::is_unconstrained() {\n let num_full_blocks = message_size / BLOCK_SIZE;\n // Intermediate hash, starting with the canonical initial value\n let mut h: STATE = initial_state;\n // Pointer into msg_block on a 64 byte scale\n for i in 0..num_full_blocks {\n let msg_block = build_msg_block(msg, message_size, BLOCK_SIZE * i);\n h = sha256_compression(msg_block, h);\n }\n\n // We now build the final un-filled block.\n let msg_byte_ptr = message_size % BLOCK_SIZE;\n let msg_block: MSG_BLOCK = if msg_byte_ptr != 0 {\n let num_full_blocks = message_size / BLOCK_SIZE;\n let msg_start = BLOCK_SIZE * num_full_blocks;\n build_msg_block(msg, message_size, msg_start)\n } else {\n // If the message size is a multiple of the block size (i.e. `msg_byte_ptr == 0`) then this block will be empty,\n // so we short-circuit in this case.\n [0; 16]\n };\n\n (h, msg_block)\n } else {\n let num_blocks = N / BLOCK_SIZE;\n\n // We store the intermediate hash states and message blocks in these two arrays which allows us to select the correct state\n // for the given message size with a lookup.\n //\n // These can be reasoned about as followed:\n // Consider a message with an unknown number of bytes, `msg_size. It can be seen that this will have `msg_size / BLOCK_SIZE` full blocks.\n // - `states[i]` should then be the state after processing the first `i` blocks.\n // - `blocks[i]` should then be the next message block after processing the first `i` blocks.\n // blocks[first_partially_filled_block_index] is the last block that is partially filled or all 0 if the message is a multiple of the block size.\n //\n // In other words:\n //\n // blocks = [block 1, block 2, ..., block N / BLOCK_SIZE, block N / BLOCK_SIZE + 1]\n // states = [INITIAL_STATE, state after block 1, state after block 2, ..., state after block N / BLOCK_SIZE]\n //\n // We place the initial state in `states[0]` as in the case where the `message_size < BLOCK_SIZE` then there are no full blocks to process and no compressions should occur.\n let mut blocks: [MSG_BLOCK; N / BLOCK_SIZE + 1] = std::mem::zeroed();\n let mut states: [STATE; N / BLOCK_SIZE + 1] = [initial_state; N / BLOCK_SIZE + 1];\n\n // Optimization for small messages. If the largest possible message is smaller than a block then we know that the first block is partially filled\n // no matter the value of `message_size`.\n //\n // Note that the condition `N >= BLOCK_SIZE` is known during monomorphization so this has no runtime cost.\n let first_partially_filled_block_index = if N >= BLOCK_SIZE {\n message_size / BLOCK_SIZE\n } else {\n 0\n };\n\n for i in 0..num_blocks {\n let msg_start = BLOCK_SIZE * i;\n let new_msg_block = build_msg_block(msg, message_size, msg_start);\n\n blocks[i] = new_msg_block;\n states[i + 1] = sha256_compression(new_msg_block, states[i]);\n }\n // If message_size/BLOCK_SIZE == N/BLOCK_SIZE, and there is a remainder, we need to process the last block.\n if N % BLOCK_SIZE != 0 {\n let new_msg_block = build_msg_block(msg, message_size, BLOCK_SIZE * num_blocks);\n\n blocks[num_blocks] = new_msg_block;\n }\n\n (states[first_partially_filled_block_index], blocks[first_partially_filled_block_index])\n }\n}\n\n// Take `BLOCK_SIZE` number of bytes from `msg` starting at `msg_start` and pack them into a `MSG_BLOCK`.\npub(crate) unconstrained fn build_msg_block_helper(\n msg: [u8; N],\n message_size: u32,\n msg_start: u32,\n) -> MSG_BLOCK {\n let mut msg_block: MSG_BLOCK = [0; INT_BLOCK_SIZE];\n\n // We insert `BLOCK_SIZE` bytes (or up to the end of the message)\n let block_input = if message_size < msg_start {\n // This function is sometimes called with `msg_start` past the end of the message.\n // In this case we return an empty block and zero pointer to signal that the result should be ignored.\n 0\n } else if message_size < msg_start + BLOCK_SIZE {\n message_size - msg_start\n } else {\n BLOCK_SIZE\n };\n\n // Figure out the number of items in the int array that we have to pack.\n // e.g. if the input is [0,1,2,3,4,5] then we need to pack it as 2 items: [0123, 4500]\n let int_input = (block_input + INT_SIZE - 1) / INT_SIZE;\n\n for i in 0..int_input {\n let mut msg_item: u32 = 0;\n // Always construct the integer as 4 bytes, even if it means going beyond the input.\n for j in 0..INT_SIZE {\n let k = i * INT_SIZE + j;\n let msg_byte = if k < block_input {\n msg[msg_start + k]\n } else {\n 0\n };\n msg_item = (msg_item << 8) + msg_byte as u32;\n }\n msg_block[i] = msg_item;\n }\n\n // Returning the index as if it was a 64 byte array.\n // We have to project it down to 16 items and bit shifting to get a byte back if we need it.\n msg_block\n}\n\n// Build a message block from the input message starting at `msg_start`.\n//\n// If `message_size` is less than `msg_start` then this is called with the old non-empty block;\n// in that case we can skip verification, ie. no need to check that everything is zero.\nfn build_msg_block(msg: [u8; N], message_size: u32, msg_start: u32) -> MSG_BLOCK {\n let msg_block =\n // Safety: We constrain the block below by reconstructing each `u32` word from the input bytes.\n unsafe { build_msg_block_helper(msg, message_size, msg_start) };\n\n if !is_unconstrained() {\n let mut msg_end = msg_start + BLOCK_SIZE;\n\n let max_read_index = std::cmp::min(message_size, msg_end);\n\n // Reconstructed packed item\n let mut msg_item: Field = 0;\n\n // Inclusive at the end so that we can compare the last item.\n for k in msg_start..=msg_end {\n if (k != msg_start) & (k % INT_SIZE == 0) {\n // If we consumed some input we can compare against the block.\n let msg_block_index = (k - msg_start) / INT_SIZE - 1;\n assert_eq(msg_block[msg_block_index] as Field, msg_item);\n\n msg_item = 0;\n }\n\n // If we have input to consume, add it at the rightmost position.\n let msg_byte = if k < max_read_index { msg[k] } else { 0 };\n msg_item = msg_item * (TWO_POW_8 as Field) + msg_byte as Field;\n }\n }\n msg_block\n}\n\n// Encode `8 * message_size` into two `u32` limbs.\nunconstrained fn encode_len(message_size: u32) -> (u32, u32) {\n let len = 8 * message_size as u64;\n let lo = len & 0xFFFFFFFF;\n let hi = (len >> 32) & 0xFFFFFFFF;\n (lo as u32, hi as u32)\n}\n\n// Write the length into the last 8 bytes of the block.\nfn attach_len_to_msg_block(mut msg_block: MSG_BLOCK, message_size: u32) -> MSG_BLOCK {\n // Safety: We assert the correctness of the decomposition below.\n // 2 `u32` limbs cannot overflow the field modulus so performing the check as `Field`s is safe.\n let (lo, hi) = unsafe { encode_len(message_size) };\n assert_eq(8 * (message_size as Field), lo as Field + hi as Field * TWO_POW_32);\n\n msg_block[INT_SIZE_PTR] = hi;\n msg_block[INT_SIZE_PTR + 1] = lo;\n msg_block\n}\n\n// Perform the final compression, then transform the `STATE` into `HASH`.\nfn hash_final_block(msg_block: MSG_BLOCK, mut state: STATE) -> HASH {\n // Hash final padded block\n state = sha256_compression(msg_block, state);\n\n // Return final hash as byte array\n let mut out_h: HASH = [0; 32]; // Digest as sequence of bytes\n for j in 0..8 {\n let h_bytes: [u8; 4] = (state[j] as Field).to_be_bytes();\n for k in 0..4 {\n out_h[4 * j + k] = h_bytes[k];\n }\n }\n\n out_h\n}\n\n/// Lookup table for the position of the padding bit within one of the `u32` words in the final message block.\nglobal PADDING_BIT_TABLE: [u32; 4] =\n [(1 << 7) * TWO_POW_24, (1 << 7) * TWO_POW_16, (1 << 7) * TWO_POW_8, (1 << 7)];\n\n/// Add 1 bit padding to end of message and compress the block if there's not enough room for the 8-byte length.\n/// Returns the updated hash state and message block that will be used to write the message size.\n///\n/// # Assumptions:\n///\n/// - `msg_block[i] == 0` for all `i > msg_byte_ptr / INT_SIZE`\n/// - `msg_block[msg_byte_ptr / INT_SIZE] & ((1 << 7) * (msg_byte_ptr % INT_SIZE)) == 0`\nfn add_padding_byte_and_compress_if_needed(\n mut msg_block: MSG_BLOCK,\n msg_byte_ptr: BLOCK_BYTE_PTR,\n h: STATE,\n) -> (STATE, MSG_BLOCK) {\n // Pad the rest such that we have a [u32; 2] block at the end representing the length\n // of the message, and a block of 1 0 ... 0 following the message (i.e. [1 << 7, 0, ..., 0]).\n // Here we rely on the fact that everything beyond the available input is set to 0.\n let index = msg_byte_ptr / INT_SIZE;\n\n // Lookup the position of the padding bit and insert it into the message block.\n msg_block[index] += PADDING_BIT_TABLE[msg_byte_ptr % INT_SIZE];\n\n // If we don't have room to write the size, compress the block and reset it.\n if msg_byte_ptr >= MSG_SIZE_PTR {\n let h = sha256_compression(msg_block, h);\n\n // In this case, the final block consists of all zeros with the last 8 bytes containing the length.\n // We set msg_block to all zeros and attach_len_to_msg_block will add the length to the last 8 bytes.\n let msg_block = [0; INT_BLOCK_SIZE];\n (h, msg_block)\n } else {\n (h, msg_block)\n }\n}\n\npub(crate) fn finalize_sha256_blocks(\n message_size: u32,\n mut h: STATE,\n mut msg_block: MSG_BLOCK,\n) -> HASH {\n let msg_byte_ptr = message_size % BLOCK_SIZE;\n\n let (h, mut msg_block) = add_padding_byte_and_compress_if_needed(msg_block, msg_byte_ptr, h);\n\n msg_block = attach_len_to_msg_block(msg_block, message_size);\n\n hash_final_block(msg_block, h)\n}\n\n/**\n * Given some state of a partially computed sha256 hash and part of the preimage, continue hashing\n * @notice used for complex/ recursive offloading of post-partial hashing\n *\n * @param N - the maximum length of the message to hash\n * @param h - the intermediate hash state\n * @param msg - the preimage to hash\n * @param message_size - the actual length of the preimage to hash\n * @return the intermediate hash state after compressing in msg to h\n */\npub fn partial_sha256_var_interstitial(\n mut h: [u32; 8],\n msg: [u8; N],\n message_size: u32,\n) -> [u32; 8] {\n assert(message_size % BLOCK_SIZE == 0, \"Message size must be a multiple of the block size\");\n if std::runtime::is_unconstrained() {\n // Safety: running as an unconstrained function\n unsafe {\n __sha_partial_var_interstitial(h, msg, message_size)\n }\n } else {\n let (h, _) = process_full_blocks(msg, message_size, h);\n\n h\n }\n}\n\n/**\n * Given some state of a partially computed sha256 hash and remaining preimage, complete the hash\n * @notice used for traditional partial hashing\n *\n * @param N - the maximum length of the message to hash\n * @param h - the intermediate hash state\n * @param msg - the remaining preimage to hash\n * @param message_size - the size of the current chunk\n * @param real_message_size - the total size of the original preimage\n * @return finalized sha256 hash\n */\npub fn partial_sha256_var_end(\n mut h: [u32; 8],\n msg: [u8; N],\n message_size: u32,\n real_message_size: u32,\n) -> [u8; 32] {\n assert(message_size % BLOCK_SIZE == 0, \"Message size must be a multiple of the block size\");\n if std::runtime::is_unconstrained() {\n // Safety: running as an unconstrained function\n unsafe {\n h = __sha_partial_var_interstitial(h, msg, message_size);\n\n // Handle setup of the final msg block.\n // This case is only hit if the msg is less than the block size,\n // or our message cannot be evenly split into blocks.\n\n finalize_last_sha256_block(h, real_message_size, msg)\n }\n } else {\n let (h, msg_block) = process_full_blocks(msg, message_size, h);\n finalize_sha256_blocks(real_message_size, h, msg_block)\n }\n}\n\nunconstrained fn __sha_partial_var_interstitial(\n mut h: [u32; 8],\n msg: [u8; N],\n message_size: u32,\n) -> [u32; 8] {\n let num_full_blocks = message_size / BLOCK_SIZE;\n // Intermediate hash, starting with the canonical initial value\n // Pointer into msg_block on a 64 byte scale\n for i in 0..num_full_blocks {\n let msg_block = build_msg_block(msg, message_size, BLOCK_SIZE * i);\n h = sha256_compression(msg_block, h);\n }\n h\n}\n\n// Helper function to finalize the message block with padding and length\nunconstrained fn finalize_last_sha256_block(\n mut h: STATE,\n message_size: u32,\n msg: [u8; N],\n) -> HASH {\n let msg_byte_ptr = message_size % BLOCK_SIZE;\n\n // We now build the final un-filled block.\n let msg_block: MSG_BLOCK = if msg_byte_ptr != 0 {\n let num_full_blocks = message_size / BLOCK_SIZE;\n let msg_start = BLOCK_SIZE * num_full_blocks;\n build_msg_block(msg, message_size, msg_start)\n } else {\n // If the message size is a multiple of the block size (i.e. `msg_byte_ptr == 0`) then this block will be empty,\n // so we short-circuit in this case.\n [0; 16]\n };\n\n // Once built, we need to add the necessary padding bytes and encoded length\n let (h, mut msg_block) = add_padding_byte_and_compress_if_needed(msg_block, msg_byte_ptr, h);\n msg_block = attach_len_to_msg_block(msg_block, message_size);\n\n hash_final_block(msg_block, h)\n}\n\nmod test_process_full_blocks {\n\n /// Wrapper to force an unconstrained runtime on process_full_blocks.\n unconstrained fn unconstrained_process_full_blocks(\n msg: [u8; N],\n message_size: u32,\n h: super::STATE,\n ) -> (super::STATE, super::MSG_BLOCK) {\n super::process_full_blocks(msg, message_size, h)\n }\n\n #[test]\n fn test_implementations_agree(msg: [u8; 100], message_size: u32) {\n let message_size = message_size % 100;\n // Safety: test function\n let unconstrained_state =\n unsafe { unconstrained_process_full_blocks(msg, message_size, super::INITIAL_STATE) };\n let state = super::process_full_blocks(msg, message_size, super::INITIAL_STATE);\n assert_eq(state, unconstrained_state);\n }\n}\n\nmod test_sha256_var {\n\n /// Wrapper to force an unconstrained runtime on sha256.\n unconstrained fn unconstrained_sha256(\n msg: [u8; N],\n message_size: u32,\n ) -> super::HASH {\n super::sha256_var(msg, message_size)\n }\n\n #[test]\n fn test_implementations_agree(msg: [u8; 100], message_size: u32) {\n let message_size = message_size % 100;\n // Safety: test function\n let unconstrained_sha = unsafe { unconstrained_sha256(msg, message_size) };\n let sha = super::sha256_var(msg, message_size);\n assert_eq(sha, unconstrained_sha);\n }\n\n}\n","path":"/home/heeckhau/nargo/github.com/noir-lang/sha256/v0.3.0/src/sha256.nr"}}} \ No newline at end of file diff --git a/crates/examples/basic_zk/verifier.rs b/crates/examples/basic_zk/verifier.rs index 52b714407b..ceb9ad15f0 100644 --- a/crates/examples/basic_zk/verifier.rs +++ b/crates/examples/basic_zk/verifier.rs @@ -166,23 +166,31 @@ pub async fn verifier let proof = msg.proof.clone(); - // Validate proof has enough data. - // The proof should start with the public inputs: - // * We expect at least 3 * 32 bytes for the three date fields (day, month, - // year) - // * and 32*32 bytes for the hash - let min_bytes = (32 + 3) * 32; + // noir-rs returns proofs as `[4-byte BE + // num_public_inputs][public_inputs][proof]`, where each public input is a + // 32-byte field element. We expect 35 public inputs: 3 date fields (day, + // month, year) + 32 hash bytes. + const EXPECTED_NUM_PUB: u32 = 3 + 32; + const PREFIX_LEN: usize = 4; + let min_bytes = PREFIX_LEN + (EXPECTED_NUM_PUB as usize) * 32; if proof.len() < min_bytes { return Err(anyhow::anyhow!( "Proof too short: expected at least {min_bytes} bytes, got {}", proof.len() )); } + let num_pub = u32::from_be_bytes(proof[0..PREFIX_LEN].try_into()?); + if num_pub != EXPECTED_NUM_PUB { + return Err(anyhow::anyhow!( + "Unexpected public input count in proof: got {num_pub}, expected {EXPECTED_NUM_PUB}" + )); + } + let public_inputs = &proof[PREFIX_LEN..PREFIX_LEN + (num_pub as usize) * 32]; // Check that the proof date is correctly included in the proof - let proof_date_day: u32 = u32::from_be_bytes(proof[28..32].try_into()?); - let proof_date_month: u32 = u32::from_be_bytes(proof[60..64].try_into()?); - let proof_date_year: i32 = i32::from_be_bytes(proof[92..96].try_into()?); + let proof_date_day: u32 = u32::from_be_bytes(public_inputs[28..32].try_into()?); + let proof_date_month: u32 = u32::from_be_bytes(public_inputs[60..64].try_into()?); + let proof_date_year: i32 = i32::from_be_bytes(public_inputs[92..96].try_into()?); let proof_date_from_proof = NaiveDate::from_ymd_opt(proof_date_year, proof_date_month, proof_date_day) .ok_or_else(|| anyhow::anyhow!("Invalid proof date in proof"))?; @@ -194,10 +202,11 @@ pub async fn verifier } // Check that the committed hash in the proof matches the hash from the - // commitment - let committed_hash_in_proof: Vec = proof + // commitment. The hash occupies public inputs 3..35 (one byte per field, + // right-aligned in each 32-byte element). + let committed_hash_in_proof: Vec = public_inputs .chunks(32) - .skip(3) // skip the first 3 chunks + .skip(3) .take(32) .map(|chunk| *chunk.last().unwrap_or(&0)) .collect();