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":"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","file_map":{"5":{"source":"use crate::meta::derive_via;\n\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { $crate::cmp::Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for u1 {\n fn eq(self, other: u1) -> bool {\n self == other\n }\n}\n\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\nimpl Eq for (A, B)\nwhere\n A: Eq,\n B: Eq,\n{\n fn eq(self, other: (A, B)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1)\n }\n}\n\nimpl Eq for (A, B, C)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n{\n fn eq(self, other: (A, B, C)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2)\n }\n}\n\nimpl Eq for (A, B, C, D)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n{\n fn eq(self, other: (A, B, C, D)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3)\n }\n}\n\nimpl Eq for (A, B, C, D, E)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n E: Eq,\n{\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n self.0.eq(other.0)\n & self.1.eq(other.1)\n & self.2.eq(other.2)\n & self.3.eq(other.3)\n & self.4.eq(other.4)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::cmp::Ord };\n let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == $crate::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = $crate::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let mut result = self.len().cmp(other.len());\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for (A, B)\nwhere\n A: Ord,\n B: Ord,\n{\n fn cmp(self, other: (A, B)) -> Ordering {\n let result = self.0.cmp(other.0);\n\n if result != Ordering::equal() {\n result\n } else {\n self.1.cmp(other.1)\n }\n }\n}\n\nimpl Ord for (A, B, C)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n{\n fn cmp(self, other: (A, B, C)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n{\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D, E)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n E: Ord,\n{\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n if result == Ordering::equal() {\n result = self.4.cmp(other.4);\n }\n\n result\n }\n}\n\n// Compares and returns the maximum of two values.\n//\n// Returns the second argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::max(1, 2), 2);\n// assert_eq(cmp::max(2, 2), 2);\n// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n// Compares and returns the minimum of two values.\n//\n// Returns the first argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::min(1, 2), 1);\n// assert_eq(cmp::min(2, 2), 2);\n// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use crate::cmp::{max, min};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0_u64, 1), 0);\n assert_eq(min(0_u64, 0), 0);\n assert_eq(min(1_u64, 1), 1);\n assert_eq(min(255_u8, 0), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0_u64, 1), 1);\n assert_eq(max(0_u64, 0), 0);\n assert_eq(max(1_u64, 1), 1);\n assert_eq(max(255_u8, 0), 255);\n }\n}\n","path":"std/cmp.nr"},"18":{"source":"pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array.\n /// This slice will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits(self: Self) -> [u1; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i] == 1);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits(self: Self) -> [u1; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i] == 1);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [u1; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1.\n pub fn sgn0(self) -> u1 {\n self as u1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array.\n/// This slice will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits(value: Field) -> [u1; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits(value: Field) -> [u1; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [u1] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [u1] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime};\n use super::field_less_than;\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [u1; 8] = field.to_be_bits();\n assert_eq(bits, [0, 0, 0, 0, 0, 0, 1, 0]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [u1; 8] = field.to_le_bits();\n assert_eq(bits, [0, 1, 0, 0, 0, 0, 0, 0]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(f\"radix must be greater than 1\");\n }\n }\n\n // TODO: Update this test to account for the Brillig restriction that the radix must be greater than 2\n //#[test]\n //fn test_to_le_radix_brillig_1() {\n // // this test should only fail in constrained mode\n // if runtime::is_unconstrained() {\n // let field = 1;\n // let out: [u8; 8] = field.to_le_radix(1);\n // crate::println(out);\n // let expected = [0; 8];\n // assert(out == expected, \"unexpected result\");\n // }\n //}\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(f\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(f\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n // TODO: Update this test to account for the Brillig restriction that the radix must be less than 512\n //#[test]\n //fn test_to_le_radix_brillig_512() {\n // // this test should only fail in constrained mode\n // if runtime::is_unconstrained() {\n // let field = 1;\n // let out: [u8; 8] = field.to_le_radix(512);\n // let mut expected = [0; 8];\n // expected[0] = 1;\n // assert(out == expected, \"unexpected result\");\n // }\n //}\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n}\n","path":"std/field/mod.nr"},"22":{"source":"pub mod hash;\npub mod aes128;\npub mod array;\npub mod slice;\npub mod ecdsa_secp256k1;\npub mod ecdsa_secp256r1;\npub mod embedded_curve_ops;\npub mod field;\npub mod collections;\npub mod compat;\npub mod convert;\npub mod option;\npub mod string;\npub mod test;\npub mod cmp;\npub mod ops;\npub mod default;\npub mod prelude;\npub mod runtime;\npub mod meta;\npub mod append;\npub mod mem;\npub mod panic;\npub mod hint;\n\nuse convert::AsPrimitive;\n\n// Oracle calls are required to be wrapped in an unconstrained function\n// Thus, the only argument to the `println` oracle is expected to always be an ident\n#[oracle(print)]\nunconstrained fn print_oracle(with_newline: bool, input: T) {}\n\nunconstrained fn print_unconstrained(with_newline: bool, input: T) {\n print_oracle(with_newline, input);\n}\n\npub fn println(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(true, input);\n }\n}\n\npub fn print(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(false, input);\n }\n}\n\npub fn verify_proof(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n) {\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, 0);\n}\n\npub fn verify_proof_with_type(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {\n if !crate::runtime::is_unconstrained() {\n crate::assert_constant(proof_type);\n }\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\n}\n\n#[foreign(recursive_aggregation)]\nfn verify_proof_internal(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {}\n\n// Asserts that the given value is known at compile-time.\n// Useful for debugging for-loop bounds.\n#[builtin(assert_constant)]\npub fn assert_constant(x: T) {}\n\n// Asserts that the given value is both true and known at compile-time.\n// The message can be a string, a format string, or any value, as long as it is known at compile-time\n#[builtin(static_assert)]\npub fn static_assert(predicate: bool, message: T) {}\n\n#[deprecated(\"wrapping operations should be done with the Wrapping traits. E.g: x.wrapping_add(y)\")]\npub fn wrapping_add(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n AsPrimitive::as_(x.as_() + y.as_())\n}\n#[deprecated(\"wrapping operations should be done with the Wrapping traits. E.g: x.wrapping_sub(y)\")]\npub fn wrapping_sub(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n //340282366920938463463374607431768211456 is 2^128, it is used to avoid underflow\n AsPrimitive::as_(x.as_() + 340282366920938463463374607431768211456 - y.as_())\n}\n#[deprecated(\"wrapping operations should be done with the Wrapping traits. E.g: x.wrapping_mul(y)\")]\npub fn wrapping_mul(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n AsPrimitive::as_(x.as_() * y.as_())\n}\n\n#[builtin(as_witness)]\npub fn as_witness(x: Field) {}\n\nmod tests {\n use super::ops::arith::WrappingMul;\n\n #[test(should_fail_with = \"custom message\")]\n fn test_static_assert_custom_message() {\n super::static_assert(1 == 2, \"custom message\");\n }\n\n #[test]\n fn test_wrapping_mul() {\n let zero: u128 = 0;\n let one: u128 = 1;\n let two_pow_64: u128 = 0x10000000000000000;\n let u128_max: u128 = 0xffffffffffffffffffffffffffffffff;\n\n // 1*0==0\n assert_eq(zero, zero.wrapping_mul(one));\n\n // 0*1==0\n assert_eq(zero, one.wrapping_mul(zero));\n\n // 1*1==1\n assert_eq(one, one.wrapping_mul(one));\n\n // 0 * ( 1 << 64 ) == 0\n assert_eq(zero, zero.wrapping_mul(two_pow_64));\n\n // ( 1 << 64 ) * 0 == 0\n assert_eq(zero, two_pow_64.wrapping_mul(zero));\n\n // 1 * ( 1 << 64 ) == 1 << 64\n assert_eq(two_pow_64, two_pow_64.wrapping_mul(one));\n\n // ( 1 << 64 ) * 1 == 1 << 64\n assert_eq(two_pow_64, one.wrapping_mul(two_pow_64));\n\n // ( 1 << 64 ) * ( 1 << 64 ) == 1 << 64\n assert_eq(zero, two_pow_64.wrapping_mul(two_pow_64));\n // -1 * -1 == 1\n assert_eq(one, u128_max.wrapping_mul(u128_max));\n }\n}\n","path":"std/lib.nr"},"50":{"source":"use dep::date::Date;\n\nfn main(\n // Public inputs\n proof_date: pub date::Date, // \"2025-08-29\"\n committed_hash: pub [u8; 32], // Hash of (blinder || dob string)\n // Private inputs\n date_of_birth: str<10>, // \"1985-03-12\"\n blinder: [u8; 16], // Random 16-byte blinder\n) {\n let is_18 = check_18(date_of_birth, proof_date);\n\n let correct_hash = check_hash(date_of_birth, blinder, committed_hash);\n\n assert(correct_hash);\n assert(is_18);\n}\n\nfn check_18(date_of_birth: str<10>, proof_date: date::Date) -> bool {\n let dob = parse_birth_date(date_of_birth);\n let is_18 = dob.add_years(18).lt(proof_date);\n println(f\"Is 18? {is_18}\");\n is_18\n}\n\nfn check_hash(date_of_birth: str<10>, blinder: [u8; 16], committed_hash: [u8; 32]) -> bool {\n let hash_input: [u8; 26] = make_hash_input(date_of_birth, blinder);\n let computed_hash = sha256::sha256_var(hash_input, 26);\n let correct_hash = computed_hash == committed_hash;\n println(f\"Correct hash? {correct_hash}\");\n correct_hash\n}\n\nfn make_hash_input(dob: str<10>, blinder: [u8; 16]) -> [u8; 26] {\n let mut input: [u8; 26] = [0; 26];\n for i in 0..10 {\n input[i] = dob.as_bytes()[i];\n }\n for i in 0..16 {\n input[10 + i] = blinder[i];\n }\n input\n}\n\npub fn parse_birth_date(birth_date: str<10>) -> date::Date {\n let date: [u8; 10] = birth_date.as_bytes();\n let date_str: str<8> =\n [date[0], date[1], date[2], date[3], date[5], date[6], date[8], date[9]].as_str_unchecked();\n Date::from_str_long_year(date_str)\n}\n\n#[test]\nfn test_max_is_over_18() {\n // Private input\n let date_of_birth = \"1985-03-12\";\n let blinder = [120, 80, 62, 10, 76, 60, 130, 98, 147, 161, 139, 126, 27, 236, 36, 56];\n\n // Public input\n let proof_date = date::Date { year: 2025, month: 9, day: 2 };\n let committed_hash = [\n 229, 118, 202, 216, 213, 230, 125, 163, 48, 178, 118, 225, 84, 7, 140, 63, 173, 255, 163,\n 208, 163, 3, 63, 204, 37, 120, 254, 246, 202, 116, 122, 145,\n ];\n\n main(proof_date, committed_hash, date_of_birth, blinder);\n}\n\n#[test(should_fail)]\nfn test_under_18() {\n // Private input\n let date_of_birth = \"2010-08-01\";\n let blinder = [160, 23, 57, 158, 141, 195, 155, 132, 109, 242, 48, 220, 70, 217, 229, 189];\n\n // Public input\n let proof_date = date::Date { year: 2025, month: 8, day: 29 };\n let committed_hash = [\n 16, 132, 194, 62, 232, 90, 157, 153, 4, 231, 1, 54, 226, 3, 87, 174, 129, 177, 80, 69, 37,\n 222, 209, 91, 168, 156, 9, 109, 108, 144, 168, 109,\n ];\n\n main(proof_date, committed_hash, date_of_birth, blinder);\n}\n","path":"/Users/heeckhau/tlsnotary/tlsn/crates/examples/interactive_zk/noir/src/main.nr"},"51":{"source":"use std::cmp::Eq;\nuse std::println;\n\nglobal UNIX_EPOCH_YEAR: u32 = 1970;\nglobal SECONDS_IN_DAY: u32 = 86400;\n\npub struct Date {\n pub day: u8,\n pub month: u8,\n pub year: u32,\n}\n\nfn get_number_from_utf8_code(code: u8) -> u8 {\n assert(code >= 48 & code <= 57);\n code - 48\n}\n\nfn number_to_utf8_code(number: u8) -> u8 {\n assert(number >= 0 & number <= 9);\n number + 48\n}\n\nimpl Date {\n pub fn new(year: u32, month: u8, day: u8) -> Self {\n assert(month >= 1 & month <= 12);\n assert(day >= 1 & day <= 31);\n let date = Self { day: day, month: month, year: year };\n assert(day <= date.get_days_in_month(month));\n date\n }\n\n pub fn from_bytes_short_year(date: [u8; 6], threshold_date: Date) -> Self {\n let firstYearDigit = get_number_from_utf8_code(date[0]);\n let secondYearDigit = get_number_from_utf8_code(date[1]);\n\n let mut year: u32 = firstYearDigit as u32 * 10 + secondYearDigit as u32;\n\n let firstMonthDigit = get_number_from_utf8_code(date[2]);\n let secondMonthDigit = get_number_from_utf8_code(date[3]);\n\n let month = firstMonthDigit * 10 + secondMonthDigit;\n\n let firstDayDigit = get_number_from_utf8_code(date[4]);\n let secondDayDigit = get_number_from_utf8_code(date[5]);\n\n let day = firstDayDigit * 10 + secondDayDigit;\n\n let mut currentYear: u32 = threshold_date.year % 100;\n\n // This way we have a smooth 100 years period according to a threshold year\n // Taking the current year as threshold year (for birthdates for example)\n // if the current year is 2023, then 24 will be interpreted as 1924\n // while 22 will be interpreted as 2022\n // A bit problematic for people over 100 years old\n if year <= currentYear {\n year += 2000;\n } else {\n year += 1900;\n }\n\n Self { day: day, month: month, year: year }\n }\n\n pub fn from_bytes_long_year(date: [u8; 8]) -> Self {\n let firstYearDigit = get_number_from_utf8_code(date[0]);\n let secondYearDigit = get_number_from_utf8_code(date[1]);\n let thirdYearDigit = get_number_from_utf8_code(date[2]);\n let fourthYearDigit = get_number_from_utf8_code(date[3]);\n\n let year: u32 = firstYearDigit as u32 * 1000\n + secondYearDigit as u32 * 100\n + thirdYearDigit as u32 * 10\n + fourthYearDigit as u32;\n\n let firstMonthDigit = get_number_from_utf8_code(date[4]);\n let secondMonthDigit = get_number_from_utf8_code(date[5]);\n\n let month = firstMonthDigit * 10 + secondMonthDigit;\n\n let firstDayDigit = get_number_from_utf8_code(date[6]);\n let secondDayDigit = get_number_from_utf8_code(date[7]);\n\n let day = firstDayDigit * 10 + secondDayDigit;\n\n Self { day: day, month: month, year: year }\n }\n\n pub fn from_str_short_year(date: str<6>, threshold_date: Date) -> Self {\n let date_bytes = date.as_bytes();\n Date::from_bytes_short_year(date_bytes, threshold_date)\n }\n\n pub fn from_str_long_year(date: str<8>) -> Self {\n let date_bytes = date.as_bytes();\n Date::from_bytes_long_year(date_bytes)\n }\n\n fn count_leap_years_since_epoch(year: u32, epoch_year: u32) -> u32 {\n let y = year - 1;\n let leaps_up_to_y = y / 4 - y / 100 + y / 400;\n let leaps_up_to_epoch_year =\n (epoch_year - 1) / 4 - (epoch_year - 1) / 100 + (epoch_year - 1) / 400;\n leaps_up_to_y - leaps_up_to_epoch_year\n }\n\n fn days_since_epoch(year: u32, epoch_year: u32) -> u32 {\n 365 * (year - epoch_year) + Date::count_leap_years_since_epoch(year, epoch_year)\n }\n\n fn estimate_start_day_and_year(days: u32, epoch_year: u32) -> (u32, u32) {\n let first_guess_year = epoch_year + days / 365;\n\n let days_lower_bound = if first_guess_year > epoch_year {\n Date::days_since_epoch(first_guess_year - 1, epoch_year)\n } else {\n 0\n };\n let day_guess = Date::days_since_epoch(first_guess_year, epoch_year);\n let days_upper_bound = Date::days_since_epoch(first_guess_year + 1, epoch_year);\n\n let use_lower_bound = (days >= days_lower_bound) & (days < day_guess);\n let use_upper_bound = days >= days_upper_bound;\n\n let mut best_year = first_guess_year;\n let mut best_start_day = day_guess;\n\n best_year = if use_lower_bound {\n first_guess_year - 1\n } else {\n best_year\n };\n best_start_day = if use_lower_bound {\n days_lower_bound\n } else {\n best_start_day\n };\n\n best_year = if use_upper_bound {\n first_guess_year + 1\n } else {\n best_year\n };\n best_start_day = if use_upper_bound {\n days_upper_bound\n } else {\n best_start_day\n };\n\n (best_year, best_start_day)\n }\n\n pub fn from_timestamp_with_epoch(timestamp: u64, epoch_year: u32) -> Self {\n let days = timestamp / SECONDS_IN_DAY as u64;\n let (year, year_start_day) = Date::estimate_start_day_and_year(days as u32, epoch_year);\n let day_of_year = days as u32 - year_start_day;\n\n let is_leap = Date::is_leap_year(Date::new(year, 1, 1));\n\n let days_at_month_start: [u32; 13] = if is_leap {\n [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]\n } else {\n [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]\n };\n\n let mut month: u32 = 1;\n for i in 0..12 {\n let advance = day_of_year >= days_at_month_start[i + 1];\n month = if advance { month + 1 } else { month };\n }\n\n let day: u32 = day_of_year - days_at_month_start[(month - 1) as u32] + 1;\n Date::new(year, month as u8, day as u8)\n }\n\n pub fn from_timestamp(timestamp: u64) -> Self {\n Date::from_timestamp_with_epoch(timestamp, UNIX_EPOCH_YEAR)\n }\n\n pub fn get_duration_in_days(self: Self, other: Self, absolute: bool) -> i64 {\n let mut duration_years = self.get_duration_between_years(other);\n let mut duration_months = self.get_duration_between_months(other);\n let mut duration_days = self.day as i64 - other.day as i64;\n if (self.year < other.year) {\n if (other.is_leap_year() & other.month > 2 & self.month > 2) {\n duration_days -= 1;\n }\n } else if (self.year > other.year) {\n if (self.is_leap_year() & self.month > 2 & other.month > 2) {\n duration_days += 1;\n }\n }\n let totalDuration: i64 = duration_years + duration_months + duration_days;\n\n if (totalDuration < 0) & absolute {\n -1 * totalDuration\n } else {\n totalDuration\n }\n }\n\n pub fn gt(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) > 0\n }\n\n pub fn lt(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) < 0\n }\n\n pub fn eq(self: Self, other: Self) -> bool {\n (self.day == other.day) & (self.month == other.month) & (self.year == other.year)\n }\n\n pub fn ne(self: Self, other: Self) -> bool {\n !self.eq(other)\n }\n\n pub fn gte(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) >= 0\n }\n\n pub fn lte(self: Self, other: Self) -> bool {\n self.get_duration_in_days(other, false) <= 0\n }\n\n pub fn println(self: Self) {\n let year = self.year;\n let month = self.month;\n let day = self.day;\n // Let's write the date in the YYYY-MM-DD format\n // since people don't agree on which format is best\n // between MM/DD/YYYY and DD/MM/YYYY\n if (month < 10) & (day < 10) {\n println(f\"Date: {year}-0{month}-0{day}\");\n } else if month < 10 {\n println(f\"Date: {year}-0{month}-{day}\");\n } else if day < 10 {\n println(f\"Date: {year}-{month}-0{day}\");\n } else {\n println(f\"Date: {year}-{month}-{day}\");\n }\n }\n\n pub fn to_bytes(self: Self) -> [u8; 8] {\n let mut date: [u8; 8] = [0; 8];\n\n let firstYearDigit = self.year / 1000;\n let secondYearDigit = (self.year - firstYearDigit * 1000) / 100;\n let thirdYearDigit = (self.year - firstYearDigit * 1000 - secondYearDigit * 100) / 10;\n let fourthYearDigit =\n self.year - firstYearDigit * 1000 - secondYearDigit * 100 - thirdYearDigit * 10;\n\n date[0] = number_to_utf8_code(firstYearDigit as u8);\n date[1] = number_to_utf8_code(secondYearDigit as u8);\n date[2] = number_to_utf8_code(thirdYearDigit as u8);\n date[3] = number_to_utf8_code(fourthYearDigit as u8);\n\n let firstMonthDigit = self.month / 10;\n let secondMonthDigit = self.month - firstMonthDigit * 10;\n\n date[4] = number_to_utf8_code(firstMonthDigit as u8);\n date[5] = number_to_utf8_code(secondMonthDigit as u8);\n\n let firstDayDigit = self.day / 10;\n let secondDayDigit = self.day - firstDayDigit * 10;\n\n date[6] = number_to_utf8_code(firstDayDigit as u8);\n date[7] = number_to_utf8_code(secondDayDigit as u8);\n\n date\n }\n\n pub fn to_string(self: Self) -> str<8> {\n let date_bytes = self.to_bytes();\n date_bytes.as_str_unchecked()\n }\n\n pub fn to_timestamp_with_epoch(self: Self, epoch_year: u32) -> u32 {\n let days = self.get_duration_in_days(Date::new(epoch_year, 1, 1), true);\n days as u32 * SECONDS_IN_DAY\n }\n\n pub fn to_timestamp(self: Self) -> u32 {\n self.to_timestamp_with_epoch(UNIX_EPOCH_YEAR)\n }\n\n pub fn is_leap_year(self: Self) -> bool {\n ((self.year % 4 == 0) & (self.year % 100 != 0)) | (self.year % 400 == 0)\n }\n\n pub fn leap_year_count(year: u32) -> i32 {\n (year / 4) as i32 - (year / 100) as i32 + (year / 400) as i32\n }\n\n pub fn get_days_in_month(self: Self, month: u8) -> u8 {\n assert(month >= 1 & month <= 12);\n if month == 2 {\n if self.is_leap_year() {\n 29\n } else {\n 28\n }\n } else {\n if (month == 1)\n | (month == 3)\n | (month == 5)\n | (month == 7)\n | (month == 8)\n | (month == 10)\n | (month == 12) {\n 31\n } else {\n 30\n }\n }\n }\n\n pub fn get_duration_between_months(self: Self, other: Self) -> i64 {\n assert(self.month >= 1 & self.month <= 12);\n assert(other.month >= 1 & other.month <= 12);\n let mut duration: i64 = 0;\n if (self.month < other.month) {\n for month in 1..13 {\n if month >= self.month & month < other.month {\n duration -= other.get_days_in_month(month) as i64;\n }\n }\n } else {\n for month in 1..13 {\n if month >= other.month & month < self.month {\n duration += self.get_days_in_month(month) as i64;\n }\n }\n }\n duration\n }\n\n pub fn get_duration_between_years(self: Self, other: Self) -> i64 {\n let mut duration: i64 = 0;\n if (self.year < other.year) {\n let mut leap_year_count: i32 =\n Date::leap_year_count(other.year - 1) - Date::leap_year_count(self.year);\n if self.is_leap_year() {\n leap_year_count += 1;\n }\n duration -= leap_year_count as i64 * 366;\n duration -=\n (other.year as i64 - self.year as i64 - leap_year_count as i64) as i64 * 365;\n } else if (self.year > other.year) {\n let mut leap_year_count: i32 =\n Date::leap_year_count(self.year - 1) - Date::leap_year_count(other.year);\n if other.is_leap_year() {\n leap_year_count += 1;\n }\n duration += leap_year_count as i64 * 366;\n duration +=\n (self.year as i64 - other.year as i64 - leap_year_count as i64) as i64 * 365;\n }\n duration\n }\n\n pub fn add_years(self: Self, years: u32) -> Self {\n Self { day: self.day, month: self.month, year: self.year + years }\n }\n\n pub fn sub_years(self: Self, years: u32) -> Self {\n Self { day: self.day, month: self.month, year: self.year - years }\n }\n\n pub fn add_months(self: Self, months: u32) -> Self {\n let mut newMonth = self.month as u32 + months;\n let mut newYear = self.year;\n let yearToAdd = (newMonth - 1) / 12;\n if newMonth > 12 {\n newYear += yearToAdd as u32;\n newMonth -= 12 * yearToAdd;\n }\n Self { day: self.day, month: newMonth as u8, year: newYear }\n }\n\n pub fn sub_months(self: Self, months: u32) -> Self {\n let mut newMonth = self.month as i32 - months as i32;\n let mut newYear = self.year;\n if newMonth < 1 {\n let yearToSub = ((newMonth as i32 - 12 as i32) * -1) / 12;\n newYear -= yearToSub as u32;\n newMonth += 12 * yearToSub;\n }\n Self { day: self.day, month: newMonth as u8, year: newYear }\n }\n\n pub fn add_days(self: Self, days: u32) -> Self {\n let mut newDay = self.day as u32 + days;\n let mut newMonth = self.month as u32;\n let mut newYear = self.year;\n let mut date = Self { day: newDay as u8, month: newMonth as u8, year: newYear };\n if newDay > self.get_days_in_month(self.month) as u32 {\n let max_months = (newDay / 30) + 1;\n let bound = self.month as u64 + max_months as u64;\n for _ in self.month as u64..bound as u64 {\n let days_in_month = date.get_days_in_month(newMonth as u8) as u32;\n if newDay > days_in_month {\n newDay -= days_in_month;\n newMonth += 1;\n if newMonth > 12 {\n newYear += 1;\n newMonth = 1;\n }\n // We need to mutate the date object inside the loop\n // so we can use get_days_in_month properly\n date.day = newDay as u8;\n date.year = newYear;\n date.month = newMonth as u8;\n }\n }\n }\n date\n }\n\n // Performance could be improved\n pub fn sub_days(self: Self, days: u32) -> Self {\n let mut newDay = self.day as i32 - days as i32;\n let mut newMonth = self.month as i32;\n let mut newYear = self.year;\n let mut date = Self { day: newDay as u8, month: newMonth as u8, year: newYear };\n if newDay < 1 {\n let max_months = (self.day as u32 + days) / 30 + 1;\n let bound = self.month as u64 + max_months as u64;\n for _ in self.month as u64..bound as u64 {\n let days_in_month = date.get_days_in_month(newMonth as u8) as i32;\n if newDay < 1 {\n newDay += days_in_month;\n newMonth -= 1;\n if newMonth < 1 {\n newYear -= 1;\n newMonth = 12;\n }\n // We need to mutate the date object inside the loop\n // so we can use get_days_in_month properly\n date.day = newDay as u8;\n date.year = newYear;\n date.month = newMonth as u8;\n }\n }\n }\n date\n }\n}\n\nimpl Eq for Date {\n fn eq(self: Self, other: Self) -> bool {\n self.eq(other)\n }\n}\n","path":"/Users/heeckhau/nargo/github.com/madztheo/noir-date.git/v0.5.4/src/date.nr"},"62":{"source":"use std::hash::sha256_compression;\nuse std::runtime::is_unconstrained;\n\nuse constants::{\n BLOCK_BYTE_PTR, BLOCK_SIZE, HASH, INITIAL_STATE, INT_BLOCK, INT_BLOCK_SIZE, INT_SIZE,\n INT_SIZE_PTR, MSG_BLOCK, MSG_SIZE_PTR, STATE, TWO_POW_16, TWO_POW_24, TWO_POW_32, TWO_POW_8,\n};\n\npub(crate) mod constants;\nmod tests;\n\n// Implementation of SHA-256 mapping a byte array of variable length to\n// 32 bytes.\n\n// Deprecated in favour of `sha256_var`\n// docs:start:sha256\npub fn sha256(input: [u8; N]) -> HASH\n// docs:end:sha256\n{\n digest(input)\n}\n\n// SHA-256 hash function\n#[no_predicates]\npub fn digest(msg: [u8; N]) -> HASH {\n sha256_var(msg, N as u64)\n}\n\n// Variable size SHA-256 hash\npub fn sha256_var(msg: [u8; N], message_size: u64) -> HASH {\n let message_size = message_size as u32;\n assert(message_size <= N);\n\n if std::runtime::is_unconstrained() {\n // Safety: SHA256 is running as an unconstrained function.\n unsafe {\n __sha256_var(msg, message_size)\n }\n } else {\n let (mut h, mut msg_block, mut msg_byte_ptr) =\n process_full_blocks(msg, message_size, INITIAL_STATE);\n\n finalize_sha256_blocks(msg, message_size, N, h, msg_block, msg_byte_ptr)\n }\n}\n\npub(crate) unconstrained fn __sha_var(\n msg: [u8; N],\n message_size: u32,\n initial_state: STATE,\n) -> HASH {\n let num_full_blocks = message_size / BLOCK_SIZE;\n // Intermediate hash, starting with the canonical initial value\n let mut h: STATE = initial_state;\n // Pointer into msg_block on a 64 byte scale\n for i in 0..num_full_blocks {\n let (msg_block, _) = build_msg_block(msg, message_size, BLOCK_SIZE * i);\n h = sha256_compression(msg_block, h);\n }\n\n // Handle setup of the final msg block.\n // This case is only hit if the msg is less than the block size,\n // or our message cannot be evenly split into blocks.\n\n finalize_last_sha256_block(h, message_size, msg)\n}\n\n// Helper function to finalize the message block with padding and length\npub(crate) unconstrained fn finalize_last_sha256_block(\n mut h: STATE,\n message_size: u32,\n msg: [u8; N],\n) -> HASH {\n let modulo = message_size % BLOCK_SIZE;\n let (mut msg_block, mut msg_byte_ptr): (INT_BLOCK, u32) = if modulo != 0 {\n let num_full_blocks = message_size / BLOCK_SIZE;\n let msg_start = BLOCK_SIZE * num_full_blocks;\n let (new_msg_block, new_msg_byte_ptr) = build_msg_block(msg, message_size, msg_start);\n (new_msg_block, new_msg_byte_ptr)\n } else {\n // If we had modulo == 0 then it means the last block was full,\n // and we can reset the pointer to zero to overwrite it.\n ([0; INT_BLOCK_SIZE], 0)\n };\n\n // Pad the rest such that we have a [u32; 2] block at the end representing the length\n // of the message, and a block of 1 0 ... 0 following the message (i.e. [1 << 7, 0, ..., 0]).\n // Here we rely on the fact that everything beyond the available input is set to 0.\n let index = msg_byte_ptr / INT_SIZE;\n msg_block[index] = set_item_byte_then_zeros(msg_block[index], msg_byte_ptr, 1 << 7);\n\n // If we don't have room to write the size, compress the block and reset it.\n let (h, mut msg_byte_ptr): (STATE, u32) = if msg_byte_ptr >= MSG_SIZE_PTR {\n // `attach_len_to_msg_block` will zero out everything after the `msg_byte_ptr`.\n (sha256_compression(msg_block, h), 0)\n } else {\n (h, msg_byte_ptr + 1)\n };\n msg_block = attach_len_to_msg_block(msg_block, msg_byte_ptr, message_size);\n\n hash_final_block(msg_block, h)\n}\n\n// Variable size SHA-256 hash\nunconstrained fn __sha256_var(msg: [u8; N], message_size: u32) -> HASH {\n __sha_var(msg, message_size, INITIAL_STATE)\n}\n\npub(crate) fn process_full_blocks(\n msg: [u8; N],\n message_size: u32,\n mut h: STATE,\n) -> (STATE, MSG_BLOCK, u32) {\n let mut msg_block: MSG_BLOCK = [0; INT_BLOCK_SIZE];\n let mut msg_byte_ptr = 0;\n let num_blocks = N / BLOCK_SIZE;\n for i in 0..num_blocks {\n let msg_start = BLOCK_SIZE * i;\n let (new_msg_block, new_msg_byte_ptr) =\n // Safety: separate verification function\n unsafe { build_msg_block(msg, message_size, msg_start) };\n\n if msg_start < message_size {\n msg_block = new_msg_block;\n }\n\n // Verify the block we are compressing was appropriately constructed\n let new_msg_byte_ptr = verify_msg_block(msg, message_size, msg_block, msg_start);\n if msg_start < message_size {\n msg_byte_ptr = new_msg_byte_ptr;\n }\n\n // If the block is filled, compress it.\n // An un-filled block is handled after this loop.\n if (msg_start < message_size) & (msg_byte_ptr == BLOCK_SIZE) {\n h = sha256_compression(msg_block, h);\n }\n }\n (h, msg_block, msg_byte_ptr)\n}\n\n// Take `BLOCK_SIZE` number of bytes from `msg` starting at `msg_start`.\n// Returns the block and the length that has been copied rather than padded with zeros.\npub(crate) unconstrained fn build_msg_block(\n msg: [u8; N],\n message_size: u32,\n msg_start: u32,\n) -> (MSG_BLOCK, BLOCK_BYTE_PTR) {\n let mut msg_block: MSG_BLOCK = [0; INT_BLOCK_SIZE];\n\n // We insert `BLOCK_SIZE` bytes (or up to the end of the message)\n let block_input = if message_size < msg_start {\n // This function is sometimes called with `msg_start` past the end of the message.\n // In this case we return an empty block and zero pointer to signal that the result should be ignored.\n 0\n } else if message_size < msg_start + BLOCK_SIZE {\n message_size - msg_start\n } else {\n BLOCK_SIZE\n };\n\n // Figure out the number of items in the int array that we have to pack.\n // e.g. if the input is [0,1,2,3,4,5] then we need to pack it as 2 items: [0123, 4500]\n let int_input = (block_input + INT_SIZE - 1) / INT_SIZE;\n\n for i in 0..int_input {\n let mut msg_item: u32 = 0;\n // Always construct the integer as 4 bytes, even if it means going beyond the input.\n for j in 0..INT_SIZE {\n let k = i * INT_SIZE + j;\n let msg_byte = if k < block_input {\n msg[msg_start + k]\n } else {\n 0\n };\n msg_item = lshift8(msg_item, 1) + msg_byte as u32;\n }\n msg_block[i] = msg_item;\n }\n\n // Returning the index as if it was a 64 byte array.\n // We have to project it down to 16 items and bit shifting to get a byte back if we need it.\n (msg_block, block_input)\n}\n\n// Verify the block we are compressing was appropriately constructed by `build_msg_block`\n// and matches the input data. Returns the index of the first unset item.\n// If `message_size` is less than `msg_start` then this is called with the old non-empty block;\n// in that case we can skip verification, ie. no need to check that everything is zero.\nfn verify_msg_block(\n msg: [u8; N],\n message_size: u32,\n msg_block: MSG_BLOCK,\n msg_start: u32,\n) -> BLOCK_BYTE_PTR {\n let mut msg_byte_ptr = 0;\n let mut msg_end = msg_start + BLOCK_SIZE;\n if msg_end > N {\n msg_end = N;\n }\n // We might have to go beyond the input to pad the fields.\n if msg_end % INT_SIZE != 0 {\n msg_end = msg_end + INT_SIZE - msg_end % INT_SIZE;\n }\n\n // Reconstructed packed item.\n let mut msg_item: u32 = 0;\n\n // Inclusive at the end so that we can compare the last item.\n let mut i: u32 = 0;\n for k in msg_start..=msg_end {\n if k % INT_SIZE == 0 {\n // If we consumed some input we can compare against the block.\n if (msg_start < message_size) & (k > msg_start) {\n assert_eq(msg_block[i], msg_item as u32);\n i = i + 1;\n msg_item = 0;\n }\n }\n // Shift the accumulator\n msg_item = lshift8(msg_item, 1);\n // If we have input to consume, add it at the rightmost position.\n if k < message_size & k < msg_end {\n msg_item = msg_item + msg[k] as u32;\n msg_byte_ptr = msg_byte_ptr + 1;\n }\n }\n\n msg_byte_ptr\n}\n\n// Verify the block we are compressing was appropriately padded with zeros by `build_msg_block`.\n// This is only relevant for the last, potentially partially filled block.\nfn verify_msg_block_padding(msg_block: MSG_BLOCK, msg_byte_ptr: BLOCK_BYTE_PTR) {\n // Check all the way to the end of the block.\n verify_msg_block_zeros(msg_block, msg_byte_ptr, INT_BLOCK_SIZE);\n}\n\n// Verify that a region of ints in the message block are (partially) zeroed,\n// up to an (exclusive) maximum which can either be the end of the block\n// or just where the size is to be written.\nfn verify_msg_block_zeros(\n msg_block: MSG_BLOCK,\n mut msg_byte_ptr: BLOCK_BYTE_PTR,\n max_int_byte_ptr: u32,\n) {\n // This variable is used to get around the compiler under-constrained check giving a warning.\n // We want to check against a constant zero, but if it does not come from the circuit inputs\n // or return values the compiler check will issue a warning.\n let zero = msg_block[0] - msg_block[0];\n\n // First integer which is supposed to be (partially) zero.\n let mut int_byte_ptr = msg_byte_ptr / INT_SIZE;\n\n // Check partial zeros.\n let modulo = msg_byte_ptr % INT_SIZE;\n if modulo != 0 {\n let zeros = INT_SIZE - modulo;\n let mask = if zeros == 3 {\n TWO_POW_24\n } else if zeros == 2 {\n TWO_POW_16\n } else {\n TWO_POW_8\n };\n assert_eq(msg_block[int_byte_ptr] % mask, zero);\n int_byte_ptr = int_byte_ptr + 1;\n }\n\n // Check the rest of the items.\n for i in 0..max_int_byte_ptr {\n if i >= int_byte_ptr {\n assert_eq(msg_block[i], zero);\n }\n }\n}\n\n// Verify that up to the byte pointer the two blocks are equal.\n// At the byte pointer the new block can be partially zeroed.\nfn verify_msg_block_equals_last(\n msg_block: MSG_BLOCK,\n last_block: MSG_BLOCK,\n mut msg_byte_ptr: BLOCK_BYTE_PTR,\n) {\n // msg_byte_ptr is the position at which they are no longer have to be the same.\n // First integer which is supposed to be (partially) zero contains that pointer.\n let mut int_byte_ptr = msg_byte_ptr / INT_SIZE;\n\n // Check partial zeros.\n let modulo = msg_byte_ptr % INT_SIZE;\n if modulo != 0 {\n // Reconstruct the partially zero item from the last block.\n let last_field = last_block[int_byte_ptr];\n let mut msg_item: u32 = 0;\n // Reset to where they are still equal.\n msg_byte_ptr = msg_byte_ptr - modulo;\n for i in 0..INT_SIZE {\n msg_item = lshift8(msg_item, 1);\n if i < modulo {\n msg_item = msg_item + get_item_byte(last_field, msg_byte_ptr) as u32;\n msg_byte_ptr = msg_byte_ptr + 1;\n }\n }\n assert_eq(msg_block[int_byte_ptr], msg_item);\n }\n\n for i in 0..INT_SIZE_PTR {\n if i < int_byte_ptr {\n assert_eq(msg_block[i], last_block[i]);\n }\n }\n}\n\n// Set the rightmost `zeros` number of bytes to 0.\n#[inline_always]\nfn set_item_zeros(item: u32, zeros: u8) -> u32 {\n lshift8(rshift8(item, zeros), zeros)\n}\n\n// Replace one byte in the item with a value, and set everything after it to zero.\nfn set_item_byte_then_zeros(msg_item: u32, msg_byte_ptr: BLOCK_BYTE_PTR, msg_byte: u8) -> u32 {\n let zeros = INT_SIZE - msg_byte_ptr % INT_SIZE;\n let zeroed_item = set_item_zeros(msg_item, zeros as u8);\n let new_item = byte_into_item(msg_byte, msg_byte_ptr);\n zeroed_item + new_item\n}\n\n// Get a byte of a message item according to its overall position in the `BLOCK_SIZE` space.\nfn get_item_byte(mut msg_item: u32, msg_byte_ptr: BLOCK_BYTE_PTR) -> u8 {\n // How many times do we have to shift to the right to get to the position we want?\n let max_shifts = INT_SIZE - 1;\n let shifts = max_shifts - msg_byte_ptr % INT_SIZE;\n msg_item = rshift8(msg_item, shifts as u8);\n // At this point the byte we want is in the rightmost position.\n msg_item as u8\n}\n\n// Project a byte into a position in a field based on the overall block pointer.\n// For example putting 1 into pointer 5 would be 100, because overall we would\n// have [____, 0100] with indexes [0123,4567].\n#[inline_always]\nfn byte_into_item(msg_byte: u8, msg_byte_ptr: BLOCK_BYTE_PTR) -> u32 {\n let mut msg_item = msg_byte as u32;\n // How many times do we have to shift to the left to get to the position we want?\n let max_shifts = INT_SIZE - 1;\n let shifts = max_shifts - msg_byte_ptr % INT_SIZE;\n lshift8(msg_item, shifts as u8)\n}\n\n// Construct a field out of 4 bytes.\n#[inline_always]\nfn make_item(b0: u8, b1: u8, b2: u8, b3: u8) -> u32 {\n let mut item = b0 as u32;\n item = lshift8(item, 1) + b1 as u32;\n item = lshift8(item, 1) + b2 as u32;\n item = lshift8(item, 1) + b3 as u32;\n item\n}\n\n// Shift by 8 bits to the left between 0 and 4 times.\n// Checks `is_unconstrained()` to just use a bitshift if we're running in an unconstrained context,\n// otherwise multiplies by 256.\n#[inline_always]\nfn lshift8(item: u32, shifts: u8) -> u32 {\n if is_unconstrained() {\n // Brillig wouldn't shift 0<<4 without overflow.\n if shifts >= 4 {\n 0\n } else {\n item << (8 * shifts)\n }\n } else {\n // We can do a for loop up to INT_SIZE or an if-else.\n if shifts == 0 {\n item\n } else if shifts == 1 {\n item * TWO_POW_8\n } else if shifts == 2 {\n item * TWO_POW_16\n } else if shifts == 3 {\n item * TWO_POW_24\n } else {\n // Doesn't make sense, but it's most likely called on 0 anyway.\n 0\n }\n }\n}\n\n// Shift by 8 bits to the right between 0 and 4 times.\n// Checks `is_unconstrained()` to just use a bitshift if we're running in an unconstrained context,\n// otherwise divides by 256.\n#[inline_always]\nfn rshift8(item: u32, shifts: u8) -> u32 {\n if is_unconstrained() {\n item >> (8 * shifts)\n } else {\n // Division wouldn't work on `Field`.\n if shifts == 0 {\n item\n } else if shifts == 1 {\n item / TWO_POW_8\n } else if shifts == 2 {\n item / TWO_POW_16\n } else if shifts == 3 {\n item / TWO_POW_24\n } else {\n 0\n }\n }\n}\n\n// Zero out all bytes between the end of the message and where the length is appended,\n// then write the length into the last 8 bytes of the block.\nunconstrained fn attach_len_to_msg_block(\n mut msg_block: MSG_BLOCK,\n mut msg_byte_ptr: BLOCK_BYTE_PTR,\n message_size: u32,\n) -> MSG_BLOCK {\n // We assume that `msg_byte_ptr` is less than 57 because if not then it is reset to zero before calling this function.\n // In any case, fill blocks up with zeros until the last 64 bits (i.e. until msg_byte_ptr = 56).\n // There can be one item which has to be partially zeroed.\n let modulo = msg_byte_ptr % INT_SIZE;\n if modulo != 0 {\n // Index of the block in which we find the item we need to partially zero.\n let i = msg_byte_ptr / INT_SIZE;\n let zeros = INT_SIZE - modulo;\n msg_block[i] = set_item_zeros(msg_block[i], zeros as u8);\n msg_byte_ptr = msg_byte_ptr + zeros;\n }\n\n // The rest can be zeroed without bit shifting anything.\n for i in (msg_byte_ptr / INT_SIZE)..INT_SIZE_PTR {\n msg_block[i] = 0;\n }\n\n // Set the last two 4 byte ints as the first/second half of the 8 bytes of the length.\n let len = 8 * message_size;\n let len_bytes: [u8; 8] = (len as Field).to_be_bytes();\n msg_block[INT_SIZE_PTR] = (len_bytes[0] as u32) << 24\n | (len_bytes[1] as u32) << 16\n | (len_bytes[2] as u32) << 8\n | (len_bytes[3] as u32);\n\n msg_block[INT_SIZE_PTR + 1] = (len_bytes[4] as u32) << 24\n | (len_bytes[5] as u32) << 16\n | (len_bytes[6] as u32) << 8\n | (len_bytes[7] as u32);\n\n msg_block\n}\n\n// Verify that the message length was correctly written by `attach_len_to_msg_block`,\n// and that everything between the byte pointer and the size pointer was zeroed,\n// and that everything before the byte pointer was untouched.\nfn verify_msg_len(\n msg_block: MSG_BLOCK,\n last_block: MSG_BLOCK,\n msg_byte_ptr: BLOCK_BYTE_PTR,\n message_size: u32,\n) {\n // Check zeros up to the size pointer.\n verify_msg_block_zeros(msg_block, msg_byte_ptr, INT_SIZE_PTR);\n\n // Check that up to the pointer we match the last block.\n verify_msg_block_equals_last(msg_block, last_block, msg_byte_ptr);\n\n // We verify the message length was inserted correctly by reversing the byte decomposition.\n std::static_assert(\n INT_SIZE_PTR + 2 == INT_BLOCK_SIZE,\n \"INT_SIZE_PTR + 2 must equal INT_BLOCK_SIZE\",\n );\n let reconstructed_len_hi = msg_block[INT_SIZE_PTR] as Field;\n let reconstructed_len_lo = msg_block[INT_SIZE_PTR + 1] as Field;\n\n let reconstructed_len: Field =\n reconstructed_len_hi * TWO_POW_32 as Field + reconstructed_len_lo;\n let len = 8 * (message_size as Field);\n assert_eq(reconstructed_len, len);\n}\n\n// Perform the final compression, then transform the `STATE` into `HASH`.\nfn hash_final_block(msg_block: MSG_BLOCK, mut state: STATE) -> HASH {\n let mut out_h: HASH = [0; 32]; // Digest as sequence of bytes\n // Hash final padded block\n state = sha256_compression(msg_block, state);\n\n // Return final hash as byte array\n for j in 0..8 {\n let h_bytes: [u8; 4] = (state[j] as Field).to_be_bytes();\n for k in 0..4 {\n out_h[4 * j + k] = h_bytes[k];\n }\n }\n\n out_h\n}\n\npub(crate) fn finalize_sha256_blocks(\n msg: [u8; N],\n message_size: u32,\n total_len: u32,\n mut h: STATE,\n mut msg_block: MSG_BLOCK,\n mut msg_byte_ptr: u32,\n) -> HASH {\n let modulo = total_len % BLOCK_SIZE;\n // Handle setup of the final msg block.\n // This case is only hit if the msg is less than the block size,\n // or our message cannot be evenly split into blocks.\n if modulo != 0 {\n let num_blocks = total_len / BLOCK_SIZE;\n let msg_start = BLOCK_SIZE * num_blocks;\n let (new_msg_block, new_msg_byte_ptr) =\n // Safety: separate verification function\n unsafe { build_msg_block(msg, message_size, msg_start) };\n\n if msg_start < message_size {\n msg_block = new_msg_block;\n }\n\n let new_msg_byte_ptr = verify_msg_block(msg, message_size, msg_block, msg_start);\n if msg_start < message_size {\n msg_byte_ptr = new_msg_byte_ptr;\n verify_msg_block_padding(msg_block, msg_byte_ptr);\n }\n }\n\n // If we had modulo == 0 then it means the last block was full,\n // and we can reset the pointer to zero to overwrite it.\n if msg_byte_ptr == BLOCK_SIZE {\n msg_byte_ptr = 0;\n }\n\n // Pad the rest such that we have a [u32; 2] block at the end representing the length\n // of the message, and a block of 1 0 ... 0 following the message (i.e. [1 << 7, 0, ..., 0]).\n // Here we rely on the fact that everything beyond the available input is set to 0.\n let index = msg_byte_ptr / INT_SIZE;\n msg_block[index] = set_item_byte_then_zeros(msg_block[index], msg_byte_ptr, 1 << 7);\n\n msg_byte_ptr = msg_byte_ptr + 1;\n let last_block = msg_block;\n\n // If we don't have room to write the size, compress the block and reset it.\n if msg_byte_ptr > MSG_SIZE_PTR {\n h = sha256_compression(msg_block, h);\n\n // `attach_len_to_msg_block` will zero out everything after the `msg_byte_ptr`.\n msg_byte_ptr = 0;\n }\n\n // Safety: separate verification function\n msg_block = unsafe { attach_len_to_msg_block(msg_block, msg_byte_ptr, message_size) };\n\n verify_msg_len(msg_block, last_block, msg_byte_ptr, message_size);\n\n hash_final_block(msg_block, h)\n}\n\n/**\n * Given some state of a partially computed sha256 hash and part of the preimage, continue hashing\n * @notice used for complex/ recursive offloading of post-partial hashing\n *\n * @param N - the maximum length of the message to hash\n * @param h - the intermediate hash state\n * @param msg - the preimage to hash\n * @param message_size - the actual length of the preimage to hash\n * @return the intermediate hash state after compressing in msg to h\n */\npub fn partial_sha256_var_interstitial(\n mut h: [u32; 8],\n msg: [u8; N],\n message_size: u32,\n) -> [u32; 8] {\n assert(message_size % BLOCK_SIZE == 0, \"Message size must be a multiple of the block size\");\n if std::runtime::is_unconstrained() {\n // Safety: running as an unconstrained function\n unsafe {\n __sha_partial_var_interstitial(h, msg, message_size)\n }\n } else {\n let (mut h, _, _) = process_full_blocks(msg, message_size, h);\n\n h\n }\n}\n\n/**\n * Given some state of a partially computed sha256 hash and remaining preimage, complete the hash\n * @notice used for traditional partial hashing\n *\n * @param N - the maximum length of the message to hash\n * @param h - the intermediate hash state\n * @param msg - the remaining preimage to hash\n * @param message_size - the size of the current chunk\n * @param real_message_size - the total size of the original preimage\n * @return finalized sha256 hash\n */\npub fn partial_sha256_var_end(\n mut h: [u32; 8],\n msg: [u8; N],\n message_size: u32,\n real_message_size: u32,\n) -> [u8; 32] {\n assert(message_size % BLOCK_SIZE == 0, \"Message size must be a multiple of the block size\");\n if std::runtime::is_unconstrained() {\n // Safety: running as an unconstrained function\n unsafe {\n h = __sha_partial_var_interstitial(h, msg, message_size);\n\n // Handle setup of the final msg block.\n // This case is only hit if the msg is less than the block size,\n // or our message cannot be evenly split into blocks.\n\n finalize_last_sha256_block(h, real_message_size, msg)\n }\n } else {\n let (mut h, mut msg_block, mut msg_byte_ptr) = process_full_blocks(msg, message_size, h);\n finalize_sha256_blocks(msg, real_message_size, N, h, msg_block, msg_byte_ptr)\n }\n}\n\nunconstrained fn __sha_partial_var_interstitial(\n mut h: [u32; 8],\n msg: [u8; N],\n message_size: u32,\n) -> [u32; 8] {\n let num_full_blocks = message_size / BLOCK_SIZE;\n // Intermediate hash, starting with the canonical initial value\n // Pointer into msg_block on a 64 byte scale\n for i in 0..num_full_blocks {\n let (msg_block, _) = build_msg_block(msg, message_size, BLOCK_SIZE * i);\n h = sha256_compression(msg_block, h);\n }\n h\n}\n\nmod equivalence_test {\n\n #[test]\n fn test_implementations_agree(msg: [u8; 100], message_size: u64) {\n let message_size = message_size % 100;\n // Safety: test function\n let unconstrained_sha = unsafe { super::__sha256_var(msg, message_size as u32) };\n let sha = super::sha256_var(msg, message_size);\n assert_eq(sha, unconstrained_sha);\n }\n}\n","path":"/Users/heeckhau/nargo/github.com/noir-lang/sha256/v0.1.5/src/sha256.nr"}},"names":["main"],"brillig_names":["print_unconstrained","build_msg_block","attach_len_to_msg_block","print_unconstrained","directive_integer_quotient","directive_invert","directive_to_radix"]}
\ No newline at end of file
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::*;