mirror of
https://github.com/tlsnotary/tlsn.git
synced 2026-01-12 16:18:43 -05:00
Compare commits
4 Commits
plot_py
...
feat/integ
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1ee91e63b | ||
|
|
57f85dcdf2 | ||
|
|
727dff3ac9 | ||
|
|
830d0ab0d5 |
190
Cargo.lock
generated
190
Cargo.lock
generated
@@ -174,9 +174,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "alloy-consensus"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b6440213a22df93a87ed512d2f668e7dc1d62a05642d107f82d61edc9e12370"
|
||||
checksum = "2e318e25fb719e747a7e8db1654170fc185024f3ed5b10f86c08d448a912f6e2"
|
||||
dependencies = [
|
||||
"alloy-eips",
|
||||
"alloy-primitives",
|
||||
@@ -201,9 +201,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-consensus-any"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15d0bea09287942405c4f9d2a4f22d1e07611c2dbd9d5bf94b75366340f9e6e0"
|
||||
checksum = "364380a845193a317bcb7a5398fc86cdb66c47ebe010771dde05f6869bf9e64a"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -253,9 +253,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-eips"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bd2c7ae05abcab4483ce821f12f285e01c0b33804e6883dd9ca1569a87ee2be"
|
||||
checksum = "a4c4d7c5839d9f3a467900c625416b24328450c65702eb3d8caff8813e4d1d33"
|
||||
dependencies = [
|
||||
"alloy-eip2124",
|
||||
"alloy-eip2930",
|
||||
@@ -288,9 +288,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-json-rpc"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "003f46c54f22854a32b9cc7972660a476968008ad505427eabab49225309ec40"
|
||||
checksum = "f72cf87cda808e593381fb9f005ffa4d2475552b7a6c5ac33d087bf77d82abd0"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-sol-types",
|
||||
@@ -303,9 +303,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-network"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f4029954d9406a40979f3a3b46950928a0fdcfe3ea8a9b0c17490d57e8aa0e3"
|
||||
checksum = "12aeb37b6f2e61b93b1c3d34d01ee720207c76fe447e2a2c217e433ac75b17f5"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-consensus-any",
|
||||
@@ -329,9 +329,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-network-primitives"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7805124ad69e57bbae7731c9c344571700b2a18d351bda9e0eba521c991d1bcb"
|
||||
checksum = "abd29ace62872083e30929cd9b282d82723196d196db589f3ceda67edcc05552"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -391,9 +391,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-any"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b43c1622aac2508d528743fd4cfdac1dea92d5a8fa894038488ff7edd0af0b32"
|
||||
checksum = "6a63fb40ed24e4c92505f488f9dd256e2afaed17faa1b7a221086ebba74f4122"
|
||||
dependencies = [
|
||||
"alloy-consensus-any",
|
||||
"alloy-rpc-types-eth",
|
||||
@@ -402,9 +402,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-eth"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed5fafb741c19b3cca4cdd04fa215c89413491f9695a3e928dee2ae5657f607e"
|
||||
checksum = "9eae0c7c40da20684548cbc8577b6b7447f7bf4ddbac363df95e3da220e41e72"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-consensus-any",
|
||||
@@ -423,9 +423,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-serde"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6f180c399ca7c1e2fe17ea58343910cad0090878a696ff5a50241aee12fc529"
|
||||
checksum = "c0df1987ed0ff2d0159d76b52e7ddfc4e4fbddacc54d2fbee765e0d14d7c01b5"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"serde",
|
||||
@@ -434,9 +434,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-signer"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecc39ad2c0a3d2da8891f4081565780703a593f090f768f884049aa3aa929cbc"
|
||||
checksum = "6ff69deedee7232d7ce5330259025b868c5e6a52fa8dffda2c861fb3a5889b24"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"async-trait",
|
||||
@@ -449,9 +449,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-signer-local"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "930e17cb1e46446a193a593a3bfff8d0ecee4e510b802575ebe300ae2e43ef75"
|
||||
checksum = "72cfe0be3ec5a8c1a46b2e5a7047ed41121d360d97f4405bb7c1c784880c86cb"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-network",
|
||||
@@ -551,9 +551,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-tx-macros"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae109e33814b49fc0a62f2528993aa8a2dd346c26959b151f05441dc0b9da292"
|
||||
checksum = "333544408503f42d7d3792bfc0f7218b643d968a03d2c0ed383ae558fb4a76d0"
|
||||
dependencies = [
|
||||
"darling 0.21.3",
|
||||
"proc-macro2",
|
||||
@@ -1783,9 +1783,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.48"
|
||||
version = "1.2.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a"
|
||||
checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
@@ -2026,7 +2026,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
||||
[[package]]
|
||||
name = "clmul"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
@@ -3747,9 +3747,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "2.1.1"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99"
|
||||
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
|
||||
dependencies = [
|
||||
"icu_collections",
|
||||
"icu_locale_core",
|
||||
@@ -3761,9 +3761,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "2.1.1"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899"
|
||||
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
@@ -4225,7 +4225,7 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
||||
[[package]]
|
||||
name = "matrix-transpose"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
@@ -4270,9 +4270,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
|
||||
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
@@ -4282,7 +4282,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-circuits"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"mpz-circuits-core",
|
||||
"mpz-circuits-data",
|
||||
@@ -4291,7 +4291,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-circuits-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"bincode 1.3.3",
|
||||
"itybity 0.3.1",
|
||||
@@ -4306,7 +4306,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-circuits-data"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"bincode 1.3.3",
|
||||
"mpz-circuits-core",
|
||||
@@ -4316,7 +4316,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-cointoss"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"mpz-cointoss-core",
|
||||
@@ -4329,7 +4329,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-cointoss-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"mpz-core",
|
||||
"opaque-debug",
|
||||
@@ -4340,7 +4340,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-common"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
@@ -4360,7 +4360,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"aes 0.9.0-rc.2",
|
||||
"bcs",
|
||||
@@ -4386,7 +4386,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-fields"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"ark-ff 0.4.2",
|
||||
"ark-secp256r1",
|
||||
@@ -4406,7 +4406,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-garble"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"derive_builder 0.11.2",
|
||||
@@ -4421,7 +4421,7 @@ dependencies = [
|
||||
"mpz-vm-core",
|
||||
"opaque-debug",
|
||||
"rand 0.9.2",
|
||||
"rangeset 0.2.0",
|
||||
"rangeset",
|
||||
"serde",
|
||||
"serio",
|
||||
"thiserror 1.0.69",
|
||||
@@ -4432,7 +4432,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-garble-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"aes 0.9.0-rc.2",
|
||||
"bitvec",
|
||||
@@ -4452,7 +4452,7 @@ dependencies = [
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
"rangeset 0.2.0",
|
||||
"rangeset",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_arrays",
|
||||
@@ -4463,7 +4463,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-hash"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"itybity 0.3.1",
|
||||
@@ -4476,7 +4476,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-ideal-vm"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -4484,7 +4484,7 @@ dependencies = [
|
||||
"mpz-core",
|
||||
"mpz-memory-core",
|
||||
"mpz-vm-core",
|
||||
"rangeset 0.2.0",
|
||||
"rangeset",
|
||||
"serde",
|
||||
"serio",
|
||||
"thiserror 1.0.69",
|
||||
@@ -4493,14 +4493,14 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-memory-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"futures",
|
||||
"itybity 0.3.1",
|
||||
"mpz-core",
|
||||
"rand 0.9.2",
|
||||
"rangeset 0.2.0",
|
||||
"rangeset",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
@@ -4508,7 +4508,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-ole"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -4526,7 +4526,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-ole-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
"itybity 0.3.1",
|
||||
@@ -4542,7 +4542,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-ot"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"cfg-if",
|
||||
@@ -4565,7 +4565,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-ot-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"aes 0.9.0-rc.2",
|
||||
"blake3",
|
||||
@@ -4593,10 +4593,26 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mpz-predicate"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"mpz-circuits",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
"rangeset",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mpz-share-conversion"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"mpz-common",
|
||||
@@ -4612,7 +4628,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-share-conversion-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"mpz-common",
|
||||
"mpz-core",
|
||||
@@ -4626,7 +4642,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-vm-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -4639,7 +4655,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-zk"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"blake3",
|
||||
@@ -4657,7 +4673,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpz-zk-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=9c343f8#9c343f86d386bc1360d6ac0a37eb1af65f48216a"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?branch=feat%2Fmpz-bool-type#9405caab5d65be1c7e7dd39c6026a9efb57a598d"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"cfg-if",
|
||||
@@ -4666,7 +4682,7 @@ dependencies = [
|
||||
"mpz-core",
|
||||
"mpz-memory-core",
|
||||
"mpz-vm-core",
|
||||
"rangeset 0.2.0",
|
||||
"rangeset",
|
||||
"rayon",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
@@ -5442,7 +5458,7 @@ version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
|
||||
dependencies = [
|
||||
"toml_edit 0.23.7",
|
||||
"toml_edit 0.23.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5759,15 +5775,6 @@ version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbbbbea733ec66275512d0b9694f34102e7d5406fdbe2ad8d21b28dce92887c"
|
||||
|
||||
[[package]]
|
||||
name = "rangeset"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc7af00a06ad692080d87495a904677592c662610edb82b4fc8782f4ed2f01f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rangeset"
|
||||
version = "0.4.0"
|
||||
@@ -5857,9 +5864,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.24"
|
||||
version = "0.12.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f"
|
||||
checksum = "b6eff9328d40131d43bd911d42d79eb6a47312002a4daefc9e37f17e74a7701a"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
@@ -5886,7 +5893,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower",
|
||||
"tower-http 0.6.7",
|
||||
"tower-http 0.6.8",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
@@ -6744,9 +6751,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.7"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
|
||||
|
||||
[[package]]
|
||||
name = "sized-chunks"
|
||||
@@ -6810,9 +6817,9 @@ checksum = "bceb57dc07c92cdae60f5b27b3fa92ecaaa42fe36c55e22dbfb0b44893e0b1f7"
|
||||
|
||||
[[package]]
|
||||
name = "sourcemap"
|
||||
version = "9.2.2"
|
||||
version = "9.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e22afbcb92ce02d23815b9795523c005cb9d3c214f8b7a66318541c240ea7935"
|
||||
checksum = "37ccaaa78a0ca68b20f8f711eaa2522a00131c48a3de5b892ca5c36cec1ce9bb"
|
||||
dependencies = [
|
||||
"base64-simd",
|
||||
"bitvec",
|
||||
@@ -6835,7 +6842,7 @@ dependencies = [
|
||||
"httparse",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"rangeset 0.4.0",
|
||||
"rangeset",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
@@ -6988,9 +6995,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sys_traits"
|
||||
version = "0.1.19"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1495a604cd38eeb30c408724966cd31ca1b68b5a97e3afc474c0d719bfeec5a"
|
||||
checksum = "6b61f4a25d0baba25511bed00c39c199d9a19cfd8107f4472724b72a84f530b1"
|
||||
dependencies = [
|
||||
"sys_traits_macros",
|
||||
]
|
||||
@@ -7224,12 +7231,13 @@ dependencies = [
|
||||
"mpz-memory-core",
|
||||
"mpz-ole",
|
||||
"mpz-ot",
|
||||
"mpz-predicate",
|
||||
"mpz-vm-core",
|
||||
"mpz-zk",
|
||||
"once_cell",
|
||||
"opaque-debug",
|
||||
"rand 0.9.2",
|
||||
"rangeset 0.4.0",
|
||||
"rangeset",
|
||||
"rstest",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.103.8",
|
||||
@@ -7308,11 +7316,12 @@ dependencies = [
|
||||
"generic-array",
|
||||
"hex",
|
||||
"itybity 0.2.1",
|
||||
"mpz-predicate",
|
||||
"opaque-debug",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
"rangeset 0.4.0",
|
||||
"rangeset",
|
||||
"rs_merkle",
|
||||
"rstest",
|
||||
"rustls-pki-types",
|
||||
@@ -7347,7 +7356,7 @@ dependencies = [
|
||||
"mpz-core",
|
||||
"mpz-ideal-vm",
|
||||
"mpz-vm-core",
|
||||
"rangeset 0.4.0",
|
||||
"rangeset",
|
||||
"serde",
|
||||
"serio",
|
||||
"thiserror 1.0.69",
|
||||
@@ -7368,12 +7377,15 @@ dependencies = [
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"k256",
|
||||
"mpz-predicate",
|
||||
"noir",
|
||||
"rangeset",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"spansy",
|
||||
"tls-server-fixture",
|
||||
"tlsn",
|
||||
"tlsn-core",
|
||||
"tlsn-formats",
|
||||
"tlsn-server-fixture",
|
||||
"tlsn-server-fixture-certs",
|
||||
@@ -7590,7 +7602,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-http 0.6.7",
|
||||
"tower-http 0.6.8",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
@@ -7851,9 +7863,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.23.7"
|
||||
version = "0.23.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d"
|
||||
checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832"
|
||||
dependencies = [
|
||||
"indexmap 2.12.1",
|
||||
"toml_datetime 0.7.3",
|
||||
@@ -7919,9 +7931,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.7"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456"
|
||||
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytes",
|
||||
|
||||
30
Cargo.toml
30
Cargo.toml
@@ -66,21 +66,21 @@ tlsn-harness-runner = { path = "crates/harness/runner" }
|
||||
tlsn-wasm = { path = "crates/wasm" }
|
||||
tlsn = { path = "crates/tlsn" }
|
||||
|
||||
mpz-circuits = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-circuits-data = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-memory-core = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-common = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-core = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-vm-core = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-garble = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-garble-core = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-ole = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-ot = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-share-conversion = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-fields = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-zk = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-hash = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-ideal-vm = { git = "https://github.com/privacy-ethereum/mpz", rev = "9c343f8" }
|
||||
mpz-circuits = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-common = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-core = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-fields = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-garble = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-garble-core = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-hash = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-ideal-vm = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-memory-core = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-ole = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-ot = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-predicate = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-share-conversion = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-vm-core = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
mpz-zk = { git = "https://github.com/privacy-ethereum/mpz", branch = "feat/mpz-bool-type" }
|
||||
|
||||
rangeset = { version = "0.4" }
|
||||
serio = { version = "0.2" }
|
||||
|
||||
@@ -27,6 +27,7 @@ tlsn-data-fixtures = { workspace = true, optional = true }
|
||||
tlsn-tls-core = { workspace = true, features = ["serde"] }
|
||||
tlsn-utils = { workspace = true }
|
||||
rangeset = { workspace = true, features = ["serde"] }
|
||||
mpz-predicate = { workspace = true }
|
||||
|
||||
aead = { workspace = true, features = ["alloc"], optional = true }
|
||||
aes-gcm = { workspace = true, optional = true }
|
||||
|
||||
@@ -1,16 +1,119 @@
|
||||
//! Proving configuration.
|
||||
|
||||
use mpz_predicate::Pred;
|
||||
use rangeset::set::{RangeSet, ToRangeSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::transcript::{Direction, Transcript, TranscriptCommitConfig, TranscriptCommitRequest};
|
||||
|
||||
/// Configuration to prove information to the verifier.
|
||||
/// Configuration for a predicate to prove over transcript data.
|
||||
///
|
||||
/// A predicate is a boolean constraint that operates on transcript bytes.
|
||||
/// The prover proves in ZK that the predicate evaluates to true.
|
||||
///
|
||||
/// The predicate itself encodes which byte indices it operates on via its
|
||||
/// atomic comparisons (e.g., `gte(42, threshold)` operates on byte index 42).
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PredicateConfig {
|
||||
/// Human-readable name for the predicate (sent to verifier as sanity
|
||||
/// check).
|
||||
name: String,
|
||||
/// Direction of transcript data the predicate operates on.
|
||||
direction: Direction,
|
||||
/// The predicate to prove.
|
||||
predicate: Pred,
|
||||
}
|
||||
|
||||
impl PredicateConfig {
|
||||
/// Creates a new predicate configuration.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - Human-readable name for the predicate.
|
||||
/// * `direction` - Whether the predicate operates on sent or received data.
|
||||
/// * `predicate` - The predicate to prove.
|
||||
pub fn new(name: impl Into<String>, direction: Direction, predicate: Pred) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
direction,
|
||||
predicate,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the predicate name.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Returns the direction of transcript data.
|
||||
pub fn direction(&self) -> Direction {
|
||||
self.direction
|
||||
}
|
||||
|
||||
/// Returns the predicate.
|
||||
pub fn predicate(&self) -> &Pred {
|
||||
&self.predicate
|
||||
}
|
||||
|
||||
/// Returns the transcript byte indices this predicate operates on.
|
||||
pub fn indices(&self) -> Vec<usize> {
|
||||
self.predicate.indices()
|
||||
}
|
||||
|
||||
/// Converts to a request (wire format).
|
||||
pub fn to_request(&self) -> PredicateRequest {
|
||||
let indices: RangeSet<usize> = self
|
||||
.predicate
|
||||
.indices()
|
||||
.into_iter()
|
||||
.map(|idx| idx..idx + 1)
|
||||
.collect();
|
||||
PredicateRequest {
|
||||
name: self.name.clone(),
|
||||
direction: self.direction,
|
||||
indices,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wire format for predicate proving request.
|
||||
///
|
||||
/// Contains only the predicate name and indices - the verifier is expected
|
||||
/// to know which predicate corresponds to the name from out-of-band agreement.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PredicateRequest {
|
||||
/// Human-readable name for the predicate.
|
||||
name: String,
|
||||
/// Direction of transcript data the predicate operates on.
|
||||
direction: Direction,
|
||||
/// Transcript byte indices the predicate operates on.
|
||||
indices: RangeSet<usize>,
|
||||
}
|
||||
|
||||
impl PredicateRequest {
|
||||
/// Returns the predicate name.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Returns the direction of transcript data.
|
||||
pub fn direction(&self) -> Direction {
|
||||
self.direction
|
||||
}
|
||||
|
||||
/// Returns the transcript byte indices as a RangeSet.
|
||||
pub fn indices(&self) -> &RangeSet<usize> {
|
||||
&self.indices
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration to prove information to the verifier.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ProveConfig {
|
||||
server_identity: bool,
|
||||
reveal: Option<(RangeSet<usize>, RangeSet<usize>)>,
|
||||
transcript_commit: Option<TranscriptCommitConfig>,
|
||||
predicates: Vec<PredicateConfig>,
|
||||
}
|
||||
|
||||
impl ProveConfig {
|
||||
@@ -35,6 +138,11 @@ impl ProveConfig {
|
||||
self.transcript_commit.as_ref()
|
||||
}
|
||||
|
||||
/// Returns the predicate configurations.
|
||||
pub fn predicates(&self) -> &[PredicateConfig] {
|
||||
&self.predicates
|
||||
}
|
||||
|
||||
/// Returns a request.
|
||||
pub fn to_request(&self) -> ProveRequest {
|
||||
ProveRequest {
|
||||
@@ -44,6 +152,7 @@ impl ProveConfig {
|
||||
.transcript_commit
|
||||
.clone()
|
||||
.map(|config| config.to_request()),
|
||||
predicates: self.predicates.iter().map(|p| p.to_request()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,6 +164,7 @@ pub struct ProveConfigBuilder<'a> {
|
||||
server_identity: bool,
|
||||
reveal: Option<(RangeSet<usize>, RangeSet<usize>)>,
|
||||
transcript_commit: Option<TranscriptCommitConfig>,
|
||||
predicates: Vec<PredicateConfig>,
|
||||
}
|
||||
|
||||
impl<'a> ProveConfigBuilder<'a> {
|
||||
@@ -65,6 +175,7 @@ impl<'a> ProveConfigBuilder<'a> {
|
||||
server_identity: false,
|
||||
reveal: None,
|
||||
transcript_commit: None,
|
||||
predicates: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,12 +248,52 @@ impl<'a> ProveConfigBuilder<'a> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Adds a predicate to prove over transcript data.
|
||||
///
|
||||
/// The predicate encodes which byte indices it operates on via its atomic
|
||||
/// comparisons (e.g., `gte(42, threshold)` operates on byte index 42).
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - Human-readable name for the predicate (sent to verifier as
|
||||
/// sanity check).
|
||||
/// * `direction` - Whether the predicate operates on sent or received data.
|
||||
/// * `predicate` - The predicate to prove.
|
||||
pub fn predicate(
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
direction: Direction,
|
||||
predicate: Pred,
|
||||
) -> Result<&mut Self, ProveConfigError> {
|
||||
let indices = predicate.indices();
|
||||
|
||||
// Predicate must reference at least one transcript byte.
|
||||
let last_idx = *indices
|
||||
.last()
|
||||
.ok_or(ProveConfigError(ErrorRepr::EmptyPredicate))?;
|
||||
|
||||
// Since indices are sorted, only check the last one for bounds.
|
||||
let transcript_len = self.transcript.len_of_direction(direction);
|
||||
if last_idx >= transcript_len {
|
||||
return Err(ProveConfigError(ErrorRepr::IndexOutOfBounds {
|
||||
direction,
|
||||
actual: last_idx,
|
||||
len: transcript_len,
|
||||
}));
|
||||
}
|
||||
|
||||
self.predicates
|
||||
.push(PredicateConfig::new(name, direction, predicate));
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Builds the configuration.
|
||||
pub fn build(self) -> Result<ProveConfig, ProveConfigError> {
|
||||
Ok(ProveConfig {
|
||||
server_identity: self.server_identity,
|
||||
reveal: self.reveal,
|
||||
transcript_commit: self.transcript_commit,
|
||||
predicates: self.predicates,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -153,6 +304,7 @@ pub struct ProveRequest {
|
||||
server_identity: bool,
|
||||
reveal: Option<(RangeSet<usize>, RangeSet<usize>)>,
|
||||
transcript_commit: Option<TranscriptCommitRequest>,
|
||||
predicates: Vec<PredicateRequest>,
|
||||
}
|
||||
|
||||
impl ProveRequest {
|
||||
@@ -171,6 +323,11 @@ impl ProveRequest {
|
||||
pub fn transcript_commit(&self) -> Option<&TranscriptCommitRequest> {
|
||||
self.transcript_commit.as_ref()
|
||||
}
|
||||
|
||||
/// Returns the predicate requests.
|
||||
pub fn predicates(&self) -> &[PredicateRequest] {
|
||||
&self.predicates
|
||||
}
|
||||
}
|
||||
|
||||
/// Error for [`ProveConfig`].
|
||||
@@ -180,10 +337,12 @@ pub struct ProveConfigError(#[from] ErrorRepr);
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum ErrorRepr {
|
||||
#[error("range is out of bounds of the transcript ({direction}): {actual} > {len}")]
|
||||
#[error("index out of bounds for {direction} transcript: {actual} >= {len}")]
|
||||
IndexOutOfBounds {
|
||||
direction: Direction,
|
||||
actual: usize,
|
||||
len: usize,
|
||||
},
|
||||
#[error("predicate must reference at least one transcript byte")]
|
||||
EmptyPredicate,
|
||||
}
|
||||
|
||||
@@ -10,10 +10,13 @@ workspace = true
|
||||
[dependencies]
|
||||
tlsn = { workspace = true }
|
||||
tlsn-formats = { workspace = true }
|
||||
tlsn-core = { workspace = true }
|
||||
tls-server-fixture = { workspace = true }
|
||||
tlsn-server-fixture = { workspace = true }
|
||||
tlsn-server-fixture-certs = { workspace = true }
|
||||
spansy = { workspace = true }
|
||||
mpz-predicate = { workspace = true }
|
||||
rangeset = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
bincode = { workspace = true }
|
||||
@@ -61,3 +64,7 @@ path = "attestation/present.rs"
|
||||
[[example]]
|
||||
name = "attestation_verify"
|
||||
path = "attestation/verify.rs"
|
||||
|
||||
[[example]]
|
||||
name = "interactive_predicate"
|
||||
path = "interactive_predicate/interactive_predicate.rs"
|
||||
|
||||
@@ -5,6 +5,7 @@ This folder contains examples demonstrating how to use the TLSNotary protocol.
|
||||
* [Interactive](./interactive/README.md): Interactive Prover and Verifier session without a trusted notary.
|
||||
* [Attestation](./attestation/README.md): Performing a simple notarization with a trusted notary.
|
||||
* [Interactive_zk](./interactive_zk/README.md): Interactive Prover and Verifier session demonstrating zero-knowledge age verification using Noir.
|
||||
* [Interactive_predicate](./interactive_predicate/README.md): Interactive session demonstrating predicate proving over transcript data (e.g., proving a JSON field is a valid string without revealing it).
|
||||
|
||||
|
||||
Refer to <https://tlsnotary.org/docs/quick_start> for a quick start guide to using TLSNotary with these examples.
|
||||
29
crates/examples/interactive_predicate/README.md
Normal file
29
crates/examples/interactive_predicate/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
## Interactive Predicate: Proving Predicates over Transcript Data
|
||||
|
||||
This example demonstrates how to use TLSNotary to prove predicates (boolean constraints) over transcript bytes in zero knowledge, without revealing the actual data.
|
||||
|
||||
In this example:
|
||||
- The server returns JSON data containing a "name" field with a string value
|
||||
- The Prover proves that the name value is a valid JSON string without revealing it
|
||||
- The Verifier learns that the string is valid JSON, but not the actual content
|
||||
|
||||
This uses `mpz_predicate` to build predicates that operate on transcript bytes. The predicate is compiled to a circuit and executed in the ZK VM to prove satisfaction.
|
||||
|
||||
### Running the Example
|
||||
|
||||
First, start the test server from the root of this repository:
|
||||
```shell
|
||||
RUST_LOG=info PORT=4000 cargo run --bin tlsn-server-fixture
|
||||
```
|
||||
|
||||
Next, run the interactive predicate example:
|
||||
```shell
|
||||
SERVER_PORT=4000 cargo run --release --example interactive_predicate
|
||||
```
|
||||
|
||||
To view more detailed debug information:
|
||||
```shell
|
||||
RUST_LOG=debug,yamux=info,uid_mux=info SERVER_PORT=4000 cargo run --release --example interactive_predicate
|
||||
```
|
||||
|
||||
> Note: In this example, the Prover and Verifier run on the same machine. In real-world scenarios, they would typically operate on separate machines.
|
||||
368
crates/examples/interactive_predicate/interactive_predicate.rs
Normal file
368
crates/examples/interactive_predicate/interactive_predicate.rs
Normal file
@@ -0,0 +1,368 @@
|
||||
//! Example demonstrating predicate proving over transcript data.
|
||||
//!
|
||||
//! This example shows how a prover can prove a predicate (boolean constraint)
|
||||
//! over transcript bytes in zero knowledge, without revealing the actual data.
|
||||
//!
|
||||
//! In this example:
|
||||
//! - The server returns JSON data containing a "name" field with a string value
|
||||
//! - The prover proves that the name value is a valid JSON string without
|
||||
//! revealing it
|
||||
//! - The verifier learns that the string is valid JSON, but not the actual
|
||||
//! content
|
||||
|
||||
use std::{
|
||||
env,
|
||||
net::{IpAddr, SocketAddr},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use http_body_util::Empty;
|
||||
use hyper::{body::Bytes, Request, StatusCode, Uri};
|
||||
use hyper_util::rt::TokioIo;
|
||||
use mpz_predicate::{json::validate_string, Pred};
|
||||
use rangeset::prelude::RangeSet;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt};
|
||||
use tracing::instrument;
|
||||
|
||||
use tlsn::{
|
||||
config::{
|
||||
prove::ProveConfig,
|
||||
prover::ProverConfig,
|
||||
tls::TlsClientConfig,
|
||||
tls_commit::{mpc::MpcTlsConfig, TlsCommitConfig, TlsCommitProtocolConfig},
|
||||
verifier::VerifierConfig,
|
||||
},
|
||||
connection::ServerName,
|
||||
prover::Prover,
|
||||
transcript::Direction,
|
||||
verifier::{Verifier, VerifierOutput},
|
||||
webpki::{CertificateDer, RootCertStore},
|
||||
};
|
||||
use tlsn_server_fixture::DEFAULT_FIXTURE_PORT;
|
||||
use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
|
||||
|
||||
/// Predicate name for JSON string validation (both parties agree on this
|
||||
/// out-of-band).
|
||||
const JSON_STRING_PREDICATE: &str = "valid_json_string";
|
||||
|
||||
// Maximum number of bytes that can be sent from prover to server.
|
||||
const MAX_SENT_DATA: usize = 1 << 12;
|
||||
// Maximum number of bytes that can be received by prover from server.
|
||||
const MAX_RECV_DATA: usize = 1 << 14;
|
||||
|
||||
/// Builds a predicate that validates a JSON string at the given indices.
|
||||
///
|
||||
/// Uses mpz_predicate's `validate_string` to ensure the bytes form a valid
|
||||
/// JSON string (proper escaping, valid UTF-8, no control characters, etc.).
|
||||
fn build_json_string_predicate(indices: &RangeSet<usize>) -> Pred {
|
||||
validate_string(indices.clone())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
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);
|
||||
|
||||
// Use the JSON endpoint that returns data.
|
||||
let uri = format!("https://{SERVER_DOMAIN}:{server_port}/formats/json");
|
||||
let server_ip: IpAddr = server_host.parse().expect("Invalid IP address");
|
||||
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 = prover(prover_socket, &server_addr, &uri);
|
||||
let verifier = verifier(verifier_socket);
|
||||
|
||||
match tokio::try_join!(prover, verifier) {
|
||||
Ok(_) => println!("\nSuccess! The prover proved that a JSON field contains a valid string without revealing it."),
|
||||
Err(e) => eprintln!("Error: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the value of a JSON field in the response body.
|
||||
/// Returns (start_index, end_index) of the value (excluding quotes for
|
||||
/// strings).
|
||||
fn find_json_string_value(data: &[u8], field_name: &str) -> Option<(usize, usize)> {
|
||||
let search_pattern = format!("\"{}\":", field_name);
|
||||
let pattern_bytes = search_pattern.as_bytes();
|
||||
|
||||
// Find the field name
|
||||
let field_pos = data
|
||||
.windows(pattern_bytes.len())
|
||||
.position(|w| w == pattern_bytes)?;
|
||||
|
||||
// Skip past the field name and colon
|
||||
let mut pos = field_pos + pattern_bytes.len();
|
||||
|
||||
// Skip whitespace
|
||||
while pos < data.len() && (data[pos] == b' ' || data[pos] == b'\n' || data[pos] == b'\r') {
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
// Check if it's a string (starts with quote)
|
||||
if pos >= data.len() || data[pos] != b'"' {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Skip opening quote
|
||||
let start = pos + 1;
|
||||
|
||||
// Find closing quote (handling escapes)
|
||||
let mut end = start;
|
||||
while end < data.len() {
|
||||
if data[end] == b'\\' {
|
||||
// Skip escaped character
|
||||
end += 2;
|
||||
} else if data[end] == b'"' {
|
||||
break;
|
||||
} else {
|
||||
end += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Some((start, end))
|
||||
}
|
||||
|
||||
#[instrument(skip(verifier_socket))]
|
||||
async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
verifier_socket: T,
|
||||
server_addr: &SocketAddr,
|
||||
uri: &str,
|
||||
) -> Result<()> {
|
||||
let uri = uri.parse::<Uri>().unwrap();
|
||||
assert_eq!(uri.scheme().unwrap().as_str(), "https");
|
||||
let server_domain = uri.authority().unwrap().host();
|
||||
|
||||
// Create a new prover and perform necessary setup.
|
||||
let prover = Prover::new(ProverConfig::builder().build()?)
|
||||
.commit(
|
||||
TlsCommitConfig::builder()
|
||||
.protocol(
|
||||
MpcTlsConfig::builder()
|
||||
.max_sent_data(tlsn_examples::MAX_SENT_DATA)
|
||||
.max_recv_data(tlsn_examples::MAX_RECV_DATA)
|
||||
.build()?,
|
||||
)
|
||||
.build()?,
|
||||
verifier_socket.compat(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Open a TCP connection to the server.
|
||||
let client_socket = tokio::net::TcpStream::connect(server_addr).await?;
|
||||
|
||||
// Bind the prover to the server connection.
|
||||
let (tls_connection, prover_fut) = prover
|
||||
.connect(
|
||||
TlsClientConfig::builder()
|
||||
.server_name(ServerName::Dns(SERVER_DOMAIN.try_into()?))
|
||||
.root_store(RootCertStore {
|
||||
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
|
||||
})
|
||||
.build()?,
|
||||
client_socket.compat(),
|
||||
)
|
||||
.await?;
|
||||
let tls_connection = TokioIo::new(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(tls_connection).await?;
|
||||
|
||||
// Spawn the connection to run in the background.
|
||||
tokio::spawn(connection);
|
||||
|
||||
// Send request for JSON data.
|
||||
let request = Request::builder()
|
||||
.uri(uri.clone())
|
||||
.header("Host", server_domain)
|
||||
.header("Connection", "close")
|
||||
.method("GET")
|
||||
.body(Empty::<Bytes>::new())?;
|
||||
let response = request_sender.send_request(request).await?;
|
||||
|
||||
assert!(response.status() == StatusCode::OK);
|
||||
|
||||
// Create proof for the Verifier.
|
||||
let mut prover = prover_task.await??;
|
||||
|
||||
// Find the "name" field value in the JSON response
|
||||
let received = prover.transcript().received();
|
||||
|
||||
// Find the HTTP body (after \r\n\r\n)
|
||||
let body_start = received
|
||||
.windows(4)
|
||||
.position(|w| w == b"\r\n\r\n")
|
||||
.map(|p| p + 4)
|
||||
.unwrap_or(0);
|
||||
|
||||
// Find the "name" field's string value
|
||||
let (value_start, value_end) =
|
||||
find_json_string_value(&received[body_start..], "name").expect("should find name field");
|
||||
|
||||
// Adjust to absolute positions in transcript
|
||||
let value_start = body_start + value_start;
|
||||
let value_end = body_start + value_end;
|
||||
|
||||
let value_bytes = &received[value_start..value_end];
|
||||
println!(
|
||||
"Prover: Found 'name' field value: \"{}\" at positions {}..{}",
|
||||
String::from_utf8_lossy(value_bytes),
|
||||
value_start,
|
||||
value_end
|
||||
);
|
||||
println!("Prover: Will prove this is a valid JSON string without revealing the actual content");
|
||||
|
||||
// Build indices for the predicate as a RangeSet
|
||||
let indices: RangeSet<usize> = (value_start..value_end).into();
|
||||
|
||||
// Build the predicate using mpz_predicate
|
||||
let predicate = build_json_string_predicate(&indices);
|
||||
|
||||
let mut builder = ProveConfig::builder(prover.transcript());
|
||||
|
||||
// Reveal the server identity.
|
||||
builder.server_identity();
|
||||
|
||||
// Reveal the sent data (the request).
|
||||
builder.reveal_sent(&(0..prover.transcript().sent().len()))?;
|
||||
|
||||
// Reveal everything EXCEPT the string value we're proving the predicate over.
|
||||
if value_start > 0 {
|
||||
builder.reveal_recv(&(0..value_start))?;
|
||||
}
|
||||
if value_end < prover.transcript().received().len() {
|
||||
builder.reveal_recv(&(value_end..prover.transcript().received().len()))?;
|
||||
}
|
||||
|
||||
// Add the predicate to prove the string is valid JSON without revealing the
|
||||
// value.
|
||||
builder.predicate(JSON_STRING_PREDICATE, Direction::Received, predicate)?;
|
||||
|
||||
let config = builder.build()?;
|
||||
|
||||
prover.prove(&config).await?;
|
||||
prover.close().await?;
|
||||
|
||||
println!("Prover: Successfully proved the predicate!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(socket))]
|
||||
async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
|
||||
socket: T,
|
||||
) -> Result<()> {
|
||||
let verifier_config = VerifierConfig::builder()
|
||||
.root_store(RootCertStore {
|
||||
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
|
||||
})
|
||||
.build()?;
|
||||
let verifier = Verifier::new(verifier_config);
|
||||
|
||||
// Validate the proposed configuration and run the TLS commitment protocol.
|
||||
let verifier = verifier.commit(socket.compat()).await?;
|
||||
|
||||
// Validate configuration.
|
||||
let reject = if let TlsCommitProtocolConfig::Mpc(mpc_tls_config) = verifier.request().protocol()
|
||||
{
|
||||
if mpc_tls_config.max_sent_data() > MAX_SENT_DATA {
|
||||
Some("max_sent_data is too large")
|
||||
} else if mpc_tls_config.max_recv_data() > MAX_RECV_DATA {
|
||||
Some("max_recv_data is too large")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
Some("expecting to use MPC-TLS")
|
||||
};
|
||||
|
||||
if reject.is_some() {
|
||||
verifier.reject(reject).await?;
|
||||
return Err(anyhow::anyhow!("protocol configuration rejected"));
|
||||
}
|
||||
|
||||
// Run the TLS commitment protocol.
|
||||
let verifier = verifier.accept().await?.run().await?;
|
||||
|
||||
// Validate the proving request.
|
||||
let verifier = verifier.verify().await?;
|
||||
|
||||
// Check that server identity is being proven.
|
||||
if !verifier.request().server_identity() {
|
||||
let verifier = verifier
|
||||
.reject(Some("expecting to verify the server name"))
|
||||
.await?;
|
||||
verifier.close().await?;
|
||||
return Err(anyhow::anyhow!("prover did not reveal the server name"));
|
||||
}
|
||||
|
||||
// Check if predicates are requested and validate them.
|
||||
let predicates = verifier.request().predicates();
|
||||
if !predicates.is_empty() {
|
||||
println!(
|
||||
"Verifier: Prover requested {} predicate(s):",
|
||||
predicates.len()
|
||||
);
|
||||
for pred in predicates {
|
||||
println!(
|
||||
" - '{}' on {:?} at {} indices",
|
||||
pred.name(),
|
||||
pred.direction(),
|
||||
pred.indices().len()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Define the predicate resolver - this maps predicate names to predicates.
|
||||
// The resolver receives the predicate name and the indices from the prover's
|
||||
// request.
|
||||
let predicate_resolver = |name: &str, indices: &RangeSet<usize>| -> Option<Pred> {
|
||||
match name {
|
||||
JSON_STRING_PREDICATE => {
|
||||
// Build the JSON string validation predicate with the provided indices
|
||||
Some(build_json_string_predicate(indices))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
|
||||
// Accept with predicate verification.
|
||||
let (
|
||||
VerifierOutput {
|
||||
server_name,
|
||||
transcript,
|
||||
..
|
||||
},
|
||||
verifier,
|
||||
) = verifier
|
||||
.accept_with_predicates(Some(&predicate_resolver))
|
||||
.await?;
|
||||
|
||||
verifier.close().await?;
|
||||
|
||||
let server_name = server_name.expect("prover should have revealed server name");
|
||||
let transcript = transcript.expect("prover should have revealed transcript data");
|
||||
|
||||
// Verify server name.
|
||||
let ServerName::Dns(server_name) = server_name;
|
||||
assert_eq!(server_name.as_str(), SERVER_DOMAIN);
|
||||
|
||||
// The verifier can see the response but with the predicated string redacted.
|
||||
let received = transcript.received_unsafe();
|
||||
let redacted = String::from_utf8_lossy(received).replace('\0', "[REDACTED]");
|
||||
println!("Verifier: Received data (string value redacted):\n{redacted}");
|
||||
|
||||
println!("Verifier: Predicate verified successfully!");
|
||||
println!("Verifier: The hidden value is proven to be a valid JSON string");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -33,6 +33,7 @@ web-spawn = { workspace = true, optional = true }
|
||||
mpz-circuits = { workspace = true, features = ["aes"] }
|
||||
mpz-common = { workspace = true }
|
||||
mpz-core = { workspace = true }
|
||||
mpz-predicate = { workspace = true }
|
||||
mpz-garble = { workspace = true }
|
||||
mpz-garble-core = { workspace = true }
|
||||
mpz-hash = { workspace = true }
|
||||
|
||||
@@ -49,6 +49,13 @@ impl ProverError {
|
||||
{
|
||||
Self::new(ErrorKind::Commit, source)
|
||||
}
|
||||
|
||||
pub(crate) fn predicate<E>(source: E) -> Self
|
||||
where
|
||||
E: Into<Box<dyn Error + Send + Sync + 'static>>,
|
||||
{
|
||||
Self::new(ErrorKind::Predicate, source)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -58,6 +65,7 @@ enum ErrorKind {
|
||||
Zk,
|
||||
Config,
|
||||
Commit,
|
||||
Predicate,
|
||||
}
|
||||
|
||||
impl fmt::Display for ProverError {
|
||||
@@ -70,6 +78,7 @@ impl fmt::Display for ProverError {
|
||||
ErrorKind::Zk => f.write_str("zk error")?,
|
||||
ErrorKind::Config => f.write_str("config error")?,
|
||||
ErrorKind::Commit => f.write_str("commit error")?,
|
||||
ErrorKind::Predicate => f.write_str("predicate error")?,
|
||||
}
|
||||
|
||||
if let Some(source) = &self.source {
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::{
|
||||
encoding::{self, MacStore},
|
||||
hash::prove_hash,
|
||||
},
|
||||
predicate::prove_predicates,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -54,6 +55,20 @@ pub(crate) async fn prove<T: Vm<Binary> + MacStore + Send + Sync>(
|
||||
});
|
||||
}
|
||||
|
||||
// Build predicate ranges from config
|
||||
let (mut predicate_sent, mut predicate_recv) = (RangeSet::default(), RangeSet::default());
|
||||
for predicate in config.predicates() {
|
||||
let indices: RangeSet<usize> = predicate
|
||||
.indices()
|
||||
.into_iter()
|
||||
.map(|idx| idx..idx + 1)
|
||||
.collect();
|
||||
match predicate.direction() {
|
||||
Direction::Sent => predicate_sent.union_mut(&indices),
|
||||
Direction::Received => predicate_recv.union_mut(&indices),
|
||||
}
|
||||
}
|
||||
|
||||
let transcript_refs = TranscriptRefs {
|
||||
sent: prove_plaintext(
|
||||
vm,
|
||||
@@ -66,6 +81,7 @@ pub(crate) async fn prove<T: Vm<Binary> + MacStore + Send + Sync>(
|
||||
.filter(|record| record.typ == ContentType::ApplicationData),
|
||||
&reveal_sent,
|
||||
&commit_sent,
|
||||
&predicate_sent,
|
||||
)
|
||||
.map_err(ProverError::commit)?,
|
||||
recv: prove_plaintext(
|
||||
@@ -79,6 +95,7 @@ pub(crate) async fn prove<T: Vm<Binary> + MacStore + Send + Sync>(
|
||||
.filter(|record| record.typ == ContentType::ApplicationData),
|
||||
&reveal_recv,
|
||||
&commit_recv,
|
||||
&predicate_recv,
|
||||
)
|
||||
.map_err(ProverError::commit)?,
|
||||
};
|
||||
@@ -100,6 +117,12 @@ pub(crate) async fn prove<T: Vm<Binary> + MacStore + Send + Sync>(
|
||||
None
|
||||
};
|
||||
|
||||
// Prove predicates over transcript data
|
||||
if !config.predicates().is_empty() {
|
||||
prove_predicates(vm, &transcript_refs, config.predicates())
|
||||
.map_err(ProverError::predicate)?;
|
||||
}
|
||||
|
||||
vm.execute_all(ctx).await.map_err(ProverError::zk)?;
|
||||
|
||||
if let Some(commit_config) = config.transcript_commit()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub(crate) mod auth;
|
||||
pub(crate) mod commit;
|
||||
pub(crate) mod predicate;
|
||||
|
||||
use mpz_memory_core::{Vector, binary::U8};
|
||||
|
||||
|
||||
@@ -25,14 +25,15 @@ pub(crate) fn prove_plaintext<'a>(
|
||||
records: impl IntoIterator<Item = &'a Record>,
|
||||
reveal: &RangeSet<usize>,
|
||||
commit: &RangeSet<usize>,
|
||||
predicate: &RangeSet<usize>,
|
||||
) -> Result<ReferenceMap, PlaintextAuthError> {
|
||||
let is_reveal_all = reveal == (0..plaintext.len());
|
||||
let is_reveal_all = reveal == (0..plaintext.len()) && predicate.is_empty();
|
||||
|
||||
let alloc_ranges = if is_reveal_all {
|
||||
commit.clone()
|
||||
} else {
|
||||
// The plaintext is only partially revealed, so we need to authenticate in ZK.
|
||||
commit.union(reveal).into_set()
|
||||
commit.union(reveal).union(predicate).into_set()
|
||||
};
|
||||
|
||||
let plaintext_refs = alloc_plaintext(vm, &alloc_ranges)?;
|
||||
@@ -49,7 +50,8 @@ pub(crate) fn prove_plaintext<'a>(
|
||||
vm.commit(*slice).map_err(PlaintextAuthError::vm)?;
|
||||
}
|
||||
} else {
|
||||
let private = commit.difference(reveal).into_set();
|
||||
// Private ranges: committed but not revealed, plus predicate ranges
|
||||
let private = commit.difference(reveal).union(predicate).into_set();
|
||||
for (_, slice) in plaintext_refs
|
||||
.index(&private)
|
||||
.expect("all ranges are allocated")
|
||||
@@ -91,14 +93,15 @@ pub(crate) fn verify_plaintext<'a>(
|
||||
records: impl IntoIterator<Item = &'a Record>,
|
||||
reveal: &RangeSet<usize>,
|
||||
commit: &RangeSet<usize>,
|
||||
predicate: &RangeSet<usize>,
|
||||
) -> Result<(ReferenceMap, PlaintextProof<'a>), PlaintextAuthError> {
|
||||
let is_reveal_all = reveal == (0..plaintext.len());
|
||||
let is_reveal_all = reveal == (0..plaintext.len()) && predicate.is_empty();
|
||||
|
||||
let alloc_ranges = if is_reveal_all {
|
||||
commit.clone()
|
||||
} else {
|
||||
// The plaintext is only partially revealed, so we need to authenticate in ZK.
|
||||
commit.union(reveal).into_set()
|
||||
commit.union(reveal).union(predicate).into_set()
|
||||
};
|
||||
|
||||
let plaintext_refs = alloc_plaintext(vm, &alloc_ranges)?;
|
||||
@@ -123,9 +126,10 @@ pub(crate) fn verify_plaintext<'a>(
|
||||
ciphertext,
|
||||
})
|
||||
} else {
|
||||
let private = commit.difference(reveal).into_set();
|
||||
// Blind ranges: committed but not revealed, plus predicate ranges
|
||||
let blind = commit.difference(reveal).union(predicate).into_set();
|
||||
for (_, slice) in plaintext_refs
|
||||
.index(&private)
|
||||
.index(&blind)
|
||||
.expect("all ranges are allocated")
|
||||
.iter()
|
||||
{
|
||||
|
||||
175
crates/tlsn/src/transcript_internal/predicate.rs
Normal file
175
crates/tlsn/src/transcript_internal/predicate.rs
Normal file
@@ -0,0 +1,175 @@
|
||||
//! Predicate proving and verification over transcript data.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use mpz_circuits::Circuit;
|
||||
use mpz_core::bitvec::BitVec;
|
||||
use mpz_memory_core::{
|
||||
DecodeFutureTyped, MemoryExt,
|
||||
binary::{Binary, Bool},
|
||||
};
|
||||
use mpz_predicate::{Pred, compiler::Compiler};
|
||||
use mpz_vm_core::{Call, CallableExt, Vm};
|
||||
use rangeset::set::RangeSet;
|
||||
use tlsn_core::{config::prove::PredicateConfig, transcript::Direction};
|
||||
|
||||
use super::{ReferenceMap, TranscriptRefs};
|
||||
|
||||
/// Error during predicate proving/verification.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub(crate) enum PredicateError {
|
||||
/// Indices not found in transcript references.
|
||||
#[error("predicate indices {0:?} not found in transcript references")]
|
||||
IndicesNotFound(RangeSet<usize>),
|
||||
/// VM error.
|
||||
#[error("VM error: {0}")]
|
||||
Vm(#[from] mpz_vm_core::VmError),
|
||||
/// Circuit call error.
|
||||
#[error("circuit call error: {0}")]
|
||||
Call(#[from] mpz_vm_core::CallError),
|
||||
/// Decode error.
|
||||
#[error("decode error: {0}")]
|
||||
Decode(#[from] mpz_memory_core::DecodeError),
|
||||
/// Missing decoding.
|
||||
#[error("missing decoding")]
|
||||
MissingDecoding,
|
||||
/// Predicate not satisfied.
|
||||
#[error("predicate evaluated to false")]
|
||||
PredicateNotSatisfied,
|
||||
}
|
||||
|
||||
/// Converts a slice of indices to a RangeSet (each index becomes a single-byte
|
||||
/// range).
|
||||
fn indices_to_rangeset(indices: &[usize]) -> RangeSet<usize> {
|
||||
indices.iter().map(|&idx| idx..idx + 1).collect()
|
||||
}
|
||||
|
||||
/// Proves predicates over transcript data (prover side).
|
||||
///
|
||||
/// Each predicate is compiled to a circuit and executed with the corresponding
|
||||
/// transcript bytes as input. The circuit outputs a single bit that must be
|
||||
/// true.
|
||||
pub(crate) fn prove_predicates<T: Vm<Binary>>(
|
||||
vm: &mut T,
|
||||
transcript_refs: &TranscriptRefs,
|
||||
predicates: &[PredicateConfig],
|
||||
) -> Result<(), PredicateError> {
|
||||
let mut compiler = Compiler::new();
|
||||
|
||||
for predicate in predicates {
|
||||
let refs = match predicate.direction() {
|
||||
Direction::Sent => &transcript_refs.sent,
|
||||
Direction::Received => &transcript_refs.recv,
|
||||
};
|
||||
|
||||
// Compile predicate to circuit
|
||||
let circuit = compiler.compile(predicate.predicate());
|
||||
|
||||
// Get indices from the predicate and convert to RangeSet
|
||||
let indices = indices_to_rangeset(&predicate.indices());
|
||||
|
||||
// Prover doesn't need to verify output - they know their data satisfies the predicate
|
||||
let _ = execute_predicate(vm, refs, &indices, &circuit)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Proof that predicates were satisfied.
|
||||
///
|
||||
/// Must be verified after `vm.execute_all()` completes.
|
||||
#[must_use]
|
||||
pub(crate) struct PredicateProof {
|
||||
/// Decode futures for each predicate output.
|
||||
outputs: Vec<DecodeFutureTyped<BitVec, bool>>,
|
||||
}
|
||||
|
||||
impl PredicateProof {
|
||||
/// Verifies that all predicates evaluated to true.
|
||||
///
|
||||
/// Must be called after `vm.execute_all()` completes.
|
||||
pub(crate) fn verify(self) -> Result<(), PredicateError> {
|
||||
for mut output in self.outputs {
|
||||
let result = output
|
||||
.try_recv()
|
||||
.map_err(PredicateError::Decode)?
|
||||
.ok_or(PredicateError::MissingDecoding)?;
|
||||
|
||||
if !result {
|
||||
return Err(PredicateError::PredicateNotSatisfied);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Verifies predicates over transcript data (verifier side).
|
||||
///
|
||||
/// The verifier must provide the same predicates that the prover used,
|
||||
/// looked up by predicate name from out-of-band agreement.
|
||||
///
|
||||
/// Returns a [`PredicateProof`] that must be verified after `vm.execute_all()`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `vm` - The zkVM.
|
||||
/// * `transcript_refs` - References to transcript data in the VM.
|
||||
/// * `predicates` - Iterator of (direction, indices, predicate) tuples.
|
||||
pub(crate) fn verify_predicates<T: Vm<Binary>>(
|
||||
vm: &mut T,
|
||||
transcript_refs: &TranscriptRefs,
|
||||
predicates: impl IntoIterator<Item = (Direction, RangeSet<usize>, Pred)>,
|
||||
) -> Result<PredicateProof, PredicateError> {
|
||||
let mut compiler = Compiler::new();
|
||||
let mut outputs = Vec::new();
|
||||
|
||||
for (direction, indices, predicate) in predicates {
|
||||
let refs = match direction {
|
||||
Direction::Sent => &transcript_refs.sent,
|
||||
Direction::Received => &transcript_refs.recv,
|
||||
};
|
||||
|
||||
// Compile predicate to circuit
|
||||
let circuit = compiler.compile(&predicate);
|
||||
|
||||
let output_fut = execute_predicate(vm, refs, &indices, &circuit)?;
|
||||
outputs.push(output_fut);
|
||||
}
|
||||
|
||||
Ok(PredicateProof { outputs })
|
||||
}
|
||||
|
||||
/// Executes a predicate circuit with transcript bytes as input.
|
||||
///
|
||||
/// Returns a decode future for the circuit output.
|
||||
fn execute_predicate<T: Vm<Binary>>(
|
||||
vm: &mut T,
|
||||
refs: &ReferenceMap,
|
||||
indices: &RangeSet<usize>,
|
||||
circuit: &Circuit,
|
||||
) -> Result<DecodeFutureTyped<BitVec, bool>, PredicateError> {
|
||||
// Get the transcript bytes for the predicate indices
|
||||
let indexed_refs = refs
|
||||
.index(indices)
|
||||
.ok_or_else(|| PredicateError::IndicesNotFound(indices.clone()))?;
|
||||
|
||||
// Build the circuit call with transcript bytes as inputs
|
||||
let circuit = Arc::new(circuit.clone());
|
||||
let mut call_builder = Call::builder(circuit);
|
||||
|
||||
// Add each byte in the range as an input to the circuit
|
||||
// The predicate circuit expects bytes in order, so we iterate through
|
||||
// the indexed refs which maintains ordering
|
||||
for (_range, vector) in indexed_refs.iter() {
|
||||
call_builder = call_builder.arg(*vector);
|
||||
}
|
||||
|
||||
let call = call_builder.build()?;
|
||||
|
||||
// Execute the circuit - output is a single bit (true/false)
|
||||
// Both parties must call decode() on the output to reveal it
|
||||
let output: Bool = vm.call(call)?;
|
||||
|
||||
// Return decode future - caller must verify output == true after execute_all
|
||||
Ok(vm.decode(output)?)
|
||||
}
|
||||
@@ -8,6 +8,7 @@ use std::sync::Arc;
|
||||
|
||||
pub use error::VerifierError;
|
||||
pub use tlsn_core::{VerifierOutput, webpki::ServerCertVerifier};
|
||||
pub use verify::PredicateResolver;
|
||||
|
||||
use crate::{
|
||||
Role,
|
||||
@@ -323,8 +324,24 @@ impl Verifier<state::Verify> {
|
||||
}
|
||||
|
||||
/// Accepts the proving request.
|
||||
///
|
||||
/// Note: If the prover requests predicate verification, use
|
||||
/// [`accept_with_predicates`](Self::accept_with_predicates) instead.
|
||||
pub async fn accept(
|
||||
self,
|
||||
) -> Result<(VerifierOutput, Verifier<state::Committed>), VerifierError> {
|
||||
self.accept_with_predicates(None).await
|
||||
}
|
||||
|
||||
/// Accepts the proving request with predicate verification support.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `predicate_resolver` - A function that resolves predicate names to
|
||||
/// circuits. Required if the prover requests any predicates.
|
||||
pub async fn accept_with_predicates(
|
||||
self,
|
||||
predicate_resolver: Option<&verify::PredicateResolver>,
|
||||
) -> Result<(VerifierOutput, Verifier<state::Committed>), VerifierError> {
|
||||
let state::Verify {
|
||||
mux_ctrl,
|
||||
@@ -353,6 +370,7 @@ impl Verifier<state::Verify> {
|
||||
request,
|
||||
handshake,
|
||||
transcript,
|
||||
predicate_resolver,
|
||||
))
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -49,6 +49,13 @@ impl VerifierError {
|
||||
{
|
||||
Self::new(ErrorKind::Verify, source)
|
||||
}
|
||||
|
||||
pub(crate) fn predicate<E>(source: E) -> Self
|
||||
where
|
||||
E: Into<Box<dyn Error + Send + Sync + 'static>>,
|
||||
{
|
||||
Self::new(ErrorKind::Predicate, source)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -59,6 +66,7 @@ enum ErrorKind {
|
||||
Zk,
|
||||
Commit,
|
||||
Verify,
|
||||
Predicate,
|
||||
}
|
||||
|
||||
impl fmt::Display for VerifierError {
|
||||
@@ -72,6 +80,7 @@ impl fmt::Display for VerifierError {
|
||||
ErrorKind::Zk => f.write_str("zk error")?,
|
||||
ErrorKind::Commit => f.write_str("commit error")?,
|
||||
ErrorKind::Verify => f.write_str("verification error")?,
|
||||
ErrorKind::Predicate => f.write_str("predicate error")?,
|
||||
}
|
||||
|
||||
if let Some(source) = &self.source {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use mpc_tls::SessionKeys;
|
||||
use mpz_common::Context;
|
||||
use mpz_memory_core::binary::Binary;
|
||||
use mpz_predicate::Pred;
|
||||
use mpz_vm_core::Vm;
|
||||
use rangeset::set::RangeSet;
|
||||
use tlsn_core::{
|
||||
@@ -21,10 +22,24 @@ use crate::{
|
||||
encoding::{self, KeyStore},
|
||||
hash::verify_hash,
|
||||
},
|
||||
predicate::verify_predicates,
|
||||
},
|
||||
verifier::VerifierError,
|
||||
};
|
||||
|
||||
/// A function that resolves predicate names to predicates.
|
||||
///
|
||||
/// The verifier must provide this to look up predicates by name,
|
||||
/// based on out-of-band agreement with the prover.
|
||||
///
|
||||
/// The function receives:
|
||||
/// - The predicate name
|
||||
/// - The byte indices the predicate operates on (from the prover's request)
|
||||
///
|
||||
/// The verifier should validate that the indices make sense for the predicate
|
||||
/// and return the appropriate predicate built with those indices.
|
||||
pub type PredicateResolver = dyn Fn(&str, &RangeSet<usize>) -> Option<Pred> + Send + Sync;
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) async fn verify<T: Vm<Binary> + KeyStore + Send + Sync>(
|
||||
ctx: &mut Context,
|
||||
@@ -35,6 +50,7 @@ pub(crate) async fn verify<T: Vm<Binary> + KeyStore + Send + Sync>(
|
||||
request: ProveRequest,
|
||||
handshake: Option<(ServerName, HandshakeData)>,
|
||||
transcript: Option<PartialTranscript>,
|
||||
predicate_resolver: Option<&PredicateResolver>,
|
||||
) -> Result<VerifierOutput, VerifierError> {
|
||||
let ciphertext_sent = collect_ciphertext(tls_transcript.sent());
|
||||
let ciphertext_recv = collect_ciphertext(tls_transcript.recv());
|
||||
@@ -101,6 +117,15 @@ pub(crate) async fn verify<T: Vm<Binary> + KeyStore + Send + Sync>(
|
||||
}
|
||||
}
|
||||
|
||||
// Build predicate ranges from request
|
||||
let (mut predicate_sent, mut predicate_recv) = (RangeSet::default(), RangeSet::default());
|
||||
for predicate_req in request.predicates() {
|
||||
match predicate_req.direction() {
|
||||
Direction::Sent => predicate_sent.union_mut(predicate_req.indices()),
|
||||
Direction::Received => predicate_recv.union_mut(predicate_req.indices()),
|
||||
}
|
||||
}
|
||||
|
||||
let (sent_refs, sent_proof) = verify_plaintext(
|
||||
vm,
|
||||
keys.client_write_key,
|
||||
@@ -113,6 +138,7 @@ pub(crate) async fn verify<T: Vm<Binary> + KeyStore + Send + Sync>(
|
||||
.filter(|record| record.typ == ContentType::ApplicationData),
|
||||
transcript.sent_authed(),
|
||||
&commit_sent,
|
||||
&predicate_sent,
|
||||
)
|
||||
.map_err(VerifierError::zk)?;
|
||||
let (recv_refs, recv_proof) = verify_plaintext(
|
||||
@@ -127,6 +153,7 @@ pub(crate) async fn verify<T: Vm<Binary> + KeyStore + Send + Sync>(
|
||||
.filter(|record| record.typ == ContentType::ApplicationData),
|
||||
transcript.received_authed(),
|
||||
&commit_recv,
|
||||
&predicate_recv,
|
||||
)
|
||||
.map_err(VerifierError::zk)?;
|
||||
|
||||
@@ -146,11 +173,38 @@ pub(crate) async fn verify<T: Vm<Binary> + KeyStore + Send + Sync>(
|
||||
);
|
||||
}
|
||||
|
||||
// Verify predicates if any were requested
|
||||
let predicate_proof = if !request.predicates().is_empty() {
|
||||
let resolver = predicate_resolver.ok_or_else(|| {
|
||||
VerifierError::predicate("predicates requested but no resolver provided")
|
||||
})?;
|
||||
|
||||
let predicates = request
|
||||
.predicates()
|
||||
.iter()
|
||||
.map(|req| {
|
||||
let predicate = resolver(req.name(), req.indices()).ok_or_else(|| {
|
||||
VerifierError::predicate(format!("unknown predicate: {}", req.name()))
|
||||
})?;
|
||||
Ok((req.direction(), req.indices().clone(), predicate))
|
||||
})
|
||||
.collect::<Result<Vec<_>, VerifierError>>()?;
|
||||
|
||||
Some(verify_predicates(vm, &transcript_refs, predicates).map_err(VerifierError::predicate)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
vm.execute_all(ctx).await.map_err(VerifierError::zk)?;
|
||||
|
||||
sent_proof.verify().map_err(VerifierError::verify)?;
|
||||
recv_proof.verify().map_err(VerifierError::verify)?;
|
||||
|
||||
// Verify predicate outputs after ZK execution
|
||||
if let Some(proof) = predicate_proof {
|
||||
proof.verify().map_err(VerifierError::predicate)?;
|
||||
}
|
||||
|
||||
let mut encoder_secret = None;
|
||||
if let Some(commit_config) = request.transcript_commit()
|
||||
&& let Some((sent, recv)) = commit_config.encoding()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use futures::{AsyncReadExt, AsyncWriteExt};
|
||||
use mpz_predicate::{Pred, eq};
|
||||
use rangeset::set::RangeSet;
|
||||
use tlsn::{
|
||||
config::{
|
||||
@@ -231,3 +232,184 @@ async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
// Predicate name for testing
|
||||
const TEST_PREDICATE: &str = "test_first_byte";
|
||||
|
||||
/// Test that a correct predicate passes verification.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
#[ignore]
|
||||
async fn test_predicate_passes() {
|
||||
let (socket_0, socket_1) = tokio::io::duplex(2 << 23);
|
||||
|
||||
// Request is "GET / HTTP/1.1\r\n..." - index 10 is '/' (in "HTTP/1.1")
|
||||
// Using index 10 to avoid overlap with revealed range (0..10)
|
||||
// Verifier uses the same predicate - should pass
|
||||
let prover_predicate = eq(10, b'/');
|
||||
|
||||
let (prover_result, verifier_result) = tokio::join!(
|
||||
prover_with_predicate(socket_0, prover_predicate),
|
||||
verifier_with_predicate(socket_1, || eq(10, b'/'))
|
||||
);
|
||||
|
||||
prover_result.expect("prover should succeed");
|
||||
verifier_result.expect("verifier should succeed with correct predicate");
|
||||
}
|
||||
|
||||
/// Test that a wrong predicate is rejected by the verifier.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
#[ignore]
|
||||
async fn test_wrong_predicate_rejected() {
|
||||
let (socket_0, socket_1) = tokio::io::duplex(2 << 23);
|
||||
|
||||
// Request is "GET / HTTP/1.1\r\n..." - index 10 is '/'
|
||||
// Verifier uses a DIFFERENT predicate that checks for 'X' - should fail
|
||||
let prover_predicate = eq(10, b'/');
|
||||
|
||||
let (prover_result, verifier_result) = tokio::join!(
|
||||
prover_with_predicate(socket_0, prover_predicate),
|
||||
verifier_with_predicate(socket_1, || eq(10, b'X'))
|
||||
);
|
||||
|
||||
// Prover may succeed or fail depending on when verifier rejects
|
||||
let _ = prover_result;
|
||||
|
||||
// Verifier should fail because predicate evaluates to false
|
||||
assert!(
|
||||
verifier_result.is_err(),
|
||||
"verifier should reject wrong predicate"
|
||||
);
|
||||
}
|
||||
|
||||
/// Test that prover can't prove a predicate their data doesn't satisfy.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
#[ignore]
|
||||
async fn test_unsatisfied_predicate_rejected() {
|
||||
let (socket_0, socket_1) = tokio::io::duplex(2 << 23);
|
||||
|
||||
// Request is "GET / HTTP/1.1\r\n..." - index 10 is '/'
|
||||
// Both parties use eq(10, b'X') but prover's data has '/' at index 10
|
||||
// This tests that a prover can't cheat - the predicate must actually be satisfied
|
||||
let prover_predicate = eq(10, b'X');
|
||||
|
||||
let (prover_result, verifier_result) = tokio::join!(
|
||||
prover_with_predicate(socket_0, prover_predicate),
|
||||
verifier_with_predicate(socket_1, || eq(10, b'X'))
|
||||
);
|
||||
|
||||
// Prover may succeed or fail depending on when verifier rejects
|
||||
let _ = prover_result;
|
||||
|
||||
// Verifier should fail because prover's data doesn't satisfy the predicate
|
||||
assert!(
|
||||
verifier_result.is_err(),
|
||||
"verifier should reject unsatisfied predicate"
|
||||
);
|
||||
}
|
||||
|
||||
#[instrument(skip(verifier_socket, predicate))]
|
||||
async fn prover_with_predicate<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
verifier_socket: T,
|
||||
predicate: Pred,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let (client_socket, server_socket) = tokio::io::duplex(2 << 16);
|
||||
|
||||
let server_task = tokio::spawn(bind(server_socket.compat()));
|
||||
|
||||
let prover = Prover::new(ProverConfig::builder().build()?)
|
||||
.commit(
|
||||
TlsCommitConfig::builder()
|
||||
.protocol(
|
||||
MpcTlsConfig::builder()
|
||||
.max_sent_data(MAX_SENT_DATA)
|
||||
.max_sent_records(MAX_SENT_RECORDS)
|
||||
.max_recv_data(MAX_RECV_DATA)
|
||||
.max_recv_records_online(MAX_RECV_RECORDS)
|
||||
.build()?,
|
||||
)
|
||||
.build()?,
|
||||
verifier_socket.compat(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (mut tls_connection, prover_fut) = prover
|
||||
.connect(
|
||||
TlsClientConfig::builder()
|
||||
.server_name(ServerName::Dns(SERVER_DOMAIN.try_into()?))
|
||||
.root_store(RootCertStore {
|
||||
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
|
||||
})
|
||||
.build()?,
|
||||
client_socket.compat(),
|
||||
)
|
||||
.await?;
|
||||
let prover_task = tokio::spawn(prover_fut);
|
||||
|
||||
tls_connection
|
||||
.write_all(b"GET / HTTP/1.1\r\nConnection: close\r\n\r\n")
|
||||
.await?;
|
||||
tls_connection.close().await?;
|
||||
|
||||
let mut response = vec![0u8; 1024];
|
||||
tls_connection.read_to_end(&mut response).await?;
|
||||
|
||||
let _ = server_task.await?;
|
||||
|
||||
let mut prover = prover_task.await??;
|
||||
|
||||
let mut builder = ProveConfig::builder(prover.transcript());
|
||||
builder.server_identity();
|
||||
builder.reveal_sent(&(0..10))?;
|
||||
builder.reveal_recv(&(0..10))?;
|
||||
builder.predicate(TEST_PREDICATE, Direction::Sent, predicate)?;
|
||||
|
||||
let config = builder.build()?;
|
||||
prover.prove(&config).await?;
|
||||
prover.close().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn verifier_with_predicate<T, F>(
|
||||
socket: T,
|
||||
make_predicate: F,
|
||||
) -> Result<VerifierOutput, Box<dyn std::error::Error + Send + Sync>>
|
||||
where
|
||||
T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static,
|
||||
F: Fn() -> Pred + Send + Sync + 'static,
|
||||
{
|
||||
let verifier = Verifier::new(
|
||||
VerifierConfig::builder()
|
||||
.root_store(RootCertStore {
|
||||
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
|
||||
})
|
||||
.build()?,
|
||||
);
|
||||
|
||||
let verifier = verifier
|
||||
.commit(socket.compat())
|
||||
.await?
|
||||
.accept()
|
||||
.await?
|
||||
.run()
|
||||
.await?;
|
||||
|
||||
let verifier = verifier.verify().await?;
|
||||
|
||||
// Resolver that builds the predicate fresh (Pred uses Rc, so can't be shared)
|
||||
let predicate_resolver = move |name: &str, _indices: &RangeSet<usize>| -> Option<Pred> {
|
||||
if name == TEST_PREDICATE {
|
||||
Some(make_predicate())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let (output, verifier) = verifier
|
||||
.accept_with_predicates(Some(&predicate_resolver))
|
||||
.await?;
|
||||
|
||||
verifier.close().await?;
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user