mirror of
https://github.com/tlsnotary/tlsn.git
synced 2026-01-09 13:27:59 -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",
|
||||||
"alloy-signer-local",
|
"alloy-signer-local",
|
||||||
"bcs",
|
"bcs",
|
||||||
|
"bincode 1.3.3",
|
||||||
"blake3",
|
"blake3",
|
||||||
"k256",
|
"k256",
|
||||||
"opaque-debug",
|
"opaque-debug",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ tiny-keccak = { workspace = true, features = ["keccak"] }
|
|||||||
alloy-primitives = { version = "1.3.1", default-features = false }
|
alloy-primitives = { version = "1.3.1", default-features = false }
|
||||||
alloy-signer = { version = "1.0", default-features = false }
|
alloy-signer = { version = "1.0", default-features = false }
|
||||||
alloy-signer-local = { version = "1.0", default-features = false }
|
alloy-signer-local = { version = "1.0", default-features = false }
|
||||||
|
bincode = { workspace = true }
|
||||||
rand06-compat = { workspace = true }
|
rand06-compat = { workspace = true }
|
||||||
rstest = { workspace = true }
|
rstest = { workspace = true }
|
||||||
tlsn-core = { workspace = true, features = ["fixtures"] }
|
tlsn-core = { workspace = true, features = ["fixtures"] }
|
||||||
@@ -37,3 +38,11 @@ workspace = true
|
|||||||
[[test]]
|
[[test]]
|
||||||
name = "api"
|
name = "api"
|
||||||
required-features = ["fixtures"]
|
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