Skip to content

Commit

Permalink
Use a local server (fixture) for the attestation example (#656)
Browse files Browse the repository at this point in the history
feat: use server fixture for tlsn examples + removed Discord example

The attestation example now has different modes: json, html and authenticated
  • Loading branch information
heeckhau committed Oct 29, 2024
1 parent db90e28 commit c6dc262
Show file tree
Hide file tree
Showing 14 changed files with 431 additions and 452 deletions.
10 changes: 6 additions & 4 deletions crates/examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ tlsn-prover = { workspace = true }
tlsn-utils = { workspace = true }
tlsn-verifier = { workspace = true }
tlsn-formats = { workspace = true }
tlsn-tls-core = { workspace = true }
tls-server-fixture = { workspace = true }
tlsn-server-fixture = { workspace = true }
tlsn-server-fixture-certs = { workspace = true }
spansy = { workspace = true }

bincode = { workspace = true }
chrono = { workspace = true }
clap = { version = "4.5", features = ["derive"] }
dotenv = { version = "0.15.0" }
futures = { workspace = true }
http-body-util = { workspace = true }
Expand Down Expand Up @@ -50,7 +56,3 @@ path = "attestation/verify.rs"
[[example]]
name = "interactive"
path = "interactive/interactive.rs"

[[example]]
name = "discord_dm"
path = "discord/discord_dm.rs"
10 changes: 4 additions & 6 deletions crates/examples/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# Examples

This folder contains examples showing how to use the TLSNotary protocol.
This folder contains examples demonstrating how to use the TLSNotary protocol.

* [attestation](./attestation/README.md) shows how to perform a simple notarization.
* [interactive](./interactive/README.md) interactive Prover and Verifier, without a trusted notary.
* [twitter](./twitter/README.md) shows how to notarize a Twitter DM.
* [discord](./discord/README.md) shows how to notarize a Discord DM.
* [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.

Refer to <https://docs.tlsnotary.org/quick_start/index.html> for a quick start with TLSNotary using these examples.
Refer to <https://docs.tlsnotary.org/quick_start/index.html> for a quick start guide to using TLSNotary with these examples.
89 changes: 62 additions & 27 deletions crates/examples/attestation/README.md
Original file line number Diff line number Diff line change
@@ -1,75 +1,110 @@
## Simple Attestation Example: Notarize Public Data from example.com (Rust) <a name="rust-simple"></a>

This example demonstrates the simplest possible use case for TLSNotary:
1. Fetch <https://example.com/> and acquire an attestation of its content.
2. Create a verifiable presentation using the attestation, while redacting the value of a header.
3. Verify the presentation.

### 1. Notarize <https://example.com/>
This example demonstrates the simplest possible use case for TLSNotary. A Prover notarizes data from a local test server with a local Notary.

Run the `prove` binary.
**Overview**:
1. Notarize a request and response from the test server and acquire an attestation of its content.
2. Create a redacted, verifiable presentation using the attestation.
3. Verify the presentation.

### 1. Notarize

Before starting the notarization, set up the local test server and local notary.

1. Run the test server:
```shell
PORT=4000 cargo run --bin tlsn-server-fixture
```
2. Run the notary server:
```shell
cd crates/notary/server
cargo run -r -- --tls-enabled false
```
3. Run the prove example:
```shell
SERVER_PORT=4000 cargo run --release --example attestation_prove
```

To see more details, run with additional debug information:
```shell
cargo run --release --example attestation_prove
RUST_LOG=debug,yamux=info,uid_mux=info SERVER_PORT=4000 cargo run --release --example attestation_prove
```

If the notarization was successful, you should see this output in the console:

If notarization is successful, you should see the following output in the console:
```log
Starting an MPC TLS connection with the server
Got a response from the server
Notarization completed successfully!
The attestation has been written to `example.attestation.tlsn` and the corresponding secrets to `example.secrets.tlsn`.
The attestation has been written to `example-json.attestation.tlsn` and the corresponding secrets to `example-json.secrets.tlsn`.
```

⚠️ In this simple example the `Notary` server is automatically started in the background. Note that this is for demonstration purposes only. In a real world example, the notary should be run by a trusted party. Consult the [Notary Server Docs](https://docs.tlsnotary.org/developers/notary_server.html) for more details on how to run a notary server.

### 2. Build a verifiable presentation
⚠️ Note: In this example, we run a local Notary server for demonstration purposes. In real-world applications, the Notary should be operated by a trusted third party. Refer to the [Notary Server Documentation](https://docs.tlsnotary.org/developers/notary_server.html) for more details on running a Notary server.

This will build a verifiable presentation with the `User-Agent` header redacted from the request. This presentation can be shared with any verifier you wish to present the data to.
### 2. Build a Verifiable Presentation

Run the `present` binary.
This step creates a verifiable presentation with optional redactions, which can be shared with any verifier.

Run the present example:
```shell
cargo run --release --example attestation_present
```

If successful, you should see this output in the console:
If successful, you’ll see this output in the console:

```log
Presentation built successfully!
The presentation has been written to `example.presentation.tlsn`.
The presentation has been written to `example-json.presentation.tlsn`.
```

### 3. Verify the presentation
You can create multiple presentations from the attestation and secrets in the notarization step, each with customized data redactions. You are invited to experiment!

This will read the presentation from the previous step, verify it, and print the disclosed data to console.
### 3. Verify the Presentation

Run the `verify` binary.
This step reads the presentation created above, verifies it, and prints the disclosed data to the console.

Run the verify binary:
```shell
cargo run --release --example attestation_verify
```

If successful, you should see this output in the console:

Upon success, you should see output similar to:
```log
Verifying presentation with {key algorithm} key: { hex encoded key }
**Ask yourself, do you trust this key?**
-------------------------------------------------------------------
Successfully verified that the data below came from a session with example.com at 2024-10-03 03:01:40 UTC.
Successfully verified that the data below came from a session with test-server.io at 2024-10-03 03:01:40 UTC.
Note that the data which the Prover chose not to disclose are shown as X.
Data sent:
...
```
⚠️ Notice that the presentation comes with a "verifying key". This is the key the Notary used when issuing the attestation that the presentation was built from. If you trust the Notary, or more specifically the verifying key, then you can trust that the presented data is authentic.
⚠️ The presentation includes a “verifying key,” which the Notary used when issuing the attestation. If you trust this key, you can trust the authenticity of the presented data.
### Next steps
### HTML
Try out the [Discord example](../discord/README.md) and notarize a Discord conversations.
In the example above, we notarized a JSON response. TLSNotary also supports notarizing HTML content. To run an HTML example, use:
```shell
# notarize
SERVER_PORT=4000 cargo run --release --example attestation_prove -- html
# present
cargo run --release --example attestation_present -- html
# verify
cargo run --release --example attestation_verify -- html
```
### Private Data
The examples above demonstrate how to use TLSNotary with publicly accessible data. TLSNotary can also be utilized for private data that requires authentication. To access this data, you can add the necessary headers (such as an authentication token) or cookies to your request. To run an example that uses an authentication token, execute the following command:
```shell
# notarize
SERVER_PORT=4000 cargo run --release --example attestation_prove -- authenticated
# present
cargo run --release --example attestation_present -- authenticated
# verify
cargo run --release --example attestation_verify -- authenticated
```
78 changes: 65 additions & 13 deletions crates/examples/attestation/present.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,37 @@
// attestation and the corresponding connection secrets. See the `prove.rs`
// example to learn how to acquire an attestation from a Notary.

use hyper::header;
use tlsn_core::{attestation::Attestation, presentation::Presentation, CryptoProvider, Secrets};
use tlsn_examples::ExampleType;
use tlsn_formats::http::HttpTranscript;

fn main() -> Result<(), Box<dyn std::error::Error>> {
use clap::Parser;

#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
/// What data to notarize
#[clap(default_value_t, value_enum)]
example_type: ExampleType,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();

create_presentation(&args.example_type).await
}

async fn create_presentation(example_type: &ExampleType) -> Result<(), Box<dyn std::error::Error>> {
let attestation_path = tlsn_examples::get_file_path(example_type, "attestation");
let secrets_path = tlsn_examples::get_file_path(example_type, "secrets");

// Read attestation from disk.
let attestation: Attestation =
bincode::deserialize(&std::fs::read("example.attestation.tlsn")?)?;
let attestation: Attestation = bincode::deserialize(&std::fs::read(attestation_path)?)?;

// Read secrets from disk.
let secrets: Secrets = bincode::deserialize(&std::fs::read("example.secrets.tlsn")?)?;
let secrets: Secrets = bincode::deserialize(&std::fs::read(secrets_path)?)?;

// Parse the HTTP transcript.
let transcript = HttpTranscript::parse(secrets.transcript())?;
Expand All @@ -24,16 +45,48 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
builder.reveal_sent(&request.without_data())?;
// Reveal the request target.
builder.reveal_sent(&request.request.target)?;
// Reveal all headers except the value of the User-Agent header.
// Reveal all headers except the values of User-Agent and Authorization.
for header in &request.headers {
if !header.name.as_str().eq_ignore_ascii_case("User-Agent") {
if !(header
.name
.as_str()
.eq_ignore_ascii_case(header::USER_AGENT.as_str())
|| header
.name
.as_str()
.eq_ignore_ascii_case(header::AUTHORIZATION.as_str()))
{
builder.reveal_sent(header)?;
} else {
builder.reveal_sent(&header.without_value())?;
}
}
// Reveal the entire response.
builder.reveal_recv(&transcript.responses[0])?;

// Reveal only parts of the response
let response = &transcript.responses[0];
builder.reveal_recv(&response.without_data())?;
for header in &response.headers {
builder.reveal_recv(header)?;
}

let content = &response.body.as_ref().unwrap().content;
match content {
tlsn_formats::http::BodyContent::Json(json) => {
// For experimentation, reveal the entire response or just a selection
let reveal_all = false;
if reveal_all {
builder.reveal_recv(response)?;
} else {
builder.reveal_recv(json.get("id").unwrap())?;
builder.reveal_recv(json.get("information.name").unwrap())?;
builder.reveal_recv(json.get("meta.version").unwrap())?;
}
}
tlsn_formats::http::BodyContent::Unknown(span) => {
builder.reveal_recv(span)?;
}
_ => {}
}

let transcript_proof = builder.build()?;

Expand All @@ -48,14 +101,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

let presentation: Presentation = builder.build()?;

let presentation_path = tlsn_examples::get_file_path(example_type, "presentation");

// Write the presentation to disk.
std::fs::write(
"example.presentation.tlsn",
bincode::serialize(&presentation)?,
)?;
std::fs::write(&presentation_path, bincode::serialize(&presentation)?)?;

println!("Presentation built successfully!");
println!("The presentation has been written to `example.presentation.tlsn`.");
println!("The presentation has been written to `{presentation_path}`.");

Ok(())
}
Loading

0 comments on commit c6dc262

Please sign in to comment.