Compare commits

..

1 Commits

Author SHA1 Message Date
th4s
f9c8e3b743 wip 2026-01-13 15:12:51 +01:00
58 changed files with 961 additions and 1440 deletions

View File

@@ -6,7 +6,7 @@ on:
tag:
description: 'Tag to publish to NPM'
required: true
default: 'v0.1.0-alpha.14'
default: 'v0.1.0-alpha.14-pre'
jobs:
release:

View File

@@ -1,4 +1,4 @@
name: Reset main branch to published release tag
name: Fast-forward main branch to published release tag
on:
workflow_dispatch:
@@ -6,7 +6,7 @@ on:
types: [published]
jobs:
reset-main-to-release:
ff-main-to-release:
runs-on: ubuntu-latest
permissions:
contents: write
@@ -17,9 +17,9 @@ jobs:
with:
ref: main
- name: Reset main to release tag
- name: Fast-forward main to release tag
run: |
tag="${{ github.event.release.tag_name }}"
git fetch origin "refs/tags/$tag:refs/tags/$tag"
git reset --hard "refs/tags/$tag"
git push --force origin main
git merge --ff-only "refs/tags/$tag"
git push origin main

186
Cargo.lock generated
View File

@@ -174,9 +174,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "alloy-consensus"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12870ab65b131f609257436935047eec3cfabee8809732f6bf5a69fe2a18cf2e"
checksum = "8e30ab0d3e3c32976f67fc1a96179989e45a69594af42003a6663332f9b0bb9d"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -201,9 +201,9 @@ dependencies = [
[[package]]
name = "alloy-consensus-any"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47c66b14d2187de0c4efe4ef678aaa57a6a34cccdbea3a0773627fac9bd128f4"
checksum = "c20736b1f9d927d875d8777ef0c2250d4c57ea828529a9dbfa2c628db57b911e"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -253,9 +253,9 @@ dependencies = [
[[package]]
name = "alloy-eips"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f076d25ddfcd2f1cbcc234e072baf97567d1df0e3fccdc1f8af8cc8b18dc6299"
checksum = "15b85157b7be31fc4adf6acfefcb0d4308cba5dbd7a8d8e62bcc02ff37d6131a"
dependencies = [
"alloy-eip2124",
"alloy-eip2930",
@@ -288,9 +288,9 @@ dependencies = [
[[package]]
name = "alloy-json-rpc"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "250dbd8496f04eabe997e6e4c5186a0630b8bc3dbe7552e1fd917d491ef811e9"
checksum = "60f045b69b5e80b8944b25afe74ae6b974f3044d84b4a7a113da04745b2524cc"
dependencies = [
"alloy-primitives",
"alloy-sol-types",
@@ -303,9 +303,9 @@ dependencies = [
[[package]]
name = "alloy-network"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd45cdac957d1fa1d0c18f54f262350eb72f1adc38dd1f8b15f33f0747c6a60c"
checksum = "2b314ed5bdc7f449c53853125af2db5ac4d3954a9f4b205e7d694f02fc1932d1"
dependencies = [
"alloy-consensus",
"alloy-consensus-any",
@@ -329,9 +329,9 @@ dependencies = [
[[package]]
name = "alloy-network-primitives"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fba5c43e055effb5bd33dbc74b1ab7fe0f367d8801a25af9e7c716b3ef5e440b"
checksum = "5e9762ac5cca67b0f6ab614f7f8314942eead1c8eeef61511ea43a6ff048dbe0"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -392,9 +392,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-any"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8faa6f22068857f58579271b15e042f4725ad35cdce2ed4778ba32ffd3102b92"
checksum = "4b4a6f49d161ef83354d5ba3c8bc83c8ee464cb90182b215551d5c4b846579be"
dependencies = [
"alloy-consensus-any",
"alloy-rpc-types-eth",
@@ -403,9 +403,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-eth"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ec734cce11f7fe889950b36b51589397528b26beb6f890834a2131ee9f174d7"
checksum = "11920b16ab7c86052f990dcb4d25312fb2889faf506c4ee13dc946b450536989"
dependencies = [
"alloy-consensus",
"alloy-consensus-any",
@@ -424,9 +424,9 @@ dependencies = [
[[package]]
name = "alloy-serde"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27f076bfd74fccc63d50546e1765359736357a953de2eb778b7b6191571735e6"
checksum = "d1a0d2d5c64881f3723232eaaf6c2d9f4f88b061c63e87194b2db785ff3aa31f"
dependencies = [
"alloy-primitives",
"serde",
@@ -435,9 +435,9 @@ dependencies = [
[[package]]
name = "alloy-signer"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d80748c209a68421ab6f737828ce6ede7543569a5cad099c1ec16fc1baa05620"
checksum = "5ea4ac9765e5a7582877ca53688e041fe184880fe75f16edf0945b24a319c710"
dependencies = [
"alloy-primitives",
"async-trait",
@@ -450,9 +450,9 @@ dependencies = [
[[package]]
name = "alloy-signer-local"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17eb1eb39351b4bf20bb0710d8d3a91eb7918d3f3de2f3835f556842e33865cb"
checksum = "3c9d85b9f7105ab5ce7dae7b0da33cd9d977601a48f759e1c82958978dd1a905"
dependencies = [
"alloy-consensus",
"alloy-network",
@@ -552,9 +552,9 @@ dependencies = [
[[package]]
name = "alloy-tx-macros"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d567f4830dea921868c7680004ae0c7f221b05e6477db6c077c7953698f56"
checksum = "e2183706e24173309b0ab0e34d3e53cf3163b71a419803b2b3b0c1fb7ff7a941"
dependencies = [
"darling 0.21.3",
"proc-macro2",
@@ -2027,8 +2027,8 @@ checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
[[package]]
name = "clmul"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"bytemuck",
"cfg-if",
@@ -4292,8 +4292,8 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]]
name = "matrix-transpose"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"thiserror 1.0.69",
]
@@ -4349,8 +4349,8 @@ dependencies = [
[[package]]
name = "mpz-circuits"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"mpz-circuits-core",
"mpz-circuits-data",
@@ -4358,8 +4358,8 @@ dependencies = [
[[package]]
name = "mpz-circuits-core"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"bincode 1.3.3",
"itybity 0.3.1",
@@ -4373,8 +4373,8 @@ dependencies = [
[[package]]
name = "mpz-circuits-data"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"bincode 1.3.3",
"mpz-circuits-core",
@@ -4383,8 +4383,8 @@ dependencies = [
[[package]]
name = "mpz-cointoss"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"futures",
"mpz-cointoss-core",
@@ -4396,8 +4396,8 @@ dependencies = [
[[package]]
name = "mpz-cointoss-core"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"mpz-core",
"opaque-debug",
@@ -4407,8 +4407,8 @@ dependencies = [
[[package]]
name = "mpz-common"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"async-trait",
"bytes",
@@ -4426,8 +4426,8 @@ dependencies = [
[[package]]
name = "mpz-core"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"aes 0.9.0-rc.2",
"bcs",
@@ -4452,8 +4452,8 @@ dependencies = [
[[package]]
name = "mpz-fields"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"ark-ff 0.4.2",
"ark-secp256r1",
@@ -4472,10 +4472,11 @@ dependencies = [
[[package]]
name = "mpz-garble"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"async-trait",
"blake3",
"derive_builder 0.11.2",
"futures",
"hashbrown 0.14.5",
@@ -4498,8 +4499,8 @@ dependencies = [
[[package]]
name = "mpz-garble-core"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"aes 0.9.0-rc.2",
"bitvec",
@@ -4529,8 +4530,8 @@ dependencies = [
[[package]]
name = "mpz-hash"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"blake3",
"itybity 0.3.1",
@@ -4542,8 +4543,8 @@ dependencies = [
[[package]]
name = "mpz-ideal-vm"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"async-trait",
"futures",
@@ -4559,8 +4560,8 @@ dependencies = [
[[package]]
name = "mpz-memory-core"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"blake3",
"futures",
@@ -4574,8 +4575,8 @@ dependencies = [
[[package]]
name = "mpz-ole"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"async-trait",
"futures",
@@ -4592,8 +4593,8 @@ dependencies = [
[[package]]
name = "mpz-ole-core"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"hybrid-array",
"itybity 0.3.1",
@@ -4608,8 +4609,8 @@ dependencies = [
[[package]]
name = "mpz-ot"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"async-trait",
"cfg-if",
@@ -4632,8 +4633,8 @@ dependencies = [
[[package]]
name = "mpz-ot-core"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"aes 0.9.0-rc.2",
"blake3",
@@ -4663,8 +4664,8 @@ dependencies = [
[[package]]
name = "mpz-share-conversion"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"async-trait",
"mpz-common",
@@ -4679,8 +4680,8 @@ dependencies = [
[[package]]
name = "mpz-share-conversion-core"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"mpz-common",
"mpz-core",
@@ -4693,8 +4694,8 @@ dependencies = [
[[package]]
name = "mpz-vm-core"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"async-trait",
"futures",
@@ -4706,8 +4707,8 @@ dependencies = [
[[package]]
name = "mpz-zk"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"async-trait",
"blake3",
@@ -4724,8 +4725,8 @@ dependencies = [
[[package]]
name = "mpz-zk-core"
version = "0.1.0-alpha.5"
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
version = "0.1.0-alpha.4"
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
dependencies = [
"blake3",
"cfg-if",
@@ -6124,9 +6125,9 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18"
[[package]]
name = "rust-embed"
version = "8.11.0"
version = "8.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27"
checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
@@ -6135,9 +6136,9 @@ dependencies = [
[[package]]
name = "rust-embed-impl"
version = "8.11.0"
version = "8.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa"
checksum = "5fa2c8c9e8711e10f9c4fd2d64317ef13feaab820a4c51541f1a8c8e2e851ab2"
dependencies = [
"proc-macro2",
"quote",
@@ -6148,9 +6149,9 @@ dependencies = [
[[package]]
name = "rust-embed-utils"
version = "8.11.0"
version = "8.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1"
checksum = "60b161f275cb337fe0a44d924a5f4df0ed69c2c39519858f931ce61c779d3475"
dependencies = [
"sha2",
"walkdir",
@@ -7285,7 +7286,7 @@ dependencies = [
[[package]]
name = "tlsn"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"aes 0.8.4",
"ctr 0.9.2",
@@ -7337,7 +7338,7 @@ dependencies = [
[[package]]
name = "tlsn-attestation"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"alloy-primitives",
"alloy-signer",
@@ -7361,7 +7362,7 @@ dependencies = [
[[package]]
name = "tlsn-cipher"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"aes 0.8.4",
"async-trait",
@@ -7378,7 +7379,7 @@ dependencies = [
[[package]]
name = "tlsn-core"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"aead",
"aes-gcm",
@@ -7418,7 +7419,7 @@ version = "0.0.0"
[[package]]
name = "tlsn-deap"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"async-trait",
"futures",
@@ -7465,7 +7466,7 @@ dependencies = [
[[package]]
name = "tlsn-formats"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"bytes",
"rstest",
@@ -7557,7 +7558,7 @@ dependencies = [
[[package]]
name = "tlsn-hmac-sha256"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"criterion",
"hex",
@@ -7577,7 +7578,7 @@ dependencies = [
[[package]]
name = "tlsn-key-exchange"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"async-trait",
"derive_builder 0.12.0",
@@ -7604,7 +7605,7 @@ dependencies = [
[[package]]
name = "tlsn-mpc-tls"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"aes 0.8.4",
"aes-gcm",
@@ -7699,7 +7700,7 @@ version = "0.0.0"
[[package]]
name = "tlsn-tls-backend"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"async-trait",
"futures",
@@ -7709,7 +7710,7 @@ dependencies = [
[[package]]
name = "tlsn-tls-client"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"aes-gcm",
"async-trait",
@@ -7737,7 +7738,7 @@ dependencies = [
[[package]]
name = "tlsn-tls-client-async"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"bytes",
"futures",
@@ -7757,7 +7758,7 @@ dependencies = [
[[package]]
name = "tlsn-tls-core"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"futures",
"hmac",
@@ -7781,9 +7782,8 @@ source = "git+https://github.com/tlsnotary/tlsn-utils?rev=6168663#6168663495281f
[[package]]
name = "tlsn-wasm"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
dependencies = [
"async_io_stream",
"bincode 1.3.3",
"console_error_panic_hook",
"enum-try-as-inner",

View File

@@ -67,21 +67,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", tag = "v0.1.0-alpha.5" }
mpz-circuits-data = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-memory-core = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-common = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-core = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-vm-core = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-garble = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-garble-core = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-ole = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-ot = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-share-conversion = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-fields = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-zk = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-hash = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-ideal-vm = { git = "https://github.com/privacy-ethereum/mpz", tag = "v0.1.0-alpha.5" }
mpz-circuits = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-circuits-data = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-memory-core = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-common = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-core = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-vm-core = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-garble = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-garble-core = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-ole = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-ot = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-share-conversion = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-fields = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-zk = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-hash = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
mpz-ideal-vm = { git = "https://github.com/privacy-ethereum/mpz", rev = "bc1d4ad" }
rangeset = { version = "0.4" }
serio = { version = "0.2" }
@@ -92,7 +92,6 @@ aead = { version = "0.4" }
aes = { version = "0.8" }
aes-gcm = { version = "0.9" }
anyhow = { version = "1.0" }
async_io_stream = { version = "0.3" }
async-trait = { version = "0.1" }
axum = { version = "0.8" }
bcs = { version = "0.1" }

View File

@@ -1,6 +1,6 @@
[package]
name = "tlsn-attestation"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2024"
[features]

View File

@@ -5,7 +5,7 @@ description = "This crate provides implementations of ciphers for two parties"
keywords = ["tls", "mpc", "2pc", "aes"]
categories = ["cryptography"]
license = "MIT OR Apache-2.0"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
[lints]

View File

@@ -1,6 +1,6 @@
[package]
name = "tlsn-deap"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
[lints]

View File

@@ -5,7 +5,7 @@ description = "A 2PC implementation of TLS HMAC-SHA256 PRF"
keywords = ["tls", "mpc", "2pc", "hmac", "sha256"]
categories = ["cryptography"]
license = "MIT OR Apache-2.0"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
[lints]

View File

@@ -32,8 +32,8 @@ async fn prf(mode: Mode) {
let server_random: [u8; 32] = [96u8; 32];
let (mut leader_exec, mut follower_exec) = test_mt_context(8);
let mut leader_ctx = leader_exec.new_context().unwrap();
let mut follower_ctx = follower_exec.new_context().unwrap();
let mut leader_ctx = leader_exec.new_context().await.unwrap();
let mut follower_ctx = follower_exec.new_context().await.unwrap();
let mut leader_vm = IdealVm::new();
let mut follower_vm = IdealVm::new();

View File

@@ -5,7 +5,7 @@ description = "Implementation of the 3-party key-exchange protocol"
keywords = ["tls", "mpc", "2pc", "pms", "key-exchange"]
categories = ["cryptography"]
license = "MIT OR Apache-2.0"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
[lints]

View File

@@ -5,7 +5,7 @@ description = "Core types for TLSNotary"
keywords = ["tls", "mpc", "2pc", "types"]
categories = ["cryptography"]
license = "MIT OR Apache-2.0"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
[lints]

View File

@@ -43,12 +43,12 @@ noir = { git = "https://github.com/zkmopro/noir-rs", tag = "v1.0.0-beta.8", feat
] }
[[example]]
name = "basic"
path = "basic/basic.rs"
name = "interactive"
path = "interactive/interactive.rs"
[[example]]
name = "basic_zk"
path = "basic_zk/basic_zk.rs"
name = "interactive_zk"
path = "interactive_zk/interactive_zk.rs"
[[example]]
name = "attestation_prove"

View File

@@ -2,9 +2,9 @@
This folder contains examples demonstrating how to use the TLSNotary protocol.
* [Basic](./basic/README.md): Basic Prover and Verifier session.
* [Attestation](./attestation/README.md): Issuing an attestation where a Verifier acts as a Notary.
* [Basic_zk](./basic_zk/README.md): Basic Prover and Verifier session demonstrating zero-knowledge age verification using Noir.
* [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.
Refer to <https://tlsnotary.org/docs/quick_start> for a quick start guide to using TLSNotary with these examples.
Refer to <https://tlsnotary.org/docs/quick_start> for a quick start guide to using TLSNotary with these examples.

View File

@@ -1,20 +1,21 @@
# Attestation Example
This example demonstrates an **attestation workflow**: notarizing data from a server with a trusted third party (Notary), then creating verifiable presentations with selective disclosure of sensitive information to a Verifier.
This example demonstrates a **TLSNotary attestation workflow**: notarizing data from a server with a trusted third party (Notary), then creating verifiable presentations with selective disclosure of sensitive information to a Verifier.
## 🔍 How It Works
```mermaid
sequenceDiagram
participant P as Prover
participant N as TLS<br/>Verifier
participant N as MPC-TLS<br/>Verifier
participant S as Server<br/>Fixture
participant V as Attestation<br/>Verifier
Note over P,S: 1. Notarization Phase
P->>N: Establish TLS connection
P->>S: Request (TLS)
S->>P: Response (TLS)
P->>N: Establish MPC-TLS connection
P->>S: Request (MPC-TLS)
S->>P: Response (MPC-TLS)
N->>P: Issue signed attestation
Note over P: 2. Presentation Phase
@@ -160,4 +161,4 @@ After running the examples, you'll find:
- 📋 **Audit Trail**: Maintain logs of notarization and verification events
- 🔄 **Key Rotation**: Plan for Notary key updates and migration
> ⚠️ **Demo Notice**: This example uses a local test server and local Notary for demonstration. In production, use trusted third-party Notary services and real server endpoints.
> ⚠️ **Demo Notice**: This example uses a local test server and local Notary for demonstration. In production, use trusted third-party Notary services and real server endpoints.

View File

@@ -33,9 +33,8 @@ use tlsn::{
connection::{ConnectionInfo, HandshakeData, ServerName, TranscriptLength},
prover::{state::Committed, Prover, ProverOutput},
transcript::{ContentType, TranscriptCommitConfig},
verifier::VerifierOutput,
verifier::{Verifier, VerifierOutput},
webpki::{CertificateDer, PrivateKeyDer, RootCertStore},
Session,
};
use tlsn_examples::ExampleType;
use tlsn_formats::http::{DefaultHttpCommitter, HttpCommit, HttpTranscript};
@@ -100,16 +99,8 @@ async fn prover<S: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
.map(|port| port.parse().expect("port should be valid integer"))
.unwrap_or(DEFAULT_FIXTURE_PORT);
// Create a session with the notary.
let session = Session::new(socket.compat());
let (driver, mut handle) = session.split();
// Spawn the session driver to run in the background.
let driver_task = tokio::spawn(driver);
// Create a new prover and perform necessary setup.
let prover = handle
.new_prover(ProverConfig::builder().build()?)?
let prover = Prover::new(ProverConfig::builder().build()?)
.commit(
TlsCommitConfig::builder()
// Select the TLS commitment protocol.
@@ -124,6 +115,7 @@ async fn prover<S: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
.build()?,
)
.build()?,
socket.compat(),
)
.await?;
@@ -232,10 +224,6 @@ async fn prover<S: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
let (attestation, secrets) = notarize(prover, &request_config, req_tx, resp_rx).await?;
// Close the session and wait for the driver to complete.
handle.close();
driver_task.await??;
// Write the attestation to disk.
let attestation_path = tlsn_examples::get_file_path(example_type, "attestation");
let secrets_path = tlsn_examples::get_file_path(example_type, "secrets");
@@ -323,13 +311,6 @@ async fn notary<S: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
request_rx: Receiver<AttestationRequest>,
attestation_tx: Sender<Attestation>,
) -> Result<()> {
// Create a session with the prover.
let session = Session::new(socket.compat());
let (driver, mut handle) = session.split();
// Spawn the session driver to run in the background.
let driver_task = tokio::spawn(driver);
// Create a root certificate store with the server-fixture's self-signed
// certificate. This is only required for offline testing with the
// server-fixture.
@@ -340,9 +321,8 @@ async fn notary<S: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
.build()
.unwrap();
let verifier = handle
.new_verifier(verifier_config)?
.commit()
let verifier = Verifier::new(verifier_config)
.commit(socket.compat())
.await?
.accept()
.await?
@@ -419,9 +399,5 @@ async fn notary<S: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
.send(attestation)
.map_err(|_| anyhow!("prover is not receiving attestation"))?;
// Close the session and wait for the driver to complete.
handle.close();
driver_task.await??;
Ok(())
}

View File

@@ -1,18 +1,18 @@
## Simple Basic Verifier: Verifying Data from an API in Rust
## Simple Interactive Verifier: Verifying Data from an API in Rust
This example demonstrates how to use TLSNotary in a simple session between a Prover and a Verifier.
This example demonstrates how to use TLSNotary in a simple interactive session between a Prover and a Verifier. It involves the Verifier first verifying the MPC-TLS session and then confirming the correctness of the data.
This example fetches data from a local test server. To start the server, run the following command from the root of this repository (not from this example's folder):
```shell
RUST_LOG=info PORT=4000 cargo run --bin tlsn-server-fixture
```
Next, run the basic example with:
Next, run the interactive example with:
```shell
SERVER_PORT=4000 cargo run --release --example basic
SERVER_PORT=4000 cargo run --release --example interactive
```
To view more detailed debug information, use the following command:
```
RUST_LOG=debug,yamux=info,uid_mux=info SERVER_PORT=4000 cargo run --release --example basic
RUST_LOG=debug,yamux=info,uid_mux=info SERVER_PORT=4000 cargo run --release --example interactive
```
> Note: In this example, the Prover and Verifier run on the same machine. In real-world scenarios, the Prover and Verifier would typically operate on separate machines.
> Note: In this example, the Prover and Verifier run on the same machine. In real-world scenarios, the Prover and Verifier would typically operate on separate machines.

View File

@@ -20,10 +20,10 @@ use tlsn::{
verifier::VerifierConfig,
},
connection::ServerName,
prover::Prover,
transcript::PartialTranscript,
verifier::VerifierOutput,
verifier::{Verifier, VerifierOutput},
webpki::{CertificateDer, RootCertStore},
Session,
};
use tlsn_server_fixture::DEFAULT_FIXTURE_PORT;
use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
@@ -77,16 +77,8 @@ async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
assert_eq!(uri.scheme().unwrap().as_str(), "https");
let server_domain = uri.authority().unwrap().host();
// Create a session with the verifier.
let session = Session::new(verifier_socket.compat());
let (driver, mut handle) = session.split();
// Spawn the session driver to run in the background.
let driver_task = tokio::spawn(driver);
// Create a new prover and perform necessary setup.
let prover = handle
.new_prover(ProverConfig::builder().build()?)?
let prover = Prover::new(ProverConfig::builder().build()?)
.commit(
TlsCommitConfig::builder()
// Select the TLS commitment protocol.
@@ -101,6 +93,7 @@ async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
.build()?,
)
.build()?,
verifier_socket.compat(),
)
.await?;
@@ -127,13 +120,14 @@ async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
// 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 and wait for Response.
// MPC-TLS: Send Request and wait for Response.
let request = Request::builder()
.uri(uri.clone())
.header("Host", server_domain)
@@ -182,10 +176,6 @@ async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
prover.prove(&config).await?;
prover.close().await?;
// Close the session and wait for the driver to complete.
handle.close();
driver_task.await??;
Ok(())
}
@@ -193,13 +183,6 @@ async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
socket: T,
) -> Result<PartialTranscript> {
// Create a session with the prover.
let session = Session::new(socket.compat());
let (driver, mut handle) = session.split();
// Spawn the session driver to run in the background.
let driver_task = tokio::spawn(driver);
// Create a root certificate store with the server-fixture's self-signed
// certificate. This is only required for offline testing with the
// server-fixture.
@@ -208,10 +191,10 @@ async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
})
.build()?;
let verifier = handle.new_verifier(verifier_config)?;
let verifier = Verifier::new(verifier_config);
// Validate the proposed configuration and then run the TLS commitment protocol.
let verifier = verifier.commit().await?;
let verifier = verifier.commit(socket.compat()).await?;
// This is the opportunity to ensure the prover does not attempt to overload the
// verifier.
@@ -258,10 +241,6 @@ async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
verifier.close().await?;
// Close the session and wait for the driver to complete.
handle.close();
driver_task.await??;
let server_name = server_name.expect("prover should have revealed server name");
let transcript = transcript.expect("prover should have revealed transcript data");

View File

@@ -1,4 +1,4 @@
# Basic Zero-Knowledge Age Verification with TLSNotary
# 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.
@@ -10,8 +10,8 @@ sequenceDiagram
participant P as Prover
participant V as Verifier
P->>S: Request tax data (with auth token) (TLS)
S->>P: Tax data including `date_of_birth` (TLS)
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
@@ -22,7 +22,7 @@ sequenceDiagram
### The Process
1. **TLS Commitment**: 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.
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.
@@ -61,7 +61,7 @@ The ZK circuit proves: **"I know a birth date that hashes to the committed value
**What the Verifier Learns:**
- ✅ The prover is 18+ years old
- ✅ The birth date is authentic (from the TLS session)
- ✅ The birth date is authentic (from the MPC-TLS session)
Everything else remains private.
@@ -74,12 +74,12 @@ Everything else remains private.
2. **Run the age verification** (in a new terminal):
```bash
SERVER_PORT=4000 cargo run --release --example basic_zk
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 basic_zk
RUST_LOG=debug,yamux=info,uid_mux=info SERVER_PORT=4000 cargo run --release --example interactive_zk
```
### Expected Output
@@ -106,11 +106,11 @@ Verified received data:
### Project Structure
```
basic_zk/
interactive_zk/
├── prover.rs # Prover implementation
├── verifier.rs # Verifier implementation
├── verifier.rs # Verifier implementation
├── types.rs # Shared types
└── basic_zk.rs # Main example runner
└── interactive_zk.rs # Main example runner
├── noir/ # Zero-knowledge circuit
│ ├── src/main.n # Noir circuit code
│ ├── target/ # Compiled circuit artifacts

View File

@@ -31,10 +31,11 @@ async fn main() -> Result<()> {
// 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, &server_addr, &uri),
verifier(verifier_socket)
prover(prover_socket, prover_extra_socket, &server_addr, &uri),
verifier(verifier_socket, verifier_extra_socket)
)?;
println!("---");

View File

@@ -32,24 +32,24 @@ use tlsn::{
},
connection::ServerName,
hash::HashAlgId,
prover::Prover,
transcript::{
hash::{PlaintextHash, PlaintextHashSecret},
Direction, TranscriptCommitConfig, TranscriptCommitConfigBuilder, TranscriptCommitmentKind,
TranscriptSecret,
},
webpki::{CertificateDer, RootCertStore},
Session,
};
use futures::io::AsyncWriteExt as _;
use tlsn_examples::{MAX_RECV_DATA, MAX_SENT_DATA};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt};
use tracing::instrument;
#[instrument(skip(verifier_socket))]
#[instrument(skip(verifier_socket, verifier_extra_socket))]
pub async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
verifier_socket: T,
mut verifier_extra_socket: T,
server_addr: &SocketAddr,
uri: &str,
) -> Result<()> {
@@ -64,16 +64,8 @@ pub async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
.ok_or_else(|| anyhow::anyhow!("URI must have authority"))?
.host();
// Create a session with the verifier.
let session = Session::new(verifier_socket.compat());
let (driver, mut handle) = session.split();
// Spawn the session driver to run in the background.
let driver_task = tokio::spawn(driver);
// Create a new prover and perform necessary setup.
let prover = handle
.new_prover(ProverConfig::builder().build()?)?
let prover = Prover::new(ProverConfig::builder().build()?)
.commit(
TlsCommitConfig::builder()
// Select the TLS commitment protocol.
@@ -88,6 +80,7 @@ pub async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
.build()?,
)
.build()?,
verifier_socket.compat(),
)
.await?;
@@ -114,13 +107,14 @@ pub async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
// 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 and wait for Response.
// MPC-TLS: Send Request and wait for Response.
let request = Request::builder()
.uri(uri.clone())
.header("Host", server_domain)
@@ -133,7 +127,7 @@ pub async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
if response.status() != StatusCode::OK {
return Err(anyhow::anyhow!(
"request failed with status {}",
"MPC-TLS request failed with status {}",
response.status()
));
}
@@ -172,13 +166,10 @@ pub async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
let prove_config = prove_config_builder.build()?;
// MPC-TLS prove
let prover_output = prover.prove(&prove_config).await?;
prover.close().await?;
// Close the session and wait for the driver to complete, reclaiming the socket.
handle.close();
let mut socket = driver_task.await??;
// Prove birthdate is more than 18 years ago.
let received_commitments = received_commitments(&prover_output.transcript_commitments);
let received_commitment = received_commitments
@@ -193,8 +184,8 @@ pub async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
// Sent zk proof bundle to verifier
let serialized_proof = bincode::serialize(&proof_bundle)?;
socket.write_all(&serialized_proof).await?;
socket.close().await?;
verifier_extra_socket.write_all(&serialized_proof).await?;
verifier_extra_socket.shutdown().await?;
Ok(())
}

View File

@@ -3,7 +3,6 @@ use crate::types::received_commitments;
use super::types::ZKProofBundle;
use anyhow::Result;
use chrono::{Local, NaiveDate};
use futures::io::AsyncReadExt as _;
use noir::barretenberg::verify::{get_ultra_honk_verification_key, verify_ultra_honk};
use serde_json::Value;
use tls_server_fixture::CA_CERT_DER;
@@ -12,39 +11,33 @@ use tlsn::{
connection::ServerName,
hash::HashAlgId,
transcript::{Direction, PartialTranscript},
verifier::VerifierOutput,
verifier::{Verifier, VerifierOutput},
webpki::{CertificateDer, RootCertStore},
Session,
};
use tlsn_examples::{MAX_RECV_DATA, MAX_SENT_DATA};
use tlsn_server_fixture_certs::SERVER_DOMAIN;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite};
use tokio_util::compat::TokioAsyncReadCompatExt;
use tracing::instrument;
#[instrument(skip(socket))]
#[instrument(skip(socket, extra_socket))]
pub async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
socket: T,
mut extra_socket: T,
) -> Result<PartialTranscript> {
// Create a session with the prover.
let session = Session::new(socket.compat());
let (driver, mut handle) = session.split();
// Spawn the session driver to run in the background.
let driver_task = tokio::spawn(driver);
// 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())],
})
.build()?;
let verifier = handle.new_verifier(verifier_config)?;
let verifier = Verifier::new(
VerifierConfig::builder()
// Create a root certificate store with the server-fixture's self-signed
// certificate. This is only required for offline testing with the
// server-fixture.
.root_store(RootCertStore {
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
})
.build()?,
);
// Validate the proposed configuration and then run the TLS commitment protocol.
let verifier = verifier.commit().await?;
let verifier = verifier.commit(socket.compat()).await?;
// This is the opportunity to ensure the prover does not attempt to overload the
// verifier.
@@ -97,10 +90,6 @@ pub async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>
verifier.close().await?;
// Close the session and wait for the driver to complete, reclaiming the socket.
handle.close();
let mut socket = driver_task.await??;
let server_name = server_name.expect("server name should be present");
let transcript = transcript.expect("transcript should be present");
@@ -137,7 +126,7 @@ pub async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>
// Receive ZKProof information from prover
let mut buf = Vec::new();
socket.read_to_end(&mut buf).await?;
extra_socket.read_to_end(&mut buf).await?;
if buf.is_empty() {
return Err(anyhow::anyhow!("No ZK proof data received from prover"));
@@ -204,16 +193,16 @@ pub async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>
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: {} != {}",
"❌ 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(anyhow::anyhow!(
"Hash in proof does not match committed hash"
"Hash in proof does not match committed hash in MPC-TLS"
));
}
tracing::info!(
"✅ The hash in the proof matches the committed hash ({})",
"✅ The hash in the proof matches the committed hash in MPC-TLS ({})",
hex::encode(&expected_hash)
);

View File

@@ -1,6 +1,6 @@
[package]
name = "tlsn-formats"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
[lints]

View File

@@ -5,7 +5,6 @@ use futures::{AsyncReadExt, AsyncWriteExt, TryFutureExt};
use harness_core::bench::{Bench, ProverMetrics};
use tlsn::{
Session,
config::{
prove::ProveConfig,
prover::ProverConfig,
@@ -13,6 +12,7 @@ use tlsn::{
tls_commit::{TlsCommitConfig, mpc::MpcTlsConfig},
},
connection::ServerName,
prover::Prover,
webpki::{CertificateDer, RootCertStore},
};
use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
@@ -20,7 +20,6 @@ use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
use crate::{
IoProvider,
bench::{Meter, RECV_PADDING},
spawn,
};
pub async fn bench_prover(provider: &IoProvider, config: &Bench) -> Result<ProverMetrics> {
@@ -29,12 +28,7 @@ pub async fn bench_prover(provider: &IoProvider, config: &Bench) -> Result<Prove
let sent = verifier_io.sent();
let recv = verifier_io.recv();
let mut session = Session::new(verifier_io);
let prover = session.new_prover(ProverConfig::builder().build()?)?;
let (session, handle) = session.split();
_ = spawn(session);
let prover = Prover::new(ProverConfig::builder().build()?);
let time_start = web_time::Instant::now();
@@ -55,6 +49,7 @@ pub async fn bench_prover(provider: &IoProvider, config: &Bench) -> Result<Prove
.build()
}?)
.build()?,
verifier_io,
)
.await?;
@@ -125,7 +120,6 @@ pub async fn bench_prover(provider: &IoProvider, config: &Bench) -> Result<Prove
prover.prove(&prove_config).await?;
prover.close().await?;
handle.close();
let time_total = time_start.elapsed().as_millis();

View File

@@ -2,34 +2,32 @@ use anyhow::Result;
use harness_core::bench::Bench;
use tlsn::{
Session,
config::verifier::VerifierConfig,
verifier::Verifier,
webpki::{CertificateDer, RootCertStore},
};
use tlsn_server_fixture_certs::CA_CERT_DER;
use crate::{IoProvider, spawn};
use crate::IoProvider;
pub async fn bench_verifier(provider: &IoProvider, _config: &Bench) -> Result<()> {
let io = provider.provide_proto_io().await?;
let mut session = Session::new(io);
let verifier = session.new_verifier(
let verifier = Verifier::new(
VerifierConfig::builder()
.root_store(RootCertStore {
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
})
.build()?,
)?;
);
let (session, handle) = session.split();
_ = spawn(session);
let verifier = verifier.commit().await?.accept().await?.run().await?;
let verifier = verifier
.commit(provider.provide_proto_io().await?)
.await?
.accept()
.await?
.run()
.await?;
let (_, verifier) = verifier.verify().await?.accept().await?;
verifier.close().await?;
handle.close();
Ok(())
}

View File

@@ -1,5 +1,4 @@
use tlsn::{
Session,
config::{
prove::ProveConfig,
prover::ProverConfig,
@@ -9,8 +8,9 @@ use tlsn::{
},
connection::ServerName,
hash::HashAlgId,
prover::Prover,
transcript::{TranscriptCommitConfig, TranscriptCommitment, TranscriptCommitmentKind},
verifier::VerifierOutput,
verifier::{Verifier, VerifierOutput},
webpki::{CertificateDer, RootCertStore},
};
use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
@@ -28,17 +28,7 @@ const MAX_RECV_DATA: usize = 1 << 11;
crate::test!("basic", prover, verifier);
async fn prover(provider: &IoProvider) {
let io = provider.provide_proto_io().await.unwrap();
let mut session = Session::new(io);
let prover = session
.new_prover(ProverConfig::builder().build().unwrap())
.unwrap();
let (session, handle) = session.split();
_ = spawn(session);
let prover = prover
let prover = Prover::new(ProverConfig::builder().build().unwrap())
.commit(
TlsCommitConfig::builder()
.protocol(
@@ -51,6 +41,7 @@ async fn prover(provider: &IoProvider) {
)
.build()
.unwrap(),
provider.provide_proto_io().await.unwrap(),
)
.await
.unwrap();
@@ -125,27 +116,18 @@ async fn prover(provider: &IoProvider) {
prover.prove(&config).await.unwrap();
prover.close().await.unwrap();
handle.close();
}
async fn verifier(provider: &IoProvider) {
let io = provider.provide_proto_io().await.unwrap();
let mut session = Session::new(io);
let config = VerifierConfig::builder()
.root_store(RootCertStore {
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
})
.build()
.unwrap();
let verifier = session.new_verifier(config).unwrap();
let (session, handle) = session.split();
_ = spawn(session);
let verifier = verifier
.commit()
let verifier = Verifier::new(config)
.commit(provider.provide_proto_io().await.unwrap())
.await
.unwrap()
.accept()
@@ -165,7 +147,6 @@ async fn verifier(provider: &IoProvider) {
) = verifier.verify().await.unwrap().accept().await.unwrap();
verifier.close().await.unwrap();
handle.close();
let ServerName::Dns(server_name) = server_name.unwrap();

View File

@@ -5,7 +5,7 @@ description = "TLSNotary MPC-TLS protocol"
keywords = ["tls", "mpc", "2pc"]
categories = ["cryptography"]
license = "MIT OR Apache-2.0"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
[lints]

View File

@@ -123,8 +123,8 @@ fn build_pair(config: Config) -> (MpcTlsLeader, MpcTlsFollower) {
let (mut mt_a, mut mt_b) = test_mt_context(8);
let ctx_a = mt_a.new_context().unwrap();
let ctx_b = mt_b.new_context().unwrap();
let ctx_a = futures::executor::block_on(mt_a.new_context()).unwrap();
let ctx_b = futures::executor::block_on(mt_b.new_context()).unwrap();
let delta_a = Delta::new(Block::random(&mut rng));
let delta_b = Delta::new(Block::random(&mut rng));

View File

@@ -5,7 +5,7 @@ description = "A TLS backend trait for TLSNotary"
keywords = ["tls", "mpc", "2pc"]
categories = ["cryptography"]
license = "MIT OR Apache-2.0"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
[lints]

View File

@@ -5,7 +5,7 @@ description = "An async TLS client for TLSNotary"
keywords = ["tls", "mpc", "2pc", "client", "async"]
categories = ["cryptography"]
license = "MIT OR Apache-2.0"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
[lints]

View File

@@ -5,7 +5,7 @@ description = "A TLS client for TLSNotary"
keywords = ["tls", "mpc", "2pc", "client", "sync"]
categories = ["cryptography"]
license = "Apache-2.0 OR ISC OR MIT"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
autobenches = false

View File

@@ -5,7 +5,7 @@ description = "Cryptographic operations for the TLSNotary TLS client"
keywords = ["tls", "mpc", "2pc"]
categories = ["cryptography"]
license = "Apache-2.0 OR ISC OR MIT"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
[lints]

View File

@@ -4,7 +4,7 @@ authors = ["TLSNotary Team"]
keywords = ["tls", "mpc", "2pc", "prover"]
categories = ["cryptography"]
license = "MIT OR Apache-2.0"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2024"
[lints]

View File

@@ -0,0 +1,21 @@
//! Execution context.
use mpz_common::context::Multithread;
use crate::mux::MuxControl;
/// Maximum concurrency for multi-threaded context.
pub(crate) const MAX_CONCURRENCY: usize = 8;
/// Builds a multi-threaded context with the given muxer.
pub(crate) fn build_mt_context(mux: MuxControl) -> Multithread {
let builder = Multithread::builder().mux(mux).concurrency(MAX_CONCURRENCY);
#[cfg(all(feature = "web", target_arch = "wasm32"))]
let builder = builder.spawn_handler(|f| {
let _ = web_spawn::spawn(f);
Ok(())
});
builder.build().unwrap()
}

View File

@@ -1,170 +0,0 @@
use std::fmt::Display;
/// TLSNotary error.
///
/// Errors are categorized by kind:
///
/// - **User** ([`is_user`](Self::is_user)): e.g. rejected by the remote party.
/// - **IO** ([`is_io`](Self::is_io)): network or communication failure.
/// - **Internal** ([`is_internal`](Self::is_internal)): an unknown internal
/// error in the library.
/// - **Config** ([`is_config`](Self::is_config)): invalid configuration
/// provided by the user.
///
/// The [`msg`](Self::msg) method returns additional context if available, such
/// as a rejection message provided by a verifier.
#[derive(Debug, thiserror::Error)]
pub struct Error {
kind: ErrorKind,
msg: Option<String>,
source: Option<Box<dyn std::error::Error + Send + Sync>>,
}
impl Error {
pub(crate) fn io() -> Self {
Self {
kind: ErrorKind::Io,
msg: None,
source: None,
}
}
pub(crate) fn internal() -> Self {
Self {
kind: ErrorKind::Internal,
msg: None,
source: None,
}
}
pub(crate) fn user() -> Self {
Self {
kind: ErrorKind::User,
msg: None,
source: None,
}
}
pub(crate) fn config() -> Self {
Self {
kind: ErrorKind::Config,
msg: None,
source: None,
}
}
pub(crate) fn with_msg(mut self, msg: impl Into<String>) -> Self {
self.msg = Some(msg.into());
self
}
pub(crate) fn with_source<T>(mut self, source: T) -> Self
where
T: Into<Box<dyn std::error::Error + Send + Sync>>,
{
self.source = Some(source.into());
self
}
/// Returns `true` if the error was user created.
pub fn is_user(&self) -> bool {
self.kind.is_user()
}
/// Returns `true` if the error originated from an IO error.
pub fn is_io(&self) -> bool {
self.kind.is_io()
}
/// Returns `true` if the error originated from an internal bug.
pub fn is_internal(&self) -> bool {
self.kind.is_internal()
}
/// Returns `true` if the error originated from invalid configuration.
pub fn is_config(&self) -> bool {
self.kind.is_config()
}
/// Returns the error message if available.
pub fn msg(&self) -> Option<&str> {
self.msg.as_deref()
}
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.kind {
ErrorKind::User => write!(f, "user error")?,
ErrorKind::Io => write!(f, "io error")?,
ErrorKind::Internal => write!(f, "internal error")?,
ErrorKind::Config => write!(f, "config error")?,
}
if let Some(msg) = &self.msg {
write!(f, ": {msg}")?;
}
if let Some(source) = &self.source {
write!(f, " caused by: {source}")?;
}
Ok(())
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Self::io().with_source(e)
}
}
impl From<mpz_common::ContextError> for Error {
fn from(e: mpz_common::ContextError) -> Self {
Self::internal().with_msg("context error").with_source(e)
}
}
impl From<mpc_tls::MpcTlsError> for Error {
fn from(e: mpc_tls::MpcTlsError) -> Self {
Self::internal().with_msg("mpc-tls error").with_source(e)
}
}
impl From<tls_client_async::ConnectionError> for Error {
fn from(e: tls_client_async::ConnectionError) -> Self {
Self::io().with_msg("tls connection error").with_source(e)
}
}
impl From<tlsn_mux::ConnectionError> for Error {
fn from(e: tlsn_mux::ConnectionError) -> Self {
Self::io().with_msg("mux connection error").with_source(e)
}
}
#[derive(Debug)]
enum ErrorKind {
User,
Io,
Internal,
Config,
}
impl ErrorKind {
fn is_user(&self) -> bool {
matches!(self, ErrorKind::User)
}
fn is_io(&self) -> bool {
matches!(self, ErrorKind::Io)
}
fn is_internal(&self) -> bool {
matches!(self, ErrorKind::Internal)
}
fn is_config(&self) -> bool {
matches!(self, ErrorKind::Config)
}
}

View File

@@ -1,66 +1,23 @@
//! TLSNotary protocol implementation.
//!
//! This crate provides the core protocol for generating and verifying proofs
//! of TLS sessions. A prover can demonstrate to a verifier that specific data
//! was exchanged with a TLS server, without revealing the full transcript.
//!
//! # Overview
//!
//! The protocol involves two parties:
//!
//! - **Prover** ([`Prover`](prover::Prover)): connects to a TLS server and
//! generates proofs about the session.
//! - **Verifier** ([`Verifier`](verifier::Verifier)): collaborates with the
//! prover during the TLS session and verifies the resulting proofs.
//!
//! Both parties communicate through an established [`Session`].
//!
//! # Workflow
//!
//! The protocol has two main phases:
//!
//! **Commitment**: The prover and verifier collaborate to construct a TLS
//! transcript commitment from the prover's communication with a TLS server.
//! This authenticates the transcript for the verifier, without the verifier
//! learning the contents.
//!
//! **Selective Disclosure**: The prover selectively reveals portions of the
//! committed transcript to the verifier, proving statements about the data
//! exchanged with the server.
//!
//! ## Steps
//!
//! 1. Establish a communication channel between prover and verifier.
//! 2. Create a [`Session`] on each side from the channel.
//! 3. Create a [`Prover`](prover::Prover) or [`Verifier`](verifier::Verifier).
//! 4. Run the commitment phase: the prover connects to the TLS server and
//! exchanges data to obtain a commitment to the TLS transcript.
//! 5. (Optional) Perform selective disclosure: the prover provably reveals
//! selected data to the verifier.
//! TLSNotary library.
#![deny(missing_docs, unreachable_pub, unused_must_use)]
#![deny(clippy::all)]
#![forbid(unsafe_code)]
mod error;
pub(crate) mod context;
pub(crate) mod ghash;
pub(crate) mod map;
pub(crate) mod mpz;
pub(crate) mod msg;
pub(crate) mod mux;
pub mod prover;
mod session;
pub(crate) mod tag;
pub(crate) mod transcript_internal;
pub mod verifier;
pub use error::Error;
pub use session::{Session, SessionDriver, SessionHandle};
pub use tlsn_attestation as attestation;
pub use tlsn_core::{config, connection, hash, transcript, webpki};
/// Result type.
pub type Result<T, E = Error> = core::result::Result<T, E>;
use std::sync::LazyLock;
use semver::Version;

View File

@@ -1,5 +1,3 @@
use std::fmt;
use semver::Version;
use serde::{Deserialize, Serialize};
@@ -42,14 +40,12 @@ impl Response {
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct RejectionReason(Option<String>);
impl fmt::Display for RejectionReason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(msg) = &self.0 {
write!(f, "{msg}")
impl From<RejectionReason> for crate::prover::ProverError {
fn from(value: RejectionReason) -> Self {
if let Some(msg) = value.0 {
crate::prover::ProverError::config(format!("verifier rejected with reason: {msg}"))
} else {
write!(f, "no reason provided")
crate::prover::ProverError::config("verifier rejected without providing a reason")
}
}
}
impl std::error::Error for RejectionReason {}

107
crates/tlsn/src/mux.rs Normal file
View File

@@ -0,0 +1,107 @@
//! Multiplexer used in the TLSNotary protocol.
use futures::{
AsyncRead, AsyncWrite, Future,
future::{FusedFuture, FutureExt},
};
use mpz_common::{ThreadId, io::Io, mux::Mux};
use tlsn_mux::{Connection, Handle};
use tracing::error;
/// Multiplexer controller providing streams.
pub(crate) struct MuxControl {
handle: Handle,
}
impl Mux for MuxControl {
fn open(&self, id: ThreadId) -> Result<Io, std::io::Error> {
let stream = self
.handle
.new_stream(id.as_ref())
.map_err(std::io::Error::other)?;
let io = Io::from_io(stream);
Ok(io)
}
}
impl From<MuxControl> for Box<dyn Mux + Send> {
fn from(val: MuxControl) -> Self {
Box::new(val)
}
}
/// Multiplexer future which must be polled for the muxer to make progress.
#[derive(Debug)]
pub(crate) struct MuxFuture<T> {
conn: Connection<T>,
}
impl<T: AsyncRead + AsyncWrite + Unpin> MuxFuture<T> {
pub(crate) fn new(socket: T) -> Self {
let mut mux_config = tlsn_mux::Config::default();
mux_config.set_max_num_streams(36);
mux_config.set_keep_alive(true);
mux_config.set_close_sync(true);
let conn = tlsn_mux::Connection::new(socket, mux_config);
Self { conn }
}
pub(crate) fn handle(&self) -> Result<MuxControl, std::io::Error> {
let handle = self.conn.handle().map_err(std::io::Error::other)?;
Ok(MuxControl { handle })
}
pub(crate) fn close(&mut self) {
self.conn.close();
}
pub(crate) fn into_io(self) -> Result<T, std::io::Error> {
self.conn
.try_into_io()
.map_err(|_| std::io::Error::other("unable to return IO, connection is not closed"))
}
}
impl<T: AsyncRead + AsyncWrite + Unpin> FusedFuture for MuxFuture<T> {
fn is_terminated(&self) -> bool {
self.conn.is_complete()
}
}
impl<T: AsyncRead + AsyncWrite + Unpin> MuxFuture<T> {
/// Awaits a future, polling the muxer future concurrently.
pub(crate) async fn poll_with<F, R>(&mut self, fut: F) -> R
where
F: Future<Output = R>,
{
let mut fut = Box::pin(fut.fuse());
let mut mux = self;
// Poll the future concurrently with the muxer future.
// If the muxer returns an error, continue polling the future
// until it completes.
loop {
futures::select! {
res = fut => return res,
res = mux => if let Err(e) = res {
error!("mux error: {:?}", e);
},
}
}
}
}
impl<T: AsyncRead + AsyncWrite + Unpin> Future for MuxFuture<T> {
type Output = Result<(), tlsn_mux::ConnectionError>;
fn poll(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
self.conn.poll(cx)
}
}

View File

@@ -1,17 +1,19 @@
//! Prover.
mod error;
mod future;
mod prove;
pub mod state;
pub use error::ProverError;
pub use future::ProverFuture;
use mpz_common::Context;
pub use tlsn_core::ProverOutput;
use crate::{
Error, Result,
context::build_mt_context,
mpz::{ProverDeps, build_prover_deps, translate_keys},
msg::{ProveRequestMsg, Response, TlsCommitRequestMsg},
mux::MuxFuture,
tag::verify_tags,
};
@@ -42,7 +44,6 @@ use tracing::{Instrument, Span, debug, info, info_span, instrument};
pub struct Prover<T: state::ProverState = state::Initialized> {
config: ProverConfig,
span: Span,
ctx: Option<Context>,
state: T,
}
@@ -51,14 +52,12 @@ impl Prover<state::Initialized> {
///
/// # Arguments
///
/// * `ctx` - A thread context.
/// * `config` - The configuration for the prover.
pub(crate) fn new(ctx: Context, config: ProverConfig) -> Self {
pub fn new(config: ProverConfig) -> Self {
let span = info_span!("prover");
Self {
config,
span,
ctx: Some(ctx),
state: state::Initialized,
}
}
@@ -71,43 +70,36 @@ impl Prover<state::Initialized> {
/// # Arguments
///
/// * `config` - The TLS commitment configuration.
/// * `socket` - The socket to the TLS verifier.
#[instrument(parent = &self.span, level = "debug", skip_all, err)]
pub async fn commit(
mut self,
pub async fn commit<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
self,
config: TlsCommitConfig,
) -> Result<Prover<state::CommitAccepted>> {
let mut ctx = self
.ctx
.take()
.ok_or_else(|| Error::internal().with_msg("commitment protocol context was dropped"))?;
socket: S,
) -> Result<Prover<state::CommitAccepted<S>>, ProverError> {
let mut mux_fut = MuxFuture::new(socket);
let mux_ctrl = mux_fut.handle()?;
let mut mt = build_mt_context(mux_ctrl);
let mut ctx = mux_fut.poll_with(mt.new_context()).await?;
// Sends protocol configuration to verifier for compatibility check.
ctx.io_mut()
.send(TlsCommitRequestMsg {
request: config.to_request(),
version: crate::VERSION.clone(),
})
.await
.map_err(|e| {
Error::io()
.with_msg("commitment protocol failed to send request")
.with_source(e)
})?;
mux_fut
.poll_with(async {
ctx.io_mut()
.send(TlsCommitRequestMsg {
request: config.to_request(),
version: crate::VERSION.clone(),
})
.await?;
ctx.io_mut()
.expect_next::<Response>()
.await
.map_err(|e| {
Error::io()
.with_msg("commitment protocol failed to receive response")
.with_source(e)
})?
.result
.map_err(|e| {
Error::user()
.with_msg("commitment protocol rejected by verifier")
.with_source(e)
})?;
ctx.io_mut()
.expect_next::<Response>()
.await?
.result
.map_err(ProverError::from)
})
.await?;
let TlsCommitProtocolConfig::Mpc(mpc_tls_config) = config.protocol().clone() else {
unreachable!("only MPC TLS is supported");
@@ -116,35 +108,34 @@ impl Prover<state::Initialized> {
let ProverDeps { vm, mut mpc_tls } = build_prover_deps(mpc_tls_config, ctx);
// Allocate resources for MPC-TLS in the VM.
let mut keys = mpc_tls.alloc().map_err(|e| {
Error::internal()
.with_msg("commitment protocol failed to allocate mpc-tls resources")
.with_source(e)
})?;
let mut keys = mpc_tls.alloc()?;
let vm_lock = vm.try_lock().expect("VM is not locked");
translate_keys(&mut keys, &vm_lock);
drop(vm_lock);
debug!("setting up mpc-tls");
mpc_tls.preprocess().await.map_err(|e| {
Error::internal()
.with_msg("commitment protocol failed during mpc-tls preprocessing")
.with_source(e)
})?;
mux_fut.poll_with(mpc_tls.preprocess()).await?;
debug!("mpc-tls setup complete");
Ok(Prover {
config: self.config,
span: self.span,
ctx: None,
state: state::CommitAccepted { mpc_tls, keys, vm },
state: state::CommitAccepted {
mux_fut,
mpc_tls,
keys,
vm,
},
})
}
}
impl Prover<state::CommitAccepted> {
impl<Io> Prover<state::CommitAccepted<Io>>
where
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
{
/// Connects to the server using the provided socket.
///
/// Returns a handle to the TLS connection, a future which returns the
@@ -160,9 +151,13 @@ impl Prover<state::CommitAccepted> {
self,
config: TlsClientConfig,
socket: S,
) -> Result<(TlsConnection, ProverFuture)> {
) -> Result<(TlsConnection, ProverFuture<Io>), ProverError> {
let state::CommitAccepted {
mpc_tls, keys, vm, ..
mut mux_fut,
mpc_tls,
keys,
vm,
..
} = self.state;
let (mpc_ctrl, mpc_fut) = mpc_tls.run();
@@ -180,11 +175,7 @@ impl Prover<state::CommitAccepted> {
let der = CertificateDer::from_slice(&cert.0);
anchor_from_trusted_cert(&der)
.map(|anchor| anchor.to_owned())
.map_err(|e| {
Error::config()
.with_msg("failed to parse root certificate")
.with_source(e)
})
.map_err(ProverError::config)
})
.collect::<Result<Vec<_>, _>>()?,
};
@@ -201,11 +192,7 @@ impl Prover<state::CommitAccepted> {
.collect(),
tls_client::PrivateKey(key.0.clone()),
)
.map_err(|e| {
Error::config()
.with_msg("failed to configure client authentication")
.with_source(e)
})?
.map_err(ProverError::config)?
} else {
rustls_config.with_no_client_auth()
};
@@ -215,11 +202,7 @@ impl Prover<state::CommitAccepted> {
Box::new(mpc_ctrl.clone()),
server_name,
)
.map_err(|e| {
Error::config()
.with_msg("failed to create tls client connection")
.with_source(e)
})?;
.map_err(ProverError::config)?;
let (conn, conn_fut) = bind_client(socket, client);
@@ -228,27 +211,20 @@ impl Prover<state::CommitAccepted> {
let mpc_ctrl = mpc_ctrl.clone();
async move {
let conn_fut = async {
conn_fut.await.map_err(|e| {
Error::io().with_msg("tls connection failed").with_source(e)
})?;
mpc_ctrl.stop().await.map_err(|e| {
Error::internal()
.with_msg("mpc-tls failed to stop")
.with_source(e)
})?;
mux_fut
.poll_with(conn_fut.map_err(ProverError::from))
.await?;
Ok::<_, crate::Error>(())
mpc_ctrl.stop().await?;
Ok::<_, ProverError>(())
};
info!("starting MPC-TLS");
let (_, (mut ctx, tls_transcript)) = futures::try_join!(
conn_fut,
mpc_fut.in_current_span().map_err(|e| {
Error::internal()
.with_msg("mpc-tls execution failed")
.with_source(e)
})
mpc_fut.in_current_span().map_err(ProverError::from)
)?;
info!("finished MPC-TLS");
@@ -259,11 +235,10 @@ impl Prover<state::CommitAccepted> {
debug!("finalizing mpc");
// Finalize DEAP.
vm.finalize(&mut ctx).await.map_err(|e| {
Error::internal()
.with_msg("mpc finalization failed")
.with_source(e)
})?;
mux_fut
.poll_with(vm.finalize(&mut ctx))
.await
.map_err(ProverError::mpc)?;
debug!("mpc finalized");
}
@@ -283,17 +258,11 @@ impl Prover<state::CommitAccepted> {
*tls_transcript.version(),
tls_transcript.recv().to_vec(),
)
.map_err(|e| {
Error::internal()
.with_msg("tag verification setup failed")
.with_source(e)
})?;
.map_err(ProverError::zk)?;
vm.execute_all(&mut ctx).await.map_err(|e| {
Error::internal()
.with_msg("executing the zkVM failed during tag verification")
.with_source(e)
})?;
mux_fut
.poll_with(vm.execute_all(&mut ctx).map_err(ProverError::zk))
.await?;
let transcript = tls_transcript
.to_transcript()
@@ -302,8 +271,9 @@ impl Prover<state::CommitAccepted> {
Ok(Prover {
config: self.config,
span: self.span,
ctx: Some(ctx),
state: state::Committed {
mux_fut,
ctx,
vm,
server_name: config.server_name().clone(),
keys,
@@ -325,7 +295,10 @@ impl Prover<state::CommitAccepted> {
}
}
impl Prover<state::Committed> {
impl<Io> Prover<state::Committed<Io>>
where
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
{
/// Returns the TLS transcript.
pub fn tls_transcript(&self) -> &TlsTranscript {
&self.state.tls_transcript
@@ -342,12 +315,10 @@ impl Prover<state::Committed> {
///
/// * `config` - The disclosure configuration.
#[instrument(parent = &self.span, level = "info", skip_all, err)]
pub async fn prove(&mut self, config: &ProveConfig) -> Result<ProverOutput> {
let ctx = self
.ctx
.as_mut()
.ok_or_else(|| Error::internal().with_msg("proving context was dropped"))?;
pub async fn prove(&mut self, config: &ProveConfig) -> Result<ProverOutput, ProverError> {
let state::Committed {
mux_fut,
ctx,
vm,
keys,
server_name,
@@ -383,35 +354,27 @@ impl Prover<state::Committed> {
transcript: partial_transcript,
};
ctx.io_mut().send(msg).await.map_err(|e| {
Error::io()
.with_msg("failed to send prove configuration")
.with_source(e)
})?;
ctx.io_mut()
.expect_next::<Response>()
.await
.map_err(|e| {
Error::io()
.with_msg("failed to receive prove response from verifier")
.with_source(e)
})?
.result
.map_err(|e| {
Error::user()
.with_msg("proving rejected by verifier")
.with_source(e)
})?;
let output = mux_fut
.poll_with(async {
ctx.io_mut().send(msg).await.map_err(ProverError::from)?;
let output = prove::prove(ctx, vm, keys, transcript, tls_transcript, config).await?;
ctx.io_mut().expect_next::<Response>().await?.result?;
prove::prove(ctx, vm, keys, transcript, tls_transcript, config).await
})
.await?;
Ok(output)
}
/// Closes the connection with the verifier.
#[instrument(parent = &self.span, level = "info", skip_all, err)]
pub async fn close(self) -> Result<()> {
Ok(())
pub async fn close(mut self) -> Result<Io, ProverError> {
let mux_fut = &mut self.state.mux_fut;
mux_fut.close();
mux_fut.await?;
self.state.mux_fut.into_io().map_err(ProverError::from)
}
}
@@ -433,11 +396,10 @@ impl ProverControl {
/// * The prover may need to close the connection to the server in order for
/// it to close the connection on its end. If neither the prover or server
/// close the connection this will cause a deadlock.
pub async fn defer_decryption(&self) -> Result<()> {
self.mpc_ctrl.defer_decryption().await.map_err(|e| {
Error::internal()
.with_msg("failed to defer decryption")
.with_source(e)
})
pub async fn defer_decryption(&self) -> Result<(), ProverError> {
self.mpc_ctrl
.defer_decryption()
.await
.map_err(ProverError::from)
}
}

View File

@@ -0,0 +1,109 @@
use std::{error::Error, fmt};
use mpc_tls::MpcTlsError;
/// Error for [`Prover`](crate::prover::Prover).
#[derive(Debug, thiserror::Error)]
pub struct ProverError {
kind: ErrorKind,
source: Option<Box<dyn Error + Send + Sync + 'static>>,
}
impl ProverError {
fn new<E>(kind: ErrorKind, source: E) -> Self
where
E: Into<Box<dyn Error + Send + Sync + 'static>>,
{
Self {
kind,
source: Some(source.into()),
}
}
pub(crate) fn config<E>(source: E) -> Self
where
E: Into<Box<dyn Error + Send + Sync + 'static>>,
{
Self::new(ErrorKind::Config, source)
}
pub(crate) fn mpc<E>(source: E) -> Self
where
E: Into<Box<dyn Error + Send + Sync + 'static>>,
{
Self::new(ErrorKind::Mpc, source)
}
pub(crate) fn zk<E>(source: E) -> Self
where
E: Into<Box<dyn Error + Send + Sync + 'static>>,
{
Self::new(ErrorKind::Zk, source)
}
pub(crate) fn commit<E>(source: E) -> Self
where
E: Into<Box<dyn Error + Send + Sync + 'static>>,
{
Self::new(ErrorKind::Commit, source)
}
}
#[derive(Debug)]
enum ErrorKind {
Io,
Mpc,
Zk,
Config,
Commit,
}
impl fmt::Display for ProverError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("prover error: ")?;
match self.kind {
ErrorKind::Io => f.write_str("io error")?,
ErrorKind::Mpc => f.write_str("mpc error")?,
ErrorKind::Zk => f.write_str("zk error")?,
ErrorKind::Config => f.write_str("config error")?,
ErrorKind::Commit => f.write_str("commit error")?,
}
if let Some(source) = &self.source {
write!(f, " caused by: {source}")?;
}
Ok(())
}
}
impl From<std::io::Error> for ProverError {
fn from(e: std::io::Error) -> Self {
Self::new(ErrorKind::Io, e)
}
}
impl From<tls_client_async::ConnectionError> for ProverError {
fn from(e: tls_client_async::ConnectionError) -> Self {
Self::new(ErrorKind::Io, e)
}
}
impl From<tlsn_mux::ConnectionError> for ProverError {
fn from(e: tlsn_mux::ConnectionError) -> Self {
Self::new(ErrorKind::Io, e)
}
}
impl From<mpz_common::ContextError> for ProverError {
fn from(e: mpz_common::ContextError) -> Self {
Self::new(ErrorKind::Mpc, e)
}
}
impl From<MpcTlsError> for ProverError {
fn from(e: MpcTlsError) -> Self {
Self::new(ErrorKind::Mpc, e)
}
}

View File

@@ -1,29 +1,29 @@
//! This module collects futures which are used by the [Prover].
use super::{Prover, ProverControl, ProverError, state};
use futures::Future;
use std::pin::Pin;
use futures::Future;
use super::{Prover, ProverControl, state};
use crate::Result;
/// Prover future which must be polled for the TLS connection to make progress.
pub struct ProverFuture {
pub struct ProverFuture<Io> {
#[allow(clippy::type_complexity)]
pub(crate) fut:
Pin<Box<dyn Future<Output = Result<Prover<state::Committed>>> + Send + 'static>>,
pub(crate) fut: Pin<
Box<
dyn Future<Output = Result<Prover<state::Committed<Io>>, ProverError>> + Send + 'static,
>,
>,
pub(crate) ctrl: ProverControl,
}
impl ProverFuture {
impl<Io> ProverFuture<Io> {
/// Returns a controller for the prover for advanced functionality.
pub fn control(&self) -> ProverControl {
self.ctrl.clone()
}
}
impl Future for ProverFuture {
type Output = Result<Prover<state::Committed>>;
impl<Io> Future for ProverFuture<Io> {
type Output = Result<Prover<state::Committed<Io>>, ProverError>;
fn poll(
mut self: Pin<&mut Self>,

View File

@@ -12,7 +12,7 @@ use tlsn_core::{
};
use crate::{
Error, Result,
prover::ProverError,
transcript_internal::{TranscriptRefs, auth::prove_plaintext, commit::hash::prove_hash},
};
@@ -23,7 +23,7 @@ pub(crate) async fn prove<T: Vm<Binary> + Send + Sync>(
transcript: &Transcript,
tls_transcript: &TlsTranscript,
config: &ProveConfig,
) -> Result<ProverOutput> {
) -> Result<ProverOutput, ProverError> {
let mut output = ProverOutput {
transcript_commitments: Vec::default(),
transcript_secrets: Vec::default(),
@@ -53,11 +53,7 @@ pub(crate) async fn prove<T: Vm<Binary> + Send + Sync>(
&reveal_sent,
&commit_sent,
)
.map_err(|e| {
Error::internal()
.with_msg("proving failed during sent plaintext commitment")
.with_source(e)
})?,
.map_err(ProverError::commit)?,
recv: prove_plaintext(
vm,
keys.server_write_key,
@@ -70,11 +66,7 @@ pub(crate) async fn prove<T: Vm<Binary> + Send + Sync>(
&reveal_recv,
&commit_recv,
)
.map_err(|e| {
Error::internal()
.with_msg("proving failed during received plaintext commitment")
.with_source(e)
})?,
.map_err(ProverError::commit)?,
};
let hash_commitments = if let Some(commit_config) = config.transcript_commit()
@@ -88,28 +80,16 @@ pub(crate) async fn prove<T: Vm<Binary> + Send + Sync>(
.iter_hash()
.map(|((dir, idx), alg)| (*dir, idx.clone(), *alg)),
)
.map_err(|e| {
Error::internal()
.with_msg("proving failed during hash commitment setup")
.with_source(e)
})?,
.map_err(ProverError::commit)?,
)
} else {
None
};
vm.execute_all(ctx).await.map_err(|e| {
Error::internal()
.with_msg("proving failed during zk execution")
.with_source(e)
})?;
vm.execute_all(ctx).await.map_err(ProverError::zk)?;
if let Some((hash_fut, hash_secrets)) = hash_commitments {
let hash_commitments = hash_fut.try_recv().map_err(|e| {
Error::internal()
.with_msg("proving failed during hash commitment finalization")
.with_source(e)
})?;
let hash_commitments = hash_fut.try_recv().map_err(ProverError::commit)?;
for (commitment, secret) in hash_commitments.into_iter().zip(hash_secrets) {
output
.transcript_commitments

View File

@@ -3,6 +3,7 @@
use std::sync::Arc;
use mpc_tls::{MpcTlsLeader, SessionKeys};
use mpz_common::Context;
use tlsn_core::{
connection::ServerName,
transcript::{TlsTranscript, Transcript},
@@ -10,7 +11,10 @@ use tlsn_core::{
use tlsn_deap::Deap;
use tokio::sync::Mutex;
use crate::mpz::{ProverMpc, ProverZk};
use crate::{
mpz::{ProverMpc, ProverZk},
mux::MuxFuture,
};
/// Entry state
pub struct Initialized;
@@ -19,16 +23,19 @@ opaque_debug::implement!(Initialized);
/// State after the verifier has accepted the proposed TLS commitment protocol
/// configuration and preprocessing has completed.
pub struct CommitAccepted {
pub struct CommitAccepted<Io> {
pub(crate) mux_fut: MuxFuture<Io>,
pub(crate) mpc_tls: MpcTlsLeader,
pub(crate) keys: SessionKeys,
pub(crate) vm: Arc<Mutex<Deap<ProverMpc, ProverZk>>>,
}
opaque_debug::implement!(CommitAccepted);
opaque_debug::implement!(CommitAccepted<Io>);
/// State after the TLS transcript has been committed.
pub struct Committed {
pub struct Committed<Io> {
pub(crate) mux_fut: MuxFuture<Io>,
pub(crate) ctx: Context,
pub(crate) vm: ProverZk,
pub(crate) server_name: ServerName,
pub(crate) keys: SessionKeys,
@@ -36,18 +43,18 @@ pub struct Committed {
pub(crate) transcript: Transcript,
}
opaque_debug::implement!(Committed);
opaque_debug::implement!(Committed<Io>);
#[allow(missing_docs)]
pub trait ProverState: sealed::Sealed {}
impl ProverState for Initialized {}
impl ProverState for CommitAccepted {}
impl ProverState for Committed {}
impl<Io> ProverState for CommitAccepted<Io> {}
impl<Io> ProverState for Committed<Io> {}
mod sealed {
pub trait Sealed {}
impl Sealed for super::Initialized {}
impl Sealed for super::CommitAccepted {}
impl Sealed for super::Committed {}
impl<Io> Sealed for super::CommitAccepted<Io> {}
impl<Io> Sealed for super::Committed<Io> {}
}

View File

@@ -1,326 +0,0 @@
use std::{
future::Future,
pin::Pin,
sync::{
Arc, Mutex,
atomic::{AtomicBool, Ordering},
},
task::{Context, Poll, Waker},
};
use futures::{AsyncRead, AsyncWrite};
use mpz_common::{ThreadId, context::Multithread, io::Io, mux::Mux};
use tlsn_core::config::{prover::ProverConfig, verifier::VerifierConfig};
use tlsn_mux::{Connection, Handle};
use crate::{
Error, Result,
prover::{Prover, state as prover_state},
verifier::{Verifier, state as verifier_state},
};
/// Maximum concurrency for multi-threaded context.
const MAX_CONCURRENCY: usize = 8;
/// A TLSNotary session over a communication channel.
///
/// Wraps an async IO stream and provides multiplexing for the protocol. Use
/// [`new_prover`](Self::new_prover) or [`new_verifier`](Self::new_verifier) to
/// create protocol participants.
///
/// The session must be polled continuously (either directly or via
/// [`split`](Self::split)) to drive the underlying connection. After the
/// session closes, the underlying IO can be reclaimed with
/// [`try_take`](Self::try_take).
///
/// **Important**: The order in which provers and verifiers are created must
/// match on both sides. For example, if the prover side calls `new_prover`
/// then `new_verifier`, the verifier side must call `new_verifier` then
/// `new_prover`.
#[must_use = "session must be polled continuously to make progress, including during closing."]
pub struct Session<Io> {
conn: Option<Connection<Io>>,
mt: Multithread,
}
impl<Io> Session<Io>
where
Io: AsyncRead + AsyncWrite + Unpin,
{
/// Creates a new session.
pub fn new(io: Io) -> Self {
let mut mux_config = tlsn_mux::Config::default();
mux_config.set_max_num_streams(36);
mux_config.set_keep_alive(true);
mux_config.set_close_sync(true);
let conn = tlsn_mux::Connection::new(io, mux_config);
let handle = conn.handle().expect("handle should be available");
let mt = build_mt_context(MuxHandle { handle });
Self {
conn: Some(conn),
mt,
}
}
/// Creates a new prover.
pub fn new_prover(
&mut self,
config: ProverConfig,
) -> Result<Prover<prover_state::Initialized>> {
let ctx = self.mt.new_context().map_err(|e| {
Error::internal()
.with_msg("failed to create new prover")
.with_source(e)
})?;
Ok(Prover::new(ctx, config))
}
/// Creates a new verifier.
pub fn new_verifier(
&mut self,
config: VerifierConfig,
) -> Result<Verifier<verifier_state::Initialized>> {
let ctx = self.mt.new_context().map_err(|e| {
Error::internal()
.with_msg("failed to create new verifier")
.with_source(e)
})?;
Ok(Verifier::new(ctx, config))
}
/// Returns `true` if the session is closed.
pub fn is_closed(&self) -> bool {
self.conn
.as_ref()
.map(|mux| mux.is_complete())
.unwrap_or_default()
}
/// Closes the session.
///
/// This will cause the session to begin closing. Session must continue to
/// be polled until completion.
pub fn close(&mut self) {
if let Some(conn) = self.conn.as_mut() {
conn.close()
}
}
/// Attempts to take the IO, returning an error if it is not available.
pub fn try_take(&mut self) -> Result<Io> {
let conn = self.conn.take().ok_or_else(|| {
Error::io().with_msg("failed to take the session io, it was already taken")
})?;
match conn.try_into_io() {
Err(conn) => {
self.conn = Some(conn);
Err(Error::io()
.with_msg("failed to take the session io, session was not completed yet"))
}
Ok(conn) => Ok(conn),
}
}
/// Polls the session.
pub fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Result<()>> {
self.conn
.as_mut()
.ok_or_else(|| {
Error::io()
.with_msg("failed to poll the session connection because it has been taken")
})?
.poll(cx)
.map_err(|e| {
Error::io()
.with_msg("error occurred while polling the session connection")
.with_source(e)
})
}
/// Splits the session into a driver and handle.
///
/// The driver must be polled to make progress. The handle is used
/// for creating provers/verifiers and closing the session.
pub fn split(self) -> (SessionDriver<Io>, SessionHandle) {
let should_close = Arc::new(AtomicBool::new(false));
let waker = Arc::new(Mutex::new(None::<Waker>));
(
SessionDriver {
conn: self.conn,
should_close: should_close.clone(),
waker: waker.clone(),
},
SessionHandle {
mt: self.mt,
should_close,
waker,
},
)
}
}
impl<Io> Future for Session<Io>
where
Io: AsyncRead + AsyncWrite + Unpin,
{
type Output = Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Session::poll(&mut (*self), cx)
}
}
/// The polling half of a split session.
///
/// Must be polled continuously to drive the session. Returns the underlying
/// IO when the session closes.
#[must_use = "driver must be polled to make progress"]
pub struct SessionDriver<Io> {
conn: Option<Connection<Io>>,
should_close: Arc<AtomicBool>,
waker: Arc<Mutex<Option<Waker>>>,
}
impl<Io> SessionDriver<Io>
where
Io: AsyncRead + AsyncWrite + Unpin,
{
/// Polls the driver.
pub fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Result<Io>> {
// Store the waker so the handle can wake us when close() is called.
{
let mut waker_guard = self.waker.lock().unwrap();
*waker_guard = Some(cx.waker().clone());
}
let conn = self
.conn
.as_mut()
.ok_or_else(|| Error::io().with_msg("session driver already completed"))?;
if self.should_close.load(Ordering::Acquire) {
conn.close();
}
match conn.poll(cx) {
Poll::Ready(Ok(())) => {}
Poll::Ready(Err(e)) => {
return Poll::Ready(Err(Error::io()
.with_msg("error polling session connection")
.with_source(e)));
}
Poll::Pending => return Poll::Pending,
}
let conn = self.conn.take().unwrap();
Poll::Ready(
conn.try_into_io()
.map_err(|_| Error::io().with_msg("failed to take session io")),
)
}
}
impl<Io> Future for SessionDriver<Io>
where
Io: AsyncRead + AsyncWrite + Unpin,
{
type Output = Result<Io>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
SessionDriver::poll(&mut *self, cx)
}
}
/// The control half of a split session.
///
/// Used to create provers/verifiers and control the session lifecycle.
pub struct SessionHandle {
mt: Multithread,
should_close: Arc<AtomicBool>,
waker: Arc<Mutex<Option<Waker>>>,
}
impl SessionHandle {
/// Creates a new prover.
pub fn new_prover(
&mut self,
config: ProverConfig,
) -> Result<Prover<prover_state::Initialized>> {
let ctx = self.mt.new_context().map_err(|e| {
Error::internal()
.with_msg("failed to create new prover")
.with_source(e)
})?;
Ok(Prover::new(ctx, config))
}
/// Creates a new verifier.
pub fn new_verifier(
&mut self,
config: VerifierConfig,
) -> Result<Verifier<verifier_state::Initialized>> {
let ctx = self.mt.new_context().map_err(|e| {
Error::internal()
.with_msg("failed to create new verifier")
.with_source(e)
})?;
Ok(Verifier::new(ctx, config))
}
/// Signals the session to close.
///
/// The driver must continue to be polled until it completes.
pub fn close(&self) {
self.should_close.store(true, Ordering::Release);
if let Some(waker) = self.waker.lock().unwrap().take() {
waker.wake();
}
}
}
/// Multiplexer controller providing streams.
struct MuxHandle {
handle: Handle,
}
impl std::fmt::Debug for MuxHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MuxHandle").finish_non_exhaustive()
}
}
impl Mux for MuxHandle {
fn open(&self, id: ThreadId) -> Result<Io, std::io::Error> {
let stream = self
.handle
.new_stream(id.as_ref())
.map_err(std::io::Error::other)?;
let io = Io::from_io(stream);
Ok(io)
}
}
/// Builds a multi-threaded context with the given muxer.
fn build_mt_context(mux: MuxHandle) -> Multithread {
let builder = Multithread::builder()
.mux(Box::new(mux) as Box<_>)
.concurrency(MAX_CONCURRENCY);
#[cfg(all(feature = "web", target_arch = "wasm32"))]
let builder = builder.spawn_handler(|f| {
let _ = web_spawn::spawn(f);
Ok(())
});
builder.build().unwrap()
}

View File

@@ -1,19 +1,22 @@
//! Verifier.
mod error;
pub mod state;
mod verify;
use std::sync::Arc;
use mpz_common::Context;
pub use error::VerifierError;
pub use tlsn_core::{VerifierOutput, webpki::ServerCertVerifier};
use crate::{
Error, Result,
context::build_mt_context,
mpz::{VerifierDeps, build_verifier_deps, translate_keys},
msg::{ProveRequestMsg, Response, TlsCommitRequestMsg},
mux::MuxFuture,
tag::verify_tags,
};
use futures::{AsyncRead, AsyncWrite, TryFutureExt};
use mpz_vm_core::prelude::*;
use serio::{SinkExt, stream::IoStreamExt};
use tlsn_core::{
@@ -41,18 +44,16 @@ pub struct SessionInfo {
pub struct Verifier<T: state::VerifierState = state::Initialized> {
config: VerifierConfig,
span: Span,
ctx: Option<Context>,
state: T,
}
impl Verifier<state::Initialized> {
/// Creates a new verifier.
pub(crate) fn new(ctx: Context, config: VerifierConfig) -> Self {
pub fn new(config: VerifierConfig) -> Self {
let span = info_span!("verifier");
Self {
config,
span,
ctx: Some(ctx),
state: state::Initialized,
}
}
@@ -61,48 +62,56 @@ impl Verifier<state::Initialized> {
///
/// This initiates the TLS commitment protocol, receiving the prover's
/// configuration and providing the opportunity to accept or reject it.
///
/// # Arguments
///
/// * `socket` - The socket to the prover.
#[instrument(parent = &self.span, level = "info", skip_all, err)]
pub async fn commit(mut self) -> Result<Verifier<state::CommitStart>> {
let mut ctx = self
.ctx
.take()
.ok_or_else(|| Error::internal().with_msg("commitment protocol context was dropped"))?;
pub async fn commit<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
self,
socket: S,
) -> Result<Verifier<state::CommitStart<S>>, VerifierError> {
let mut mux_fut = MuxFuture::new(socket);
let mux_ctrl = mux_fut.handle()?;
let mut mt = build_mt_context(mux_ctrl);
let mut ctx = mux_fut.poll_with(mt.new_context()).await?;
// Receives protocol configuration from prover to perform compatibility check.
let TlsCommitRequestMsg { request, version } =
ctx.io_mut().expect_next().await.map_err(|e| {
Error::io()
.with_msg("commitment protocol failed to receive request")
.with_source(e)
})?;
mux_fut.poll_with(ctx.io_mut().expect_next()).await?;
if version != *crate::VERSION {
let msg = format!(
"prover version does not match with verifier: {version} != {}",
*crate::VERSION
);
ctx.io_mut()
.send(Response::err(Some(msg.clone())))
.await
.map_err(|e| {
Error::io()
.with_msg("commitment protocol failed to send version mismatch response")
.with_source(e)
})?;
mux_fut
.poll_with(ctx.io_mut().send(Response::err(Some(msg.clone()))))
.await?;
return Err(Error::config().with_msg(msg));
mux_fut.close();
mux_fut.await?;
return Err(VerifierError::config(msg));
}
Ok(Verifier {
config: self.config,
span: self.span,
ctx: Some(ctx),
state: state::CommitStart { request },
state: state::CommitStart {
mux_fut,
ctx,
request,
},
})
}
}
impl Verifier<state::CommitStart> {
impl<Io> Verifier<state::CommitStart<Io>>
where
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
{
/// Returns the TLS commitment request.
pub fn request(&self) -> &TlsCommitRequest {
&self.state.request
@@ -110,18 +119,14 @@ impl Verifier<state::CommitStart> {
/// Accepts the proposed protocol configuration.
#[instrument(parent = &self.span, level = "info", skip_all, err)]
pub async fn accept(mut self) -> Result<Verifier<state::CommitAccepted>> {
let mut ctx = self
.ctx
.take()
.ok_or_else(|| Error::internal().with_msg("commitment protocol context was dropped"))?;
let state::CommitStart { request } = self.state;
pub async fn accept(self) -> Result<Verifier<state::CommitAccepted<Io>>, VerifierError> {
let state::CommitStart {
mut mux_fut,
mut ctx,
request,
} = self.state;
ctx.io_mut().send(Response::ok()).await.map_err(|e| {
Error::io()
.with_msg("commitment protocol failed to send acceptance")
.with_source(e)
})?;
mux_fut.poll_with(ctx.io_mut().send(Response::ok())).await?;
let TlsCommitProtocolConfig::Mpc(mpc_tls_config) = request.protocol().clone() else {
unreachable!("only MPC TLS is supported");
@@ -130,64 +135,66 @@ impl Verifier<state::CommitStart> {
let VerifierDeps { vm, mut mpc_tls } = build_verifier_deps(mpc_tls_config, ctx);
// Allocate resources for MPC-TLS in the VM.
let mut keys = mpc_tls.alloc().map_err(|e| {
Error::internal()
.with_msg("commitment protocol failed to allocate mpc-tls resources")
.with_source(e)
})?;
let mut keys = mpc_tls.alloc()?;
let vm_lock = vm.try_lock().expect("VM is not locked");
translate_keys(&mut keys, &vm_lock);
drop(vm_lock);
debug!("setting up mpc-tls");
mpc_tls.preprocess().await.map_err(|e| {
Error::internal()
.with_msg("commitment protocol failed during mpc-tls preprocessing")
.with_source(e)
})?;
mux_fut.poll_with(mpc_tls.preprocess()).await?;
debug!("mpc-tls setup complete");
Ok(Verifier {
config: self.config,
span: self.span,
ctx: None,
state: state::CommitAccepted { mpc_tls, keys, vm },
state: state::CommitAccepted {
mux_fut,
mpc_tls,
keys,
vm,
},
})
}
/// Rejects the proposed protocol configuration.
#[instrument(parent = &self.span, level = "info", skip_all, err)]
pub async fn reject(mut self, msg: Option<&str>) -> Result<()> {
let mut ctx = self
.ctx
.take()
.ok_or_else(|| Error::internal().with_msg("commitment protocol context was dropped"))?;
pub async fn reject(self, msg: Option<&str>) -> Result<(), VerifierError> {
let state::CommitStart {
mut mux_fut,
mut ctx,
..
} = self.state;
ctx.io_mut().send(Response::err(msg)).await.map_err(|e| {
Error::io()
.with_msg("commitment protocol failed to send rejection")
.with_source(e)
})?;
mux_fut
.poll_with(ctx.io_mut().send(Response::err(msg)))
.await?;
mux_fut.close();
mux_fut.await?;
Ok(())
}
}
impl Verifier<state::CommitAccepted> {
impl<Io> Verifier<state::CommitAccepted<Io>>
where
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
{
/// Runs the verifier until the TLS connection is closed.
#[instrument(parent = &self.span, level = "info", skip_all, err)]
pub async fn run(self) -> Result<Verifier<state::Committed>> {
let state::CommitAccepted { mpc_tls, vm, keys } = self.state;
pub async fn run(self) -> Result<Verifier<state::Committed<Io>>, VerifierError> {
let state::CommitAccepted {
mut mux_fut,
mpc_tls,
vm,
keys,
} = self.state;
info!("starting MPC-TLS");
let (mut ctx, tls_transcript) = mpc_tls.run().await.map_err(|e| {
Error::internal()
.with_msg("mpc-tls execution failed")
.with_source(e)
})?;
let (mut ctx, tls_transcript) = mux_fut.poll_with(mpc_tls.run()).await?;
info!("finished MPC-TLS");
@@ -196,11 +203,10 @@ impl Verifier<state::CommitAccepted> {
debug!("finalizing mpc");
vm.finalize(&mut ctx).await.map_err(|e| {
Error::internal()
.with_msg("mpc finalization failed")
.with_source(e)
})?;
mux_fut
.poll_with(vm.finalize(&mut ctx))
.await
.map_err(VerifierError::mpc)?;
debug!("mpc finalized");
}
@@ -220,32 +226,23 @@ impl Verifier<state::CommitAccepted> {
*tls_transcript.version(),
tls_transcript.recv().to_vec(),
)
.map_err(|e| {
Error::internal()
.with_msg("tag verification setup failed")
.with_source(e)
})?;
.map_err(VerifierError::zk)?;
vm.execute_all(&mut ctx).await.map_err(|e| {
Error::internal()
.with_msg("tag verification zk execution failed")
.with_source(e)
})?;
mux_fut
.poll_with(vm.execute_all(&mut ctx).map_err(VerifierError::zk))
.await?;
// Verify the tags.
// After the verification, the entire TLS trancript becomes
// authenticated from the verifier's perspective.
tag_proof.verify().map_err(|e| {
Error::internal()
.with_msg("tag verification failed")
.with_source(e)
})?;
tag_proof.verify().map_err(VerifierError::zk)?;
Ok(Verifier {
config: self.config,
span: self.span,
ctx: Some(ctx),
state: state::Committed {
mux_fut,
ctx,
vm,
keys,
tls_transcript,
@@ -254,7 +251,10 @@ impl Verifier<state::CommitAccepted> {
}
}
impl Verifier<state::Committed> {
impl<Io> Verifier<state::Committed<Io>>
where
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
{
/// Returns the TLS transcript.
pub fn tls_transcript(&self) -> &TlsTranscript {
&self.state.tls_transcript
@@ -262,12 +262,10 @@ impl Verifier<state::Committed> {
/// Begins verification of statements from the prover.
#[instrument(parent = &self.span, level = "info", skip_all, err)]
pub async fn verify(mut self) -> Result<Verifier<state::Verify>> {
let mut ctx = self
.ctx
.take()
.ok_or_else(|| Error::internal().with_msg("verification context was dropped"))?;
pub async fn verify(self) -> Result<Verifier<state::Verify<Io>>, VerifierError> {
let state::Committed {
mut mux_fut,
mut ctx,
vm,
keys,
tls_transcript,
@@ -277,17 +275,16 @@ impl Verifier<state::Committed> {
request,
handshake,
transcript,
} = ctx.io_mut().expect_next().await.map_err(|e| {
Error::io()
.with_msg("verification failed to receive prove request")
.with_source(e)
})?;
} = mux_fut
.poll_with(ctx.io_mut().expect_next().map_err(VerifierError::from))
.await?;
Ok(Verifier {
config: self.config,
span: self.span,
ctx: Some(ctx),
state: state::Verify {
mux_fut,
ctx,
vm,
keys,
tls_transcript,
@@ -300,24 +297,31 @@ impl Verifier<state::Committed> {
/// Closes the connection with the prover.
#[instrument(parent = &self.span, level = "info", skip_all, err)]
pub async fn close(self) -> Result<()> {
Ok(())
pub async fn close(mut self) -> Result<Io, VerifierError> {
let mux_fut = &mut self.state.mux_fut;
mux_fut.close();
mux_fut.await?;
self.state.mux_fut.into_io().map_err(VerifierError::from)
}
}
impl Verifier<state::Verify> {
impl<Io> Verifier<state::Verify<Io>>
where
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
{
/// Returns the proving request.
pub fn request(&self) -> &ProveRequest {
&self.state.request
}
/// Accepts the proving request.
pub async fn accept(mut self) -> Result<(VerifierOutput, Verifier<state::Committed>)> {
let mut ctx = self
.ctx
.take()
.ok_or_else(|| Error::internal().with_msg("verification context was dropped"))?;
pub async fn accept(
self,
) -> Result<(VerifierOutput, Verifier<state::Committed<Io>>), VerifierError> {
let state::Verify {
mut mux_fut,
mut ctx,
mut vm,
keys,
tls_transcript,
@@ -326,37 +330,32 @@ impl Verifier<state::Verify> {
transcript,
} = self.state;
ctx.io_mut().send(Response::ok()).await.map_err(|e| {
Error::io()
.with_msg("verification failed to send acceptance")
.with_source(e)
})?;
mux_fut.poll_with(ctx.io_mut().send(Response::ok())).await?;
let cert_verifier = ServerCertVerifier::new(self.config.root_store()).map_err(|e| {
Error::config()
.with_msg("failed to create certificate verifier")
.with_source(e)
})?;
let cert_verifier =
ServerCertVerifier::new(self.config.root_store()).map_err(VerifierError::config)?;
let output = verify::verify(
&mut ctx,
&mut vm,
&keys,
&cert_verifier,
&tls_transcript,
request,
handshake,
transcript,
)
.await?;
let output = mux_fut
.poll_with(verify::verify(
&mut ctx,
&mut vm,
&keys,
&cert_verifier,
&tls_transcript,
request,
handshake,
transcript,
))
.await?;
Ok((
output,
Verifier {
config: self.config,
span: self.span,
ctx: Some(ctx),
state: state::Committed {
mux_fut,
ctx,
vm,
keys,
tls_transcript,
@@ -366,29 +365,29 @@ impl Verifier<state::Verify> {
}
/// Rejects the proving request.
pub async fn reject(mut self, msg: Option<&str>) -> Result<Verifier<state::Committed>> {
let mut ctx = self
.ctx
.take()
.ok_or_else(|| Error::internal().with_msg("verification context was dropped"))?;
pub async fn reject(
self,
msg: Option<&str>,
) -> Result<Verifier<state::Committed<Io>>, VerifierError> {
let state::Verify {
mut mux_fut,
mut ctx,
vm,
keys,
tls_transcript,
..
} = self.state;
ctx.io_mut().send(Response::err(msg)).await.map_err(|e| {
Error::io()
.with_msg("verification failed to send rejection")
.with_source(e)
})?;
mux_fut
.poll_with(ctx.io_mut().send(Response::err(msg)))
.await?;
Ok(Verifier {
config: self.config,
span: self.span,
ctx: Some(ctx),
state: state::Committed {
mux_fut,
ctx,
vm,
keys,
tls_transcript,

View File

@@ -0,0 +1,103 @@
use std::{error::Error, fmt};
use mpc_tls::MpcTlsError;
/// Error for [`Verifier`](crate::verifier::Verifier).
#[derive(Debug, thiserror::Error)]
pub struct VerifierError {
kind: ErrorKind,
source: Option<Box<dyn Error + Send + Sync + 'static>>,
}
impl VerifierError {
fn new<E>(kind: ErrorKind, source: E) -> Self
where
E: Into<Box<dyn Error + Send + Sync + 'static>>,
{
Self {
kind,
source: Some(source.into()),
}
}
pub(crate) fn config<E>(source: E) -> Self
where
E: Into<Box<dyn Error + Send + Sync + 'static>>,
{
Self::new(ErrorKind::Config, source)
}
pub(crate) fn mpc<E>(source: E) -> Self
where
E: Into<Box<dyn Error + Send + Sync + 'static>>,
{
Self::new(ErrorKind::Mpc, source)
}
pub(crate) fn zk<E>(source: E) -> Self
where
E: Into<Box<dyn Error + Send + Sync + 'static>>,
{
Self::new(ErrorKind::Zk, source)
}
pub(crate) fn verify<E>(source: E) -> Self
where
E: Into<Box<dyn Error + Send + Sync + 'static>>,
{
Self::new(ErrorKind::Verify, source)
}
}
#[derive(Debug)]
enum ErrorKind {
Io,
Config,
Mpc,
Zk,
Verify,
}
impl fmt::Display for VerifierError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("verifier error: ")?;
match self.kind {
ErrorKind::Io => f.write_str("io error")?,
ErrorKind::Config => f.write_str("config error")?,
ErrorKind::Mpc => f.write_str("mpc error")?,
ErrorKind::Zk => f.write_str("zk error")?,
ErrorKind::Verify => f.write_str("verification error")?,
}
if let Some(source) = &self.source {
write!(f, " caused by: {source}")?;
}
Ok(())
}
}
impl From<std::io::Error> for VerifierError {
fn from(e: std::io::Error) -> Self {
Self::new(ErrorKind::Io, e)
}
}
impl From<tlsn_mux::ConnectionError> for VerifierError {
fn from(e: tlsn_mux::ConnectionError) -> Self {
Self::new(ErrorKind::Io, e)
}
}
impl From<mpz_common::ContextError> for VerifierError {
fn from(e: mpz_common::ContextError) -> Self {
Self::new(ErrorKind::Mpc, e)
}
}
impl From<MpcTlsError> for VerifierError {
fn from(e: MpcTlsError) -> Self {
Self::new(ErrorKind::Mpc, e)
}
}

View File

@@ -2,7 +2,9 @@
use std::sync::Arc;
use crate::mux::MuxFuture;
use mpc_tls::{MpcTlsFollower, SessionKeys};
use mpz_common::Context;
use tlsn_core::{
config::{prove::ProveRequest, tls_commit::TlsCommitRequest},
connection::{HandshakeData, ServerName},
@@ -22,33 +24,40 @@ pub struct Initialized;
opaque_debug::implement!(Initialized);
/// State after receiving protocol configuration from the prover.
pub struct CommitStart {
pub struct CommitStart<Io> {
pub(crate) mux_fut: MuxFuture<Io>,
pub(crate) ctx: Context,
pub(crate) request: TlsCommitRequest,
}
opaque_debug::implement!(CommitStart);
opaque_debug::implement!(CommitStart<Io>);
/// State after accepting the proposed TLS commitment protocol configuration and
/// performing preprocessing.
pub struct CommitAccepted {
pub struct CommitAccepted<Io> {
pub(crate) mux_fut: MuxFuture<Io>,
pub(crate) mpc_tls: MpcTlsFollower,
pub(crate) keys: SessionKeys,
pub(crate) vm: Arc<Mutex<Deap<VerifierMpc, VerifierZk>>>,
}
opaque_debug::implement!(CommitAccepted);
opaque_debug::implement!(CommitAccepted<Io>);
/// State after the TLS transcript has been committed.
pub struct Committed {
pub struct Committed<Io> {
pub(crate) mux_fut: MuxFuture<Io>,
pub(crate) ctx: Context,
pub(crate) vm: VerifierZk,
pub(crate) keys: SessionKeys,
pub(crate) tls_transcript: TlsTranscript,
}
opaque_debug::implement!(Committed);
opaque_debug::implement!(Committed<Io>);
/// State after receiving a proving request.
pub struct Verify {
pub struct Verify<Io> {
pub(crate) mux_fut: MuxFuture<Io>,
pub(crate) ctx: Context,
pub(crate) vm: VerifierZk,
pub(crate) keys: SessionKeys,
pub(crate) tls_transcript: TlsTranscript,
@@ -57,19 +66,19 @@ pub struct Verify {
pub(crate) transcript: Option<PartialTranscript>,
}
opaque_debug::implement!(Verify);
opaque_debug::implement!(Verify<Io>);
impl VerifierState for Initialized {}
impl VerifierState for CommitStart {}
impl VerifierState for CommitAccepted {}
impl VerifierState for Committed {}
impl VerifierState for Verify {}
impl<Io> VerifierState for CommitStart<Io> {}
impl<Io> VerifierState for CommitAccepted<Io> {}
impl<Io> VerifierState for Committed<Io> {}
impl<Io> VerifierState for Verify<Io> {}
mod sealed {
pub trait Sealed {}
impl Sealed for super::Initialized {}
impl Sealed for super::CommitStart {}
impl Sealed for super::CommitAccepted {}
impl Sealed for super::Committed {}
impl Sealed for super::Verify {}
impl<Io> Sealed for super::CommitStart<Io> {}
impl<Io> Sealed for super::CommitAccepted<Io> {}
impl<Io> Sealed for super::Committed<Io> {}
impl<Io> Sealed for super::Verify<Io> {}
}

View File

@@ -14,8 +14,8 @@ use tlsn_core::{
};
use crate::{
Error, Result,
transcript_internal::{TranscriptRefs, auth::verify_plaintext, commit::hash::verify_hash},
verifier::VerifierError,
};
#[allow(clippy::too_many_arguments)]
@@ -28,33 +28,35 @@ pub(crate) async fn verify<T: Vm<Binary> + Send + Sync>(
request: ProveRequest,
handshake: Option<(ServerName, HandshakeData)>,
transcript: Option<PartialTranscript>,
) -> Result<VerifierOutput> {
) -> Result<VerifierOutput, VerifierError> {
let ciphertext_sent = collect_ciphertext(tls_transcript.sent());
let ciphertext_recv = collect_ciphertext(tls_transcript.recv());
let transcript = if let Some((auth_sent, auth_recv)) = request.reveal() {
let Some(transcript) = transcript else {
return Err(Error::internal().with_msg(
"verification failed: prover requested to reveal data but did not send transcript",
return Err(VerifierError::verify(
"prover requested to reveal data but did not send transcript",
));
};
if transcript.len_sent() != ciphertext_sent.len()
|| transcript.len_received() != ciphertext_recv.len()
{
return Err(
Error::internal().with_msg("verification failed: transcript length mismatch")
);
return Err(VerifierError::verify(
"prover sent transcript with incorrect length",
));
}
if transcript.sent_authed() != auth_sent {
return Err(Error::internal().with_msg("verification failed: sent auth data mismatch"));
return Err(VerifierError::verify(
"prover sent transcript with incorrect sent authed data",
));
}
if transcript.received_authed() != auth_recv {
return Err(
Error::internal().with_msg("verification failed: received auth data mismatch")
);
return Err(VerifierError::verify(
"prover sent transcript with incorrect received authed data",
));
}
transcript
@@ -70,11 +72,7 @@ pub(crate) async fn verify<T: Vm<Binary> + Send + Sync>(
tls_transcript.server_ephemeral_key(),
&name,
)
.map_err(|e| {
Error::internal()
.with_msg("verification failed: certificate verification failed")
.with_source(e)
})?;
.map_err(VerifierError::verify)?;
Some(name)
} else {
@@ -104,11 +102,7 @@ pub(crate) async fn verify<T: Vm<Binary> + Send + Sync>(
transcript.sent_authed(),
&commit_sent,
)
.map_err(|e| {
Error::internal()
.with_msg("verification failed during sent plaintext verification")
.with_source(e)
})?;
.map_err(VerifierError::zk)?;
let (recv_refs, recv_proof) = verify_plaintext(
vm,
keys.server_write_key,
@@ -122,11 +116,7 @@ pub(crate) async fn verify<T: Vm<Binary> + Send + Sync>(
transcript.received_authed(),
&commit_recv,
)
.map_err(|e| {
Error::internal()
.with_msg("verification failed during received plaintext verification")
.with_source(e)
})?;
.map_err(VerifierError::zk)?;
let transcript_refs = TranscriptRefs {
sent: sent_refs,
@@ -139,37 +129,18 @@ pub(crate) async fn verify<T: Vm<Binary> + Send + Sync>(
&& commit_config.has_hash()
{
hash_commitments = Some(
verify_hash(vm, &transcript_refs, commit_config.iter_hash().cloned()).map_err(|e| {
Error::internal()
.with_msg("verification failed during hash commitment setup")
.with_source(e)
})?,
verify_hash(vm, &transcript_refs, commit_config.iter_hash().cloned())
.map_err(VerifierError::verify)?,
);
}
vm.execute_all(ctx).await.map_err(|e| {
Error::internal()
.with_msg("verification failed during zk execution")
.with_source(e)
})?;
vm.execute_all(ctx).await.map_err(VerifierError::zk)?;
sent_proof.verify().map_err(|e| {
Error::internal()
.with_msg("verification failed: sent plaintext proof invalid")
.with_source(e)
})?;
recv_proof.verify().map_err(|e| {
Error::internal()
.with_msg("verification failed: received plaintext proof invalid")
.with_source(e)
})?;
sent_proof.verify().map_err(VerifierError::verify)?;
recv_proof.verify().map_err(VerifierError::verify)?;
if let Some(hash_commitments) = hash_commitments {
for commitment in hash_commitments.try_recv().map_err(|e| {
Error::internal()
.with_msg("verification failed during hash commitment finalization")
.with_source(e)
})? {
for commitment in hash_commitments.try_recv().map_err(VerifierError::verify)? {
transcript_commitments.push(TranscriptCommitment::Hash(commitment));
}
}

View File

@@ -1,6 +1,5 @@
use futures::{AsyncReadExt, AsyncWriteExt};
use tlsn::{
Session,
config::{
prove::ProveConfig,
prover::ProverConfig,
@@ -19,7 +18,9 @@ use tlsn_core::ProverOutput;
use tlsn_server_fixture::bind;
use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_util::compat::TokioAsyncReadCompatExt;
use tracing::instrument;
// Maximum number of bytes that can be sent from prover to server
const MAX_SENT_DATA: usize = 1 << 12;
@@ -36,34 +37,9 @@ async fn test() {
tracing_subscriber::fmt::init();
let (socket_0, socket_1) = tokio::io::duplex(2 << 23);
let mut session_p = Session::new(socket_0.compat());
let mut session_v = Session::new(socket_1.compat());
let prover = session_p
.new_prover(ProverConfig::builder().build().unwrap())
.unwrap();
let verifier = session_v
.new_verifier(
VerifierConfig::builder()
.root_store(RootCertStore {
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
})
.build()
.unwrap(),
)
.unwrap();
let (session_p_driver, session_p_handle) = session_p.split();
let (session_v_driver, session_v_handle) = session_v.split();
tokio::spawn(session_p_driver);
tokio::spawn(session_v_driver);
let ((_full_transcript, _prover_output), verifier_output) =
tokio::join!(run_prover(prover), run_verifier(verifier));
session_p_handle.close();
session_v_handle.close();
tokio::join!(prover(socket_0), verifier(socket_1));
let partial_transcript = verifier_output.transcript.unwrap();
let ServerName::Dns(server_name) = verifier_output.server_name.unwrap();
@@ -80,12 +56,15 @@ async fn test() {
);
}
async fn run_prover(prover: Prover) -> (Transcript, ProverOutput) {
#[instrument(skip(verifier_socket))]
async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
verifier_socket: T,
) -> (Transcript, ProverOutput) {
let (client_socket, server_socket) = tokio::io::duplex(2 << 16);
let server_task = tokio::spawn(bind(server_socket.compat()));
let prover = prover
let prover = Prover::new(ProverConfig::builder().build().unwrap())
.commit(
TlsCommitConfig::builder()
.protocol(
@@ -99,6 +78,7 @@ async fn run_prover(prover: Prover) -> (Transcript, ProverOutput) {
)
.build()
.unwrap(),
verifier_socket.compat(),
)
.await
.unwrap();
@@ -170,9 +150,21 @@ async fn run_prover(prover: Prover) -> (Transcript, ProverOutput) {
(transcript, output)
}
async fn run_verifier(verifier: Verifier) -> VerifierOutput {
#[instrument(skip(socket))]
async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
socket: T,
) -> VerifierOutput {
let verifier = Verifier::new(
VerifierConfig::builder()
.root_store(RootCertStore {
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
})
.build()
.unwrap(),
);
let verifier = verifier
.commit()
.commit(socket.compat())
.await
.unwrap()
.accept()

View File

@@ -1,6 +1,6 @@
[package]
name = "tlsn-wasm"
version = "0.1.0-alpha.14"
version = "0.1.0-alpha.14-pre"
edition = "2021"
repository = "https://github.com/tlsnotary/tlsn.git"
description = "A core WebAssembly package for TLSNotary."
@@ -26,7 +26,6 @@ tlsn-server-fixture-certs = { workspace = true }
tlsn-tls-client-async = { workspace = true }
tlsn-tls-core = { workspace = true }
async_io_stream = { workspace = true }
bincode = { workspace = true }
console_error_panic_hook = { version = "0.1" }
enum-try-as-inner = { workspace = true }

View File

@@ -16,7 +16,6 @@ use tlsn::{
connection::ServerName,
prover::{state, Prover},
webpki::{CertificateDer, PrivateKeyDer, RootCertStore},
Session, SessionHandle,
};
use tracing::info;
use wasm_bindgen::{prelude::*, JsError};
@@ -33,34 +32,16 @@ pub struct JsProver {
state: State,
}
#[derive(EnumTryAsInner)]
#[derive(Debug, EnumTryAsInner)]
#[derive_err(Debug)]
enum State {
Initialized,
CommitAccepted {
prover: Prover<state::CommitAccepted>,
handle: SessionHandle,
},
Committed {
prover: Prover<state::Committed>,
handle: SessionHandle,
},
Initialized(Prover<state::Initialized>),
CommitAccepted(Prover<state::CommitAccepted>),
Committed(Prover<state::Committed>),
Complete,
Error,
}
impl std::fmt::Debug for State {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
State::Initialized => write!(f, "Initialized"),
State::CommitAccepted { .. } => write!(f, "CommitAccepted"),
State::Committed { .. } => write!(f, "Committed"),
State::Complete => write!(f, "Complete"),
State::Error => write!(f, "Error"),
}
}
}
impl State {
fn take(&mut self) -> Self {
std::mem::replace(self, State::Error)
@@ -73,7 +54,9 @@ impl JsProver {
pub fn new(config: ProverConfig) -> Result<JsProver> {
Ok(JsProver {
config,
state: State::Initialized,
state: State::Initialized(Prover::new(
tlsn::config::prover::ProverConfig::builder().build()?,
)),
})
}
@@ -82,11 +65,9 @@ impl JsProver {
/// This performs all MPC setup prior to establishing the connection to the
/// application server.
pub async fn setup(&mut self, verifier_url: &str) -> Result<()> {
let State::Initialized = self.state.take() else {
return Err(JsError::new("prover is not in initialized state"));
};
let prover = self.state.take().try_into_initialized()?;
let tls_commit_config = TlsCommitConfig::builder()
let config = TlsCommitConfig::builder()
.protocol({
let mut builder = MpcTlsConfig::builder()
.max_sent_data(self.config.max_sent_data)
@@ -118,23 +99,9 @@ impl JsProver {
info!("connected to verifier");
let session = Session::new(verifier_conn.into_io());
let (driver, mut handle) = session.split();
spawn_local(async move {
if let Err(e) = driver.await {
tracing::error!("session driver error: {e}");
}
});
let prover = prover.commit(config, verifier_conn.into_io()).await?;
let prover_config = tlsn::config::prover::ProverConfig::builder().build()?;
let prover = handle.new_prover(prover_config)?;
let prover = prover
.commit(tls_commit_config)
.await
.map_err(|e| JsError::new(&e.to_string()))?;
self.state = State::CommitAccepted { prover, handle };
self.state = State::CommitAccepted(prover);
Ok(())
}
@@ -145,9 +112,7 @@ impl JsProver {
ws_proxy_url: &str,
request: HttpRequest,
) -> Result<HttpResponse> {
let State::CommitAccepted { prover, handle } = self.state.take() else {
return Err(JsError::new("prover is not in commit accepted state"));
};
let prover = self.state.take().try_into_commit_accepted()?;
let mut builder = TlsClientConfig::builder()
.server_name(ServerName::Dns(
@@ -175,7 +140,7 @@ impl JsProver {
builder = builder.client_auth((certs, key));
}
let tls_config = builder.build()?;
let config = builder.build()?;
info!("connecting to server");
@@ -183,39 +148,32 @@ impl JsProver {
info!("connected to server");
let (tls_conn, prover_fut) = prover
.connect(tls_config, server_conn.into_io())
.await
.map_err(|e| JsError::new(&e.to_string()))?;
let (tls_conn, prover_fut) = prover.connect(config, server_conn.into_io()).await?;
info!("sending request");
let (response, prover) = futures::try_join!(
send_request(tls_conn, request),
prover_fut.map_err(|e| JsError::new(&e.to_string()))
prover_fut.map_err(Into::into)
)?;
info!("response received");
self.state = State::Committed { prover, handle };
self.state = State::Committed(prover);
Ok(response)
}
/// Returns the transcript.
pub fn transcript(&self) -> Result<Transcript> {
let State::Committed { prover, .. } = &self.state else {
return Err(JsError::new("prover is not in committed state"));
};
let prover = self.state.try_as_committed()?;
Ok(Transcript::from(prover.transcript()))
}
/// Reveals data to the verifier and finalizes the protocol.
pub async fn reveal(&mut self, reveal: Reveal) -> Result<()> {
let State::Committed { mut prover, handle } = self.state.take() else {
return Err(JsError::new("prover is not in committed state"));
};
let mut prover = self.state.take().try_into_committed()?;
info!("revealing data");
@@ -235,16 +193,8 @@ impl JsProver {
let config = builder.build()?;
prover
.prove(&config)
.await
.map_err(|e| JsError::new(&e.to_string()))?;
prover
.close()
.await
.map_err(|e| JsError::new(&e.to_string()))?;
handle.close();
prover.prove(&config).await?;
prover.close().await?;
info!("Finalized");

View File

@@ -9,12 +9,10 @@ use tlsn::{
transcript::ContentType,
verifier::{state, Verifier},
webpki::RootCertStore,
Session, SessionHandle,
};
use tracing::info;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use ws_stream_wasm::WsMeta;
use ws_stream_wasm::{WsMeta, WsStream};
use crate::types::VerifierOutput;
@@ -29,23 +27,15 @@ pub struct JsVerifier {
#[derive(EnumTryAsInner)]
#[derive_err(Debug)]
enum State {
Initialized,
Connected {
verifier: Verifier<state::Initialized>,
handle: SessionHandle,
},
Initialized(Verifier<state::Initialized>),
Connected((Verifier<state::Initialized>, WsStream)),
Complete,
Error,
}
impl std::fmt::Debug for State {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
State::Initialized => write!(f, "Initialized"),
State::Connected { .. } => write!(f, "Connected"),
State::Complete => write!(f, "Complete"),
State::Error => write!(f, "Error"),
}
write!(f, "State")
}
}
@@ -59,17 +49,19 @@ impl State {
impl JsVerifier {
#[wasm_bindgen(constructor)]
pub fn new(config: VerifierConfig) -> JsVerifier {
let tlsn_config = tlsn::config::verifier::VerifierConfig::builder()
.root_store(RootCertStore::mozilla())
.build()
.unwrap();
JsVerifier {
state: State::Initialized,
state: State::Initialized(Verifier::new(tlsn_config)),
config,
}
}
/// Connect to the prover.
pub async fn connect(&mut self, prover_url: &str) -> Result<()> {
let State::Initialized = self.state.take() else {
return Err(JsError::new("verifier is not in initialized state"));
};
let verifier = self.state.take().try_into_initialized()?;
info!("Connecting to prover");
@@ -77,75 +69,40 @@ impl JsVerifier {
info!("Connected to prover");
let session = Session::new(prover_conn.into_io());
let (driver, mut handle) = session.split();
spawn_local(async move {
if let Err(e) = driver.await {
tracing::error!("session driver error: {e}");
}
});
let verifier_config = tlsn::config::verifier::VerifierConfig::builder()
.root_store(RootCertStore::mozilla())
.build()
.map_err(|e| JsError::new(&e.to_string()))?;
let verifier = handle
.new_verifier(verifier_config)
.map_err(|e| JsError::new(&e.to_string()))?;
self.state = State::Connected { verifier, handle };
self.state = State::Connected((verifier, prover_conn));
Ok(())
}
/// Verifies the connection and finalizes the protocol.
pub async fn verify(&mut self) -> Result<VerifierOutput> {
let State::Connected { verifier, handle } = self.state.take() else {
return Err(JsError::new("verifier is not in connected state"));
};
let (verifier, prover_conn) = self.state.take().try_into_connected()?;
let max_sent_data = self.config.max_sent_data;
let max_recv_data = self.config.max_recv_data;
let max_sent_records = self.config.max_sent_records;
let max_recv_records_online = self.config.max_recv_records_online;
let verifier = verifier
.commit()
.await
.map_err(|e| JsError::new(&e.to_string()))?;
let verifier = verifier.commit(prover_conn.into_io()).await?;
let request = verifier.request();
let TlsCommitProtocolConfig::Mpc(mpc_tls_config) = request.protocol() else {
return Err(JsError::new("only MPC protocol is supported"));
unimplemented!("only MPC protocol is supported");
};
let reject = if mpc_tls_config.max_sent_data() > max_sent_data {
let reject = if mpc_tls_config.max_sent_data() > self.config.max_sent_data {
Some("max_sent_data is too large")
} else if mpc_tls_config.max_recv_data() > max_recv_data {
} else if mpc_tls_config.max_recv_data() > self.config.max_recv_data {
Some("max_recv_data is too large")
} else if mpc_tls_config.max_sent_records() > max_sent_records {
} else if mpc_tls_config.max_sent_records() > self.config.max_sent_records {
Some("max_sent_records is too large")
} else if mpc_tls_config.max_recv_records_online() > max_recv_records_online {
} else if mpc_tls_config.max_recv_records_online() > self.config.max_recv_records_online {
Some("max_recv_records_online is too large")
} else {
None
};
if reject.is_some() {
verifier
.reject(reject)
.await
.map_err(|e| JsError::new(&e.to_string()))?;
verifier.reject(reject).await?;
return Err(JsError::new("protocol configuration rejected"));
}
let verifier = verifier
.accept()
.await
.map_err(|e| JsError::new(&e.to_string()))?
.run()
.await
.map_err(|e| JsError::new(&e.to_string()))?;
let verifier = verifier.accept().await?.run().await?;
let sent = verifier
.tls_transcript()
@@ -172,19 +129,8 @@ impl JsVerifier {
},
};
let (output, verifier) = verifier
.verify()
.await
.map_err(|e| JsError::new(&e.to_string()))?
.accept()
.await
.map_err(|e| JsError::new(&e.to_string()))?;
verifier
.close()
.await
.map_err(|e| JsError::new(&e.to_string()))?;
handle.close();
let (output, verifier) = verifier.verify().await?.accept().await?;
verifier.close().await?;
self.state = State::Complete;
@@ -193,8 +139,8 @@ impl JsVerifier {
let ServerName::Dns(name) = name;
name.to_string()
}),
connection_info: crate::types::ConnectionInfo::from(connection_info),
transcript: output.transcript.map(crate::types::PartialTranscript::from),
connection_info: connection_info.into(),
transcript: output.transcript.map(|t| t.into()),
})
}
}