mirror of
https://github.com/tlsnotary/tlsn.git
synced 2026-01-14 17:17:56 -05:00
Compare commits
5 Commits
feat/retur
...
v0.1.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a3d73c5bd | ||
|
|
2e24c62d9a | ||
|
|
a08c54a224 | ||
|
|
0656f7c742 | ||
|
|
d30538aafb |
2
.github/workflows/releng.yml
vendored
2
.github/workflows/releng.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
tag:
|
||||
description: 'Tag to publish to NPM'
|
||||
required: true
|
||||
default: 'v0.1.0-alpha.14-pre'
|
||||
default: 'v0.1.0-alpha.14'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
|
||||
10
.github/workflows/updatemain.yml
vendored
10
.github/workflows/updatemain.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Fast-forward main branch to published release tag
|
||||
name: Reset main branch to published release tag
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
ff-main-to-release:
|
||||
reset-main-to-release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -17,9 +17,9 @@ jobs:
|
||||
with:
|
||||
ref: main
|
||||
|
||||
- name: Fast-forward main to release tag
|
||||
- name: Reset main to release tag
|
||||
run: |
|
||||
tag="${{ github.event.release.tag_name }}"
|
||||
git fetch origin "refs/tags/$tag:refs/tags/$tag"
|
||||
git merge --ff-only "refs/tags/$tag"
|
||||
git push origin main
|
||||
git reset --hard "refs/tags/$tag"
|
||||
git push --force origin main
|
||||
186
Cargo.lock
generated
186
Cargo.lock
generated
@@ -174,9 +174,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "alloy-consensus"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e30ab0d3e3c32976f67fc1a96179989e45a69594af42003a6663332f9b0bb9d"
|
||||
checksum = "12870ab65b131f609257436935047eec3cfabee8809732f6bf5a69fe2a18cf2e"
|
||||
dependencies = [
|
||||
"alloy-eips",
|
||||
"alloy-primitives",
|
||||
@@ -201,9 +201,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-consensus-any"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c20736b1f9d927d875d8777ef0c2250d4c57ea828529a9dbfa2c628db57b911e"
|
||||
checksum = "47c66b14d2187de0c4efe4ef678aaa57a6a34cccdbea3a0773627fac9bd128f4"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -253,9 +253,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-eips"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15b85157b7be31fc4adf6acfefcb0d4308cba5dbd7a8d8e62bcc02ff37d6131a"
|
||||
checksum = "f076d25ddfcd2f1cbcc234e072baf97567d1df0e3fccdc1f8af8cc8b18dc6299"
|
||||
dependencies = [
|
||||
"alloy-eip2124",
|
||||
"alloy-eip2930",
|
||||
@@ -288,9 +288,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-json-rpc"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60f045b69b5e80b8944b25afe74ae6b974f3044d84b4a7a113da04745b2524cc"
|
||||
checksum = "250dbd8496f04eabe997e6e4c5186a0630b8bc3dbe7552e1fd917d491ef811e9"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-sol-types",
|
||||
@@ -303,9 +303,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-network"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b314ed5bdc7f449c53853125af2db5ac4d3954a9f4b205e7d694f02fc1932d1"
|
||||
checksum = "fd45cdac957d1fa1d0c18f54f262350eb72f1adc38dd1f8b15f33f0747c6a60c"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-consensus-any",
|
||||
@@ -329,9 +329,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-network-primitives"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e9762ac5cca67b0f6ab614f7f8314942eead1c8eeef61511ea43a6ff048dbe0"
|
||||
checksum = "fba5c43e055effb5bd33dbc74b1ab7fe0f367d8801a25af9e7c716b3ef5e440b"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -392,9 +392,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-any"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b4a6f49d161ef83354d5ba3c8bc83c8ee464cb90182b215551d5c4b846579be"
|
||||
checksum = "8faa6f22068857f58579271b15e042f4725ad35cdce2ed4778ba32ffd3102b92"
|
||||
dependencies = [
|
||||
"alloy-consensus-any",
|
||||
"alloy-rpc-types-eth",
|
||||
@@ -403,9 +403,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-eth"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11920b16ab7c86052f990dcb4d25312fb2889faf506c4ee13dc946b450536989"
|
||||
checksum = "1ec734cce11f7fe889950b36b51589397528b26beb6f890834a2131ee9f174d7"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-consensus-any",
|
||||
@@ -424,9 +424,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-serde"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1a0d2d5c64881f3723232eaaf6c2d9f4f88b061c63e87194b2db785ff3aa31f"
|
||||
checksum = "27f076bfd74fccc63d50546e1765359736357a953de2eb778b7b6191571735e6"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"serde",
|
||||
@@ -435,9 +435,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-signer"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ea4ac9765e5a7582877ca53688e041fe184880fe75f16edf0945b24a319c710"
|
||||
checksum = "d80748c209a68421ab6f737828ce6ede7543569a5cad099c1ec16fc1baa05620"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"async-trait",
|
||||
@@ -450,9 +450,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-signer-local"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c9d85b9f7105ab5ce7dae7b0da33cd9d977601a48f759e1c82958978dd1a905"
|
||||
checksum = "17eb1eb39351b4bf20bb0710d8d3a91eb7918d3f3de2f3835f556842e33865cb"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-network",
|
||||
@@ -552,9 +552,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-tx-macros"
|
||||
version = "1.4.0"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2183706e24173309b0ab0e34d3e53cf3163b71a419803b2b3b0c1fb7ff7a941"
|
||||
checksum = "bb0d567f4830dea921868c7680004ae0c7f221b05e6477db6c077c7953698f56"
|
||||
dependencies = [
|
||||
"darling 0.21.3",
|
||||
"proc-macro2",
|
||||
@@ -2027,8 +2027,8 @@ checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
|
||||
|
||||
[[package]]
|
||||
name = "clmul"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
@@ -4292,8 +4292,8 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
||||
|
||||
[[package]]
|
||||
name = "matrix-transpose"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
@@ -4349,8 +4349,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-circuits"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"mpz-circuits-core",
|
||||
"mpz-circuits-data",
|
||||
@@ -4358,8 +4358,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-circuits-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"bincode 1.3.3",
|
||||
"itybity 0.3.1",
|
||||
@@ -4373,8 +4373,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-circuits-data"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"bincode 1.3.3",
|
||||
"mpz-circuits-core",
|
||||
@@ -4383,8 +4383,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-cointoss"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"mpz-cointoss-core",
|
||||
@@ -4396,8 +4396,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-cointoss-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"mpz-core",
|
||||
"opaque-debug",
|
||||
@@ -4407,8 +4407,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-common"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
@@ -4426,8 +4426,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"aes 0.9.0-rc.2",
|
||||
"bcs",
|
||||
@@ -4452,8 +4452,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-fields"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"ark-ff 0.4.2",
|
||||
"ark-secp256r1",
|
||||
@@ -4472,11 +4472,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-garble"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"blake3",
|
||||
"derive_builder 0.11.2",
|
||||
"futures",
|
||||
"hashbrown 0.14.5",
|
||||
@@ -4499,8 +4498,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-garble-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"aes 0.9.0-rc.2",
|
||||
"bitvec",
|
||||
@@ -4530,8 +4529,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-hash"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"itybity 0.3.1",
|
||||
@@ -4543,8 +4542,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-ideal-vm"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -4560,8 +4559,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-memory-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"futures",
|
||||
@@ -4575,8 +4574,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-ole"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -4593,8 +4592,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-ole-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
"itybity 0.3.1",
|
||||
@@ -4609,8 +4608,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-ot"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"cfg-if",
|
||||
@@ -4633,8 +4632,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-ot-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"aes 0.9.0-rc.2",
|
||||
"blake3",
|
||||
@@ -4664,8 +4663,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-share-conversion"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"mpz-common",
|
||||
@@ -4680,8 +4679,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-share-conversion-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"mpz-common",
|
||||
"mpz-core",
|
||||
@@ -4694,8 +4693,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-vm-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -4707,8 +4706,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-zk"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"blake3",
|
||||
@@ -4725,8 +4724,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mpz-zk-core"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?rev=bc1d4ad#bc1d4ad6b921ccb369f9f1a43b68c3c036f7d82c"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "git+https://github.com/privacy-ethereum/mpz?tag=v0.1.0-alpha.5#2974a8370ccf554aded53deb6ea76e081645eeb5"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"cfg-if",
|
||||
@@ -6125,9 +6124,9 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18"
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "8.9.0"
|
||||
version = "8.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca"
|
||||
checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27"
|
||||
dependencies = [
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
@@ -6136,9 +6135,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "8.9.0"
|
||||
version = "8.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fa2c8c9e8711e10f9c4fd2d64317ef13feaab820a4c51541f1a8c8e2e851ab2"
|
||||
checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -6149,9 +6148,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "8.9.0"
|
||||
version = "8.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b161f275cb337fe0a44d924a5f4df0ed69c2c39519858f931ce61c779d3475"
|
||||
checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1"
|
||||
dependencies = [
|
||||
"sha2",
|
||||
"walkdir",
|
||||
@@ -7286,7 +7285,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"aes 0.8.4",
|
||||
"ctr 0.9.2",
|
||||
@@ -7338,7 +7337,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-attestation"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-signer",
|
||||
@@ -7362,7 +7361,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-cipher"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"aes 0.8.4",
|
||||
"async-trait",
|
||||
@@ -7379,7 +7378,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-core"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"aes-gcm",
|
||||
@@ -7419,7 +7418,7 @@ version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-deap"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -7466,7 +7465,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-formats"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"rstest",
|
||||
@@ -7558,7 +7557,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-hmac-sha256"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"hex",
|
||||
@@ -7578,7 +7577,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-key-exchange"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"derive_builder 0.12.0",
|
||||
@@ -7605,7 +7604,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-mpc-tls"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"aes 0.8.4",
|
||||
"aes-gcm",
|
||||
@@ -7700,7 +7699,7 @@ version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-tls-backend"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -7710,7 +7709,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-tls-client"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"async-trait",
|
||||
@@ -7738,7 +7737,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-tls-client-async"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures",
|
||||
@@ -7758,7 +7757,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-tls-core"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"hmac",
|
||||
@@ -7782,8 +7781,9 @@ source = "git+https://github.com/tlsnotary/tlsn-utils?rev=6168663#6168663495281f
|
||||
|
||||
[[package]]
|
||||
name = "tlsn-wasm"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
dependencies = [
|
||||
"async_io_stream",
|
||||
"bincode 1.3.3",
|
||||
"console_error_panic_hook",
|
||||
"enum-try-as-inner",
|
||||
|
||||
31
Cargo.toml
31
Cargo.toml
@@ -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", 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" }
|
||||
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" }
|
||||
|
||||
rangeset = { version = "0.4" }
|
||||
serio = { version = "0.2" }
|
||||
@@ -92,6 +92,7 @@ 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" }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tlsn-attestation"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -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-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tlsn-deap"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -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-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -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().await.unwrap();
|
||||
let mut follower_ctx = follower_exec.new_context().await.unwrap();
|
||||
let mut leader_ctx = leader_exec.new_context().unwrap();
|
||||
let mut follower_ctx = follower_exec.new_context().unwrap();
|
||||
|
||||
let mut leader_vm = IdealVm::new();
|
||||
let mut follower_vm = IdealVm::new();
|
||||
|
||||
@@ -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-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -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-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -43,12 +43,12 @@ noir = { git = "https://github.com/zkmopro/noir-rs", tag = "v1.0.0-beta.8", feat
|
||||
] }
|
||||
|
||||
[[example]]
|
||||
name = "interactive"
|
||||
path = "interactive/interactive.rs"
|
||||
name = "basic"
|
||||
path = "basic/basic.rs"
|
||||
|
||||
[[example]]
|
||||
name = "interactive_zk"
|
||||
path = "interactive_zk/interactive_zk.rs"
|
||||
name = "basic_zk"
|
||||
path = "basic_zk/basic_zk.rs"
|
||||
|
||||
[[example]]
|
||||
name = "attestation_prove"
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
This folder contains examples demonstrating how to use the TLSNotary protocol.
|
||||
|
||||
* [Interactive](./interactive/README.md): Interactive Prover and Verifier session without a trusted notary.
|
||||
* [Attestation](./attestation/README.md): Performing a simple notarization with a trusted notary.
|
||||
* [Interactive_zk](./interactive_zk/README.md): Interactive Prover and Verifier session demonstrating zero-knowledge age verification using Noir.
|
||||
* [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.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
# Attestation Example
|
||||
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## 🔍 How It Works
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant P as Prover
|
||||
participant N as MPC-TLS<br/>Verifier
|
||||
participant N as 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 MPC-TLS connection
|
||||
P->>S: Request (MPC-TLS)
|
||||
S->>P: Response (MPC-TLS)
|
||||
P->>N: Establish TLS connection
|
||||
P->>S: Request (TLS)
|
||||
S->>P: Response (TLS)
|
||||
N->>P: Issue signed attestation
|
||||
|
||||
Note over P: 2. Presentation Phase
|
||||
@@ -161,4 +160,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.
|
||||
|
||||
@@ -33,8 +33,9 @@ use tlsn::{
|
||||
connection::{ConnectionInfo, HandshakeData, ServerName, TranscriptLength},
|
||||
prover::{state::Committed, Prover, ProverOutput},
|
||||
transcript::{ContentType, TranscriptCommitConfig},
|
||||
verifier::{Verifier, VerifierOutput},
|
||||
verifier::VerifierOutput,
|
||||
webpki::{CertificateDer, PrivateKeyDer, RootCertStore},
|
||||
Session,
|
||||
};
|
||||
use tlsn_examples::ExampleType;
|
||||
use tlsn_formats::http::{DefaultHttpCommitter, HttpCommit, HttpTranscript};
|
||||
@@ -99,8 +100,16 @@ 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 = Prover::new(ProverConfig::builder().build()?)
|
||||
let prover = handle
|
||||
.new_prover(ProverConfig::builder().build()?)?
|
||||
.commit(
|
||||
TlsCommitConfig::builder()
|
||||
// Select the TLS commitment protocol.
|
||||
@@ -115,7 +124,6 @@ async fn prover<S: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
|
||||
.build()?,
|
||||
)
|
||||
.build()?,
|
||||
socket.compat(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -224,6 +232,10 @@ 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");
|
||||
@@ -311,6 +323,13 @@ 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.
|
||||
@@ -321,8 +340,9 @@ async fn notary<S: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let verifier = Verifier::new(verifier_config)
|
||||
.commit(socket.compat())
|
||||
let verifier = handle
|
||||
.new_verifier(verifier_config)?
|
||||
.commit()
|
||||
.await?
|
||||
.accept()
|
||||
.await?
|
||||
@@ -399,5 +419,9 @@ 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(())
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
## Simple Interactive Verifier: Verifying Data from an API in Rust
|
||||
## Simple Basic Verifier: Verifying Data from an API in Rust
|
||||
|
||||
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 demonstrates how to use TLSNotary in a simple session between a Prover and a Verifier.
|
||||
|
||||
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 interactive example with:
|
||||
Next, run the basic example with:
|
||||
```shell
|
||||
SERVER_PORT=4000 cargo run --release --example interactive
|
||||
SERVER_PORT=4000 cargo run --release --example basic
|
||||
```
|
||||
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 interactive
|
||||
RUST_LOG=debug,yamux=info,uid_mux=info SERVER_PORT=4000 cargo run --release --example basic
|
||||
```
|
||||
|
||||
> ℹ️ 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.
|
||||
@@ -20,10 +20,10 @@ use tlsn::{
|
||||
verifier::VerifierConfig,
|
||||
},
|
||||
connection::ServerName,
|
||||
prover::Prover,
|
||||
transcript::PartialTranscript,
|
||||
verifier::{Verifier, VerifierOutput},
|
||||
verifier::VerifierOutput,
|
||||
webpki::{CertificateDer, RootCertStore},
|
||||
Session,
|
||||
};
|
||||
use tlsn_server_fixture::DEFAULT_FIXTURE_PORT;
|
||||
use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
|
||||
@@ -77,8 +77,16 @@ 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 = Prover::new(ProverConfig::builder().build()?)
|
||||
let prover = handle
|
||||
.new_prover(ProverConfig::builder().build()?)?
|
||||
.commit(
|
||||
TlsCommitConfig::builder()
|
||||
// Select the TLS commitment protocol.
|
||||
@@ -93,7 +101,6 @@ async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
.build()?,
|
||||
)
|
||||
.build()?,
|
||||
verifier_socket.compat(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -120,14 +127,13 @@ 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);
|
||||
|
||||
// MPC-TLS: Send Request and wait for Response.
|
||||
// Send Request and wait for Response.
|
||||
let request = Request::builder()
|
||||
.uri(uri.clone())
|
||||
.header("Host", server_domain)
|
||||
@@ -176,6 +182,10 @@ 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(())
|
||||
}
|
||||
|
||||
@@ -183,6 +193,13 @@ 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.
|
||||
@@ -191,10 +208,10 @@ async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
|
||||
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
|
||||
})
|
||||
.build()?;
|
||||
let verifier = Verifier::new(verifier_config);
|
||||
let verifier = handle.new_verifier(verifier_config)?;
|
||||
|
||||
// Validate the proposed configuration and then run the TLS commitment protocol.
|
||||
let verifier = verifier.commit(socket.compat()).await?;
|
||||
let verifier = verifier.commit().await?;
|
||||
|
||||
// This is the opportunity to ensure the prover does not attempt to overload the
|
||||
// verifier.
|
||||
@@ -241,6 +258,10 @@ 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");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Interactive Zero-Knowledge Age Verification with TLSNotary
|
||||
# Basic 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) (MPC-TLS)
|
||||
S->>P: Tax data including `date_of_birth` (MPC-TLS)
|
||||
P->>S: Request tax data (with auth token) (TLS)
|
||||
S->>P: Tax data including `date_of_birth` (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. **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.
|
||||
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.
|
||||
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 MPC-TLS session)
|
||||
- ✅ The birth date is authentic (from the 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 interactive_zk
|
||||
SERVER_PORT=4000 cargo run --release --example basic_zk
|
||||
```
|
||||
|
||||
3. **For detailed logs**:
|
||||
```bash
|
||||
RUST_LOG=debug,yamux=info,uid_mux=info SERVER_PORT=4000 cargo run --release --example interactive_zk
|
||||
RUST_LOG=debug,yamux=info,uid_mux=info SERVER_PORT=4000 cargo run --release --example basic_zk
|
||||
```
|
||||
|
||||
### Expected Output
|
||||
@@ -106,11 +106,11 @@ Verified received data:
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
interactive_zk/
|
||||
basic_zk/
|
||||
├── prover.rs # Prover implementation
|
||||
├── verifier.rs # Verifier implementation
|
||||
├── verifier.rs # Verifier implementation
|
||||
├── types.rs # Shared types
|
||||
└── interactive_zk.rs # Main example runner
|
||||
└── basic_zk.rs # Main example runner
|
||||
├── noir/ # Zero-knowledge circuit
|
||||
│ ├── src/main.n # Noir circuit code
|
||||
│ ├── target/ # Compiled circuit artifacts
|
||||
@@ -31,11 +31,10 @@ 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, prover_extra_socket, &server_addr, &uri),
|
||||
verifier(verifier_socket, verifier_extra_socket)
|
||||
prover(prover_socket, &server_addr, &uri),
|
||||
verifier(verifier_socket)
|
||||
)?;
|
||||
|
||||
println!("---");
|
||||
@@ -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, AsyncWriteExt};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt};
|
||||
use tracing::instrument;
|
||||
|
||||
#[instrument(skip(verifier_socket, verifier_extra_socket))]
|
||||
#[instrument(skip(verifier_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,8 +64,16 @@ 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 = Prover::new(ProverConfig::builder().build()?)
|
||||
let prover = handle
|
||||
.new_prover(ProverConfig::builder().build()?)?
|
||||
.commit(
|
||||
TlsCommitConfig::builder()
|
||||
// Select the TLS commitment protocol.
|
||||
@@ -80,7 +88,6 @@ pub async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
.build()?,
|
||||
)
|
||||
.build()?,
|
||||
verifier_socket.compat(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -107,14 +114,13 @@ 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);
|
||||
|
||||
// MPC-TLS: Send Request and wait for Response.
|
||||
// Send Request and wait for Response.
|
||||
let request = Request::builder()
|
||||
.uri(uri.clone())
|
||||
.header("Host", server_domain)
|
||||
@@ -127,7 +133,7 @@ pub async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
|
||||
if response.status() != StatusCode::OK {
|
||||
return Err(anyhow::anyhow!(
|
||||
"MPC-TLS request failed with status {}",
|
||||
"request failed with status {}",
|
||||
response.status()
|
||||
));
|
||||
}
|
||||
@@ -166,10 +172,13 @@ 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
|
||||
@@ -184,8 +193,8 @@ pub async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
|
||||
// Sent zk proof bundle to verifier
|
||||
let serialized_proof = bincode::serialize(&proof_bundle)?;
|
||||
verifier_extra_socket.write_all(&serialized_proof).await?;
|
||||
verifier_extra_socket.shutdown().await?;
|
||||
socket.write_all(&serialized_proof).await?;
|
||||
socket.close().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -3,6 +3,7 @@ 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;
|
||||
@@ -11,33 +12,39 @@ use tlsn::{
|
||||
connection::ServerName,
|
||||
hash::HashAlgId,
|
||||
transcript::{Direction, PartialTranscript},
|
||||
verifier::{Verifier, VerifierOutput},
|
||||
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, AsyncReadExt, AsyncWrite};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio_util::compat::TokioAsyncReadCompatExt;
|
||||
use tracing::instrument;
|
||||
|
||||
#[instrument(skip(socket, extra_socket))]
|
||||
#[instrument(skip(socket))]
|
||||
pub async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
|
||||
socket: T,
|
||||
mut extra_socket: T,
|
||||
) -> Result<PartialTranscript> {
|
||||
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()?,
|
||||
);
|
||||
// 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)?;
|
||||
|
||||
// Validate the proposed configuration and then run the TLS commitment protocol.
|
||||
let verifier = verifier.commit(socket.compat()).await?;
|
||||
let verifier = verifier.commit().await?;
|
||||
|
||||
// This is the opportunity to ensure the prover does not attempt to overload the
|
||||
// verifier.
|
||||
@@ -90,6 +97,10 @@ 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");
|
||||
|
||||
@@ -126,7 +137,7 @@ pub async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>
|
||||
|
||||
// Receive ZKProof information from prover
|
||||
let mut buf = Vec::new();
|
||||
extra_socket.read_to_end(&mut buf).await?;
|
||||
socket.read_to_end(&mut buf).await?;
|
||||
|
||||
if buf.is_empty() {
|
||||
return Err(anyhow::anyhow!("No ZK proof data received from prover"));
|
||||
@@ -193,16 +204,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 in MPC-TLS: {} != {}",
|
||||
"❌ The hash in the proof does not match the committed hash: {} != {}",
|
||||
hex::encode(&committed_hash_in_proof),
|
||||
hex::encode(&expected_hash)
|
||||
);
|
||||
return Err(anyhow::anyhow!(
|
||||
"Hash in proof does not match committed hash in MPC-TLS"
|
||||
"Hash in proof does not match committed hash"
|
||||
));
|
||||
}
|
||||
tracing::info!(
|
||||
"✅ The hash in the proof matches the committed hash in MPC-TLS ({})",
|
||||
"✅ The hash in the proof matches the committed hash ({})",
|
||||
hex::encode(&expected_hash)
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tlsn-formats"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -5,6 +5,7 @@ use futures::{AsyncReadExt, AsyncWriteExt, TryFutureExt};
|
||||
|
||||
use harness_core::bench::{Bench, ProverMetrics};
|
||||
use tlsn::{
|
||||
Session,
|
||||
config::{
|
||||
prove::ProveConfig,
|
||||
prover::ProverConfig,
|
||||
@@ -12,7 +13,6 @@ 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,6 +20,7 @@ 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> {
|
||||
@@ -28,7 +29,12 @@ pub async fn bench_prover(provider: &IoProvider, config: &Bench) -> Result<Prove
|
||||
let sent = verifier_io.sent();
|
||||
let recv = verifier_io.recv();
|
||||
|
||||
let prover = Prover::new(ProverConfig::builder().build()?);
|
||||
let mut session = Session::new(verifier_io);
|
||||
|
||||
let prover = session.new_prover(ProverConfig::builder().build()?)?;
|
||||
let (session, handle) = session.split();
|
||||
|
||||
_ = spawn(session);
|
||||
|
||||
let time_start = web_time::Instant::now();
|
||||
|
||||
@@ -49,7 +55,6 @@ pub async fn bench_prover(provider: &IoProvider, config: &Bench) -> Result<Prove
|
||||
.build()
|
||||
}?)
|
||||
.build()?,
|
||||
verifier_io,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -120,6 +125,7 @@ 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();
|
||||
|
||||
|
||||
@@ -2,32 +2,34 @@ 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;
|
||||
use crate::{IoProvider, spawn};
|
||||
|
||||
pub async fn bench_verifier(provider: &IoProvider, _config: &Bench) -> Result<()> {
|
||||
let verifier = Verifier::new(
|
||||
let io = provider.provide_proto_io().await?;
|
||||
let mut session = Session::new(io);
|
||||
|
||||
let verifier = session.new_verifier(
|
||||
VerifierConfig::builder()
|
||||
.root_store(RootCertStore {
|
||||
roots: vec![CertificateDer(CA_CERT_DER.to_vec())],
|
||||
})
|
||||
.build()?,
|
||||
);
|
||||
)?;
|
||||
|
||||
let verifier = verifier
|
||||
.commit(provider.provide_proto_io().await?)
|
||||
.await?
|
||||
.accept()
|
||||
.await?
|
||||
.run()
|
||||
.await?;
|
||||
let (session, handle) = session.split();
|
||||
|
||||
_ = spawn(session);
|
||||
|
||||
let verifier = verifier.commit().await?.accept().await?.run().await?;
|
||||
let (_, verifier) = verifier.verify().await?.accept().await?;
|
||||
verifier.close().await?;
|
||||
handle.close();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use tlsn::{
|
||||
Session,
|
||||
config::{
|
||||
prove::ProveConfig,
|
||||
prover::ProverConfig,
|
||||
@@ -8,9 +9,8 @@ use tlsn::{
|
||||
},
|
||||
connection::ServerName,
|
||||
hash::HashAlgId,
|
||||
prover::Prover,
|
||||
transcript::{TranscriptCommitConfig, TranscriptCommitment, TranscriptCommitmentKind},
|
||||
verifier::{Verifier, VerifierOutput},
|
||||
verifier::VerifierOutput,
|
||||
webpki::{CertificateDer, RootCertStore},
|
||||
};
|
||||
use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
|
||||
@@ -28,7 +28,17 @@ const MAX_RECV_DATA: usize = 1 << 11;
|
||||
crate::test!("basic", prover, verifier);
|
||||
|
||||
async fn prover(provider: &IoProvider) {
|
||||
let prover = Prover::new(ProverConfig::builder().build().unwrap())
|
||||
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
|
||||
.commit(
|
||||
TlsCommitConfig::builder()
|
||||
.protocol(
|
||||
@@ -41,7 +51,6 @@ async fn prover(provider: &IoProvider) {
|
||||
)
|
||||
.build()
|
||||
.unwrap(),
|
||||
provider.provide_proto_io().await.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -116,18 +125,27 @@ 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 verifier = Verifier::new(config)
|
||||
.commit(provider.provide_proto_io().await.unwrap())
|
||||
let (session, handle) = session.split();
|
||||
|
||||
_ = spawn(session);
|
||||
|
||||
let verifier = verifier
|
||||
.commit()
|
||||
.await
|
||||
.unwrap()
|
||||
.accept()
|
||||
@@ -147,6 +165,7 @@ 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();
|
||||
|
||||
|
||||
@@ -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-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -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 = futures::executor::block_on(mt_a.new_context()).unwrap();
|
||||
let ctx_b = futures::executor::block_on(mt_b.new_context()).unwrap();
|
||||
let ctx_a = mt_a.new_context().unwrap();
|
||||
let ctx_b = mt_b.new_context().unwrap();
|
||||
|
||||
let delta_a = Delta::new(Block::random(&mut rng));
|
||||
let delta_b = Delta::new(Block::random(&mut rng));
|
||||
|
||||
@@ -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-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -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-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -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-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
autobenches = false
|
||||
|
||||
|
||||
@@ -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-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -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-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2024"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
//! 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()
|
||||
}
|
||||
170
crates/tlsn/src/error.rs
Normal file
170
crates/tlsn/src/error.rs
Normal file
@@ -0,0 +1,170 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,66 @@
|
||||
//! TLSNotary library.
|
||||
//! 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.
|
||||
|
||||
#![deny(missing_docs, unreachable_pub, unused_must_use)]
|
||||
#![deny(clippy::all)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub(crate) mod context;
|
||||
mod error;
|
||||
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;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::fmt;
|
||||
|
||||
use semver::Version;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -40,12 +42,14 @@ impl Response {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub(crate) struct RejectionReason(Option<String>);
|
||||
|
||||
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}"))
|
||||
impl fmt::Display for RejectionReason {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(msg) = &self.0 {
|
||||
write!(f, "{msg}")
|
||||
} else {
|
||||
crate::prover::ProverError::config("verifier rejected without providing a reason")
|
||||
write!(f, "no reason provided")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for RejectionReason {}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
//! 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)
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
//! 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::{
|
||||
context::build_mt_context,
|
||||
Error, Result,
|
||||
mpz::{ProverDeps, build_prover_deps, translate_keys},
|
||||
msg::{ProveRequestMsg, Response, TlsCommitRequestMsg},
|
||||
mux::MuxFuture,
|
||||
tag::verify_tags,
|
||||
};
|
||||
|
||||
@@ -44,6 +42,7 @@ 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,
|
||||
}
|
||||
|
||||
@@ -52,12 +51,14 @@ impl Prover<state::Initialized> {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `ctx` - A thread context.
|
||||
/// * `config` - The configuration for the prover.
|
||||
pub fn new(config: ProverConfig) -> Self {
|
||||
pub(crate) fn new(ctx: Context, config: ProverConfig) -> Self {
|
||||
let span = info_span!("prover");
|
||||
Self {
|
||||
config,
|
||||
span,
|
||||
ctx: Some(ctx),
|
||||
state: state::Initialized,
|
||||
}
|
||||
}
|
||||
@@ -70,36 +71,43 @@ 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<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
self,
|
||||
pub async fn commit(
|
||||
mut self,
|
||||
config: TlsCommitConfig,
|
||||
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?;
|
||||
) -> Result<Prover<state::CommitAccepted>> {
|
||||
let mut ctx = self
|
||||
.ctx
|
||||
.take()
|
||||
.ok_or_else(|| Error::internal().with_msg("commitment protocol context was dropped"))?;
|
||||
|
||||
// Sends protocol configuration to verifier for compatibility check.
|
||||
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?
|
||||
.result
|
||||
.map_err(ProverError::from)
|
||||
ctx.io_mut()
|
||||
.send(TlsCommitRequestMsg {
|
||||
request: config.to_request(),
|
||||
version: crate::VERSION.clone(),
|
||||
})
|
||||
.await?;
|
||||
.await
|
||||
.map_err(|e| {
|
||||
Error::io()
|
||||
.with_msg("commitment protocol failed to send request")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
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)
|
||||
})?;
|
||||
|
||||
let TlsCommitProtocolConfig::Mpc(mpc_tls_config) = config.protocol().clone() else {
|
||||
unreachable!("only MPC TLS is supported");
|
||||
@@ -108,34 +116,35 @@ 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()?;
|
||||
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 vm_lock = vm.try_lock().expect("VM is not locked");
|
||||
translate_keys(&mut keys, &vm_lock);
|
||||
drop(vm_lock);
|
||||
|
||||
debug!("setting up mpc-tls");
|
||||
|
||||
mux_fut.poll_with(mpc_tls.preprocess()).await?;
|
||||
mpc_tls.preprocess().await.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("commitment protocol failed during mpc-tls preprocessing")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
debug!("mpc-tls setup complete");
|
||||
|
||||
Ok(Prover {
|
||||
config: self.config,
|
||||
span: self.span,
|
||||
state: state::CommitAccepted {
|
||||
mux_fut,
|
||||
mpc_tls,
|
||||
keys,
|
||||
vm,
|
||||
},
|
||||
ctx: None,
|
||||
state: state::CommitAccepted { mpc_tls, keys, vm },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<Io> Prover<state::CommitAccepted<Io>>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
{
|
||||
impl Prover<state::CommitAccepted> {
|
||||
/// Connects to the server using the provided socket.
|
||||
///
|
||||
/// Returns a handle to the TLS connection, a future which returns the
|
||||
@@ -151,13 +160,9 @@ where
|
||||
self,
|
||||
config: TlsClientConfig,
|
||||
socket: S,
|
||||
) -> Result<(TlsConnection, ProverFuture<Io>), ProverError> {
|
||||
) -> Result<(TlsConnection, ProverFuture)> {
|
||||
let state::CommitAccepted {
|
||||
mut mux_fut,
|
||||
mpc_tls,
|
||||
keys,
|
||||
vm,
|
||||
..
|
||||
mpc_tls, keys, vm, ..
|
||||
} = self.state;
|
||||
|
||||
let (mpc_ctrl, mpc_fut) = mpc_tls.run();
|
||||
@@ -175,7 +180,11 @@ where
|
||||
let der = CertificateDer::from_slice(&cert.0);
|
||||
anchor_from_trusted_cert(&der)
|
||||
.map(|anchor| anchor.to_owned())
|
||||
.map_err(ProverError::config)
|
||||
.map_err(|e| {
|
||||
Error::config()
|
||||
.with_msg("failed to parse root certificate")
|
||||
.with_source(e)
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
};
|
||||
@@ -192,7 +201,11 @@ where
|
||||
.collect(),
|
||||
tls_client::PrivateKey(key.0.clone()),
|
||||
)
|
||||
.map_err(ProverError::config)?
|
||||
.map_err(|e| {
|
||||
Error::config()
|
||||
.with_msg("failed to configure client authentication")
|
||||
.with_source(e)
|
||||
})?
|
||||
} else {
|
||||
rustls_config.with_no_client_auth()
|
||||
};
|
||||
@@ -202,7 +215,11 @@ where
|
||||
Box::new(mpc_ctrl.clone()),
|
||||
server_name,
|
||||
)
|
||||
.map_err(ProverError::config)?;
|
||||
.map_err(|e| {
|
||||
Error::config()
|
||||
.with_msg("failed to create tls client connection")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
let (conn, conn_fut) = bind_client(socket, client);
|
||||
|
||||
@@ -211,20 +228,27 @@ where
|
||||
let mpc_ctrl = mpc_ctrl.clone();
|
||||
async move {
|
||||
let conn_fut = async {
|
||||
mux_fut
|
||||
.poll_with(conn_fut.map_err(ProverError::from))
|
||||
.await?;
|
||||
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)
|
||||
})?;
|
||||
|
||||
mpc_ctrl.stop().await?;
|
||||
|
||||
Ok::<_, ProverError>(())
|
||||
Ok::<_, crate::Error>(())
|
||||
};
|
||||
|
||||
info!("starting MPC-TLS");
|
||||
|
||||
let (_, (mut ctx, tls_transcript)) = futures::try_join!(
|
||||
conn_fut,
|
||||
mpc_fut.in_current_span().map_err(ProverError::from)
|
||||
mpc_fut.in_current_span().map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("mpc-tls execution failed")
|
||||
.with_source(e)
|
||||
})
|
||||
)?;
|
||||
|
||||
info!("finished MPC-TLS");
|
||||
@@ -235,10 +259,11 @@ where
|
||||
debug!("finalizing mpc");
|
||||
|
||||
// Finalize DEAP.
|
||||
mux_fut
|
||||
.poll_with(vm.finalize(&mut ctx))
|
||||
.await
|
||||
.map_err(ProverError::mpc)?;
|
||||
vm.finalize(&mut ctx).await.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("mpc finalization failed")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
debug!("mpc finalized");
|
||||
}
|
||||
@@ -258,11 +283,17 @@ where
|
||||
*tls_transcript.version(),
|
||||
tls_transcript.recv().to_vec(),
|
||||
)
|
||||
.map_err(ProverError::zk)?;
|
||||
.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("tag verification setup failed")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
mux_fut
|
||||
.poll_with(vm.execute_all(&mut ctx).map_err(ProverError::zk))
|
||||
.await?;
|
||||
vm.execute_all(&mut ctx).await.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("executing the zkVM failed during tag verification")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
let transcript = tls_transcript
|
||||
.to_transcript()
|
||||
@@ -271,9 +302,8 @@ where
|
||||
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,
|
||||
@@ -295,10 +325,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Io> Prover<state::Committed<Io>>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
{
|
||||
impl Prover<state::Committed> {
|
||||
/// Returns the TLS transcript.
|
||||
pub fn tls_transcript(&self) -> &TlsTranscript {
|
||||
&self.state.tls_transcript
|
||||
@@ -315,10 +342,12 @@ where
|
||||
///
|
||||
/// * `config` - The disclosure configuration.
|
||||
#[instrument(parent = &self.span, level = "info", skip_all, err)]
|
||||
pub async fn prove(&mut self, config: &ProveConfig) -> Result<ProverOutput, ProverError> {
|
||||
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"))?;
|
||||
let state::Committed {
|
||||
mux_fut,
|
||||
ctx,
|
||||
vm,
|
||||
keys,
|
||||
server_name,
|
||||
@@ -354,27 +383,35 @@ where
|
||||
transcript: partial_transcript,
|
||||
};
|
||||
|
||||
let output = mux_fut
|
||||
.poll_with(async {
|
||||
ctx.io_mut().send(msg).await.map_err(ProverError::from)?;
|
||||
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)
|
||||
})?;
|
||||
|
||||
ctx.io_mut().expect_next::<Response>().await?.result?;
|
||||
|
||||
prove::prove(ctx, vm, keys, transcript, tls_transcript, config).await
|
||||
})
|
||||
.await?;
|
||||
let output = prove::prove(ctx, vm, keys, transcript, tls_transcript, config).await?;
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
/// Closes the connection with the verifier.
|
||||
#[instrument(parent = &self.span, level = "info", skip_all, err)]
|
||||
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)
|
||||
pub async fn close(self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,10 +433,11 @@ 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<(), ProverError> {
|
||||
self.mpc_ctrl
|
||||
.defer_decryption()
|
||||
.await
|
||||
.map_err(ProverError::from)
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -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<Io> {
|
||||
pub struct ProverFuture {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fut: Pin<
|
||||
Box<
|
||||
dyn Future<Output = Result<Prover<state::Committed<Io>>, ProverError>> + Send + 'static,
|
||||
>,
|
||||
>,
|
||||
pub(crate) fut:
|
||||
Pin<Box<dyn Future<Output = Result<Prover<state::Committed>>> + Send + 'static>>,
|
||||
pub(crate) ctrl: ProverControl,
|
||||
}
|
||||
|
||||
impl<Io> ProverFuture<Io> {
|
||||
impl ProverFuture {
|
||||
/// Returns a controller for the prover for advanced functionality.
|
||||
pub fn control(&self) -> ProverControl {
|
||||
self.ctrl.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Io> Future for ProverFuture<Io> {
|
||||
type Output = Result<Prover<state::Committed<Io>>, ProverError>;
|
||||
impl Future for ProverFuture {
|
||||
type Output = Result<Prover<state::Committed>>;
|
||||
|
||||
fn poll(
|
||||
mut self: Pin<&mut Self>,
|
||||
|
||||
@@ -12,7 +12,7 @@ use tlsn_core::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
prover::ProverError,
|
||||
Error, Result,
|
||||
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, ProverError> {
|
||||
) -> Result<ProverOutput> {
|
||||
let mut output = ProverOutput {
|
||||
transcript_commitments: Vec::default(),
|
||||
transcript_secrets: Vec::default(),
|
||||
@@ -53,7 +53,11 @@ pub(crate) async fn prove<T: Vm<Binary> + Send + Sync>(
|
||||
&reveal_sent,
|
||||
&commit_sent,
|
||||
)
|
||||
.map_err(ProverError::commit)?,
|
||||
.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("proving failed during sent plaintext commitment")
|
||||
.with_source(e)
|
||||
})?,
|
||||
recv: prove_plaintext(
|
||||
vm,
|
||||
keys.server_write_key,
|
||||
@@ -66,7 +70,11 @@ pub(crate) async fn prove<T: Vm<Binary> + Send + Sync>(
|
||||
&reveal_recv,
|
||||
&commit_recv,
|
||||
)
|
||||
.map_err(ProverError::commit)?,
|
||||
.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("proving failed during received plaintext commitment")
|
||||
.with_source(e)
|
||||
})?,
|
||||
};
|
||||
|
||||
let hash_commitments = if let Some(commit_config) = config.transcript_commit()
|
||||
@@ -80,16 +88,28 @@ pub(crate) async fn prove<T: Vm<Binary> + Send + Sync>(
|
||||
.iter_hash()
|
||||
.map(|((dir, idx), alg)| (*dir, idx.clone(), *alg)),
|
||||
)
|
||||
.map_err(ProverError::commit)?,
|
||||
.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("proving failed during hash commitment setup")
|
||||
.with_source(e)
|
||||
})?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
vm.execute_all(ctx).await.map_err(ProverError::zk)?;
|
||||
vm.execute_all(ctx).await.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("proving failed during zk execution")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
if let Some((hash_fut, hash_secrets)) = hash_commitments {
|
||||
let hash_commitments = hash_fut.try_recv().map_err(ProverError::commit)?;
|
||||
let hash_commitments = hash_fut.try_recv().map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("proving failed during hash commitment finalization")
|
||||
.with_source(e)
|
||||
})?;
|
||||
for (commitment, secret) in hash_commitments.into_iter().zip(hash_secrets) {
|
||||
output
|
||||
.transcript_commitments
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use mpc_tls::{MpcTlsLeader, SessionKeys};
|
||||
use mpz_common::Context;
|
||||
use tlsn_core::{
|
||||
connection::ServerName,
|
||||
transcript::{TlsTranscript, Transcript},
|
||||
@@ -11,10 +10,7 @@ use tlsn_core::{
|
||||
use tlsn_deap::Deap;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
mpz::{ProverMpc, ProverZk},
|
||||
mux::MuxFuture,
|
||||
};
|
||||
use crate::mpz::{ProverMpc, ProverZk};
|
||||
|
||||
/// Entry state
|
||||
pub struct Initialized;
|
||||
@@ -23,19 +19,16 @@ opaque_debug::implement!(Initialized);
|
||||
|
||||
/// State after the verifier has accepted the proposed TLS commitment protocol
|
||||
/// configuration and preprocessing has completed.
|
||||
pub struct CommitAccepted<Io> {
|
||||
pub(crate) mux_fut: MuxFuture<Io>,
|
||||
pub struct CommitAccepted {
|
||||
pub(crate) mpc_tls: MpcTlsLeader,
|
||||
pub(crate) keys: SessionKeys,
|
||||
pub(crate) vm: Arc<Mutex<Deap<ProverMpc, ProverZk>>>,
|
||||
}
|
||||
|
||||
opaque_debug::implement!(CommitAccepted<Io>);
|
||||
opaque_debug::implement!(CommitAccepted);
|
||||
|
||||
/// State after the TLS transcript has been committed.
|
||||
pub struct Committed<Io> {
|
||||
pub(crate) mux_fut: MuxFuture<Io>,
|
||||
pub(crate) ctx: Context,
|
||||
pub struct Committed {
|
||||
pub(crate) vm: ProverZk,
|
||||
pub(crate) server_name: ServerName,
|
||||
pub(crate) keys: SessionKeys,
|
||||
@@ -43,18 +36,18 @@ pub struct Committed<Io> {
|
||||
pub(crate) transcript: Transcript,
|
||||
}
|
||||
|
||||
opaque_debug::implement!(Committed<Io>);
|
||||
opaque_debug::implement!(Committed);
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub trait ProverState: sealed::Sealed {}
|
||||
|
||||
impl ProverState for Initialized {}
|
||||
impl<Io> ProverState for CommitAccepted<Io> {}
|
||||
impl<Io> ProverState for Committed<Io> {}
|
||||
impl ProverState for CommitAccepted {}
|
||||
impl ProverState for Committed {}
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
impl Sealed for super::Initialized {}
|
||||
impl<Io> Sealed for super::CommitAccepted<Io> {}
|
||||
impl<Io> Sealed for super::Committed<Io> {}
|
||||
impl Sealed for super::CommitAccepted {}
|
||||
impl Sealed for super::Committed {}
|
||||
}
|
||||
|
||||
326
crates/tlsn/src/session.rs
Normal file
326
crates/tlsn/src/session.rs
Normal file
@@ -0,0 +1,326 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,22 +1,19 @@
|
||||
//! Verifier.
|
||||
|
||||
mod error;
|
||||
pub mod state;
|
||||
mod verify;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use error::VerifierError;
|
||||
use mpz_common::Context;
|
||||
pub use tlsn_core::{VerifierOutput, webpki::ServerCertVerifier};
|
||||
|
||||
use crate::{
|
||||
context::build_mt_context,
|
||||
Error, Result,
|
||||
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::{
|
||||
@@ -44,16 +41,18 @@ 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 fn new(config: VerifierConfig) -> Self {
|
||||
pub(crate) fn new(ctx: Context, config: VerifierConfig) -> Self {
|
||||
let span = info_span!("verifier");
|
||||
Self {
|
||||
config,
|
||||
span,
|
||||
ctx: Some(ctx),
|
||||
state: state::Initialized,
|
||||
}
|
||||
}
|
||||
@@ -62,56 +61,48 @@ 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<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?;
|
||||
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"))?;
|
||||
|
||||
// Receives protocol configuration from prover to perform compatibility check.
|
||||
let TlsCommitRequestMsg { request, version } =
|
||||
mux_fut.poll_with(ctx.io_mut().expect_next()).await?;
|
||||
ctx.io_mut().expect_next().await.map_err(|e| {
|
||||
Error::io()
|
||||
.with_msg("commitment protocol failed to receive request")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
if version != *crate::VERSION {
|
||||
let msg = format!(
|
||||
"prover version does not match with verifier: {version} != {}",
|
||||
*crate::VERSION
|
||||
);
|
||||
mux_fut
|
||||
.poll_with(ctx.io_mut().send(Response::err(Some(msg.clone()))))
|
||||
.await?;
|
||||
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.close();
|
||||
mux_fut.await?;
|
||||
|
||||
return Err(VerifierError::config(msg));
|
||||
return Err(Error::config().with_msg(msg));
|
||||
}
|
||||
|
||||
Ok(Verifier {
|
||||
config: self.config,
|
||||
span: self.span,
|
||||
state: state::CommitStart {
|
||||
mux_fut,
|
||||
ctx,
|
||||
request,
|
||||
},
|
||||
ctx: Some(ctx),
|
||||
state: state::CommitStart { request },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<Io> Verifier<state::CommitStart<Io>>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
{
|
||||
impl Verifier<state::CommitStart> {
|
||||
/// Returns the TLS commitment request.
|
||||
pub fn request(&self) -> &TlsCommitRequest {
|
||||
&self.state.request
|
||||
@@ -119,14 +110,18 @@ where
|
||||
|
||||
/// Accepts the proposed protocol configuration.
|
||||
#[instrument(parent = &self.span, level = "info", skip_all, err)]
|
||||
pub async fn accept(self) -> Result<Verifier<state::CommitAccepted<Io>>, VerifierError> {
|
||||
let state::CommitStart {
|
||||
mut mux_fut,
|
||||
mut ctx,
|
||||
request,
|
||||
} = self.state;
|
||||
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;
|
||||
|
||||
mux_fut.poll_with(ctx.io_mut().send(Response::ok())).await?;
|
||||
ctx.io_mut().send(Response::ok()).await.map_err(|e| {
|
||||
Error::io()
|
||||
.with_msg("commitment protocol failed to send acceptance")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
let TlsCommitProtocolConfig::Mpc(mpc_tls_config) = request.protocol().clone() else {
|
||||
unreachable!("only MPC TLS is supported");
|
||||
@@ -135,66 +130,64 @@ where
|
||||
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()?;
|
||||
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 vm_lock = vm.try_lock().expect("VM is not locked");
|
||||
translate_keys(&mut keys, &vm_lock);
|
||||
drop(vm_lock);
|
||||
|
||||
debug!("setting up mpc-tls");
|
||||
|
||||
mux_fut.poll_with(mpc_tls.preprocess()).await?;
|
||||
mpc_tls.preprocess().await.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("commitment protocol failed during mpc-tls preprocessing")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
debug!("mpc-tls setup complete");
|
||||
|
||||
Ok(Verifier {
|
||||
config: self.config,
|
||||
span: self.span,
|
||||
state: state::CommitAccepted {
|
||||
mux_fut,
|
||||
mpc_tls,
|
||||
keys,
|
||||
vm,
|
||||
},
|
||||
ctx: None,
|
||||
state: state::CommitAccepted { mpc_tls, keys, vm },
|
||||
})
|
||||
}
|
||||
|
||||
/// Rejects the proposed protocol configuration.
|
||||
#[instrument(parent = &self.span, level = "info", skip_all, err)]
|
||||
pub async fn reject(self, msg: Option<&str>) -> Result<(), VerifierError> {
|
||||
let state::CommitStart {
|
||||
mut mux_fut,
|
||||
mut ctx,
|
||||
..
|
||||
} = self.state;
|
||||
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"))?;
|
||||
|
||||
mux_fut
|
||||
.poll_with(ctx.io_mut().send(Response::err(msg)))
|
||||
.await?;
|
||||
|
||||
mux_fut.close();
|
||||
mux_fut.await?;
|
||||
ctx.io_mut().send(Response::err(msg)).await.map_err(|e| {
|
||||
Error::io()
|
||||
.with_msg("commitment protocol failed to send rejection")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Io> Verifier<state::CommitAccepted<Io>>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
{
|
||||
impl Verifier<state::CommitAccepted> {
|
||||
/// 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<Io>>, VerifierError> {
|
||||
let state::CommitAccepted {
|
||||
mut mux_fut,
|
||||
mpc_tls,
|
||||
vm,
|
||||
keys,
|
||||
} = self.state;
|
||||
pub async fn run(self) -> Result<Verifier<state::Committed>> {
|
||||
let state::CommitAccepted { mpc_tls, vm, keys } = self.state;
|
||||
|
||||
info!("starting MPC-TLS");
|
||||
|
||||
let (mut ctx, tls_transcript) = mux_fut.poll_with(mpc_tls.run()).await?;
|
||||
let (mut ctx, tls_transcript) = mpc_tls.run().await.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("mpc-tls execution failed")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
info!("finished MPC-TLS");
|
||||
|
||||
@@ -203,10 +196,11 @@ where
|
||||
|
||||
debug!("finalizing mpc");
|
||||
|
||||
mux_fut
|
||||
.poll_with(vm.finalize(&mut ctx))
|
||||
.await
|
||||
.map_err(VerifierError::mpc)?;
|
||||
vm.finalize(&mut ctx).await.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("mpc finalization failed")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
debug!("mpc finalized");
|
||||
}
|
||||
@@ -226,23 +220,32 @@ where
|
||||
*tls_transcript.version(),
|
||||
tls_transcript.recv().to_vec(),
|
||||
)
|
||||
.map_err(VerifierError::zk)?;
|
||||
.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("tag verification setup failed")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
mux_fut
|
||||
.poll_with(vm.execute_all(&mut ctx).map_err(VerifierError::zk))
|
||||
.await?;
|
||||
vm.execute_all(&mut ctx).await.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("tag verification zk execution failed")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
// Verify the tags.
|
||||
// After the verification, the entire TLS trancript becomes
|
||||
// authenticated from the verifier's perspective.
|
||||
tag_proof.verify().map_err(VerifierError::zk)?;
|
||||
tag_proof.verify().map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("tag verification failed")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
Ok(Verifier {
|
||||
config: self.config,
|
||||
span: self.span,
|
||||
ctx: Some(ctx),
|
||||
state: state::Committed {
|
||||
mux_fut,
|
||||
ctx,
|
||||
vm,
|
||||
keys,
|
||||
tls_transcript,
|
||||
@@ -251,10 +254,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Io> Verifier<state::Committed<Io>>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
{
|
||||
impl Verifier<state::Committed> {
|
||||
/// Returns the TLS transcript.
|
||||
pub fn tls_transcript(&self) -> &TlsTranscript {
|
||||
&self.state.tls_transcript
|
||||
@@ -262,10 +262,12 @@ where
|
||||
|
||||
/// Begins verification of statements from the prover.
|
||||
#[instrument(parent = &self.span, level = "info", skip_all, err)]
|
||||
pub async fn verify(self) -> Result<Verifier<state::Verify<Io>>, VerifierError> {
|
||||
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"))?;
|
||||
let state::Committed {
|
||||
mut mux_fut,
|
||||
mut ctx,
|
||||
vm,
|
||||
keys,
|
||||
tls_transcript,
|
||||
@@ -275,16 +277,17 @@ where
|
||||
request,
|
||||
handshake,
|
||||
transcript,
|
||||
} = mux_fut
|
||||
.poll_with(ctx.io_mut().expect_next().map_err(VerifierError::from))
|
||||
.await?;
|
||||
} = ctx.io_mut().expect_next().await.map_err(|e| {
|
||||
Error::io()
|
||||
.with_msg("verification failed to receive prove request")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
Ok(Verifier {
|
||||
config: self.config,
|
||||
span: self.span,
|
||||
ctx: Some(ctx),
|
||||
state: state::Verify {
|
||||
mux_fut,
|
||||
ctx,
|
||||
vm,
|
||||
keys,
|
||||
tls_transcript,
|
||||
@@ -297,31 +300,24 @@ where
|
||||
|
||||
/// Closes the connection with the prover.
|
||||
#[instrument(parent = &self.span, level = "info", skip_all, err)]
|
||||
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)
|
||||
pub async fn close(self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Io> Verifier<state::Verify<Io>>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
{
|
||||
impl Verifier<state::Verify> {
|
||||
/// Returns the proving request.
|
||||
pub fn request(&self) -> &ProveRequest {
|
||||
&self.state.request
|
||||
}
|
||||
|
||||
/// Accepts the proving request.
|
||||
pub async fn accept(
|
||||
self,
|
||||
) -> Result<(VerifierOutput, Verifier<state::Committed<Io>>), VerifierError> {
|
||||
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"))?;
|
||||
let state::Verify {
|
||||
mut mux_fut,
|
||||
mut ctx,
|
||||
mut vm,
|
||||
keys,
|
||||
tls_transcript,
|
||||
@@ -330,32 +326,37 @@ where
|
||||
transcript,
|
||||
} = self.state;
|
||||
|
||||
mux_fut.poll_with(ctx.io_mut().send(Response::ok())).await?;
|
||||
ctx.io_mut().send(Response::ok()).await.map_err(|e| {
|
||||
Error::io()
|
||||
.with_msg("verification failed to send acceptance")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
let cert_verifier =
|
||||
ServerCertVerifier::new(self.config.root_store()).map_err(VerifierError::config)?;
|
||||
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 output = mux_fut
|
||||
.poll_with(verify::verify(
|
||||
&mut ctx,
|
||||
&mut vm,
|
||||
&keys,
|
||||
&cert_verifier,
|
||||
&tls_transcript,
|
||||
request,
|
||||
handshake,
|
||||
transcript,
|
||||
))
|
||||
.await?;
|
||||
let output = 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,
|
||||
@@ -365,29 +366,29 @@ where
|
||||
}
|
||||
|
||||
/// Rejects the proving request.
|
||||
pub async fn reject(
|
||||
self,
|
||||
msg: Option<&str>,
|
||||
) -> Result<Verifier<state::Committed<Io>>, VerifierError> {
|
||||
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"))?;
|
||||
let state::Verify {
|
||||
mut mux_fut,
|
||||
mut ctx,
|
||||
vm,
|
||||
keys,
|
||||
tls_transcript,
|
||||
..
|
||||
} = self.state;
|
||||
|
||||
mux_fut
|
||||
.poll_with(ctx.io_mut().send(Response::err(msg)))
|
||||
.await?;
|
||||
ctx.io_mut().send(Response::err(msg)).await.map_err(|e| {
|
||||
Error::io()
|
||||
.with_msg("verification failed to send rejection")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
Ok(Verifier {
|
||||
config: self.config,
|
||||
span: self.span,
|
||||
ctx: Some(ctx),
|
||||
state: state::Committed {
|
||||
mux_fut,
|
||||
ctx,
|
||||
vm,
|
||||
keys,
|
||||
tls_transcript,
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
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},
|
||||
@@ -24,40 +22,33 @@ pub struct Initialized;
|
||||
opaque_debug::implement!(Initialized);
|
||||
|
||||
/// State after receiving protocol configuration from the prover.
|
||||
pub struct CommitStart<Io> {
|
||||
pub(crate) mux_fut: MuxFuture<Io>,
|
||||
pub(crate) ctx: Context,
|
||||
pub struct CommitStart {
|
||||
pub(crate) request: TlsCommitRequest,
|
||||
}
|
||||
|
||||
opaque_debug::implement!(CommitStart<Io>);
|
||||
opaque_debug::implement!(CommitStart);
|
||||
|
||||
/// State after accepting the proposed TLS commitment protocol configuration and
|
||||
/// performing preprocessing.
|
||||
pub struct CommitAccepted<Io> {
|
||||
pub(crate) mux_fut: MuxFuture<Io>,
|
||||
pub struct CommitAccepted {
|
||||
pub(crate) mpc_tls: MpcTlsFollower,
|
||||
pub(crate) keys: SessionKeys,
|
||||
pub(crate) vm: Arc<Mutex<Deap<VerifierMpc, VerifierZk>>>,
|
||||
}
|
||||
|
||||
opaque_debug::implement!(CommitAccepted<Io>);
|
||||
opaque_debug::implement!(CommitAccepted);
|
||||
|
||||
/// State after the TLS transcript has been committed.
|
||||
pub struct Committed<Io> {
|
||||
pub(crate) mux_fut: MuxFuture<Io>,
|
||||
pub(crate) ctx: Context,
|
||||
pub struct Committed {
|
||||
pub(crate) vm: VerifierZk,
|
||||
pub(crate) keys: SessionKeys,
|
||||
pub(crate) tls_transcript: TlsTranscript,
|
||||
}
|
||||
|
||||
opaque_debug::implement!(Committed<Io>);
|
||||
opaque_debug::implement!(Committed);
|
||||
|
||||
/// State after receiving a proving request.
|
||||
pub struct Verify<Io> {
|
||||
pub(crate) mux_fut: MuxFuture<Io>,
|
||||
pub(crate) ctx: Context,
|
||||
pub struct Verify {
|
||||
pub(crate) vm: VerifierZk,
|
||||
pub(crate) keys: SessionKeys,
|
||||
pub(crate) tls_transcript: TlsTranscript,
|
||||
@@ -66,19 +57,19 @@ pub struct Verify<Io> {
|
||||
pub(crate) transcript: Option<PartialTranscript>,
|
||||
}
|
||||
|
||||
opaque_debug::implement!(Verify<Io>);
|
||||
opaque_debug::implement!(Verify);
|
||||
|
||||
impl VerifierState for Initialized {}
|
||||
impl<Io> VerifierState for CommitStart<Io> {}
|
||||
impl<Io> VerifierState for CommitAccepted<Io> {}
|
||||
impl<Io> VerifierState for Committed<Io> {}
|
||||
impl<Io> VerifierState for Verify<Io> {}
|
||||
impl VerifierState for CommitStart {}
|
||||
impl VerifierState for CommitAccepted {}
|
||||
impl VerifierState for Committed {}
|
||||
impl VerifierState for Verify {}
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
impl Sealed for super::Initialized {}
|
||||
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> {}
|
||||
impl Sealed for super::CommitStart {}
|
||||
impl Sealed for super::CommitAccepted {}
|
||||
impl Sealed for super::Committed {}
|
||||
impl Sealed for super::Verify {}
|
||||
}
|
||||
|
||||
@@ -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,35 +28,33 @@ pub(crate) async fn verify<T: Vm<Binary> + Send + Sync>(
|
||||
request: ProveRequest,
|
||||
handshake: Option<(ServerName, HandshakeData)>,
|
||||
transcript: Option<PartialTranscript>,
|
||||
) -> Result<VerifierOutput, VerifierError> {
|
||||
) -> Result<VerifierOutput> {
|
||||
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(VerifierError::verify(
|
||||
"prover requested to reveal data but did not send transcript",
|
||||
return Err(Error::internal().with_msg(
|
||||
"verification failed: 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(VerifierError::verify(
|
||||
"prover sent transcript with incorrect length",
|
||||
));
|
||||
return Err(
|
||||
Error::internal().with_msg("verification failed: transcript length mismatch")
|
||||
);
|
||||
}
|
||||
|
||||
if transcript.sent_authed() != auth_sent {
|
||||
return Err(VerifierError::verify(
|
||||
"prover sent transcript with incorrect sent authed data",
|
||||
));
|
||||
return Err(Error::internal().with_msg("verification failed: sent auth data mismatch"));
|
||||
}
|
||||
|
||||
if transcript.received_authed() != auth_recv {
|
||||
return Err(VerifierError::verify(
|
||||
"prover sent transcript with incorrect received authed data",
|
||||
));
|
||||
return Err(
|
||||
Error::internal().with_msg("verification failed: received auth data mismatch")
|
||||
);
|
||||
}
|
||||
|
||||
transcript
|
||||
@@ -72,7 +70,11 @@ pub(crate) async fn verify<T: Vm<Binary> + Send + Sync>(
|
||||
tls_transcript.server_ephemeral_key(),
|
||||
&name,
|
||||
)
|
||||
.map_err(VerifierError::verify)?;
|
||||
.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("verification failed: certificate verification failed")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
Some(name)
|
||||
} else {
|
||||
@@ -102,7 +104,11 @@ pub(crate) async fn verify<T: Vm<Binary> + Send + Sync>(
|
||||
transcript.sent_authed(),
|
||||
&commit_sent,
|
||||
)
|
||||
.map_err(VerifierError::zk)?;
|
||||
.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("verification failed during sent plaintext verification")
|
||||
.with_source(e)
|
||||
})?;
|
||||
let (recv_refs, recv_proof) = verify_plaintext(
|
||||
vm,
|
||||
keys.server_write_key,
|
||||
@@ -116,7 +122,11 @@ pub(crate) async fn verify<T: Vm<Binary> + Send + Sync>(
|
||||
transcript.received_authed(),
|
||||
&commit_recv,
|
||||
)
|
||||
.map_err(VerifierError::zk)?;
|
||||
.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("verification failed during received plaintext verification")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
let transcript_refs = TranscriptRefs {
|
||||
sent: sent_refs,
|
||||
@@ -129,18 +139,37 @@ 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(VerifierError::verify)?,
|
||||
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)
|
||||
})?,
|
||||
);
|
||||
}
|
||||
|
||||
vm.execute_all(ctx).await.map_err(VerifierError::zk)?;
|
||||
vm.execute_all(ctx).await.map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("verification failed during zk execution")
|
||||
.with_source(e)
|
||||
})?;
|
||||
|
||||
sent_proof.verify().map_err(VerifierError::verify)?;
|
||||
recv_proof.verify().map_err(VerifierError::verify)?;
|
||||
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)
|
||||
})?;
|
||||
|
||||
if let Some(hash_commitments) = hash_commitments {
|
||||
for commitment in hash_commitments.try_recv().map_err(VerifierError::verify)? {
|
||||
for commitment in hash_commitments.try_recv().map_err(|e| {
|
||||
Error::internal()
|
||||
.with_msg("verification failed during hash commitment finalization")
|
||||
.with_source(e)
|
||||
})? {
|
||||
transcript_commitments.push(TranscriptCommitment::Hash(commitment));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use futures::{AsyncReadExt, AsyncWriteExt};
|
||||
use tlsn::{
|
||||
Session,
|
||||
config::{
|
||||
prove::ProveConfig,
|
||||
prover::ProverConfig,
|
||||
@@ -18,9 +19,7 @@ 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;
|
||||
@@ -37,9 +36,34 @@ 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!(prover(socket_0), verifier(socket_1));
|
||||
tokio::join!(run_prover(prover), run_verifier(verifier));
|
||||
|
||||
session_p_handle.close();
|
||||
session_v_handle.close();
|
||||
|
||||
let partial_transcript = verifier_output.transcript.unwrap();
|
||||
let ServerName::Dns(server_name) = verifier_output.server_name.unwrap();
|
||||
@@ -56,15 +80,12 @@ async fn test() {
|
||||
);
|
||||
}
|
||||
|
||||
#[instrument(skip(verifier_socket))]
|
||||
async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
verifier_socket: T,
|
||||
) -> (Transcript, ProverOutput) {
|
||||
async fn run_prover(prover: Prover) -> (Transcript, ProverOutput) {
|
||||
let (client_socket, server_socket) = tokio::io::duplex(2 << 16);
|
||||
|
||||
let server_task = tokio::spawn(bind(server_socket.compat()));
|
||||
|
||||
let prover = Prover::new(ProverConfig::builder().build().unwrap())
|
||||
let prover = prover
|
||||
.commit(
|
||||
TlsCommitConfig::builder()
|
||||
.protocol(
|
||||
@@ -78,7 +99,6 @@ async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
)
|
||||
.build()
|
||||
.unwrap(),
|
||||
verifier_socket.compat(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -150,21 +170,9 @@ async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
(transcript, output)
|
||||
}
|
||||
|
||||
#[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(),
|
||||
);
|
||||
|
||||
async fn run_verifier(verifier: Verifier) -> VerifierOutput {
|
||||
let verifier = verifier
|
||||
.commit(socket.compat())
|
||||
.commit()
|
||||
.await
|
||||
.unwrap()
|
||||
.accept()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tlsn-wasm"
|
||||
version = "0.1.0-alpha.14-pre"
|
||||
version = "0.1.0-alpha.14"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/tlsnotary/tlsn.git"
|
||||
description = "A core WebAssembly package for TLSNotary."
|
||||
@@ -26,6 +26,7 @@ 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 }
|
||||
|
||||
@@ -16,6 +16,7 @@ use tlsn::{
|
||||
connection::ServerName,
|
||||
prover::{state, Prover},
|
||||
webpki::{CertificateDer, PrivateKeyDer, RootCertStore},
|
||||
Session, SessionHandle,
|
||||
};
|
||||
use tracing::info;
|
||||
use wasm_bindgen::{prelude::*, JsError};
|
||||
@@ -32,16 +33,34 @@ pub struct JsProver {
|
||||
state: State,
|
||||
}
|
||||
|
||||
#[derive(Debug, EnumTryAsInner)]
|
||||
#[derive(EnumTryAsInner)]
|
||||
#[derive_err(Debug)]
|
||||
enum State {
|
||||
Initialized(Prover<state::Initialized>),
|
||||
CommitAccepted(Prover<state::CommitAccepted>),
|
||||
Committed(Prover<state::Committed>),
|
||||
Initialized,
|
||||
CommitAccepted {
|
||||
prover: Prover<state::CommitAccepted>,
|
||||
handle: SessionHandle,
|
||||
},
|
||||
Committed {
|
||||
prover: Prover<state::Committed>,
|
||||
handle: SessionHandle,
|
||||
},
|
||||
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)
|
||||
@@ -54,9 +73,7 @@ impl JsProver {
|
||||
pub fn new(config: ProverConfig) -> Result<JsProver> {
|
||||
Ok(JsProver {
|
||||
config,
|
||||
state: State::Initialized(Prover::new(
|
||||
tlsn::config::prover::ProverConfig::builder().build()?,
|
||||
)),
|
||||
state: State::Initialized,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -65,9 +82,11 @@ 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 prover = self.state.take().try_into_initialized()?;
|
||||
let State::Initialized = self.state.take() else {
|
||||
return Err(JsError::new("prover is not in initialized state"));
|
||||
};
|
||||
|
||||
let config = TlsCommitConfig::builder()
|
||||
let tls_commit_config = TlsCommitConfig::builder()
|
||||
.protocol({
|
||||
let mut builder = MpcTlsConfig::builder()
|
||||
.max_sent_data(self.config.max_sent_data)
|
||||
@@ -99,9 +118,23 @@ impl JsProver {
|
||||
|
||||
info!("connected to verifier");
|
||||
|
||||
let prover = prover.commit(config, verifier_conn.into_io()).await?;
|
||||
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}");
|
||||
}
|
||||
});
|
||||
|
||||
self.state = State::CommitAccepted(prover);
|
||||
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 };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -112,7 +145,9 @@ impl JsProver {
|
||||
ws_proxy_url: &str,
|
||||
request: HttpRequest,
|
||||
) -> Result<HttpResponse> {
|
||||
let prover = self.state.take().try_into_commit_accepted()?;
|
||||
let State::CommitAccepted { prover, handle } = self.state.take() else {
|
||||
return Err(JsError::new("prover is not in commit accepted state"));
|
||||
};
|
||||
|
||||
let mut builder = TlsClientConfig::builder()
|
||||
.server_name(ServerName::Dns(
|
||||
@@ -140,7 +175,7 @@ impl JsProver {
|
||||
builder = builder.client_auth((certs, key));
|
||||
}
|
||||
|
||||
let config = builder.build()?;
|
||||
let tls_config = builder.build()?;
|
||||
|
||||
info!("connecting to server");
|
||||
|
||||
@@ -148,32 +183,39 @@ impl JsProver {
|
||||
|
||||
info!("connected to server");
|
||||
|
||||
let (tls_conn, prover_fut) = prover.connect(config, server_conn.into_io()).await?;
|
||||
let (tls_conn, prover_fut) = prover
|
||||
.connect(tls_config, server_conn.into_io())
|
||||
.await
|
||||
.map_err(|e| JsError::new(&e.to_string()))?;
|
||||
|
||||
info!("sending request");
|
||||
|
||||
let (response, prover) = futures::try_join!(
|
||||
send_request(tls_conn, request),
|
||||
prover_fut.map_err(Into::into)
|
||||
prover_fut.map_err(|e| JsError::new(&e.to_string()))
|
||||
)?;
|
||||
|
||||
info!("response received");
|
||||
|
||||
self.state = State::Committed(prover);
|
||||
self.state = State::Committed { prover, handle };
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
/// Returns the transcript.
|
||||
pub fn transcript(&self) -> Result<Transcript> {
|
||||
let prover = self.state.try_as_committed()?;
|
||||
let State::Committed { prover, .. } = &self.state else {
|
||||
return Err(JsError::new("prover is not in committed state"));
|
||||
};
|
||||
|
||||
Ok(Transcript::from(prover.transcript()))
|
||||
}
|
||||
|
||||
/// Reveals data to the verifier and finalizes the protocol.
|
||||
pub async fn reveal(&mut self, reveal: Reveal) -> Result<()> {
|
||||
let mut prover = self.state.take().try_into_committed()?;
|
||||
let State::Committed { mut prover, handle } = self.state.take() else {
|
||||
return Err(JsError::new("prover is not in committed state"));
|
||||
};
|
||||
|
||||
info!("revealing data");
|
||||
|
||||
@@ -193,8 +235,16 @@ impl JsProver {
|
||||
|
||||
let config = builder.build()?;
|
||||
|
||||
prover.prove(&config).await?;
|
||||
prover.close().await?;
|
||||
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();
|
||||
|
||||
info!("Finalized");
|
||||
|
||||
|
||||
@@ -9,10 +9,12 @@ use tlsn::{
|
||||
transcript::ContentType,
|
||||
verifier::{state, Verifier},
|
||||
webpki::RootCertStore,
|
||||
Session, SessionHandle,
|
||||
};
|
||||
use tracing::info;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use ws_stream_wasm::{WsMeta, WsStream};
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use ws_stream_wasm::WsMeta;
|
||||
|
||||
use crate::types::VerifierOutput;
|
||||
|
||||
@@ -27,15 +29,23 @@ pub struct JsVerifier {
|
||||
#[derive(EnumTryAsInner)]
|
||||
#[derive_err(Debug)]
|
||||
enum State {
|
||||
Initialized(Verifier<state::Initialized>),
|
||||
Connected((Verifier<state::Initialized>, WsStream)),
|
||||
Initialized,
|
||||
Connected {
|
||||
verifier: Verifier<state::Initialized>,
|
||||
handle: SessionHandle,
|
||||
},
|
||||
Complete,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "State")
|
||||
match self {
|
||||
State::Initialized => write!(f, "Initialized"),
|
||||
State::Connected { .. } => write!(f, "Connected"),
|
||||
State::Complete => write!(f, "Complete"),
|
||||
State::Error => write!(f, "Error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,19 +59,17 @@ 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(Verifier::new(tlsn_config)),
|
||||
state: State::Initialized,
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
/// Connect to the prover.
|
||||
pub async fn connect(&mut self, prover_url: &str) -> Result<()> {
|
||||
let verifier = self.state.take().try_into_initialized()?;
|
||||
let State::Initialized = self.state.take() else {
|
||||
return Err(JsError::new("verifier is not in initialized state"));
|
||||
};
|
||||
|
||||
info!("Connecting to prover");
|
||||
|
||||
@@ -69,40 +77,75 @@ impl JsVerifier {
|
||||
|
||||
info!("Connected to prover");
|
||||
|
||||
self.state = State::Connected((verifier, prover_conn));
|
||||
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 };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verifies the connection and finalizes the protocol.
|
||||
pub async fn verify(&mut self) -> Result<VerifierOutput> {
|
||||
let (verifier, prover_conn) = self.state.take().try_into_connected()?;
|
||||
let State::Connected { verifier, handle } = self.state.take() else {
|
||||
return Err(JsError::new("verifier is not in connected state"));
|
||||
};
|
||||
|
||||
let verifier = verifier.commit(prover_conn.into_io()).await?;
|
||||
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 request = verifier.request();
|
||||
|
||||
let TlsCommitProtocolConfig::Mpc(mpc_tls_config) = request.protocol() else {
|
||||
unimplemented!("only MPC protocol is supported");
|
||||
return Err(JsError::new("only MPC protocol is supported"));
|
||||
};
|
||||
|
||||
let reject = if mpc_tls_config.max_sent_data() > self.config.max_sent_data {
|
||||
let reject = if mpc_tls_config.max_sent_data() > max_sent_data {
|
||||
Some("max_sent_data is too large")
|
||||
} else if mpc_tls_config.max_recv_data() > self.config.max_recv_data {
|
||||
} else if mpc_tls_config.max_recv_data() > max_recv_data {
|
||||
Some("max_recv_data is too large")
|
||||
} else if mpc_tls_config.max_sent_records() > self.config.max_sent_records {
|
||||
} else if mpc_tls_config.max_sent_records() > max_sent_records {
|
||||
Some("max_sent_records is too large")
|
||||
} else if mpc_tls_config.max_recv_records_online() > self.config.max_recv_records_online {
|
||||
} else if mpc_tls_config.max_recv_records_online() > max_recv_records_online {
|
||||
Some("max_recv_records_online is too large")
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if reject.is_some() {
|
||||
verifier.reject(reject).await?;
|
||||
verifier
|
||||
.reject(reject)
|
||||
.await
|
||||
.map_err(|e| JsError::new(&e.to_string()))?;
|
||||
return Err(JsError::new("protocol configuration rejected"));
|
||||
}
|
||||
|
||||
let verifier = verifier.accept().await?.run().await?;
|
||||
let verifier = verifier
|
||||
.accept()
|
||||
.await
|
||||
.map_err(|e| JsError::new(&e.to_string()))?
|
||||
.run()
|
||||
.await
|
||||
.map_err(|e| JsError::new(&e.to_string()))?;
|
||||
|
||||
let sent = verifier
|
||||
.tls_transcript()
|
||||
@@ -129,8 +172,19 @@ impl JsVerifier {
|
||||
},
|
||||
};
|
||||
|
||||
let (output, verifier) = verifier.verify().await?.accept().await?;
|
||||
verifier.close().await?;
|
||||
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();
|
||||
|
||||
self.state = State::Complete;
|
||||
|
||||
@@ -139,8 +193,8 @@ impl JsVerifier {
|
||||
let ServerName::Dns(name) = name;
|
||||
name.to_string()
|
||||
}),
|
||||
connection_info: connection_info.into(),
|
||||
transcript: output.transcript.map(|t| t.into()),
|
||||
connection_info: crate::types::ConnectionInfo::from(connection_info),
|
||||
transcript: output.transcript.map(crate::types::PartialTranscript::from),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user