-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Interactive Prover in Typescript (Verifier in Rust) (#74)
feat: interactive verifier demo * Verifier in Rust * Prover in both Rust and TypeScript/React --------- Co-authored-by: Pete Thomas <[email protected]> Co-authored-by: yuroitaki <[email protected]>
- Loading branch information
1 parent
18a30d3
commit 1ded413
Showing
20 changed files
with
1,771 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"rust-analyzer.linkedProjects": [ | ||
"interactive-demo/verifier-rs/Cargo.toml", | ||
"interactive-demo/prover-rs/Cargo.toml" | ||
], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
**/target/ | ||
**/Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Test Rust Prover | ||
|
||
1. Start the verifier: | ||
```bash | ||
cd verifier-rs; cargo run --release | ||
``` | ||
2. Run the prover: | ||
```bash | ||
cd prover-rs; cargo run --release | ||
``` | ||
|
||
# Test Browser Prover | ||
1. Start the verifier: | ||
```bash | ||
cd verifier-rs; cargo run --release | ||
``` | ||
2. Since a web browser doesn't have the ability to make TCP connection, we need to use a websocket proxy server to access <swapi.dev>. | ||
```bash | ||
cargo install wstcp | ||
|
||
wstcp --bind-addr 127.0.0.1:55688 swapi.dev:443 | ||
``` | ||
3. Run the prover | ||
1. Build tlsn-js | ||
```bash | ||
cd .. | ||
npm i | ||
npm run build | ||
npm link | ||
``` | ||
2. Build demo prover-ts | ||
```bash | ||
cd prover-ts | ||
npm i | ||
npm link | ||
npm run dev | ||
``` | ||
3. Open <http://localhost:8080/> and click **Start Prover** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
[package] | ||
name = "interactive-networked-prover" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
async-tungstenite = { version = "0.25", features = ["tokio-runtime"] } | ||
futures = "0.3" | ||
http = "1.1" | ||
http-body-util = "0.1" | ||
hyper = {version = "1.1", features = ["client", "http1"]} | ||
hyper-util = {version = "0.1", features = ["full"]} | ||
regex = "1.10.3" | ||
tokio = {version = "1", features = [ | ||
"rt", | ||
"rt-multi-thread", | ||
"macros", | ||
"net", | ||
"io-std", | ||
"fs", | ||
]} | ||
tokio-util = { version = "0.7", features = ["compat"] } | ||
tracing = "0.1.40" | ||
tracing-subscriber = { version ="0.3.18", features = ["env-filter"] } | ||
uuid = { version = "1.4.1", features = ["v4", "fast-rng"] } | ||
ws_stream_tungstenite = { version = "0.13", features = ["tokio_io"] } | ||
|
||
tlsn-core = { git = "https://github.com/tlsnotary/tlsn.git", tag = "v0.1.0-alpha.7", package = "tlsn-core" } | ||
tlsn-prover = { git = "https://github.com/tlsnotary/tlsn.git", tag = "v0.1.0-alpha.7", package = "tlsn-prover" } | ||
tlsn-common = { git = "https://github.com/tlsnotary/tlsn.git", tag = "v0.1.0-alpha.7", package = "tlsn-common" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
## Interactive Prover | ||
An implementation of the interactive prover in Rust. | ||
|
||
## Running the prover | ||
1. Configure this prover setting via the global variables defined in [main.rs](./src/main.rs) — please ensure that the hardcoded `SERVER_URL` and `VERIFICATION_SESSION_ID` have the same values on the verifier side. | ||
2. Start the prover by running the following in a terminal at the root of this crate. | ||
```bash | ||
cargo run --release | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
use async_tungstenite::{tokio::connect_async_with_config, tungstenite::protocol::WebSocketConfig}; | ||
use http_body_util::Empty; | ||
use hyper::{body::Bytes, Request, StatusCode, Uri}; | ||
use hyper_util::rt::TokioIo; | ||
use regex::Regex; | ||
use tlsn_common::config::ProtocolConfig; | ||
use tlsn_core::transcript::Idx; | ||
use tlsn_prover::{state::Prove, Prover, ProverConfig}; | ||
use tokio::io::{AsyncRead, AsyncWrite}; | ||
use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt}; | ||
use tracing::{debug, info}; | ||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; | ||
use ws_stream_tungstenite::WsStream; | ||
|
||
const TRACING_FILTER: &str = "INFO"; | ||
|
||
const VERIFIER_HOST: &str = "localhost"; | ||
const VERIFIER_PORT: u16 = 9816; | ||
// Maximum number of bytes that can be sent from prover to server | ||
const MAX_SENT_DATA: usize = 1 << 12; | ||
// Maximum number of bytes that can be received by prover from server | ||
const MAX_RECV_DATA: usize = 1 << 14; | ||
|
||
const SECRET: &str = "TLSNotary's private key 🤡"; | ||
/// Make sure the following url's domain is the same as SERVER_DOMAIN on the verifier side | ||
const SERVER_URL: &str = "https://swapi.dev/api/people/1"; | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
tracing_subscriber::registry() | ||
.with(EnvFilter::try_from_default_env().unwrap_or_else(|_| TRACING_FILTER.into())) | ||
.with(tracing_subscriber::fmt::layer()) | ||
.init(); | ||
|
||
run_prover(VERIFIER_HOST, VERIFIER_PORT, SERVER_URL).await; | ||
} | ||
|
||
async fn run_prover(verifier_host: &str, verifier_port: u16, server_uri: &str) { | ||
info!("Sending websocket request..."); | ||
let request = http::Request::builder() | ||
.uri(format!("ws://{}:{}/verify", verifier_host, verifier_port,)) | ||
.header("Host", verifier_host) | ||
.header("Sec-WebSocket-Key", uuid::Uuid::new_v4().to_string()) | ||
.header("Sec-WebSocket-Version", "13") | ||
.header("Connection", "Upgrade") | ||
.header("Upgrade", "Websocket") | ||
.body(()) | ||
.unwrap(); | ||
|
||
let (verifier_ws_stream, _) = | ||
connect_async_with_config(request, Some(WebSocketConfig::default())) | ||
.await | ||
.unwrap(); | ||
|
||
info!("Websocket connection established!"); | ||
let verifier_ws_socket = WsStream::new(verifier_ws_stream); | ||
prover(verifier_ws_socket, server_uri).await; | ||
info!("Proving is successful!"); | ||
} | ||
|
||
async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(verifier_socket: T, uri: &str) { | ||
debug!("Starting proving..."); | ||
|
||
let uri = uri.parse::<Uri>().unwrap(); | ||
assert_eq!(uri.scheme().unwrap().as_str(), "https"); | ||
let server_domain = uri.authority().unwrap().host(); | ||
let server_port = uri.port_u16().unwrap_or(443); | ||
|
||
// Create prover and connect to verifier. | ||
// | ||
// Perform the setup phase with the verifier. | ||
let prover = Prover::new( | ||
ProverConfig::builder() | ||
.server_name(server_domain) | ||
.protocol_config( | ||
ProtocolConfig::builder() | ||
.max_sent_data(MAX_SENT_DATA) | ||
.max_recv_data(MAX_RECV_DATA) | ||
.build() | ||
.unwrap(), | ||
) | ||
.build() | ||
.unwrap(), | ||
) | ||
.setup(verifier_socket.compat()) | ||
.await | ||
.unwrap(); | ||
|
||
// Connect to TLS Server. | ||
let tls_client_socket = tokio::net::TcpStream::connect((server_domain, server_port)) | ||
.await | ||
.unwrap(); | ||
|
||
// Pass server connection into the prover. | ||
let (mpc_tls_connection, prover_fut) = | ||
prover.connect(tls_client_socket.compat()).await.unwrap(); | ||
|
||
// Wrap the connection in a TokioIo compatibility layer to use it with hyper. | ||
let mpc_tls_connection = TokioIo::new(mpc_tls_connection.compat()); | ||
|
||
// Spawn the Prover to run in the background. | ||
let prover_task = tokio::spawn(prover_fut); | ||
|
||
// MPC-TLS Handshake. | ||
let (mut request_sender, connection) = | ||
hyper::client::conn::http1::handshake(mpc_tls_connection) | ||
.await | ||
.unwrap(); | ||
|
||
tokio::spawn(connection); | ||
|
||
// MPC-TLS: Send Request and wait for Response. | ||
info!("Send Request and wait for Response"); | ||
let request = Request::builder() | ||
.uri(uri.clone()) | ||
.header("Host", server_domain) | ||
.header("Connection", "close") | ||
.header("Secret", SECRET) | ||
.method("GET") | ||
.body(Empty::<Bytes>::new()) | ||
.unwrap(); | ||
let response = request_sender.send_request(request).await.unwrap(); | ||
|
||
debug!("TLS response: {:?}", response); | ||
assert!(response.status() == StatusCode::OK); | ||
|
||
// Create proof for the Verifier. | ||
let mut prover = prover_task.await.unwrap().unwrap().start_prove(); | ||
|
||
let idx_sent = redact_and_reveal_sent_data(&mut prover); | ||
let idx_recv = redact_and_reveal_received_data(&mut prover); | ||
|
||
// Reveal parts of the transcript | ||
prover.prove_transcript(idx_sent, idx_recv).await.unwrap(); | ||
|
||
// Finalize. | ||
prover.finalize().await.unwrap() | ||
} | ||
|
||
/// Redacts and reveals received data to the verifier. | ||
fn redact_and_reveal_received_data(prover: &mut Prover<Prove>) -> Idx { | ||
let recv_transcript = prover.transcript().received(); | ||
let recv_transcript_len = recv_transcript.len(); | ||
|
||
// Get the homeworld from the received data. | ||
let received_string = String::from_utf8(recv_transcript.to_vec()).unwrap(); | ||
debug!("Received data: {}", received_string); | ||
let re = Regex::new(r#""homeworld"\s?:\s?"(.*?)""#).unwrap(); | ||
let homeworld_match = re.captures(&received_string).unwrap().get(1).unwrap(); | ||
|
||
// Reveal everything except for the homeworld. | ||
let start = homeworld_match.start(); | ||
let end = homeworld_match.end(); | ||
Idx::new([0..start, end..recv_transcript_len]) | ||
} | ||
|
||
/// Redacts and reveals sent data to the verifier. | ||
fn redact_and_reveal_sent_data(prover: &mut Prover<Prove>) -> Idx { | ||
let sent_transcript = prover.transcript().sent(); | ||
let sent_transcript_len = sent_transcript.len(); | ||
|
||
let sent_string: String = String::from_utf8(sent_transcript.to_vec()).unwrap(); | ||
let secret_start = sent_string.find(SECRET).unwrap(); | ||
|
||
debug!("Send data: {}", sent_string); | ||
|
||
// Reveal everything except for the SECRET. | ||
Idx::new([ | ||
0..secret_start, | ||
secret_start + SECRET.len()..sent_transcript_len, | ||
]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package-lock.json |
Oops, something went wrong.