diff --git a/.github/workflows/rustdoc.yml b/.github/workflows/rustdoc.yml index 70531d029..d20975583 100644 --- a/.github/workflows/rustdoc.yml +++ b/.github/workflows/rustdoc.yml @@ -23,7 +23,6 @@ jobs: - name: "rustdoc" run: crates/wasm/build-docs.sh - - name: Deploy uses: peaceiris/actions-gh-pages@v3 if: ${{ github.ref == 'refs/heads/dev' }} diff --git a/Cargo.lock b/Cargo.lock index 2d9437c77..db21af1ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,77 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "acir" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acir_field", + "base64 0.22.1", + "bincode 2.0.1", + "brillig", + "color-eyre", + "flate2", + "noir_protobuf", + "num_enum", + "prost", + "prost-build", + "protoc-prebuilt", + "rmp-serde", + "serde", + "serde-big-array", + "strum 0.24.1", + "strum_macros 0.24.3", + "thiserror 1.0.69", +] + +[[package]] +name = "acir_field" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "ark-bn254", + "ark-ff 0.5.0", + "ark-std 0.5.0", + "cfg-if", + "hex", + "num-bigint", + "serde", +] + +[[package]] +name = "acvm" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acir", + "acvm_blackbox_solver", + "brillig_vm", + "fxhash", + "indexmap 2.11.4", + "serde", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "acvm_blackbox_solver" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acir", + "blake2", + "blake3", + "k256", + "keccak", + "libaes", + "log", + "num-bigint", + "p256", + "sha2", + "thiserror 1.0.69", +] + [[package]] name = "addr2line" version = "0.24.2" @@ -103,22 +174,24 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-consensus" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fbf458101ed6c389e9bb70a34ebc56039868ad10472540614816cdedc8f5265" +checksum = "b190875b4e4d8838a49e9c1489a27c07583232a269a1a625a8260049134bd6be" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", "alloy-trie", + "alloy-tx-macros", "auto_impl", "c-kzg", - "derive_more 2.0.1", + "derive_more", "either", "k256", "once_cell", "rand 0.8.5", + "secp256k1", "serde", "serde_with", "thiserror 2.0.16", @@ -126,9 +199,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc982af629e511292310fe85b433427fd38cb3105147632b574abc997db44c91" +checksum = "545370c7dc047fa2c632a965b76bb429cc24674d2fcddacdcb0d998b09731b9e" dependencies = [ "alloy-consensus", "alloy-eips", @@ -140,9 +213,9 @@ dependencies = [ [[package]] name = "alloy-eip2124" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675264c957689f0fd75f5993a73123c2cc3b5c235a38f5b9037fe6c826bfb2c0" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -153,9 +226,9 @@ dependencies = [ [[package]] name = "alloy-eip2930" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +checksum = "7b82752a889170df67bbb36d42ca63c531eb16274f0d7299ae2a680facba17bd" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -164,9 +237,9 @@ dependencies = [ [[package]] name = "alloy-eip7702" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b15b13d38b366d01e818fe8e710d4d702ef7499eacd44926a06171dd9585d0c" +checksum = "9d4769c6ffddca380b0070d71c8b7f30bed375543fe76bb2f74ec0acf4b7cd16" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -176,9 +249,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e86967eb559920e4b9102e4cb825fe30f2e9467988353ce4809f0d3f2c90cd4" +checksum = "2a33d1723ecf64166c2a0371e25d1bce293b873527a7617688c9375384098ea1" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -188,18 +261,19 @@ dependencies = [ "alloy-serde", "auto_impl", "c-kzg", - "derive_more 2.0.1", + "derive_more", "either", - "once_cell", "serde", + "serde_with", "sha2", + "thiserror 2.0.16", ] [[package]] name = "alloy-json-abi" -version = "0.8.25" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6beff64ad0aa6ad1019a3db26fef565aefeb011736150ab73ed3366c3cfd1b" +checksum = "125a1c373261b252e53e04d6e92c37d881833afc1315fceab53fd46045695640" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -209,12 +283,13 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27434beae2514d4a2aa90f53832cbdf6f23e4b5e2656d95eaf15f9276e2418b6" +checksum = "d24aba9adc7e22cec5ae396980cac73792f5cb5407dc1efc07292e7f96fb65d5" dependencies = [ "alloy-primitives", "alloy-sol-types", + "http 1.3.1", "serde", "serde_json", "thiserror 2.0.16", @@ -223,9 +298,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a33a38c7486b1945f8d093ff027add2f3a8f83c7300dbad6165cc49150085e" +checksum = "c3e52ba8f09d0c31765582cd7f39ede2dfba5afa159f1376afc29c9157564246" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -240,7 +315,7 @@ dependencies = [ "alloy-sol-types", "async-trait", "auto_impl", - "derive_more 2.0.1", + "derive_more", "futures-utils-wasm", "serde", "serde_json", @@ -249,9 +324,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db973a7a23cbe96f2958e5687c51ce2d304b5c6d0dc5ccb3de8667ad8476f50b" +checksum = "f37bf78f46f2717973639c4f11e6330691fea62c4d116d720e0dcfd49080c126" dependencies = [ "alloy-consensus", "alloy-eips", @@ -262,24 +337,24 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.25" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c77490fe91a0ce933a1f219029521f20fc28c2c0ca95d53fa4da9c00b8d9d4e" +checksum = "bc9485c56de23438127a731a6b4c87803d49faf1a7068dcd1d8768aca3a9edb9" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", - "derive_more 2.0.1", + "derive_more", "foldhash", "hashbrown 0.15.5", - "indexmap 2.11.1", + "indexmap 2.11.4", "itoa", "k256", "keccak-asm", "paste", "proptest", - "rand 0.8.5", + "rand 0.9.2", "ruint", "rustc-hash", "serde", @@ -311,9 +386,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604dea1f00fd646debe8033abe8e767c732868bf8a5ae9df6321909ccbc99c56" +checksum = "c14ba5de4025eb7ce19a5c19706b3c2fd86a0b4f9ad8c9ef0dce0d5e66be7157" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -322,9 +397,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e13d71eac04513a71af4b3df580f52f2b4dcbff9d971cc9a52519acf55514cb" +checksum = "7357279a96304232d37adbe2064a9392dddd9b0e8beca2a12a8fc0872c8a81dd" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -337,14 +412,15 @@ dependencies = [ "itertools 0.14.0", "serde", "serde_json", + "serde_with", "thiserror 2.0.16", ] [[package]] name = "alloy-serde" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1cd73fc054de6353c7f22ff9b846b0f0f145cd0112da07d4119e41e9959207" +checksum = "5f0ee5af728e144e0e5bde52114c7052249a9833d9fba79aeacfbdee1aad69e8" dependencies = [ "alloy-primitives", "serde", @@ -353,9 +429,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96fbde54bee943cd94ebacc8a62c50b38c7dfd2552dcd79ff61aea778b1bfcc" +checksum = "0efbce76baf1b012e379a5e486822c71b0de0a957ddedd5410427789516a47b9" dependencies = [ "alloy-primitives", "async-trait", @@ -368,9 +444,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "0.12.6" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6e72002cc1801d8b41e9892165e3a6551b7bd382bd9d0414b21e90c0c62551" +checksum = "f52345adc3b784889659ff2930c02047974916b6aacbf0ae013ee6578d2df266" dependencies = [ "alloy-consensus", "alloy-network", @@ -384,9 +460,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.8.25" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10ae8e9a91d328ae954c22542415303919aabe976fe7a92eb06db1b68fd59f2" +checksum = "d20d867dcf42019d4779519a1ceb55eba8d7f3d0e4f0a89bcba82b8f9eb01e48" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -398,14 +474,14 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "0.8.25" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ad5da86c127751bc607c174d6c9fe9b85ef0889a9ca0c641735d77d4f98f26" +checksum = "b74e91b0b553c115d14bd0ed41898309356dc85d0e3d4b9014c4e7715e48c8ad" dependencies = [ "alloy-sol-macro-input", "const-hex", "heck 0.5.0", - "indexmap 2.11.1", + "indexmap 2.11.4", "proc-macro-error2", "proc-macro2", "quote", @@ -416,9 +492,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "0.8.25" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3d30f0d3f9ba3b7686f3ff1de9ee312647aac705604417a2f40c604f409a9e" +checksum = "84194d31220803f5f62d0a00f583fd3a062b36382e2bea446f1af96727754565" dependencies = [ "const-hex", "dunce", @@ -432,43 +508,55 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "0.8.25" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c" +checksum = "fe8c27b3cf6b2bb8361904732f955bc7c05e00be5f469cec7e2280b6167f3ff0" dependencies = [ "serde", - "winnow", + "winnow 0.7.13", ] [[package]] name = "alloy-sol-types" -version = "0.8.25" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43d5e60466a440230c07761aa67671d4719d46f43be8ea6e7ed334d8db4a9ab" +checksum = "f5383d34ea00079e6dd89c652bcbdb764db160cef84e6250926961a0b2295d04" dependencies = [ "alloy-json-abi", "alloy-primitives", "alloy-sol-macro", - "const-hex", "serde", ] [[package]] name = "alloy-trie" -version = "0.7.9" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a94854e420f07e962f7807485856cde359ab99ab6413883e15235ad996e8b" +checksum = "e3412d52bb97c6c6cc27ccc28d4e6e8cf605469101193b50b0bd5813b1f990b5" dependencies = [ "alloy-primitives", "alloy-rlp", "arrayvec", - "derive_more 1.0.0", + "derive_more", "nybbles", "serde", "smallvec", "tracing", ] +[[package]] +name = "alloy-tx-macros" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb91a93165a8646618ae6366f301ec1edd52f452665c371e12201516593925a0" +dependencies = [ + "alloy-primitives", + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -540,6 +628,17 @@ version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-std 0.5.0", +] + [[package]] name = "ark-ec" version = "0.4.2" @@ -547,7 +646,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ "ark-ff 0.4.2", - "ark-poly", + "ark-poly 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", "derivative", @@ -557,6 +656,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "zeroize", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -595,6 +715,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -615,6 +755,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.106", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -640,6 +790,31 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "ark-grumpkin" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef677b59f5aff4123207c4dceb1c0ec8fdde2d4af7886f48be42ad864bfa0352" +dependencies = [ + "ark-bn254", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-std 0.5.0", +] + [[package]] name = "ark-poly" version = "0.4.2" @@ -653,13 +828,28 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", +] + [[package]] name = "ark-secp256r1" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" dependencies = [ - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-std 0.4.0", ] @@ -680,12 +870,25 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ - "ark-serialize-derive", + "ark-serialize-derive 0.4.2", "ark-std 0.4.0", "digest 0.10.7", "num-bigint", ] +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint", +] + [[package]] name = "ark-serialize-derive" version = "0.4.2" @@ -697,6 +900,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -717,6 +931,16 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -806,11 +1030,11 @@ dependencies = [ [[package]] name = "async-io" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", @@ -819,7 +1043,7 @@ dependencies = [ "polling", "rustix 1.1.2", "slab", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -835,9 +1059,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel 2.5.0", "async-io", @@ -853,9 +1077,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ "async-io", "async-lock", @@ -866,7 +1090,7 @@ dependencies = [ "rustix 1.1.2", "signal-hook-registry", "slab", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -968,29 +1192,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "aws-lc-rs" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd" -dependencies = [ - "bindgen 0.72.1", - "cc", - "cmake", - "dunce", - "fs_extra", -] - [[package]] name = "axum" version = "0.7.9" @@ -1181,9 +1382,22 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.8.0" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +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" @@ -1204,6 +1418,12 @@ dependencies = [ "serde", ] +[[package]] +name = "binary-merge" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597bb81c80a54b6a4381b23faba8d7774b144c94cbd1d6fe3f1329bd776554ab" + [[package]] name = "bincode" version = "1.3.3" @@ -1214,30 +1434,30 @@ dependencies = [ ] [[package]] -name = "bindgen" -version = "0.71.1" +name = "bincode" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.106", + "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.72.1" +version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ "bitflags", "cexpr", @@ -1268,12 +1488,37 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + [[package]] name = "bitflags" version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + [[package]] name = "bitvec" version = "1.0.1" @@ -1287,6 +1532,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "blake3" version = "1.8.2" @@ -1336,6 +1590,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "bn254_blackbox_solver" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acir", + "acvm_blackbox_solver", + "ark-bn254", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-grumpkin", + "hex", + "lazy_static", + "num-bigint", +] + [[package]] name = "bon" version = "3.7.2" @@ -1361,6 +1631,46 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "cfg_aliases", +] + +[[package]] +name = "brillig" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acir_field", + "serde", +] + +[[package]] +name = "brillig_vm" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acir", + "acvm_blackbox_solver", + "num-bigint", + "num-traits", + "thiserror 1.0.69", +] + +[[package]] +name = "build-data" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e6d5ca7a4989b90a9fafea85ce3c8bc9f0e0a76edcdcb330fe0c4fda92251f" +dependencies = [ + "chrono", + "safe-regex", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -1416,9 +1726,9 @@ checksum = "2e93abca9e28e0a1b9877922aacb20576e05d4679ffa78c3d6dc22a26a216659" [[package]] name = "c-kzg" -version = "1.0.3" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +checksum = "7318cfa722931cb5fe0838b98d3ce5621e75f6a6408abc21721d80de9223f2e4" dependencies = [ "blst", "cc", @@ -1457,13 +1767,11 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.36" +version = "1.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" dependencies = [ "find-msvc-tools", - "jobserver", - "libc", "shlex", ] @@ -1482,6 +1790,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "charming" version = "0.5.1" @@ -1496,6 +1810,15 @@ 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" @@ -1695,12 +2018,51 @@ dependencies = [ ] [[package]] -name = "cmake" -version = "0.1.54" +name = "codespan" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "3362992a0d9f1dd7c3d0e89e0ab2bb540b7a95fea8cd798090e758fda2899b5e" dependencies = [ - "cc", + "codespan-reporting", + "serde", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + +[[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]] @@ -1730,15 +2092,14 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dccd746bf9b1038c0507b7cec21eb2b11222db96a2902c96e8c185d6d20fb9c4" +checksum = "b6407bff74dea37e0fa3dc1c1c974e5d46405f0c987bf9997a0762adce71eda6" dependencies = [ "cfg-if", "cpufeatures", - "hex", "proptest", - "serde", + "serde_core", ] [[package]] @@ -2082,6 +2443,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", + "serde", "strsim 0.11.1", "syn 2.0.106", ] @@ -2143,7 +2505,7 @@ checksum = "7902cd1dde9e8ffc953428933f37f9b943dc123265709220cded6277946cadf7" dependencies = [ "anyhow", "az", - "bincode", + "bincode 1.3.3", "bit-set", "bit-vec", "bytes", @@ -2155,7 +2517,7 @@ dependencies = [ "deno_path_util", "deno_unsync", "futures", - "indexmap 2.11.1", + "indexmap 2.11.4", "libc", "parking_lot", "percent-encoding", @@ -2210,13 +2572,13 @@ version = "0.224.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55db7994eccbdad457ca5091c545af712234c8f6e4389cadb2a24d2ecbbe7e89" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "proc-macro-rules", "proc-macro2", "quote", "stringcase", - "strum", - "strum_macros", + "strum 0.27.2", + "strum_macros 0.27.2", "syn 2.0.106", "thiserror 2.0.16", ] @@ -2370,33 +2732,13 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "derive_more" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" -dependencies = [ - "derive_more-impl 1.0.0", -] - [[package]] name = "derive_more" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" dependencies = [ - "derive_more-impl 2.0.1", -] - -[[package]] -name = "derive_more-impl" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", + "derive_more-impl", ] [[package]] @@ -2488,6 +2830,18 @@ dependencies = [ "spki", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "either" version = "1.15.0" @@ -2519,6 +2873,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "enum-try-as-inner" version = "0.1.1" @@ -2587,6 +2961,16 @@ 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" @@ -2633,9 +3017,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] name = "fixed-hash" @@ -2649,6 +3033,32 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fm" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "codespan-reporting", + "iter-extended", + "serde", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2670,12 +3080,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "fslock" version = "0.2.1" @@ -2766,12 +3170,12 @@ dependencies = [ [[package]] name = "futures-rustls" -version = "0.26.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" +checksum = "c8d8a2499f0fecc0492eb3e47eab4e92da7875e1028ad2528f214ac3346ca04e" dependencies = [ "futures-io", - "rustls 0.23.31", + "rustls 0.22.4", "rustls-pki-types", ] @@ -2817,6 +3221,15 @@ 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" @@ -2851,7 +3264,7 @@ dependencies = [ "js-sys", "libc", "r-efi", - "wasi 0.14.5+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", "wasm-bindgen", ] @@ -2944,7 +3357,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.3.1", - "indexmap 2.11.1", + "indexmap 2.11.4", "slab", "tokio", "tokio-util", @@ -3008,10 +3421,18 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ + "allocator-api2", + "equivalent", "foldhash", "serde", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "heck" version = "0.4.1" @@ -3035,8 +3456,14 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" dependencies = [ - "serde", + "arrayvec", ] [[package]] @@ -3169,10 +3596,27 @@ dependencies = [ ] [[package]] -name = "hyper-util" -version = "0.1.16" +name = "hyper-rustls" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.3.1", + "hyper", + "hyper-util", + "rustls 0.23.32", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots 1.0.2", +] + +[[package]] +name = "hyper-util" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64 0.22.1", "bytes", @@ -3196,9 +3640,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3337,6 +3781,21 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd62e6b5e86ea8eeeb8db1de02880a6abc01a397b2ebb64b5d74ac255318f5cb" +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "serde", + "sized-chunks", + "typenum", + "version_check", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -3357,6 +3816,12 @@ dependencies = [ "syn 2.0.106", ] +[[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" @@ -3370,13 +3835,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.1" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "serde", + "serde_core", ] [[package]] @@ -3397,6 +3863,15 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "inplace-vec-builder" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf64c2edc8226891a71f127587a2861b132d2b942310843814d5001d99a1d307" +dependencies = [ + "smallvec", +] + [[package]] name = "inventory" version = "0.3.21" @@ -3453,6 +3928,11 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "iter-extended" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" + [[package]] name = "itertools" version = "0.10.5" @@ -3501,26 +3981,56 @@ dependencies = [ "rayon", ] -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.3", - "libc", -] - [[package]] name = "js-sys" -version = "0.3.78" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" dependencies = [ "once_cell", "wasm-bindgen", ] +[[package]] +name = "jsonrpsee" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fba77a59c4c644fd48732367624d1bcf6f409f9c9a286fbc71d2f1fc0b2ea16" +dependencies = [ + "jsonrpsee-core", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693c93cbb7db25f4108ed121304b671a36002c2db67dff2ee4391a688c738547" +dependencies = [ + "async-trait", + "futures-util", + "http 1.3.1", + "jsonrpsee-types", + "pin-project", + "serde", + "serde_json", + "thiserror 2.0.16", + "tokio", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66df7256371c45621b3b7d2fb23aea923d577616b9c0e9c0b950a6ea5c2be0ca" +dependencies = [ + "http 1.3.1", + "serde", + "serde_json", + "thiserror 2.0.16", +] + [[package]] name = "k256" version = "0.13.4" @@ -3570,6 +4080,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[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.175" @@ -3629,6 +4145,12 @@ dependencies = [ "value-bag", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "ludi" version = "0.1.0" @@ -3741,7 +4263,7 @@ name = "mpz-circuits" version = "0.1.0-alpha.3" source = "git+https://github.com/privacy-ethereum/mpz?rev=3d90b6c#3d90b6cd5ec34f51735d4cebe7988d259d4dc528" dependencies = [ - "bincode", + "bincode 1.3.3", "itybity 0.3.1", "once_cell", "rand 0.9.2", @@ -4094,12 +4616,242 @@ 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" +dependencies = [ + "acvm", + "fm", + "iter-extended", + "jsonrpsee", + "noir_greybox_fuzzer", + "noirc_abi", + "noirc_driver", + "noirc_errors", + "noirc_frontend", + "noirc_printable_type", + "rayon", + "serde", + "serde_json", + "tempfile", + "thiserror 1.0.69", + "tracing", + "walkdir", +] + [[package]] name = "nohash-hasher" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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" +dependencies = [ + "acir", + "acvm", + "acvm_blackbox_solver", + "base64 0.22.1", + "base64ct", + "bb", + "bincode 1.3.3", + "bn254_blackbox_solver", + "clap", + "flate2", + "hex", + "nargo", + "proptest", + "reqwest", + "serde", + "serde_json", + "thiserror 1.0.69", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "noir_greybox_fuzzer" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acvm", + "build-data", + "fm", + "noirc_abi", + "noirc_artifacts", + "num-traits", + "proptest", + "rand 0.8.5", + "rand_xorshift", + "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" +dependencies = [ + "acvm", + "iter-extended", + "noirc_printable_type", + "num-bigint", + "num-traits", + "serde", + "serde_json", + "thiserror 1.0.69", + "toml 0.7.8", +] + +[[package]] +name = "noirc_arena" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" + +[[package]] +name = "noirc_artifacts" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acvm", + "codespan-reporting", + "fm", + "noirc_abi", + "noirc_driver", + "noirc_errors", + "noirc_printable_type", + "serde", +] + +[[package]] +name = "noirc_driver" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acvm", + "build-data", + "clap", + "fm", + "fxhash", + "iter-extended", + "noirc_abi", + "noirc_errors", + "noirc_evaluator", + "noirc_frontend", + "rust-embed", + "serde", + "tracing", +] + +[[package]] +name = "noirc_errors" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acvm", + "base64 0.22.1", + "codespan", + "codespan-reporting", + "flate2", + "fm", + "fxhash", + "noirc_printable_type", + "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" +dependencies = [ + "acvm", + "bn254_blackbox_solver", + "cfg-if", + "chrono", + "fm", + "fxhash", + "im", + "iter-extended", + "noirc_errors", + "noirc_frontend", + "noirc_printable_type", + "num-bigint", + "num-integer", + "num-traits", + "petgraph 0.8.2", + "rayon", + "serde", + "serde_json", + "serde_with", + "smallvec", + "thiserror 1.0.69", + "tracing", + "vec-collections", +] + +[[package]] +name = "noirc_frontend" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acvm", + "bn254_blackbox_solver", + "cfg-if", + "fm", + "fxhash", + "im", + "iter-extended", + "noirc_arena", + "noirc_errors", + "noirc_printable_type", + "num-bigint", + "num-traits", + "petgraph 0.8.2", + "rangemap", + "rustc-hash", + "serde", + "serde_json", + "small-ord-set", + "smol_str", + "strum 0.24.1", + "strum_macros 0.24.3", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "noirc_printable_type" +version = "1.0.0-beta.8" +source = "git+https://github.com/noir-lang/noir.git?rev=b33131574388d836341cea9b6380f3b1a8493eb8#b33131574388d836341cea9b6380f3b1a8493eb8" +dependencies = [ + "acvm", + "iter-extended", + "serde", + "serde_json", +] + [[package]] name = "nom" version = "7.1.3" @@ -4181,14 +4933,37 @@ dependencies = [ ] [[package]] -name = "nybbles" -version = "0.3.4" +name = "num_enum" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "nybbles" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa11e84403164a9f12982ab728f3c67c6fd4ab5b5f0254ffc217bdbd3b28ab0" dependencies = [ "alloy-rlp", - "const-hex", + "cfg-if", "proptest", + "ruint", "serde", "smallvec", ] @@ -4242,6 +5017,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" +[[package]] +name = "owo-colors" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e" + [[package]] name = "p256" version = "0.13.2" @@ -4335,9 +5116,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" dependencies = [ "memchr", "thiserror 2.0.16", @@ -4346,9 +5127,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" +checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663" dependencies = [ "pest", "pest_generator", @@ -4356,9 +5137,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" +checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f" dependencies = [ "pest", "pest_meta", @@ -4369,14 +5150,36 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" +checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420" 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.11.4", +] + +[[package]] +name = "petgraph" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54acf3a685220b533e437e264e4d932cfbdc4cc7ec0cd232ed73c08d03b8a7ca" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap 2.11.4", + "serde", +] + [[package]] name = "pharos" version = "0.5.3" @@ -4470,16 +5273,16 @@ dependencies = [ [[package]] name = "polling" -version = "3.10.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", "rustix 1.1.2", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -4579,11 +5382,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.6", ] [[package]] @@ -4642,17 +5445,17 @@ dependencies = [ [[package]] name = "proptest" -version = "1.7.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" +checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set", "bit-vec", "bitflags", "lazy_static", "num-traits", - "rand 0.9.2", - "rand_chacha 0.9.0", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax", "rusty-fork", @@ -4660,12 +5463,129 @@ dependencies = [ "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.106", + "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.106", +] + +[[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.32", + "socket2", + "thiserror 2.0.16", + "tokio", + "tracing", + "web-time 1.1.0", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.2", + "ring 0.17.14", + "rustc-hash", + "rustls 0.23.32", + "rustls-pki-types", + "slab", + "thiserror 2.0.16", + "tinyvec", + "tracing", + "web-time 1.1.0", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + [[package]] name = "quote" version = "1.0.40" @@ -4707,6 +5627,7 @@ checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", + "serde", ] [[package]] @@ -4755,17 +5676,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom 0.3.3", + "serde", ] [[package]] name = "rand_xorshift" -version = "0.4.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.6.4", ] +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rangemap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7e49bb0bf967717f7bd674458b3d6b0c5f48ec7e3038166026a69fc22223" + [[package]] name = "rangeset" version = "0.2.0" @@ -4861,21 +5798,28 @@ checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ "base64 0.22.1", "bytes", + "futures-channel", "futures-core", + "futures-util", "http 1.3.1", "http-body", "http-body-util", "hyper", + "hyper-rustls", "hyper-util", "js-sys", "log", "percent-encoding", "pin-project-lite", + "quinn", + "rustls 0.23.32", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", + "tokio-rustls", "tower", "tower-http 0.6.6", "tower-service", @@ -4883,6 +5827,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 1.0.2", ] [[package]] @@ -4943,6 +5888,28 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + [[package]] name = "rs_merkle" version = "1.4.2" @@ -5011,6 +5978,40 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +[[package]] +name = "rust-embed" +version = "8.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "025908b8682a26ba8d12f6f2d66b987584a4a87bc024abc5bbc12553a8cd178a" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6065f1a4392b71819ec1ea1df1120673418bf386f50de1d6f54204d836d4349c" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.106", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6cc0c81648b20b70c491ff8cce00c1c3b223bb8ed2b5d41f0e54c6c4c0a3594" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rust-multipart-rfc7578_2" version = "0.6.1" @@ -5060,7 +6061,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.26", + "semver 1.0.27", ] [[package]] @@ -5103,15 +6104,28 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.31" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "ring 0.17.14", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ - "aws-lc-rs", "log", "once_cell", + "ring 0.17.14", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.6", "subtle", "zeroize", ] @@ -5131,16 +6145,27 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ + "web-time 1.1.0", "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.5" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a37813727b78798e53c2bec3f5e8fe12a6d6f8389bf9ca7802add4c9905ad8" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring 0.17.14", + "rustls-pki-types", + "untrusted 0.9.0", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" dependencies = [ - "aws-lc-rs", "ring 0.17.14", "rustls-pki-types", "untrusted 0.9.0", @@ -5170,6 +6195,53 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "safe-proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "492d1a72624b0bd5b7f0193ea5834a1905534a517573a117e949e895f342906c" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "safe-quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcaa9a650f2f98ba4da0190623210c85945cb78b262709f606c57655eda173e1" +dependencies = [ + "safe-proc-macro2", +] + +[[package]] +name = "safe-regex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5194fafa3cb9da89e0cab6dffa1f3fdded586bd6396d12be11b4cae0c7ee45c2" +dependencies = [ + "safe-regex-macro", +] + +[[package]] +name = "safe-regex-compiler" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e822ae1e61251bcfd698317c237cf83f7c57161a5dc24ee609a85697f1ed15b3" +dependencies = [ + "safe-proc-macro2", + "safe-quote", +] + +[[package]] +name = "safe-regex-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2768de7e6ef19f59c5fd3c3ac207ef12b68a49f95e3172d67e4a04cfd992ca06" +dependencies = [ + "safe-proc-macro2", + "safe-regex-compiler", +] + [[package]] name = "same-file" version = "1.0.6" @@ -5234,6 +6306,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + [[package]] name = "semver" version = "0.11.0" @@ -5245,11 +6338,12 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" dependencies = [ "serde", + "serde_core", ] [[package]] @@ -5269,13 +6363,23 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" dependencies = [ + "serde_core", "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde-wasm-bindgen" version = "0.6.5" @@ -5297,10 +6401,19 @@ dependencies = [ ] [[package]] -name = "serde_derive" -version = "1.0.219" +name = "serde_core" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", @@ -5320,25 +6433,27 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] @@ -5386,7 +6501,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.1", + "indexmap 2.11.4", "schemars 0.9.0", "schemars 1.0.4", "serde", @@ -5424,7 +6539,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96005f01d74e0866a7c27bc47e6051e286339df96c5ab10dd0ee833043a0fbd5" dependencies = [ - "bincode", + "bincode 1.3.3", "bytes", "futures-channel", "futures-core", @@ -5458,6 +6573,18 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha256" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f880fc8562bdeb709793f00eb42a2ad0e672c4f883bbe59122b926eca935c8f6" +dependencies = [ + "async-trait", + "bytes", + "hex", + "sha2", +] + [[package]] name = "sha3" version = "0.10.8" @@ -5550,12 +6677,31 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + [[package]] name = "slab" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +[[package]] +name = "small-ord-set" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf7035a2b2268a5be8c1395738565b06beda836097e12021cdefc06b127a0e7e" +dependencies = [ + "smallvec", +] + [[package]] name = "smallvec" version = "1.15.1" @@ -5565,6 +6711,16 @@ dependencies = [ "serde", ] +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + [[package]] name = "socket2" version = "0.6.0" @@ -5575,6 +6731,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "sorted-iter" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bceb57dc07c92cdae60f5b27b3fa92ecaaa42fe36c55e22dbfb0b44893e0b1f7" + [[package]] name = "sourcemap" version = "9.2.2" @@ -5653,13 +6815,32 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + [[package]] name = "strum" version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ - "strum_macros", + "strum_macros 0.27.2", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", ] [[package]] @@ -5704,9 +6885,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.25" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4560533fbd6914b94a8fb5cc803ed6801c3455668db3b810702c57612bac9412" +checksum = "a0b198d366dbec045acfcd97295eb653a7a2b40e4dc764ef1e79aafcad439d3c" dependencies = [ "paste", "proc-macro2", @@ -5922,6 +7103,21 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tls-server-fixture" version = "0.0.0" @@ -5962,8 +7158,8 @@ dependencies = [ "rangeset", "rstest", "rustls-pki-types", - "rustls-webpki", - "semver 1.0.26", + "rustls-webpki 0.103.6", + "semver 1.0.27", "serde", "serio", "thiserror 1.0.69", @@ -5983,7 +7179,7 @@ dependencies = [ "tracing-subscriber", "uid-mux", "web-spawn", - "webpki-roots", + "webpki-roots 1.0.2", ] [[package]] @@ -6035,7 +7231,7 @@ dependencies = [ "aead", "aes-gcm", "bimap", - "bincode", + "bincode 1.3.3", "blake3", "generic-array", "hex", @@ -6048,7 +7244,7 @@ dependencies = [ "rs_merkle", "rstest", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.6", "serde", "sha2", "thiserror 1.0.69", @@ -6058,7 +7254,7 @@ dependencies = [ "tlsn-utils", "web-time 0.2.4", "webpki-root-certs", - "webpki-roots", + "webpki-roots 1.0.2", "zeroize", ] @@ -6092,7 +7288,7 @@ dependencies = [ name = "tlsn-examples" version = "0.0.0" dependencies = [ - "bincode", + "bincode 1.3.3", "chrono", "clap", "futures", @@ -6101,6 +7297,8 @@ dependencies = [ "hyper", "hyper-util", "k256", + "noir", + "serde", "serde_json", "spansy", "tls-server-fixture", @@ -6176,7 +7374,7 @@ dependencies = [ "csv", "itertools 0.14.0", "tlsn-harness-core", - "toml", + "toml 0.8.23", ] [[package]] @@ -6197,7 +7395,7 @@ dependencies = [ "tlsn-server-fixture", "tokio", "tokio-util", - "toml", + "toml 0.8.23", "tower", "tower-http 0.5.2", "tracing", @@ -6284,7 +7482,7 @@ dependencies = [ "rand_chacha 0.9.0", "rstest", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.6", "serde", "serio", "thiserror 1.0.69", @@ -6360,14 +7558,14 @@ dependencies = [ "rustls 0.20.9", "rustls-pemfile", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.6", "sct", "sha2", "tlsn-tls-backend", "tlsn-tls-core", "tokio", "web-time 0.2.4", - "webpki-roots", + "webpki-roots 1.0.2", ] [[package]] @@ -6381,7 +7579,7 @@ dependencies = [ "hyper-util", "rstest", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.6", "thiserror 1.0.69", "tls-server-fixture", "tlsn-tls-client", @@ -6400,7 +7598,7 @@ dependencies = [ "ring 0.17.14", "rustls-pemfile", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.6", "sct", "serde", "sha2", @@ -6418,7 +7616,7 @@ source = "git+https://github.com/tlsnotary/tlsn-utils?rev=6168663#6168663495281f name = "tlsn-wasm" version = "0.1.0-alpha.13-pre" dependencies = [ - "bincode", + "bincode 1.3.3", "console_error_panic_hook", "enum-try-as-inner", "futures", @@ -6479,6 +7677,16 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "tokio-rustls" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" +dependencies = [ + "rustls 0.23.32", + "tokio", +] + [[package]] name = "tokio-tungstenite" version = "0.23.1" @@ -6505,6 +7713,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.19.15", +] + [[package]] name = "toml" version = "0.8.23" @@ -6513,8 +7733,8 @@ checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] @@ -6526,18 +7746,61 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.11.4", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "winnow 0.5.40", +] + [[package]] name = "toml_edit" version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "toml_write", - "winnow", + "winnow 0.7.13", +] + +[[package]] +name = "toml_edit" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +dependencies = [ + "indexmap 2.11.4", + "toml_datetime 0.7.2", + "toml_parser", + "winnow 0.7.13", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ + "winnow 0.7.13", ] [[package]] @@ -6651,6 +7914,16 @@ 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" @@ -6808,6 +8081,12 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -6846,6 +8125,27 @@ 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.32", + "rustls-pki-types", + "url", + "webpki-roots 0.26.11", +] + [[package]] name = "url" version = "2.5.7" @@ -6892,7 +8192,7 @@ version = "137.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33995a1fee055ff743281cde33a41f0d618ee0bdbe8bdf6859e11864499c2595" dependencies = [ - "bindgen 0.71.1", + "bindgen", "bitflags", "fslock", "gzip-header", @@ -6914,12 +8214,33 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" +[[package]] +name = "vec-collections" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9965c8f2ffed1dbcd16cafe18a009642f540fa22661c6cfd6309ddb02e4982" +dependencies = [ + "binary-merge", + "inplace-vec-builder", + "lazy_static", + "num-traits", + "serde", + "smallvec", + "sorted-iter", +] + [[package]] name = "version_check" 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" @@ -6962,27 +8283,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.5+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ "wasip2", ] [[package]] name = "wasip2" -version = "1.0.0+wasi-0.2.4" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" dependencies = [ "cfg-if", "once_cell", @@ -6993,9 +8314,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" dependencies = [ "bumpalo", "log", @@ -7007,9 +8328,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.51" +version = "0.4.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" +checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" dependencies = [ "cfg-if", "js-sys", @@ -7020,9 +8341,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7030,9 +8351,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ "proc-macro2", "quote", @@ -7043,9 +8364,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" dependencies = [ "unicode-ident", ] @@ -7076,9 +8397,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.78" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" dependencies = [ "js-sys", "wasm-bindgen", @@ -7123,6 +8444,15 @@ 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.2", +] + [[package]] name = "webpki-roots" version = "1.0.2" @@ -7192,15 +8522,15 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.1.3", - "windows-result", - "windows-strings", + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", ] [[package]] @@ -7244,8 +8574,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ "windows-link 0.1.3", - "windows-result", - "windows-strings", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -7257,6 +8587,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -7266,6 +8605,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -7497,6 +8845,15 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "0.7.13" @@ -7524,9 +8881,9 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wit-bindgen" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" @@ -7701,3 +9058,15 @@ dependencies = [ "quote", "syn 2.0.106", ] + +[[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", +] diff --git a/Cargo.toml b/Cargo.toml index 1ac3bea2c..73e23cdb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,7 +110,7 @@ elliptic-curve = { version = "0.13" } enum-try-as-inner = { version = "0.1" } env_logger = { version = "0.10" } futures = { version = "0.3" } -futures-rustls = { version = "0.26" } +futures-rustls = { version = "0.25" } generic-array = { version = "0.14" } ghash = { version = "0.5" } hex = { version = "0.4" } diff --git a/crates/attestation/Cargo.toml b/crates/attestation/Cargo.toml index 18c2f424e..9a21e0ad0 100644 --- a/crates/attestation/Cargo.toml +++ b/crates/attestation/Cargo.toml @@ -23,9 +23,9 @@ thiserror = { workspace = true } tiny-keccak = { workspace = true, features = ["keccak"] } [dev-dependencies] -alloy-primitives = { version = "0.8.22", default-features = false } -alloy-signer = { version = "0.12", default-features = false } -alloy-signer-local = { version = "0.12", default-features = false } +alloy-primitives = { version = "1.3.1", default-features = false } +alloy-signer = { version = "1.0", default-features = false } +alloy-signer-local = { version = "1.0", default-features = false } rand06-compat = { workspace = true } rstest = { workspace = true } tlsn-core = { workspace = true, features = ["fixtures"] } diff --git a/crates/core/src/hash.rs b/crates/core/src/hash.rs index f8eb38833..0300f2408 100644 --- a/crates/core/src/hash.rs +++ b/crates/core/src/hash.rs @@ -191,6 +191,11 @@ impl Hash { len: value.len(), } } + + /// Returns a byte slice of the hash value. + pub fn as_bytes(&self) -> &[u8] { + &self.value[..self.len] + } } impl rs_merkle::Hash for Hash { diff --git a/crates/examples/Cargo.toml b/crates/examples/Cargo.toml index f37b35d22..c67aff53f 100644 --- a/crates/examples/Cargo.toml +++ b/crates/examples/Cargo.toml @@ -24,6 +24,7 @@ hex = { workspace = true } hyper = { workspace = true, features = ["client", "http1"] } hyper-util = { workspace = true, features = ["full"] } k256 = { workspace = true, features = ["ecdsa"] } +serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } tokio = { workspace = true, features = [ "rt", @@ -36,11 +37,16 @@ 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 = ["barretenberg"] } [[example]] name = "interactive" path = "interactive/interactive.rs" +[[example]] +name = "interactive_zk" +path = "interactive_zk/interactive_zk.rs" + [[example]] name = "attestation_prove" path = "attestation/prove.rs" diff --git a/crates/examples/interactive_zk/.gitignore b/crates/examples/interactive_zk/.gitignore new file mode 100644 index 000000000..cf01f1021 --- /dev/null +++ b/crates/examples/interactive_zk/.gitignore @@ -0,0 +1,5 @@ +!noir/target/ +# Ignore everything inside noir/target +noir/target/* +# Except noir.json +!noir/target/noir.json \ No newline at end of file diff --git a/crates/examples/interactive_zk/README.md b/crates/examples/interactive_zk/README.md new file mode 100644 index 000000000..0f99105b4 --- /dev/null +++ b/crates/examples/interactive_zk/README.md @@ -0,0 +1,167 @@ +# Interactive Zero-Knowledge Age Verification with TLSNotary + +This example demonstrates **privacy-preserving age verification** using TLSNotary and zero-knowledge proofs. It allows a prover to demonstrate they are 18+ years old without revealing their actual birth date or any other personal information. + +## 🔍 How It Works (simplified overview) + +```mermaid +sequenceDiagram + participant S as Tax Server
(fixture) + participant P as Prover + participant V as Verifier + + P->>S: Request tax data (with auth token) (MPC-TLS) + S->>P: Tax data including `date_of_birth` (MPC-TLS) + P->>V: Share transcript with redactions + P->>V: Commit to blinded hash of birth date + P->>P: Generate ZK proof of age ≥ 18 + P->>V: Send ZK proof + V->>V: Verify transcript & ZK proof + V->>V: ✅ Confirm: Prover is 18+ (no birth date revealed) +``` + +### The Process + +1. **MPC-TLS Session**: The Prover fetches tax information containing their birth date, while the Verifier jointly verifies the TLS session to ensure the data comes from the authentic server. +2. **Selective Disclosure**: + * The authorization token is **redacted**: the Verifier sees the plaintext request but not the token. + * The birth date is **committed** as a blinded hash: the Verifier cannot see the date, but the Prover is cryptographically bound to it. + (Depending on the use case more data can be redacted or revealed) +3. **Zero-Knowledge Proof**: The Prover generates a ZK proof that the committed birth date corresponds to an age ≥ 18. +4. **Verification**: The Verifier checks both the TLS transcript and the ZK proof, confirming age ≥ 18 without learning the actual date of birth. + + +### Example Data + +The tax server returns data like this: +```json +{ + "tax_year": 2024, + "taxpayer": { + "idnr": "12345678901", + "first_name": "Max", + "last_name": "Mustermann", + "date_of_birth": "1985-03-12", + // ... + } +} +``` + +## 🔐 Zero-Knowledge Proof Details + +The ZK circuit proves: **"I know a birth date that hashes to the committed value AND indicates I am 18+ years old"** + +**Public Inputs:** +- ✅ Verification date +- ✅ Committed blinded hash of birth date + +**Private Inputs (Hidden):** +- 🔒 Actual birth date plaintext +- 🔒 Random blinder used in hash commitment + +**What the Verifier Learns:** +- ✅ The prover is 18+ years old +- ✅ The birth date is authentic (from the MPC-TLS session) + +Everything else remains private. + +## 🏃 Run the Example + +1. **Start the test server** (from repository root): + ```bash + RUST_LOG=info PORT=4000 cargo run --bin tlsn-server-fixture + ``` + +2. **Run the age verification** (in a new terminal): + ```bash + SERVER_PORT=4000 cargo run --release --example interactive_zk + ``` + +3. **For detailed logs**: + ```bash + RUST_LOG=debug,yamux=info,uid_mux=info SERVER_PORT=4000 cargo run --release --example interactive_zk + ``` + +### Expected Output + +``` +Successfully verified https://test-server.io:4000/elster +Age verified in ZK: 18+ ✅ + +Verified sent data: +GET https://test-server.io:4000/elster HTTP/1.1 +host: test-server.io +connection: close +authorization: 🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈 + +Verified received data: +🙈🙈🙈🙈🙈🙈🙈🙈[truncated for brevity]...🙈🙈🙈🙈🙈"tax_year":2024🙈🙈🙈🙈🙈... +``` + +> 💡 **Note**: In this demo, both Prover and Verifier run on the same machine. In production, they would operate on separate systems. +> 💡 **Note**: This demo assumes that the tax server serves correct data, and that only the submitter of the tax data has access to the specified page. + +## 🛠 Development + +### Project Structure + +``` +interactive_zk/ +├── prover.rs # Prover implementation +├── verifier.rs # Verifier implementation +├── types.rs # Shared types +└── interactive_zk.rs # Main example runner +├── noir/ # Zero-knowledge circuit +│ ├── src/main.n # Noir circuit code +│ ├── target/ # Compiled circuit artifacts +│ └── Nargo.toml # Noir project config +│ └── Prover.toml # Example input for `nargo execute` +│ └── generate_test_data.rs # Rust script to generate Noir test data +└── README.md +``` + +### Noir Circuit Commands + +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`: +```sh +# Install correct Noir and BB versions (important for compatibility!) +noirup --version 1.0.0-beta.8 +bbup -v 1.0.0-nightly.20250723 +``` + +If you don't have `noirup` and `bbup` installed yet, check [Noir's Quick Start](https://noir-lang.org/docs/getting_started/quick_start). + +To compile the circuit, go to the `noir` folder and run `nargo compile`. + +To check and experiment with the Noir circuit, you can use these commands: + +* Execute Circuit: Compile the circuit and run it with sample data from `Prover.toml`: + ```sh + nargo execute + ``` +* Generate Verification Key: Create the verification key needed to verify proofs + ```sh + bb write_vk -b ./target/noir.json -o ./target + ``` +* Generate Proof: Create a zero-knowledge proof using the circuit and witness data. + ```sh + bb prove --bytecode_path ./target/noir.json --witness_path ./target/noir.gz -o ./target + ``` +* Verify Proof: Verify that a proof is valid using the verification key. + ```sh + bb verify -k ./target/vk -p ./target/proof + ``` +* Run the Noir tests: + ```sh + nargo test --show-output + ``` + To create extra tests, you can use `./generate_test_data.rs` to help with generating correct blinders and hashes. + +## 📚 Learn More + +- [TLSNotary Documentation](https://docs.tlsnotary.org/) +- [Noir Language Guide](https://noir-lang.org/) +- [Zero-Knowledge Proofs Explained](https://ethereum.org/en/zero-knowledge-proofs/) +- [Mopro ZK Toolkit](https://zkmopro.org/) diff --git a/crates/examples/interactive_zk/interactive_zk.rs b/crates/examples/interactive_zk/interactive_zk.rs new file mode 100644 index 000000000..6e3ae412f --- /dev/null +++ b/crates/examples/interactive_zk/interactive_zk.rs @@ -0,0 +1,59 @@ +mod prover; +mod types; +mod verifier; + +use prover::prover; +use std::{ + env, + net::{IpAddr, SocketAddr}, +}; +use tlsn_server_fixture::DEFAULT_FIXTURE_PORT; +use tlsn_server_fixture_certs::SERVER_DOMAIN; +use verifier::verifier; + +#[tokio::main] +async fn main() -> Result<(), Box> { + tracing_subscriber::fmt::init(); + + let server_host: String = env::var("SERVER_HOST").unwrap_or("127.0.0.1".into()); + let server_port: u16 = env::var("SERVER_PORT") + .map(|port| port.parse().expect("port should be valid integer")) + .unwrap_or(DEFAULT_FIXTURE_PORT); + + // We use SERVER_DOMAIN here to make sure it matches the domain in the test + // server's certificate. + let uri = format!("https://{SERVER_DOMAIN}:{server_port}/elster"); + let server_ip: IpAddr = server_host + .parse() + .map_err(|e| format!("Invalid IP address '{}': {}", server_host, e))?; + let server_addr = SocketAddr::from((server_ip, server_port)); + + // Connect prover and verifier. + let (prover_socket, verifier_socket) = tokio::io::duplex(1 << 23); + let (prover_extra_socket, verifier_extra_socket) = tokio::io::duplex(1 << 23); + + let (_, transcript) = tokio::try_join!( + prover(prover_socket, prover_extra_socket, &server_addr, &uri), + verifier(verifier_socket, verifier_extra_socket) + )?; + + println!("---"); + println!("Successfully verified {}", &uri); + println!("Age verified in ZK: 18+ ✅\n"); + + println!( + "Verified sent data:\n{}", + bytes_to_redacted_string(transcript.sent_unsafe()) + ); + println!( + "Verified received data:\n{}", + bytes_to_redacted_string(transcript.received_unsafe()) + ); + + Ok(()) +} + +/// Render redacted bytes as `🙈`. +pub fn bytes_to_redacted_string(bytes: &[u8]) -> String { + String::from_utf8_lossy(bytes).replace('\0', "🙈") +} diff --git a/crates/examples/interactive_zk/noir/Nargo.toml b/crates/examples/interactive_zk/noir/Nargo.toml new file mode 100644 index 000000000..0c237f5fc --- /dev/null +++ b/crates/examples/interactive_zk/noir/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "noir" +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" } diff --git a/crates/examples/interactive_zk/noir/Prover.toml b/crates/examples/interactive_zk/noir/Prover.toml new file mode 100644 index 000000000..1a67e36b3 --- /dev/null +++ b/crates/examples/interactive_zk/noir/Prover.toml @@ -0,0 +1,8 @@ +blinder = [108, 93, 120, 205, 15, 35, 159, 124, 243, 96, 22, 128, 16, 149, 219, 216] +committed_hash = [186, 158, 101, 39, 49, 48, 26, 83, 242, 96, 10, 221, 121, 174, 62, 50, 136, 132, 232, 58, 25, 32, 66, 196, 99, 85, 66, 85, 255, 1, 202, 254] +date_of_birth = "1985-03-12" + +[proof_date] +day = "29" +month = "08" +year = "2025" diff --git a/crates/examples/interactive_zk/noir/generate_test_data.rs b/crates/examples/interactive_zk/noir/generate_test_data.rs new file mode 100755 index 000000000..7951c8991 --- /dev/null +++ b/crates/examples/interactive_zk/noir/generate_test_data.rs @@ -0,0 +1,64 @@ +#!/usr/bin/env -S cargo +nightly -Zscript +--- +[package] +name = "generate_test_data" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +sha2 = "0.10" +rand = "0.8" +chrono = "0.4" +--- +use chrono::Datelike; +use chrono::Local; +use rand::RngCore; +use sha2::{Digest, Sha256}; + +fn main() { + // 1. Birthdate string (fixed) + let dob_str = "1985-03-12"; // 10 bytes long + + let proof_date = Local::now().date_naive(); + let proof_year = proof_date.year(); + let proof_month = proof_date.month(); + let proof_day = proof_date.day(); + + // 2. Generate random 16-byte blinder + let mut blinder = [0u8; 16]; + rand::thread_rng().fill_bytes(&mut blinder); + + // 3. Concatenate blinder + dob string bytes + let mut preimage = Vec::with_capacity(26); + preimage.extend_from_slice(dob_str.as_bytes()); + preimage.extend_from_slice(&blinder); + + // 4. Hash it + let hash = Sha256::digest(&preimage); + + let blinder = blinder + .iter() + .map(|b| b.to_string()) + .collect::>() + .join(", "); + let committed_hash = hash + .iter() + .map(|b| b.to_string()) + .collect::>() + .join(", "); + + println!( + " +// Private input +let date_of_birth = \"{dob_str}\"; +let blinder = [{blinder}]; + +// Public input +let proof_date = date::Date {{ year: {proof_year}, month: {proof_month}, day: {proof_day} }}; +let committed_hash = [{committed_hash}]; + +main(proof_date, committed_hash, date_of_birth, blinder); +" + ); +} diff --git a/crates/examples/interactive_zk/noir/src/main.nr b/crates/examples/interactive_zk/noir/src/main.nr new file mode 100644 index 000000000..9549e7358 --- /dev/null +++ b/crates/examples/interactive_zk/noir/src/main.nr @@ -0,0 +1,82 @@ +use dep::date::Date; + +fn main( + // Public inputs + proof_date: pub date::Date, // "2025-08-29" + committed_hash: pub [u8; 32], // Hash of (blinder || dob string) + // Private inputs + date_of_birth: str<10>, // "1985-03-12" + blinder: [u8; 16], // Random 16-byte blinder +) { + let is_18 = check_18(date_of_birth, proof_date); + + let correct_hash = check_hash(date_of_birth, blinder, committed_hash); + + assert(correct_hash); + assert(is_18); +} + +fn check_18(date_of_birth: str<10>, proof_date: date::Date) -> bool { + let dob = parse_birth_date(date_of_birth); + let is_18 = dob.add_years(18).lt(proof_date); + println(f"Is 18? {is_18}"); + is_18 +} + +fn check_hash(date_of_birth: str<10>, blinder: [u8; 16], committed_hash: [u8; 32]) -> bool { + let hash_input: [u8; 26] = make_hash_input(date_of_birth, blinder); + let computed_hash = sha256::sha256_var(hash_input, 26); + let correct_hash = computed_hash == committed_hash; + println(f"Correct hash? {correct_hash}"); + correct_hash +} + +fn make_hash_input(dob: str<10>, blinder: [u8; 16]) -> [u8; 26] { + let mut input: [u8; 26] = [0; 26]; + for i in 0..10 { + input[i] = dob.as_bytes()[i]; + } + for i in 0..16 { + input[10 + i] = blinder[i]; + } + input +} + +pub fn parse_birth_date(birth_date: str<10>) -> date::Date { + let date: [u8; 10] = birth_date.as_bytes(); + let date_str: str<8> = + [date[0], date[1], date[2], date[3], date[5], date[6], date[8], date[9]].as_str_unchecked(); + Date::from_str_long_year(date_str) +} + +#[test] +fn test_max_is_over_18() { + // Private input + let date_of_birth = "1985-03-12"; + let blinder = [120, 80, 62, 10, 76, 60, 130, 98, 147, 161, 139, 126, 27, 236, 36, 56]; + + // Public input + let proof_date = date::Date { year: 2025, month: 9, day: 2 }; + let committed_hash = [ + 229, 118, 202, 216, 213, 230, 125, 163, 48, 178, 118, 225, 84, 7, 140, 63, 173, 255, 163, + 208, 163, 3, 63, 204, 37, 120, 254, 246, 202, 116, 122, 145, + ]; + + main(proof_date, committed_hash, date_of_birth, blinder); +} + +#[test(should_fail)] +fn test_under_18() { + // Private input + let date_of_birth = "2010-08-01"; + let blinder = [160, 23, 57, 158, 141, 195, 155, 132, 109, 242, 48, 220, 70, 217, 229, 189]; + + // Public input + let proof_date = date::Date { year: 2025, month: 8, day: 29 }; + let committed_hash = [ + 16, 132, 194, 62, 232, 90, 157, 153, 4, 231, 1, 54, 226, 3, 87, 174, 129, 177, 80, 69, 37, + 222, 209, 91, 168, 156, 9, 109, 108, 144, 168, 109, + ]; + + main(proof_date, committed_hash, date_of_birth, blinder); +} diff --git a/crates/examples/interactive_zk/noir/target/noir.json b/crates/examples/interactive_zk/noir/target/noir.json new file mode 100644 index 000000000..03217d89f --- /dev/null +++ b/crates/examples/interactive_zk/noir/target/noir.json @@ -0,0 +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":"7Z3Rruy2sW3/xc9+UFWRLFZ+JQgCJ/EJDGw4gRMf4CLIv1+xSM7Z2xet1Vu9/HZfopHt1TWabNWUWlJL//nubz/+5de///mnn//nH//67g9//M93f/nlpy9ffvr7n7/8468//Punf/x8/ut/vjvG/9T63R/k++9qmwufiz4XkYt2zIXMhc6FzUWZi1mlzSptVmmzSptVfFbxWcVnFZ9VfFbxWcVnFZ9VfFbxWaXPKn1W6bNKn1X6rNJnlT6r9Fmlzyp9VolZJWaVmFViVolZJWaVmFViVolZJWYVOY61lLXUtbS1LGtZ17Ktpa9lX8uznp5LOdZS1vKsp/89YXxQYzpsTofN6bA5HTanw+Z02JwOm9NhczpsTofN6bA5HTanw+Z02JwOm9NhczpsTofN6ShzAuqcgLomoK4JqGsC2hqgrwH6GqCvAeby/O99LPtaxlzqsZZnvRhLXUtby7KWdS3HhB4n2JjxMZU2/mXMnY3P6HzjUo4NsmF8TGWAbSgb6oa2YdQZY6vjVWNw1TaUDXVD2+DrbWQnJcSC7KYE2aAbbEPZUDeMOmPqspsGZD8lyIZRZ0xfds6Yn+ydhFiQ/ZMgG3SDbTjtOmZ1rDoT2oaxpo55HquMjskcK42OiYo9P7HnJ/b8xJ6f2POT/dTOVVvHqj3yQusMjFzGXI4h5lLWUtfyNGibsZHLupZtLUc9n70ylmNk2mdHaMyWyGVbS1/LvpYxlznIWI1xrM44VmscqzdWVtgKC1tpYatbchlzmf0yQTboBttQNoyqdcWG+WqrhBEMlo1jG8qGuqFtGPZY3TVBNugG21A21A1tw2kvYyXQviEW2LFBNpwFSzZk2TBepasPy+7DCbahbKgb2gbf0DfEgjrsY8bqqOyrVyfYhrKhbmgbfEPfMCr31asTRuVYvVqP1asTzspVVq9OaBvOynV3b7XVvQlj1a5ldW+tq3sn2IZReXTLWL9rdviovDu87g6vu8PbsTq8yerwCSOVdXX4hLKhbmgbfEPfMCrb6vm2e37CqFxWz7e6er7tnm+759vu+TZGMdqijVGMvmjnm9fRF34MkA264azsMuCs7DrgrOw24KzsZYBvGNubOmBscE6p5hbHB8gG3WAbyoa6oW0YBfuAWDCaaIJsGAXHKEYTTSgb6oa2wTf0DbFgNJHHmYmWmfj/95pe2GsaS1n1ZNWTVU9WPVn1ZNWTVU9WPVn1ZNXTVU9XPV31xserKyJ1JaSugNT/np/b3rn+879/+fHH8Rk+7G2f++D//OGXH3/+93d/+PnXL1++/+5/f/jya/7Rv/75w8+5/PcPv5z/9Vznf/z5b+fyLPg/P335cdB/v+erj+cv7SHrxaGGl6u++nof4Zev937ceH3V3leBEwMV2usVylF2haL9ToU2MmJWaFFuVaj+ZgU/6q7gemseYmT6rBBd3q5Q71XApxnhNyq0Y+zrZYV26J330MrYwM8Kpd6qcLQD76Hdmcl2bl52hXMzcKeCOObh3PTeqWC9Yh4eevvmKG5WqHgP6setCoFP0452q0IPVri1TlrBKKy0dz+L4+k6qfq8xLlTXPdaefK9ySxHf2+ViB47KiPkzns4d7jLfhMnu9yr0Q/WiHs1uGadu/zSbtUw41jsVticr4uKGuXWCjpeF6yh9z4Xe5jTok/n1K5W0vM7HCZVrD5dxcZfPS1Szr39XeQcTL9ZBG0/isTN4WjlcJ5vCqxdNa5xRbNzZ+Vekfe7//yEG9c085trWmlcS9q9rqkcS61u92o430ft/VYNV3aNl3vd6+6scWsHdtTgWPqhz2qMrdDFfvSB/ejgxyL96xIX69i5F7yzvXnpz0pcjqQbZ6OXe7PxVY3abtZ4mNF2bw3rzm7p3d+vceuLwahRUCMOeXs+7tYI4fYytL5fw/RmDX2o0d+fj5s14iHFoukn1Ij3x3Jzy9CF76PbrX5pB3YuT763D/KbGn6zhrOGlXs1uJVrR+3v12j1Zo3KGq7vz8fdGr2wRrS3a5wH7m7WsIca8fZ83K0hKqxxs1++qlGO98dSbua6P6wfx71tVBNuo5rc2zacR4weatwZi+FI4LnPjdfXrw+G9qvjV4jj+nAE7bcF5PJrR+O3DrtXgt85ysMm8ptKGD6OUm4OBEfRzhNrx70SVVki7pVo6JHS+r0Sjk1befjO820l+FWyt1sl6sNOS3laIq5WbsG3N9OH+KzydYmLd3GeIdtzcZ4RK09LXHwl1rLXLL1ZAEfKtfmb7+BmAexPa785jX03+Xlm8Hhawt+dRn93Gv3dafTfcxqlCqbx4XTDb0qc5/renMfrCq9M5Kvv4W6Ft6dSBaPQKs/fhL89lf72VPrbU/m7rpXqHVMZ8W6Jx3MW31LCsHOoVuz9Eu8P5GYJa/hA7HmTv1wijrcHcrNEwQlaLervvou7JQpOTWqJ522qb2emvp2Z+nZm6u+amVUxitqeZ6a+nZn6dmbq25mpv2tm1s73cJS3S+i9d9EqSzycEfjtVIzvRu99oJcVXvpAX3wPdyu8/YG67G886tWev4l4eyrj7amMt6cyftepZAUPfbdEP55uhi8PbODYynnY6dm3T7k6OyTnhhOHNrSIvfs24vnb6M8r+GF7r8aP+nTfSsrFZ9qEJ7rkYu2ux+WpYVwJIedRn3KzSuFBr/Pr0N33UngIb1xf8bzKxRnziMJLO+pxt4awRr9Zo/F9uN6twffRP2Est2tgqxYRdz8XHvM+jkPfHcwHRS7XsyoP69nzLwTS9P317IMaL61n1zVeW88+qPHSOvLyWG7XeG09+6DGa+vZi4N5Zz37Ks8u1rMP1tbWWOX51lv8akAdZySjq3xCjXazBrZ752f9CTXq7bE4a+jNGpU1/DNq+N2xNNboN9eyhpNOJ+vd/YDWHqr09hlV4m73NZ63eaOKGy+d83q7Sn2o4vIZ7+VzqkS7XYWfUZfjbpWjfUIVBsLJt/eEgxfBStS7sxs8c3pWeb6+xCfsw8Yn7MPGJ+zDxifsw8Yn7MPGJ+zDxmfsw8bvvw8bD4kSzw8T6fH+PuxHNV5Zzz6o8dJ69lGNV9aR18dyu8ZL69lHNV5az14dzFvr2WOe9Zt7F3rgrMPJz4+Lqry/D/sNNdrNGi/tw75eo94eyyv7sB/UeGkf9htq+N2xvL8PqweOk57cbu7DqnBP+HzP7TOqmN4dEY/OvVFFePn2eYpdPqOK3Z4XXgZ+nuM/7lbhRamXVa6Pn+JIcFN9vuXSixpyNH7HP1rY3Sr4yeo7Vdxwjdjhxe9WEfmMKsF5uUrr6yr9YXb78+8qH1Xh0ekjpH/Ce7lf5XGrHM/P4X9UpXIHIfz5vNhlFV65dHJ7PqJyvL81fLnGxdbwusZrW8PrGq9tDV+v4XfH8srW8FvWkbtr2vlS/hJSxD6jipWbVaTyeKoe9W6VxnNVjz+6/W2VKp/RO/UT9iTrJ+xJ1k/Yk6yfsCdZP2FPsurv3DtfrSMXa9r1/oWiSNNebtbouHeBPb9a+uX3cbuGCd+Hxc0ale/j4tNt5f2OebnGRcdc13itY65rvNYxr9e4O6evffd6+bMNf7vG1ZUIlzX4k5FWLo6+Xtao+D11qxfrmH/CeuqfsJ76J6yn/gnrqX/Ceuq/93r6+Nm2+n6NfjNP24H7wbSL87HXNfBb+eai79fQm3PqvFORt6f7mf3yxjLYurSnvzbLTeGzCu/eAIz3lCgPv/v7f97BxTT0Yx+q6c9/q6bxwekwnsfyezXyi8U6MvL8B28f1FAeozG/NxsN/X5czMZFu3cM5MwOVPjtrYauKoyTgZyLixpX1wv2wt/7ngkaN6s0fhnr/vyOQxoXFw12wSmOfh5Gu1XDAzuU/Xh+lx47rtYPazhvdPLz35V/MBr8SvX+aDougfRun1Cjys3Pl9vZk5/f7cOOi5ufdF7p09vzNc2Oi3cSrSMI/fmvj7+hht+r8XiHrYubBb1c43nPfFADa1n0djMDzmN26N4oz+84ZHJ5F6YmvMCgPb/LlsnVDaFevjWVXCVjefyBd7G7VSz4o+Ty/H4sH43oxbtTiX9CJn1UhfNiTf1mFT94qyx/fg+Rj94LDzhb63dH5Lxblp1Zd7eKBavU42YHuHIHx4ve7EaLwm682pZeVuGer8Tj7vO3VQnmflzc+eajKvxF3XGU592oF9uxM1K4+3juRl/c+e5ivy0UzRiP+37fVONx+3GR/S/XEPmEGjfH8uJ27LrGS9ug19/Hxbbweg1pPBF2flV7PhrzyxNhzILj4u5oH1XhtuM8y31RJa5Ps9eHE+TP97uuTrec2y7nnRpL1LsjwjfAccrzedIW/Yzt2AcjenH7fl3l1e379WekvCuXqt5e6/zhJO7tT9rqw11pnt+19aMqvOPiecDxuDciOVjlPOuvN6t8dTqr367ycDnhG1V4/6RzV+5mSvmh2Hs6Nx/tM6pc7G1/UAX3dZdzM/QpVS464LrKw+Eh1+d7LN9Sxe6OSLkP5hd3Hb7c7xlXBfJGPkd/vr60q1OxXnlhkl/cceuDKrxz/bi23j6jysU24KMqnF2/+Iza+7dStfb+vVQ/Gs3DutKf70NdHk8MxbH/+vSIpLWrn0AfxpXt4V6Z9VtK8Pfkx8Muy29KuFzusTiPrR733sXBd2HP3sX1bLaH64ufHnC3q7Mx7x5wL9j4Xdza7er12GCV9vVh7j+d/++Hv/70y9dP/BuPMRoXoYynGOXS1rKcyzIf45fLtpY+VrX5YK5YD+YaYTaeSpPLUa/P59Lk0tZy1Iv5aJpctrX0nOz1eJqE8dCVQ9YjahLGY1eO9TS7CbahDCjrYTUJbUNWruuRNQlZua3H1iRk5b4eXZNgG7JyrAfYJLQNnrsm6zE2CZGb9v0oG8HDbPLRZvk4m0n5ULrYj7SZlA90w2NtFA+2yYep5aNtJsWmfLxNPmEtH3AzSUH5yLi6H3MzKR1tP+pmUjr2M/cWxaZ85I3uR4MtUtBwjNzIR98sGg6T9fibRcNh+UicDsrH8Nl6RtiifBDfeKemIAOlY7xnq6AGSoev54ktSscYx3zWX9Jw5JPI5tP+kgw0HPlUsvnAv6QGGo75qLIOitzNXU8bW5SOfPCYgtKRzwssoHTsZ44JHjqWV0/NJwROik35jMBJw1HxlMCKxwTmw8PyOYGTKqiBHNRBsSmfLDUfLyYgBRmogCooHXjU4KQOik3Z1JMEpCADFVAFwdHh6HB0OAKOgCPgCDgCjoAj4Ag4Ao7Yjnw+2SIBKSgdsZ5RtqiCGshBHTQcY88hn1S2SEAKMlABVVADOaiD4FA4FA6FQ+FQOBQOhUPhUDgUDoMj+3xsZDX7fJKBCqiCGshB6RgPdcs+T8o+nyQgBRkoHeNBbtnnkxrIQR0Um7LPJwlIQQaCo8JR4ahwVDgqHA2OBkeDo8HR4GhwNDgaHA2OBkf2+XjcnmafT1KQgQqogoYjH8OXfT6pg2JT9vkkASnIQAVUQXB0ODocHY6AI+AIOAKOgCPgCDgCjuzzfLJg9vkgyz6fJCAFGaiAKqiBHNRBcAgcAofAIXAIHAJH9vl49qFln0/qoNiUfT52XC37fJKC0lEHFVAFNZCDOigd5zbAss8nCSgdfZCBCqiCGshB6YhBsSn7fNJwjO9yln0+aTjG0W3LPp9UQQ3koA6KTdnnkwSkIDgqHBWOCkeFI/u866DYlH0+SUAKMlA6xieYfT6pgRzUQbEp+3ySgBRkIDgcDofD4XA4HI4OR4cj+3xcHmLZ55MKqIIayEEdFJuyzycJCI6AI+AIOLLPx7Udln0+qYNiUck+nyQgBRmogCqogRzUQXAIHAKHwCFwCBwCh8AhcAgcAofCoXBkn49DbSX7fFIBVVADOaiDYlP2+SQBwWFwGBwGh8FhcBgcBkf2+fiuXmafJynIQAVUQQ3koA6KTRWOCkf2+Ti8X7LPJxVQBTWQgzooNmWfTxIQHA2OBkeDo8HR4GhwNDgcDofD4XA4ss/H8YmSfT6pgRyUDh0Um+ZTwpMElI4yyEAFVEEN5KAOSse5rSjZ55MEpCADFVA6xvqSfT7JQR0Ui2r2+SQBKchABVRBDeSgDoJD4BA4BA6BQ+AQOAQOgUPgEDgUjuzzcSilZp9PMlABVVADeR69G9RBsWn0+SIBKchABVRBDQSHwWFwFDgKHAWOAkeBo8BR4ChwFDhKOs7tUa0HSEAKMlABVVA66iAHdVBsagdIQOnwQQYqoApqIAd1UGzKh99PEhAcDofD4XA4HA6Hw+FwdDg6HB2ODkeHo8PR4ehw9HSM9bTHpjhAAlKQgYZjHF6ro88XNZCDOigWtdHniwSkIAMVUAU1kIM6CA6BQ+AQOAQOgUPgkHTIIAd1UGzSAyQgBRmogCoIDoVD4VA4DA6Dw+AwOLLPJQ8SV1ADOSgd42Bx9nlS9vmkdIxDx9nnkwxUQBXUQOlogzooNmWfj4sJW/b5JAUZqIAqKB0xyEEdNBzjIq2WfT5pOMbR2pZ9PslABVRBDeSgDopN2eeT4HA4HA6Hw+HIPh9np1r2+aQOik3Z55MElI7xCWafTyqgCmogB3VQbMo+nyQgOAKOgCPgCDgCjoAjtsOzz8dxb88+n6QgAxVQBTWQgzooNgkcAofAIXBkn4/j7Z59PqmBHNRBsSn7fJKAFGQgOBQOhUPhUDgUDoPD4Mg+H+cDPPt8UgFVUAM5qINiU/b5JAHBUeAocBQ4ChwFjgJHgSP7fNzy3LPPJynIQAVUQQ3koA6KTQ2OBsfs83Eya/Z5UgFVUAM5qINi0+zzJAHB4XA4HA6Hw+FwOBwOR4ejw9Hh6HB0ODoc2eeW5+Yc1EHDMc7yePb5JAENxzjf49nnkwpoOMaZH88+n+SgdIyOyj4f1LPPJwkoHePEXvb5pAKqoHS0QQ7qoNiUfT7OH/Xs80lwCBwCh8AhcAgcAofAoXBkn4+zSz37fJKBCqiCGshBHRSbss/HOaqefT5JQekY85d9PqmCGshBHZSOMd7s80kCSscYZfb5pJyrPqiCGshBHRSbss8nCUhBBoKjwlHhqHBUOCocDY4GR4OjwdHgaHA0OBocDY4Gh8PhcDjWK8d65VivHOuVY71yrFeO9cqxXnWsVx2OjnF0jKNjHB3j6BhHxzg6xtExjsA4Ao6AI+AIOAKOgCPgCDhiO+I4QAJSkIH2XAX6PGafJzloz1Wgz2P2eZKAdM1fCBxSQBXUQA7qIIxDMQ7FOBTjUDgUDoVD4VA4FA6Fw+AwOAwOg8PgMDgMc2WYq+zzSbGpYK4K5ir7fJKByp4/9HmgzwN9HujzQJ8H+jzQ54E+D/R5oM8DfR7o80CfB/o80OeBPg/0eaDPA30e6PNAnwf6PNDn0TBXDXM1+zxJQJgrx1zNPk+qoLbnz+FwjMMxjo5xoM8DfR7o80CfB/o80OeBPg/0eaDPA30e6PNAnwf6PNDngT4P9HmgzwN9HujzcevFNUUnClGJRtwTdmIlNqIT+5rIE2mTgyhEJRqxECuxEZ3YibQpbUqb0qa0KW1Km9KmtCltSpvRZrQZZ9I4k1aIlciZNM6kdWIAy4H5LbQVjq1wbIVjKxxb4dgKx1Y4tsKxVY6t0lZpq7RV2iptlbZKW6Wt0tZoa7Q12hptjTPZOJOtEZ3ImWycST+IQlTMr9PmHJtzbM6xOcfmHJtzbJ1j6xxb59g6bZ22TlunrdPWaeu0BW1BW9AWtAVtQVtwJoMzGZ24c1fkwEzKIUQlGnFvqEQO2ORoRCd2IsYmzBJhlgizRJglwiwRZokwS4RZIswSYZYIs0SYJcIsEWaJMEuEWSLMEmGWiGImRTmTdhCFyJk0zqQVYiU2zK/RZhybcWyFY2OWCLNEmCXCLBFmiTBLhFkizBJhlgizRJglwiwRZokwS4RZIswSYZYIs0SYJcIsEWaJMEuEWSKNtkZbo63R1mhrtDltTpvTxiwRZokwS4RZIsySvIRPx11OJK/hW5hZMn6jIHkV30blHwxbzWtVM0sWVmIjOrETA5hZslCIw5aXLeYVfRsLMW25TmaWLHRiJ8bGvLBvY9o8UYlGTFtPrMS2pySv79vYiQGUgyhEJRqxECuRNqFNaBPalDalTWlT2pQ2pU1pU9qUNqXNaDPajDajzWgz2ubBiHnBMW1Gm9FWaCu0FdoKbYW2Qlvh2ApthbZCW6Wt0lZpq7RV2iptlbZKW6Wt0pZZMueh0dZoa7Q12hptjbZGW6Ot0eYcm9PmtDltTpvT5rQ5bU6b08YsUWZJXiq4kbbMkjkPnbZOW6et09ZpC9qCtqAtaAuOLWgL2oK2oC1gs+MgClGJRizESmxEJyKVjVlizBJjlhizxJglxiwxZokxS4xZYswSY5YYs8SYJcYsMWaJMUuMWWLMEmOWGLPEmCXGLDFmiRm2OMYsMWaJMUvyAsONtDFLjFlizBJjlhizxJglxiwxZokxS4xZYswSY5YYs8SYJcYsMWaJMUuMWZIXHa55YJYYs8SYJXnh4UbamCXGLDFmiTFLjFlizBJjlhizxJglxiwxZokxS4xZYswSY5YYs8SYJcYsyYsR1zwwS4xZYswS67QxS4xZYswSY5YYs8SYJcYsMWaJMUuMWWLMEmOWGLPEmCXGLCnMksIsKcySwizJixTnPBRmSWGWFGZJ4X5JYZYUZklhlhRmSWGWFGZJYZYUZklhlhRmSWGWFGZJYZYUZklhlhRmSWGWFGZJYZYURU4WZklhlhRmSeF+SWGWFGZJYZYUZklhlhRmSWGWFGZJYZYUZklhlhRmSWGWFGZJYZYUZklhlhRmSWGWFGZJYZYUZklhlhTulxRmSWGWFGZJYZYUZklhlhRmSWGWFGZJYZYUZklhlhRmSV7mqC1/epVZslCJRizESmxEJ3ZiADttnbZOW6et09Zp67R12jptnbagLWgL2oK2oC2zZPyuRfICyI1O7MTYmBdBbhRi2lqiEQsxbT2xEZ3YiQHMLFmYtkhUohGHbfwYQ/KaSPX8FVxmycJhG4/9k7wscmMAM0s8f4yXWbJQiUYsxEpsRCd2YgCNNqPNaDPajLbMEs9ZzyxZ6MRODGBmyUIhpi0/ocyShYWYtvwAMksWOrETA5hZsjBt+Qllliw04rD1/NwyS3p+WJklPT+WzJKFw9ZzHjJLJmaWLBSiEo1YiJXYiE6krdHmtDltTpvT5rRllvT8VWdmyUIndmIAM0sWClGJRixE2jptnbZOW6ctaAvagragLWgL2oK2oC1oC9jmhZYLhZi2mmjEQqzERnRiJwYws2ShEGkT2oQ2oU1oE9qENqFNaVPalDalTWnLLOktsRGd2IkBzCxZKEQlpq0nDtt4lIzMazEXNqITOzGAmSULhahEG/eQzF8XjyzZWAdKYiM6/6ATA38wsmSj4A9GlmxM2/zdMm21EmmrTqStBrDR1oRIW+PYWoG40dYakbbWibT5QaTNlUibc2xeIXbanDPptDlnstPWOZOdtm5E2jrH1hvEnbbOmey0BWcyaAvOZNAWhUhbcGzhEAdtgZnMizlnhbyac6PyD4xY+AeV2PgHTuxbnFd1rn+Vg0ibKNGItAk+t7y408Zl7pJXd27sxLSNjs0LPG1c+i15hedGJRqxECuxEZ3YicM2rpOWvNRzoxCVmLZ8ZyNLTLPCyJKNw5Y3lMgrPjcOm+bYRpYsHFmyUYhKNGIhVmIjOnHY8qYRefXnwsyShcOWd5DIC0DN5k0JjFiIldiITuzEYcs7P+SFoBuFqMRhy7s/5MWgG4ct7/+Ql4NudGInpi3FmSULhajEtOXsZJYsrBBnlixMW37GmSULA5hZspC2TltmycJCrBBnlix0iDNLFg5bfn/Ly0Qtb1eR14luVKIRC7ESh63NYsPW5r92YmzMC0Y3ClGJRizESkybJzqxEwOYWbJQiEo0YiFWIm1Cm9AmtCltSpvSprQpbUqb0qa0KW1Km9FmtBltRpvRZrQZbUab0Wa0FdoKbYW2QluhrdBWaCu0FdoKbZW2SlulrdKWWZJfMvM6042N6MRODGBmyUIhKtGItDXaMkvyO2Rec7r/lbZGm9OWWTJf5rQ5bU6b0+a0OW1Om9PWaeu0ddo6bZ22TlunrdPWaeu0BW1BW9AWtAVtQVvQFrQFbQFbXpS6Eba8LHX/qxELsRIbX+b8106kTWgT2oQ2oU1oE9qENqFNaBPalDalTWlT2pQ2pU1pU9qUNqXNaDPajDajzWgz2ow2o81oM9oKbYW2QluhrdBWaCu0FdoKbYW2SlulrdJWaWOWBLMkKm3MkmCWBLMkmCXRaGOWBLMkmCXBLAlmSTBLglkSzJJglgSzJJglwSwJZkkwS4JZEsySYJYEsySYJcEsCWZJMEuCWRLMkmCWBLMkmCXBLAlmSTBLglkSzJJglgSzJJglwSwJZkkgS/RAluiBLNEDWaIHskQPZIkeyBI9kCV6IEv0QJbocdAmtAltM0tqYtpaYiFWYiM6sRMDOLNkohCVSJvSprQpbUqb0qa0GW1Gm9FmtBltRpvRZrQZbUZboa3QVmgrtBXaZpaMW3P+7w+//PTDX778+K/v/vCfcWPGX3/+674L4/l///1//rn/y19++enLl5/+/ud//vKPv/74t19/+XHcsXH8t++O8T+n5o9Fv6/6p3PNOv/lj+PuwiIx7u8o66/+OH7Uqhbnn4w/b/K9y/7zc/34Xo86/q/k/43vVWS8WvHqKt+fh9PXq8+993bg1ee3LbWOV9v56pKvtv3mavu+Nbw57d+f59b/9N9xA8r/Cw==","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 diff --git a/crates/examples/interactive_zk/prover.rs b/crates/examples/interactive_zk/prover.rs new file mode 100644 index 000000000..c264017b3 --- /dev/null +++ b/crates/examples/interactive_zk/prover.rs @@ -0,0 +1,371 @@ +use std::net::SocketAddr; + +use crate::types::received_commitments; + +use super::types::ZKProofBundle; + +use chrono::{Datelike, Local, NaiveDate}; +use http_body_util::Empty; +use hyper::{body::Bytes, header, Request, StatusCode, Uri}; +use hyper_util::rt::TokioIo; +use k256::sha2::{Digest, Sha256}; +use noir::{ + barretenberg::{ + prove::prove_ultra_honk, srs::setup_srs_from_bytecode, + verify::get_ultra_honk_verification_key, + }, + witness::from_vec_str_to_witness_map, +}; +use serde_json::Value; +use spansy::{ + http::{BodyContent, Requests, Responses}, + Spanned, +}; +use tls_server_fixture::CA_CERT_DER; +use tlsn::{ + config::{CertificateDer, ProtocolConfig, RootCertStore}, + connection::ServerName, + hash::HashAlgId, + prover::{ProveConfig, ProveConfigBuilder, Prover, ProverConfig, TlsConfig}, + transcript::{ + hash::{PlaintextHash, PlaintextHashSecret}, + Direction, TranscriptCommitConfig, TranscriptCommitConfigBuilder, TranscriptCommitmentKind, + TranscriptSecret, + }, +}; + +use tlsn_examples::MAX_RECV_DATA; +use tokio::io::AsyncWriteExt; + +use tlsn_examples::MAX_SENT_DATA; +use tokio::io::{AsyncRead, AsyncWrite}; +use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt}; +use tracing::instrument; + +#[instrument(skip(verifier_socket, verifier_extra_socket))] +pub async fn prover( + verifier_socket: T, + mut verifier_extra_socket: T, + server_addr: &SocketAddr, + uri: &str, +) -> Result<(), Box> { + let uri = uri.parse::()?; + + if uri.scheme().map(|s| s.as_str()) != Some("https") { + return Err("URI must use HTTPS scheme".into()); + } + + let server_domain = uri.authority().ok_or("URI must have authority")?.host(); + + // Create a root certificate store with the server-fixture's self-signed + // certificate. This is only required for offline testing with the + // server-fixture. + let mut tls_config_builder = TlsConfig::builder(); + tls_config_builder.root_store(RootCertStore { + roots: vec![CertificateDer(CA_CERT_DER.to_vec())], + }); + let tls_config = tls_config_builder.build()?; + + // Set up protocol configuration for prover. + let mut prover_config_builder = ProverConfig::builder(); + prover_config_builder + .server_name(ServerName::Dns(server_domain.try_into()?)) + .tls_config(tls_config) + .protocol_config( + ProtocolConfig::builder() + .max_sent_data(MAX_SENT_DATA) + .max_recv_data(MAX_RECV_DATA) + .build()?, + ); + + let prover_config = prover_config_builder.build()?; + + // Create prover and connect to verifier. + // + // Perform the setup phase with the verifier. + let prover = Prover::new(prover_config) + .setup(verifier_socket.compat()) + .await?; + + // Connect to TLS Server. + let tls_client_socket = tokio::net::TcpStream::connect(server_addr).await?; + + // Pass server connection into the prover. + let (mpc_tls_connection, prover_fut) = prover.connect(tls_client_socket.compat()).await?; + + // Wrap the connection in a TokioIo compatibility layer to use it with hyper. + let mpc_tls_connection = TokioIo::new(mpc_tls_connection.compat()); + + // Spawn the Prover to run in the background. + let prover_task = tokio::spawn(prover_fut); + + // MPC-TLS Handshake. + let (mut request_sender, connection) = + hyper::client::conn::http1::handshake(mpc_tls_connection).await?; + + // Spawn the connection to run in the background. + tokio::spawn(connection); + + // MPC-TLS: Send Request and wait for Response. + let request = Request::builder() + .uri(uri.clone()) + .header("Host", server_domain) + .header("Connection", "close") + .header(header::AUTHORIZATION, "Bearer random_auth_token") + .method("GET") + .body(Empty::::new())?; + + let response = request_sender.send_request(request).await?; + + if response.status() != StatusCode::OK { + return Err(format!("MPC-TLS request failed with status {}", response.status()).into()); + } + + // Create proof for the Verifier. + let mut prover = prover_task.await??; + + let transcript = prover.transcript().clone(); + let mut prove_config_builder = ProveConfig::builder(&transcript); + + // Reveal the DNS name. + prove_config_builder.server_identity(); + + let sent: &[u8] = transcript.sent(); + let received: &[u8] = transcript.received(); + let sent_len = sent.len(); + let recv_len = received.len(); + tracing::info!("Sent length: {}, Received length: {}", sent_len, recv_len); + + // Reveal the entire HTTP request except for the authorization bearer token + reveal_request(sent, &mut prove_config_builder)?; + + // Create hash commitment for the date of birth field from the response + let mut transcript_commitment_builder = TranscriptCommitConfig::builder(&transcript); + transcript_commitment_builder.default_kind(TranscriptCommitmentKind::Hash { + alg: HashAlgId::SHA256, + }); + reveal_received( + received, + &mut prove_config_builder, + &mut transcript_commitment_builder, + )?; + + let transcripts_commitment_config = transcript_commitment_builder.build()?; + prove_config_builder.transcript_commit(transcripts_commitment_config); + + let prove_config = prove_config_builder.build()?; + + // MPC-TLS prove + let prover_output = prover.prove(&prove_config).await?; + prover.close().await?; + + // Prove birthdate is more than 18 years ago. + let received_commitments = received_commitments(&prover_output.transcript_commitments); + let received_commitment = received_commitments + .first() + .ok_or("No received commitments found")?; // committed hash (of date of birth string) + let received_secrets = received_secrets(&prover_output.transcript_secrets); + let received_secret = received_secrets + .first() + .ok_or("No received secrets found")?; // hash blinder + let proof_input = prepare_zk_proof_input(received, received_commitment, received_secret)?; + let proof_bundle = generate_zk_proof(&proof_input)?; + + // Sent zk proof bundle to verifier + let serialized_proof = bincode::serialize(&proof_bundle)?; + verifier_extra_socket.write_all(&serialized_proof).await?; + verifier_extra_socket.shutdown().await?; + + Ok(()) +} + +// Reveal everything from the request, except for the authorization token. +fn reveal_request( + request: &[u8], + builder: &mut ProveConfigBuilder<'_>, +) -> Result<(), Box> { + let reqs = Requests::new_from_slice(request).collect::, _>>()?; + + let req = reqs.first().ok_or("No requests found")?; + + if req.request.method.as_str() != "GET" { + return Err(format!("Expected GET method, found {}", req.request.method.as_str()).into()); + } + + let authorization_header = req + .headers_with_name(header::AUTHORIZATION.as_str()) + .next() + .ok_or("Authorization header not found")?; + + let start_pos = authorization_header + .span() + .indices() + .min() + .ok_or("Could not find authorization header start position")? + + header::AUTHORIZATION.as_str().len() + + 2; + let end_pos = + start_pos + authorization_header.span().len() - header::AUTHORIZATION.as_str().len() - 2; + + builder.reveal_sent(&(0..start_pos))?; + builder.reveal_sent(&(end_pos..request.len()))?; + + Ok(()) +} + +fn reveal_received( + received: &[u8], + builder: &mut ProveConfigBuilder<'_>, + transcript_commitment_builder: &mut TranscriptCommitConfigBuilder, +) -> Result<(), Box> { + let resp = Responses::new_from_slice(received).collect::, _>>()?; + + let response = resp.first().ok_or("No responses found")?; + let body = response.body.as_ref().ok_or("Response body not found")?; + + let BodyContent::Json(json) = &body.content else { + return Err("Expected JSON body content".into()); + }; + + // reveal tax year + let tax_year = json + .get("tax_year") + .ok_or("tax_year field not found in JSON")?; + let start_pos = tax_year + .span() + .indices() + .min() + .ok_or("Could not find tax_year start position")? + - 11; + let end_pos = tax_year + .span() + .indices() + .max() + .ok_or("Could not find tax_year end position")? + + 1; + builder.reveal_recv(&(start_pos..end_pos))?; + + // commit to hash of date of birth + let dob = json + .get("taxpayer.date_of_birth") + .ok_or("taxpayer.date_of_birth field not found in JSON")?; + + transcript_commitment_builder.commit_recv(dob.span())?; + + Ok(()) +} + +// extract secret from prover output +fn received_secrets(transcript_secrets: &[TranscriptSecret]) -> Vec<&PlaintextHashSecret> { + transcript_secrets + .iter() + .filter_map(|secret| match secret { + TranscriptSecret::Hash(hash) if hash.direction == Direction::Received => Some(hash), + _ => None, + }) + .collect() +} + +#[derive(Debug)] +pub struct ZKProofInput { + dob: Vec, + proof_date: NaiveDate, + blinder: Vec, + committed_hash: Vec, +} + +// Verify that the blinded, committed hash is correct +fn prepare_zk_proof_input( + received: &[u8], + received_commitment: &PlaintextHash, + received_secret: &PlaintextHashSecret, +) -> Result> { + assert_eq!(received_commitment.direction, Direction::Received); + assert_eq!(received_commitment.hash.alg, HashAlgId::SHA256); + + let hash = &received_commitment.hash; + + let dob_start = received_commitment + .idx + .min() + .ok_or("No start index for DOB")?; + let dob_end = received_commitment + .idx + .end() + .ok_or("No end index for DOB")?; + let dob = received[dob_start..dob_end].to_vec(); + let blinder = received_secret.blinder.as_bytes().to_vec(); + let committed_hash = hash.value.as_bytes().to_vec(); + let proof_date = Local::now().date_naive(); + + assert_eq!(received_secret.direction, Direction::Received); + assert_eq!(received_secret.alg, HashAlgId::SHA256); + + let mut hasher = Sha256::new(); + hasher.update(&dob); + hasher.update(&blinder); + let computed_hash = hasher.finalize(); + + if committed_hash != computed_hash.as_slice() { + return Err("Computed hash does not match committed hash".into()); + } + + Ok(ZKProofInput { + dob, + proof_date, + committed_hash, + blinder, + }) +} + +fn generate_zk_proof( + proof_input: &ZKProofInput, +) -> Result> { + tracing::info!("🔒 Generating ZK proof with Noir..."); + + const PROGRAM_JSON: &str = include_str!("./noir/target/noir.json"); + + // 1. Load bytecode from program.json + let json: Value = serde_json::from_str(PROGRAM_JSON)?; + let bytecode = json["bytecode"] + .as_str() + .ok_or("bytecode field not found in program.json")?; + + let mut inputs: Vec = vec![]; + inputs.push(proof_input.proof_date.day().to_string()); + inputs.push(proof_input.proof_date.month().to_string()); + inputs.push(proof_input.proof_date.year().to_string()); + inputs.extend(proof_input.committed_hash.iter().map(|b| b.to_string())); + inputs.extend(proof_input.dob.iter().map(|b| b.to_string())); + inputs.extend(proof_input.blinder.iter().map(|b| b.to_string())); + + let proof_date = proof_input.proof_date.to_string(); + tracing::info!( + "Public inputs : Proof date ({}) and committed hash ({})", + proof_date, + hex::encode(&proof_input.committed_hash) + ); + tracing::info!( + "Private inputs: Blinder ({}) and Date of Birth ({})", + hex::encode(&proof_input.blinder), + String::from_utf8_lossy(&proof_input.dob) + ); + + tracing::debug!("Witness inputs {:?}", inputs); + + let input_refs: Vec<&str> = inputs.iter().map(String::as_str).collect(); + let witness = from_vec_str_to_witness_map(input_refs)?; + + // Setup SRS + setup_srs_from_bytecode(bytecode, None, false)?; + + // Verification key + let vk = get_ultra_honk_verification_key(bytecode, false)?; + + // Generate proof + let proof = prove_ultra_honk(bytecode, witness.clone(), vk.clone(), false)?; + tracing::info!("✅ Proof generated ({} bytes)", proof.len()); + + let proof_bundle = ZKProofBundle { vk, proof }; + Ok(proof_bundle) +} diff --git a/crates/examples/interactive_zk/types.rs b/crates/examples/interactive_zk/types.rs new file mode 100644 index 000000000..3cf70188d --- /dev/null +++ b/crates/examples/interactive_zk/types.rs @@ -0,0 +1,21 @@ +use serde::{Deserialize, Serialize}; +use tlsn::transcript::{hash::PlaintextHash, Direction, TranscriptCommitment}; + +#[derive(Serialize, Deserialize, Debug)] +pub struct ZKProofBundle { + pub vk: Vec, + pub proof: Vec, +} + +// extract commitment from prover output +pub fn received_commitments( + transcript_commitments: &[TranscriptCommitment], +) -> Vec<&PlaintextHash> { + transcript_commitments + .iter() + .filter_map(|commitment| match commitment { + TranscriptCommitment::Hash(hash) if hash.direction == Direction::Received => Some(hash), + _ => None, + }) + .collect() +} diff --git a/crates/examples/interactive_zk/verifier.rs b/crates/examples/interactive_zk/verifier.rs new file mode 100644 index 000000000..a754400e8 --- /dev/null +++ b/crates/examples/interactive_zk/verifier.rs @@ -0,0 +1,184 @@ +use crate::types::received_commitments; + +use super::types::ZKProofBundle; +use chrono::{Local, NaiveDate}; +use noir::barretenberg::verify::{get_ultra_honk_verification_key, verify_ultra_honk}; +use serde_json::Value; +use tls_server_fixture::CA_CERT_DER; +use tlsn::{ + config::{CertificateDer, ProtocolConfigValidator, RootCertStore}, + connection::ServerName, + hash::HashAlgId, + transcript::{Direction, PartialTranscript}, + verifier::{Verifier, VerifierConfig, VerifierOutput, VerifyConfig}, +}; +use tlsn_examples::{MAX_RECV_DATA, MAX_SENT_DATA}; +use tlsn_server_fixture_certs::SERVER_DOMAIN; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite}; +use tokio_util::compat::TokioAsyncReadCompatExt; +use tracing::instrument; + +#[instrument(skip(socket, extra_socket))] +pub async fn verifier( + socket: T, + mut extra_socket: T, +) -> Result> { + // Set up Verifier. + let config_validator = ProtocolConfigValidator::builder() + .max_sent_data(MAX_SENT_DATA) + .max_recv_data(MAX_RECV_DATA) + .build()?; + + // Create a root certificate store with the server-fixture's self-signed + // certificate. This is only required for offline testing with the + // server-fixture. + let verifier_config = VerifierConfig::builder() + .root_store(RootCertStore { + roots: vec![CertificateDer(CA_CERT_DER.to_vec())], + }) + .protocol_config_validator(config_validator) + .build()?; + + let verifier = Verifier::new(verifier_config); + + // Receive authenticated data. + let VerifierOutput { + server_name, + transcript, + transcript_commitments, + .. + } = verifier + .verify(socket.compat(), &VerifyConfig::default()) + .await?; + + let server_name = server_name.ok_or("Prover should have revealed server name")?; + let transcript = transcript.ok_or("Prover should have revealed transcript data")?; + + // Create hash commitment for the date of birth field from the response + let sent = transcript.sent_unsafe().to_vec(); + let sent_data = String::from_utf8(sent.clone()) + .map_err(|e| format!("Verifier expected valid UTF-8 sent data: {}", e))?; + + if !sent_data.contains(SERVER_DOMAIN) { + return Err(format!( + "Verification failed: Expected host {} not found in sent data", + SERVER_DOMAIN + ) + .into()); + } + + // Check received data. + let received_commitments = received_commitments(&transcript_commitments); + let received_commitment = received_commitments + .first() + .ok_or("Missing received hash commitment")?; + + assert!(received_commitment.direction == Direction::Received); + assert!(received_commitment.hash.alg == HashAlgId::SHA256); + + let committed_hash = &received_commitment.hash; + + // Check Session info: server name. + let ServerName::Dns(server_name) = server_name; + if server_name.as_str() != SERVER_DOMAIN { + return Err(format!( + "Server name mismatch: expected {}, got {}", + SERVER_DOMAIN, + server_name.as_str() + ) + .into()); + } + + // Receive ZKProof information from prover + let mut buf = Vec::new(); + extra_socket.read_to_end(&mut buf).await?; + + if buf.is_empty() { + return Err("No ZK proof data received from prover".into()); + } + + let msg: ZKProofBundle = bincode::deserialize(&buf) + .map_err(|e| format!("Failed to deserialize ZK proof bundle: {}", e))?; + + // Verify zk proof + const PROGRAM_JSON: &str = include_str!("./noir/target/noir.json"); + let json: Value = serde_json::from_str(PROGRAM_JSON) + .map_err(|e| format!("Failed to parse Noir circuit: {}", e))?; + + let bytecode = json["bytecode"] + .as_str() + .ok_or("Bytecode field missing in noir.json")?; + + let vk = get_ultra_honk_verification_key(bytecode, false) + .map_err(|e| format!("Failed to get verification key: {}", e))?; + + if vk != msg.vk { + return Err("Verification key mismatch between computed and provided by prover".into()); + } + + 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; + if proof.len() < min_bytes { + return Err(format!( + "Proof too short: expected at least {} bytes, got {}", + min_bytes, + proof.len() + ) + .into()); + } + + // 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_from_proof = + NaiveDate::from_ymd_opt(proof_date_year, proof_date_month, proof_date_day) + .ok_or("Invalid proof date in proof")?; + let today = Local::now().date_naive(); + if (today - proof_date_from_proof).num_days() < 0 { + return Err(format!( + "The proof date can only be today or in the past: provided {}, today {}", + proof_date_from_proof, today + ) + .into()); + } + + // Check that the committed hash in the proof matches the hash from the + // commitment + let committed_hash_in_proof: Vec = proof + .chunks(32) + .skip(3) // skip the first 3 chunks + .take(32) + .map(|chunk| *chunk.last().unwrap_or(&0)) + .collect(); + let expected_hash = committed_hash.value.as_bytes().to_vec(); + if committed_hash_in_proof != expected_hash { + tracing::error!( + "❌ The hash in the proof does not match the committed hash in MPC-TLS: {} != {}", + hex::encode(&committed_hash_in_proof), + hex::encode(&expected_hash) + ); + return Err("Hash in proof does not match committed hash in MPC-TLS".into()); + } + tracing::info!( + "✅ The hash in the proof matches the committed hash in MPC-TLS ({})", + hex::encode(&expected_hash) + ); + + // Finally verify the proof + let is_valid = verify_ultra_honk(msg.proof, msg.vk) + .map_err(|e| format!("ZKProof Verification failed: {}", e))?; + if !is_valid { + tracing::error!("❌ Age verification ZKProof failed to verify"); + return Err("Age verification ZKProof failed to verify".into()); + } + tracing::info!("✅ Age verification ZKProof successfully verified"); + + Ok(transcript) +} diff --git a/crates/server-fixture/server/src/data/elster.json b/crates/server-fixture/server/src/data/elster.json new file mode 100644 index 000000000..78398858e --- /dev/null +++ b/crates/server-fixture/server/src/data/elster.json @@ -0,0 +1,37 @@ +{ + "tax_year": 2024, + "taxpayer": { + "idnr": "12345678901", + "first_name": "Max", + "last_name": "Mustermann", + "date_of_birth": "1985-03-12", + "address": { + "street": "Musterstraße 1", + "postal_code": "10115", + "city": "Berlin" + } + }, + "income": { + "employment_income": 54200.00, + "other_income": 1200.00, + "capital_gains": 350.00 + }, + "deductions": { + "pension_insurance": 4200.00, + "health_insurance": 3600.00, + "donations": 500.00, + "work_related_expenses": 1100.00 + }, + "assessment": { + "taxable_income": 49200.00, + "income_tax": 9156.00, + "solidarity_surcharge": 503.58, + "total_tax": 9659.58, + "prepaid_tax": 9500.00, + "refund": 159.58 + }, + "submission": { + "submitted_at": "2025-03-01T14:22:30Z", + "submitted_by": "ElsterOnline-Portal" + } +} \ No newline at end of file diff --git a/crates/server-fixture/server/src/lib.rs b/crates/server-fixture/server/src/lib.rs index c0aa7f2f4..6581078ae 100644 --- a/crates/server-fixture/server/src/lib.rs +++ b/crates/server-fixture/server/src/lib.rs @@ -47,6 +47,7 @@ fn app(state: AppState) -> Router { .route("/formats/json", get(json)) .route("/formats/html", get(html)) .route("/protected", get(protected_route)) + .route("/elster", get(elster_route)) .layer(TraceLayer::new_for_http()) .with_state(Arc::new(Mutex::new(state))) } @@ -196,6 +197,12 @@ async fn protected_route(_: AuthenticatedUser) -> Result, StatusCode get_json_value(include_str!("data/protected_data.json")) } +async fn elster_route(_: AuthenticatedUser) -> Result, StatusCode> { + info!("Handling /elster"); + + get_json_value(include_str!("data/elster.json")) +} + #[cfg(test)] mod tests { use super::*;