mirror of
https://github.com/tlsnotary/tlsn.git
synced 2026-01-08 21:08:04 -05:00
add example of presentation verification with no syscalls
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -7264,6 +7264,7 @@ dependencies = [
|
||||
"alloy-signer",
|
||||
"alloy-signer-local",
|
||||
"bcs",
|
||||
"bincode 1.3.3",
|
||||
"blake3",
|
||||
"k256",
|
||||
"opaque-debug",
|
||||
|
||||
@@ -26,6 +26,7 @@ tiny-keccak = { workspace = true, features = ["keccak"] }
|
||||
alloy-primitives = { version = "1.3.1", default-features = false }
|
||||
alloy-signer = { version = "1.0", default-features = false }
|
||||
alloy-signer-local = { version = "1.0", default-features = false }
|
||||
bincode = { workspace = true }
|
||||
rand06-compat = { workspace = true }
|
||||
rstest = { workspace = true }
|
||||
tlsn-core = { workspace = true, features = ["fixtures"] }
|
||||
@@ -37,3 +38,11 @@ workspace = true
|
||||
[[test]]
|
||||
name = "api"
|
||||
required-features = ["fixtures"]
|
||||
|
||||
[[example]]
|
||||
name = "prover_tcp"
|
||||
required-features = ["fixtures"]
|
||||
|
||||
[[example]]
|
||||
name = "verifier_tcp"
|
||||
required-features = ["fixtures"]
|
||||
|
||||
132
crates/attestation/examples/prover_tcp.rs
Normal file
132
crates/attestation/examples/prover_tcp.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
//! Prover that creates a presentation and sends it over TCP.
|
||||
//! Compiled with normal getrandom.
|
||||
|
||||
use std::io::Write;
|
||||
use std::net::TcpListener;
|
||||
|
||||
use tlsn_attestation::{
|
||||
Attestation, AttestationConfig, CryptoProvider,
|
||||
request::{Request, RequestConfig},
|
||||
signing::SignatureAlgId,
|
||||
};
|
||||
use tlsn_core::{
|
||||
connection::{CertBinding, CertBindingV1_2},
|
||||
fixtures::{self, ConnectionFixture, encoder_secret},
|
||||
hash::Blake3,
|
||||
transcript::{
|
||||
Direction, Transcript, TranscriptCommitConfigBuilder, TranscriptCommitment,
|
||||
TranscriptSecret,
|
||||
encoding::{EncodingCommitment, EncodingTree},
|
||||
},
|
||||
};
|
||||
use tlsn_data_fixtures::http::{request::GET_WITH_HEADER, response::OK_JSON};
|
||||
|
||||
fn main() {
|
||||
let mut provider = CryptoProvider::default();
|
||||
provider.signer.set_secp256k1(&[42u8; 32]).unwrap();
|
||||
|
||||
let transcript = Transcript::new(GET_WITH_HEADER, OK_JSON);
|
||||
let (sent_len, recv_len) = transcript.len();
|
||||
let encodings_provider = fixtures::encoding_provider(GET_WITH_HEADER, OK_JSON);
|
||||
|
||||
let ConnectionFixture {
|
||||
server_name,
|
||||
connection_info,
|
||||
server_cert_data,
|
||||
} = ConnectionFixture::tlsnotary(transcript.length());
|
||||
|
||||
let CertBinding::V1_2(CertBindingV1_2 {
|
||||
server_ephemeral_key,
|
||||
..
|
||||
}) = server_cert_data.binding.clone()
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let mut transcript_commitment_builder = TranscriptCommitConfigBuilder::new(&transcript);
|
||||
transcript_commitment_builder
|
||||
.commit_sent(&(0..sent_len))
|
||||
.unwrap()
|
||||
.commit_recv(&(0..recv_len))
|
||||
.unwrap();
|
||||
|
||||
let transcripts_commitment_config = transcript_commitment_builder.build().unwrap();
|
||||
|
||||
let encoding_tree = EncodingTree::new(
|
||||
&Blake3::default(),
|
||||
transcripts_commitment_config.iter_encoding(),
|
||||
&encodings_provider,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let encoding_commitment = EncodingCommitment {
|
||||
root: encoding_tree.root(),
|
||||
};
|
||||
|
||||
let request_config = RequestConfig::default();
|
||||
let mut request_builder = Request::builder(&request_config);
|
||||
|
||||
request_builder
|
||||
.server_name(server_name.clone())
|
||||
.handshake_data(server_cert_data)
|
||||
.transcript(transcript)
|
||||
.transcript_commitments(
|
||||
vec![TranscriptSecret::Encoding(encoding_tree)],
|
||||
vec![TranscriptCommitment::Encoding(encoding_commitment.clone())],
|
||||
);
|
||||
|
||||
let (request, secrets) = request_builder.build(&provider).unwrap();
|
||||
|
||||
let attestation_config = AttestationConfig::builder()
|
||||
.supported_signature_algs([SignatureAlgId::SECP256K1])
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let mut attestation_builder = Attestation::builder(&attestation_config)
|
||||
.accept_request(request.clone())
|
||||
.unwrap();
|
||||
|
||||
attestation_builder
|
||||
.connection_info(connection_info.clone())
|
||||
.server_ephemeral_key(server_ephemeral_key)
|
||||
.encoder_secret(encoder_secret())
|
||||
.transcript_commitments(vec![TranscriptCommitment::Encoding(encoding_commitment)]);
|
||||
|
||||
let attestation = attestation_builder.build(&provider).unwrap();
|
||||
request.validate(&attestation, &provider).unwrap();
|
||||
|
||||
let mut transcript_proof_builder = secrets.transcript_proof_builder();
|
||||
transcript_proof_builder
|
||||
.reveal(&(0..sent_len), Direction::Sent)
|
||||
.unwrap();
|
||||
transcript_proof_builder
|
||||
.reveal(&(0..recv_len), Direction::Received)
|
||||
.unwrap();
|
||||
|
||||
let transcript_proof = transcript_proof_builder.build().unwrap();
|
||||
|
||||
let mut builder = attestation.presentation_builder(&provider);
|
||||
builder.identity_proof(secrets.identity_proof());
|
||||
builder.transcript_proof(transcript_proof);
|
||||
|
||||
let presentation = builder.build().unwrap();
|
||||
|
||||
// Serialize presentation
|
||||
let presentation_bytes = bincode::serialize(&presentation).unwrap();
|
||||
|
||||
// Send over TCP
|
||||
let listener = TcpListener::bind("127.0.0.1:19844").unwrap();
|
||||
println!("Prover listening on 127.0.0.1:19844");
|
||||
println!("Presentation size: {} bytes", presentation_bytes.len());
|
||||
|
||||
let (mut stream, _) = listener.accept().unwrap();
|
||||
println!("Verifier connected, sending presentation...");
|
||||
|
||||
// Send length first, then data
|
||||
let len = presentation_bytes.len() as u32;
|
||||
stream.write_all(&len.to_be_bytes()).unwrap();
|
||||
stream.write_all(&presentation_bytes).unwrap();
|
||||
stream.flush().unwrap();
|
||||
|
||||
println!("Presentation sent successfully");
|
||||
}
|
||||
48
crates/attestation/examples/test_no_syscall_verify.sh
Executable file
48
crates/attestation/examples/test_no_syscall_verify.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
# Test that presentation verification works without getrandom syscalls.
|
||||
#
|
||||
# This script:
|
||||
# 1. Builds prover with normal getrandom (needs RNG for creating attestation)
|
||||
# 2. Builds verifier with getrandom_backend="unsupported" (no syscalls)
|
||||
# 3. Runs both and verifies they communicate successfully
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CRATE_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
cd "$CRATE_DIR"
|
||||
|
||||
echo "=== Building prover (normal getrandom) ==="
|
||||
cargo build --example prover_tcp --features fixtures
|
||||
|
||||
echo ""
|
||||
echo "=== Building verifier (getrandom_backend=unsupported) ==="
|
||||
RUSTFLAGS='--cfg getrandom_backend="unsupported"' cargo build --example verifier_tcp --features fixtures
|
||||
|
||||
echo ""
|
||||
echo "=== Running test ==="
|
||||
|
||||
# Start prover in background
|
||||
../../target/debug/examples/prover_tcp &
|
||||
PROVER_PID=$!
|
||||
|
||||
# Give prover time to start listening
|
||||
sleep 1
|
||||
|
||||
# Run verifier
|
||||
../../target/debug/examples/verifier_tcp
|
||||
VERIFIER_EXIT=$?
|
||||
|
||||
# Clean up
|
||||
kill $PROVER_PID 2>/dev/null || true
|
||||
|
||||
if [ $VERIFIER_EXIT -eq 0 ]; then
|
||||
echo ""
|
||||
echo "=== TEST PASSED ==="
|
||||
echo "Presentation verification works without getrandom syscalls!"
|
||||
exit 0
|
||||
else
|
||||
echo ""
|
||||
echo "=== TEST FAILED ==="
|
||||
exit 1
|
||||
fi
|
||||
39
crates/attestation/examples/verifier_tcp.rs
Normal file
39
crates/attestation/examples/verifier_tcp.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
//! Verifier that receives a presentation over TCP and verifies it.
|
||||
//! Compiled with getrandom_backend="unsupported" to prove verification
|
||||
//! doesn't need syscalls.
|
||||
|
||||
use std::io::Read;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use tlsn_attestation::{CryptoProvider, presentation::Presentation};
|
||||
|
||||
fn main() {
|
||||
println!("Verifier connecting to 127.0.0.1:19844...");
|
||||
|
||||
let mut stream = TcpStream::connect("127.0.0.1:19844").unwrap();
|
||||
println!("Connected to prover");
|
||||
|
||||
// Read length first
|
||||
let mut len_bytes = [0u8; 4];
|
||||
stream.read_exact(&mut len_bytes).unwrap();
|
||||
let len = u32::from_be_bytes(len_bytes) as usize;
|
||||
println!("Expecting {} bytes", len);
|
||||
|
||||
// Read presentation data
|
||||
let mut presentation_bytes = vec![0u8; len];
|
||||
stream.read_exact(&mut presentation_bytes).unwrap();
|
||||
println!("Received presentation");
|
||||
|
||||
// Deserialize
|
||||
let presentation: Presentation = bincode::deserialize(&presentation_bytes).unwrap();
|
||||
println!("Deserialized presentation");
|
||||
|
||||
// Verify - this should work without getrandom!
|
||||
let provider = CryptoProvider::default();
|
||||
let output = presentation.verify(&provider).unwrap();
|
||||
|
||||
println!("Verification SUCCESS!");
|
||||
println!("Server name: {:?}", output.server_name);
|
||||
println!("Transcript sent length: {}", output.transcript.as_ref().map(|t| t.sent_unsafe().len()).unwrap_or(0));
|
||||
println!("Transcript recv length: {}", output.transcript.as_ref().map(|t| t.received_unsafe().len()).unwrap_or(0));
|
||||
}
|
||||
Reference in New Issue
Block a user