mirror of
https://github.com/tlsnotary/tlsn.git
synced 2026-01-08 22:28:15 -05:00
fix(tlsn): do not implicitly reveal encoder secret (#1011)
This commit is contained in:
@@ -5,7 +5,7 @@ use rand::{Rng, rng};
|
|||||||
use tlsn_core::{
|
use tlsn_core::{
|
||||||
connection::{ConnectionInfo, ServerEphemKey},
|
connection::{ConnectionInfo, ServerEphemKey},
|
||||||
hash::HashAlgId,
|
hash::HashAlgId,
|
||||||
transcript::TranscriptCommitment,
|
transcript::{TranscriptCommitment, encoding::EncoderSecret},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -25,6 +25,7 @@ pub struct Sign {
|
|||||||
connection_info: Option<ConnectionInfo>,
|
connection_info: Option<ConnectionInfo>,
|
||||||
server_ephemeral_key: Option<ServerEphemKey>,
|
server_ephemeral_key: Option<ServerEphemKey>,
|
||||||
cert_commitment: ServerCertCommitment,
|
cert_commitment: ServerCertCommitment,
|
||||||
|
encoder_secret: Option<EncoderSecret>,
|
||||||
extensions: Vec<Extension>,
|
extensions: Vec<Extension>,
|
||||||
transcript_commitments: Vec<TranscriptCommitment>,
|
transcript_commitments: Vec<TranscriptCommitment>,
|
||||||
}
|
}
|
||||||
@@ -86,6 +87,7 @@ impl<'a> AttestationBuilder<'a, Accept> {
|
|||||||
connection_info: None,
|
connection_info: None,
|
||||||
server_ephemeral_key: None,
|
server_ephemeral_key: None,
|
||||||
cert_commitment,
|
cert_commitment,
|
||||||
|
encoder_secret: None,
|
||||||
transcript_commitments: Vec::new(),
|
transcript_commitments: Vec::new(),
|
||||||
extensions,
|
extensions,
|
||||||
},
|
},
|
||||||
@@ -106,6 +108,12 @@ impl AttestationBuilder<'_, Sign> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the secret for encoding commitments.
|
||||||
|
pub fn encoder_secret(&mut self, secret: EncoderSecret) -> &mut Self {
|
||||||
|
self.state.encoder_secret = Some(secret);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds an extension to the attestation.
|
/// Adds an extension to the attestation.
|
||||||
pub fn extension(&mut self, extension: Extension) -> &mut Self {
|
pub fn extension(&mut self, extension: Extension) -> &mut Self {
|
||||||
self.state.extensions.push(extension);
|
self.state.extensions.push(extension);
|
||||||
@@ -129,6 +137,7 @@ impl AttestationBuilder<'_, Sign> {
|
|||||||
connection_info,
|
connection_info,
|
||||||
server_ephemeral_key,
|
server_ephemeral_key,
|
||||||
cert_commitment,
|
cert_commitment,
|
||||||
|
encoder_secret,
|
||||||
extensions,
|
extensions,
|
||||||
transcript_commitments,
|
transcript_commitments,
|
||||||
} = self.state;
|
} = self.state;
|
||||||
@@ -159,6 +168,7 @@ impl AttestationBuilder<'_, Sign> {
|
|||||||
AttestationBuilderError::new(ErrorKind::Field, "handshake data was not set")
|
AttestationBuilderError::new(ErrorKind::Field, "handshake data was not set")
|
||||||
})?),
|
})?),
|
||||||
cert_commitment: field_id.next(cert_commitment),
|
cert_commitment: field_id.next(cert_commitment),
|
||||||
|
encoder_secret: encoder_secret.map(|secret| field_id.next(secret)),
|
||||||
extensions: extensions
|
extensions: extensions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|extension| field_id.next(extension))
|
.map(|extension| field_id.next(extension))
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ use tlsn_core::{
|
|||||||
connection::{ConnectionInfo, ServerEphemKey},
|
connection::{ConnectionInfo, ServerEphemKey},
|
||||||
hash::{Hash, HashAlgorithm, TypedHash},
|
hash::{Hash, HashAlgorithm, TypedHash},
|
||||||
merkle::MerkleTree,
|
merkle::MerkleTree,
|
||||||
transcript::TranscriptCommitment,
|
transcript::{TranscriptCommitment, encoding::EncoderSecret},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -327,6 +327,7 @@ pub struct Body {
|
|||||||
connection_info: Field<ConnectionInfo>,
|
connection_info: Field<ConnectionInfo>,
|
||||||
server_ephemeral_key: Field<ServerEphemKey>,
|
server_ephemeral_key: Field<ServerEphemKey>,
|
||||||
cert_commitment: Field<ServerCertCommitment>,
|
cert_commitment: Field<ServerCertCommitment>,
|
||||||
|
encoder_secret: Option<Field<EncoderSecret>>,
|
||||||
extensions: Vec<Field<Extension>>,
|
extensions: Vec<Field<Extension>>,
|
||||||
transcript_commitments: Vec<Field<TranscriptCommitment>>,
|
transcript_commitments: Vec<Field<TranscriptCommitment>>,
|
||||||
}
|
}
|
||||||
@@ -372,6 +373,7 @@ impl Body {
|
|||||||
connection_info: conn_info,
|
connection_info: conn_info,
|
||||||
server_ephemeral_key,
|
server_ephemeral_key,
|
||||||
cert_commitment,
|
cert_commitment,
|
||||||
|
encoder_secret,
|
||||||
extensions,
|
extensions,
|
||||||
transcript_commitments,
|
transcript_commitments,
|
||||||
} = self;
|
} = self;
|
||||||
@@ -389,6 +391,13 @@ impl Body {
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if let Some(encoder_secret) = encoder_secret {
|
||||||
|
fields.push((
|
||||||
|
encoder_secret.id,
|
||||||
|
hasher.hash_separated(&encoder_secret.data),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
for field in extensions.iter() {
|
for field in extensions.iter() {
|
||||||
fields.push((field.id, hasher.hash_separated(&field.data)));
|
fields.push((field.id, hasher.hash_separated(&field.data)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,11 @@ impl Presentation {
|
|||||||
transcript.verify_with_provider(
|
transcript.verify_with_provider(
|
||||||
&provider.hash,
|
&provider.hash,
|
||||||
&attestation.body.connection_info().transcript_length,
|
&attestation.body.connection_info().transcript_length,
|
||||||
|
attestation
|
||||||
|
.body
|
||||||
|
.encoder_secret
|
||||||
|
.as_ref()
|
||||||
|
.map(|field| &field.data),
|
||||||
attestation.body.transcript_commitments(),
|
attestation.body.transcript_commitments(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -49,5 +49,6 @@ impl_domain_separator!(tlsn_core::connection::ConnectionInfo);
|
|||||||
impl_domain_separator!(tlsn_core::connection::CertBinding);
|
impl_domain_separator!(tlsn_core::connection::CertBinding);
|
||||||
impl_domain_separator!(tlsn_core::transcript::TranscriptCommitment);
|
impl_domain_separator!(tlsn_core::transcript::TranscriptCommitment);
|
||||||
impl_domain_separator!(tlsn_core::transcript::TranscriptSecret);
|
impl_domain_separator!(tlsn_core::transcript::TranscriptSecret);
|
||||||
|
impl_domain_separator!(tlsn_core::transcript::encoding::EncoderSecret);
|
||||||
impl_domain_separator!(tlsn_core::transcript::encoding::EncodingCommitment);
|
impl_domain_separator!(tlsn_core::transcript::encoding::EncodingCommitment);
|
||||||
impl_domain_separator!(tlsn_core::transcript::hash::PlaintextHash);
|
impl_domain_separator!(tlsn_core::transcript::hash::PlaintextHash);
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ fn test_api() {
|
|||||||
|
|
||||||
let encoding_commitment = EncodingCommitment {
|
let encoding_commitment = EncodingCommitment {
|
||||||
root: encoding_tree.root(),
|
root: encoding_tree.root(),
|
||||||
secret: encoder_secret(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let request_config = RequestConfig::default();
|
let request_config = RequestConfig::default();
|
||||||
@@ -96,6 +95,7 @@ fn test_api() {
|
|||||||
.connection_info(connection_info.clone())
|
.connection_info(connection_info.clone())
|
||||||
// Server key Notary received during handshake
|
// Server key Notary received during handshake
|
||||||
.server_ephemeral_key(server_ephemeral_key)
|
.server_ephemeral_key(server_ephemeral_key)
|
||||||
|
.encoder_secret(encoder_secret())
|
||||||
.transcript_commitments(vec![TranscriptCommitment::Encoding(encoding_commitment)]);
|
.transcript_commitments(vec![TranscriptCommitment::Encoding(encoding_commitment)]);
|
||||||
|
|
||||||
let attestation = attestation_builder.build(&provider).unwrap();
|
let attestation = attestation_builder.build(&provider).unwrap();
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::{
|
use crate::{
|
||||||
connection::{HandshakeData, ServerName},
|
connection::{HandshakeData, ServerName},
|
||||||
transcript::{
|
transcript::{
|
||||||
Direction, PartialTranscript, Transcript, TranscriptCommitConfig, TranscriptCommitRequest,
|
encoding::EncoderSecret, Direction, PartialTranscript, Transcript, TranscriptCommitConfig,
|
||||||
TranscriptCommitment, TranscriptSecret,
|
TranscriptCommitRequest, TranscriptCommitment, TranscriptSecret,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -220,6 +220,8 @@ pub struct VerifierOutput {
|
|||||||
pub server_name: Option<ServerName>,
|
pub server_name: Option<ServerName>,
|
||||||
/// Transcript data.
|
/// Transcript data.
|
||||||
pub transcript: Option<PartialTranscript>,
|
pub transcript: Option<PartialTranscript>,
|
||||||
|
/// Encoding commitment secret.
|
||||||
|
pub encoder_secret: Option<EncoderSecret>,
|
||||||
/// Transcript commitments.
|
/// Transcript commitments.
|
||||||
pub transcript_commitments: Vec<TranscriptCommitment>,
|
pub transcript_commitments: Vec<TranscriptCommitment>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,4 @@ use crate::hash::TypedHash;
|
|||||||
pub struct EncodingCommitment {
|
pub struct EncodingCommitment {
|
||||||
/// Merkle root of the encoding commitments.
|
/// Merkle root of the encoding commitments.
|
||||||
pub root: TypedHash,
|
pub root: TypedHash,
|
||||||
/// Seed used to generate the encodings.
|
|
||||||
pub secret: EncoderSecret,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::{
|
|||||||
merkle::{MerkleError, MerkleProof},
|
merkle::{MerkleError, MerkleProof},
|
||||||
transcript::{
|
transcript::{
|
||||||
commit::MAX_TOTAL_COMMITTED_DATA,
|
commit::MAX_TOTAL_COMMITTED_DATA,
|
||||||
encoding::{new_encoder, Encoder, EncodingCommitment},
|
encoding::{new_encoder, Encoder, EncoderSecret, EncodingCommitment},
|
||||||
Direction,
|
Direction,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -48,13 +48,14 @@ impl EncodingProof {
|
|||||||
pub fn verify_with_provider(
|
pub fn verify_with_provider(
|
||||||
&self,
|
&self,
|
||||||
provider: &HashProvider,
|
provider: &HashProvider,
|
||||||
|
secret: &EncoderSecret,
|
||||||
commitment: &EncodingCommitment,
|
commitment: &EncodingCommitment,
|
||||||
sent: &[u8],
|
sent: &[u8],
|
||||||
recv: &[u8],
|
recv: &[u8],
|
||||||
) -> Result<(RangeSet<usize>, RangeSet<usize>), EncodingProofError> {
|
) -> Result<(RangeSet<usize>, RangeSet<usize>), EncodingProofError> {
|
||||||
let hasher = provider.get(&commitment.root.alg)?;
|
let hasher = provider.get(&commitment.root.alg)?;
|
||||||
|
|
||||||
let encoder = new_encoder(&commitment.secret);
|
let encoder = new_encoder(secret);
|
||||||
let Self {
|
let Self {
|
||||||
inclusion_proof,
|
inclusion_proof,
|
||||||
openings,
|
openings,
|
||||||
@@ -232,10 +233,7 @@ mod test {
|
|||||||
use crate::{
|
use crate::{
|
||||||
fixtures::{encoder_secret, encoder_secret_tampered_seed, encoding_provider},
|
fixtures::{encoder_secret, encoder_secret_tampered_seed, encoding_provider},
|
||||||
hash::Blake3,
|
hash::Blake3,
|
||||||
transcript::{
|
transcript::{encoding::EncodingTree, Transcript},
|
||||||
encoding::{EncoderSecret, EncodingTree},
|
|
||||||
Transcript,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -246,7 +244,7 @@ mod test {
|
|||||||
commitment: EncodingCommitment,
|
commitment: EncodingCommitment,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_encoding_fixture(secret: EncoderSecret) -> EncodingFixture {
|
fn new_encoding_fixture() -> EncodingFixture {
|
||||||
let transcript = Transcript::new(POST_JSON, OK_JSON);
|
let transcript = Transcript::new(POST_JSON, OK_JSON);
|
||||||
|
|
||||||
let idx_0 = (Direction::Sent, RangeSet::from(0..POST_JSON.len()));
|
let idx_0 = (Direction::Sent, RangeSet::from(0..POST_JSON.len()));
|
||||||
@@ -257,10 +255,7 @@ mod test {
|
|||||||
|
|
||||||
let proof = tree.proof([&idx_0, &idx_1].into_iter()).unwrap();
|
let proof = tree.proof([&idx_0, &idx_1].into_iter()).unwrap();
|
||||||
|
|
||||||
let commitment = EncodingCommitment {
|
let commitment = EncodingCommitment { root: tree.root() };
|
||||||
root: tree.root(),
|
|
||||||
secret,
|
|
||||||
};
|
|
||||||
|
|
||||||
EncodingFixture {
|
EncodingFixture {
|
||||||
transcript,
|
transcript,
|
||||||
@@ -275,11 +270,12 @@ mod test {
|
|||||||
transcript,
|
transcript,
|
||||||
proof,
|
proof,
|
||||||
commitment,
|
commitment,
|
||||||
} = new_encoding_fixture(encoder_secret_tampered_seed());
|
} = new_encoding_fixture();
|
||||||
|
|
||||||
let err = proof
|
let err = proof
|
||||||
.verify_with_provider(
|
.verify_with_provider(
|
||||||
&HashProvider::default(),
|
&HashProvider::default(),
|
||||||
|
&encoder_secret_tampered_seed(),
|
||||||
&commitment,
|
&commitment,
|
||||||
transcript.sent(),
|
transcript.sent(),
|
||||||
transcript.received(),
|
transcript.received(),
|
||||||
@@ -295,13 +291,19 @@ mod test {
|
|||||||
transcript,
|
transcript,
|
||||||
proof,
|
proof,
|
||||||
commitment,
|
commitment,
|
||||||
} = new_encoding_fixture(encoder_secret());
|
} = new_encoding_fixture();
|
||||||
|
|
||||||
let sent = &transcript.sent()[transcript.sent().len() - 1..];
|
let sent = &transcript.sent()[transcript.sent().len() - 1..];
|
||||||
let recv = &transcript.received()[transcript.received().len() - 2..];
|
let recv = &transcript.received()[transcript.received().len() - 2..];
|
||||||
|
|
||||||
let err = proof
|
let err = proof
|
||||||
.verify_with_provider(&HashProvider::default(), &commitment, sent, recv)
|
.verify_with_provider(
|
||||||
|
&HashProvider::default(),
|
||||||
|
&encoder_secret(),
|
||||||
|
&commitment,
|
||||||
|
sent,
|
||||||
|
recv,
|
||||||
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
assert!(matches!(err.kind, ErrorKind::Proof));
|
assert!(matches!(err.kind, ErrorKind::Proof));
|
||||||
@@ -313,7 +315,7 @@ mod test {
|
|||||||
transcript,
|
transcript,
|
||||||
mut proof,
|
mut proof,
|
||||||
commitment,
|
commitment,
|
||||||
} = new_encoding_fixture(encoder_secret());
|
} = new_encoding_fixture();
|
||||||
|
|
||||||
let Opening { idx, .. } = proof.openings.values_mut().next().unwrap();
|
let Opening { idx, .. } = proof.openings.values_mut().next().unwrap();
|
||||||
|
|
||||||
@@ -322,6 +324,7 @@ mod test {
|
|||||||
let err = proof
|
let err = proof
|
||||||
.verify_with_provider(
|
.verify_with_provider(
|
||||||
&HashProvider::default(),
|
&HashProvider::default(),
|
||||||
|
&encoder_secret(),
|
||||||
&commitment,
|
&commitment,
|
||||||
transcript.sent(),
|
transcript.sent(),
|
||||||
transcript.received(),
|
transcript.received(),
|
||||||
@@ -337,7 +340,7 @@ mod test {
|
|||||||
transcript,
|
transcript,
|
||||||
mut proof,
|
mut proof,
|
||||||
commitment,
|
commitment,
|
||||||
} = new_encoding_fixture(encoder_secret());
|
} = new_encoding_fixture();
|
||||||
|
|
||||||
let Opening { blinder, .. } = proof.openings.values_mut().next().unwrap();
|
let Opening { blinder, .. } = proof.openings.values_mut().next().unwrap();
|
||||||
|
|
||||||
@@ -346,6 +349,7 @@ mod test {
|
|||||||
let err = proof
|
let err = proof
|
||||||
.verify_with_provider(
|
.verify_with_provider(
|
||||||
&HashProvider::default(),
|
&HashProvider::default(),
|
||||||
|
&encoder_secret(),
|
||||||
&commitment,
|
&commitment,
|
||||||
transcript.sent(),
|
transcript.sent(),
|
||||||
transcript.received(),
|
transcript.received(),
|
||||||
|
|||||||
@@ -222,14 +222,12 @@ mod tests {
|
|||||||
|
|
||||||
let proof = tree.proof([&idx_0, &idx_1].into_iter()).unwrap();
|
let proof = tree.proof([&idx_0, &idx_1].into_iter()).unwrap();
|
||||||
|
|
||||||
let commitment = EncodingCommitment {
|
let commitment = EncodingCommitment { root: tree.root() };
|
||||||
root: tree.root(),
|
|
||||||
secret: encoder_secret(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let (auth_sent, auth_recv) = proof
|
let (auth_sent, auth_recv) = proof
|
||||||
.verify_with_provider(
|
.verify_with_provider(
|
||||||
&HashProvider::default(),
|
&HashProvider::default(),
|
||||||
|
&encoder_secret(),
|
||||||
&commitment,
|
&commitment,
|
||||||
transcript.sent(),
|
transcript.sent(),
|
||||||
transcript.received(),
|
transcript.received(),
|
||||||
@@ -260,14 +258,12 @@ mod tests {
|
|||||||
.proof([&idx_0, &idx_1, &idx_2, &idx_3].into_iter())
|
.proof([&idx_0, &idx_1, &idx_2, &idx_3].into_iter())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let commitment = EncodingCommitment {
|
let commitment = EncodingCommitment { root: tree.root() };
|
||||||
root: tree.root(),
|
|
||||||
secret: encoder_secret(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let (auth_sent, auth_recv) = proof
|
let (auth_sent, auth_recv) = proof
|
||||||
.verify_with_provider(
|
.verify_with_provider(
|
||||||
&HashProvider::default(),
|
&HashProvider::default(),
|
||||||
|
&encoder_secret(),
|
||||||
&commitment,
|
&commitment,
|
||||||
transcript.sent(),
|
transcript.sent(),
|
||||||
transcript.received(),
|
transcript.received(),
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::{
|
|||||||
hash::{HashAlgId, HashProvider},
|
hash::{HashAlgId, HashProvider},
|
||||||
transcript::{
|
transcript::{
|
||||||
commit::{TranscriptCommitment, TranscriptCommitmentKind},
|
commit::{TranscriptCommitment, TranscriptCommitmentKind},
|
||||||
encoding::{EncodingProof, EncodingProofError, EncodingTree},
|
encoding::{EncoderSecret, EncodingProof, EncodingProofError, EncodingTree},
|
||||||
hash::{hash_plaintext, PlaintextHash, PlaintextHashSecret},
|
hash::{hash_plaintext, PlaintextHash, PlaintextHashSecret},
|
||||||
Direction, PartialTranscript, RangeSet, Transcript, TranscriptSecret,
|
Direction, PartialTranscript, RangeSet, Transcript, TranscriptSecret,
|
||||||
},
|
},
|
||||||
@@ -51,6 +51,7 @@ impl TranscriptProof {
|
|||||||
self,
|
self,
|
||||||
provider: &HashProvider,
|
provider: &HashProvider,
|
||||||
length: &TranscriptLength,
|
length: &TranscriptLength,
|
||||||
|
encoder_secret: Option<&EncoderSecret>,
|
||||||
commitments: impl IntoIterator<Item = &'a TranscriptCommitment>,
|
commitments: impl IntoIterator<Item = &'a TranscriptCommitment>,
|
||||||
) -> Result<PartialTranscript, TranscriptProofError> {
|
) -> Result<PartialTranscript, TranscriptProofError> {
|
||||||
let mut encoding_commitment = None;
|
let mut encoding_commitment = None;
|
||||||
@@ -86,6 +87,13 @@ impl TranscriptProof {
|
|||||||
|
|
||||||
// Verify encoding proof.
|
// Verify encoding proof.
|
||||||
if let Some(proof) = self.encoding_proof {
|
if let Some(proof) = self.encoding_proof {
|
||||||
|
let secret = encoder_secret.ok_or_else(|| {
|
||||||
|
TranscriptProofError::new(
|
||||||
|
ErrorKind::Encoding,
|
||||||
|
"contains an encoding proof but missing encoder secret",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
let commitment = encoding_commitment.ok_or_else(|| {
|
let commitment = encoding_commitment.ok_or_else(|| {
|
||||||
TranscriptProofError::new(
|
TranscriptProofError::new(
|
||||||
ErrorKind::Encoding,
|
ErrorKind::Encoding,
|
||||||
@@ -95,6 +103,7 @@ impl TranscriptProof {
|
|||||||
|
|
||||||
let (auth_sent, auth_recv) = proof.verify_with_provider(
|
let (auth_sent, auth_recv) = proof.verify_with_provider(
|
||||||
provider,
|
provider,
|
||||||
|
secret,
|
||||||
commitment,
|
commitment,
|
||||||
self.transcript.sent_unsafe(),
|
self.transcript.sent_unsafe(),
|
||||||
self.transcript.received_unsafe(),
|
self.transcript.received_unsafe(),
|
||||||
@@ -575,7 +584,7 @@ mod tests {
|
|||||||
use tlsn_data_fixtures::http::{request::GET_WITH_HEADER, response::OK_JSON};
|
use tlsn_data_fixtures::http::{request::GET_WITH_HEADER, response::OK_JSON};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
fixtures::encoding_provider,
|
fixtures::{encoder_secret, encoding_provider},
|
||||||
hash::{Blake3, Blinder, HashAlgId},
|
hash::{Blake3, Blinder, HashAlgId},
|
||||||
transcript::TranscriptCommitConfigBuilder,
|
transcript::TranscriptCommitConfigBuilder,
|
||||||
};
|
};
|
||||||
@@ -602,7 +611,12 @@ mod tests {
|
|||||||
|
|
||||||
let provider = HashProvider::default();
|
let provider = HashProvider::default();
|
||||||
let err = transcript_proof
|
let err = transcript_proof
|
||||||
.verify_with_provider(&provider, &transcript.length(), &[])
|
.verify_with_provider(
|
||||||
|
&provider,
|
||||||
|
&transcript.length(),
|
||||||
|
Some(&encoder_secret()),
|
||||||
|
&[],
|
||||||
|
)
|
||||||
.err()
|
.err()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -676,6 +690,7 @@ mod tests {
|
|||||||
.verify_with_provider(
|
.verify_with_provider(
|
||||||
&provider,
|
&provider,
|
||||||
&transcript.length(),
|
&transcript.length(),
|
||||||
|
None,
|
||||||
&[TranscriptCommitment::Hash(commitment)],
|
&[TranscriptCommitment::Hash(commitment)],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -724,6 +739,7 @@ mod tests {
|
|||||||
.verify_with_provider(
|
.verify_with_provider(
|
||||||
&provider,
|
&provider,
|
||||||
&transcript.length(),
|
&transcript.length(),
|
||||||
|
None,
|
||||||
&[TranscriptCommitment::Hash(commitment)],
|
&[TranscriptCommitment::Hash(commitment)],
|
||||||
)
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ pub(crate) async fn transfer<K: KeyStore>(
|
|||||||
store: &K,
|
store: &K,
|
||||||
sent: &ReferenceMap,
|
sent: &ReferenceMap,
|
||||||
recv: &ReferenceMap,
|
recv: &ReferenceMap,
|
||||||
) -> Result<EncodingCommitment, EncodingError> {
|
) -> Result<(EncoderSecret, EncodingCommitment), EncodingError> {
|
||||||
let secret = EncoderSecret::new(rand::rng().random(), store.delta().as_block().to_bytes());
|
let secret = EncoderSecret::new(rand::rng().random(), store.delta().as_block().to_bytes());
|
||||||
let encoder = new_encoder(&secret);
|
let encoder = new_encoder(&secret);
|
||||||
|
|
||||||
@@ -83,9 +83,8 @@ pub(crate) async fn transfer<K: KeyStore>(
|
|||||||
ctx.io_mut().with_limit(frame_limit).send(encodings).await?;
|
ctx.io_mut().with_limit(frame_limit).send(encodings).await?;
|
||||||
|
|
||||||
let root = ctx.io_mut().expect_next().await?;
|
let root = ctx.io_mut().expect_next().await?;
|
||||||
ctx.io_mut().send(secret.clone()).await?;
|
|
||||||
|
|
||||||
Ok(EncodingCommitment { root, secret })
|
Ok((secret, EncodingCommitment { root }))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receives and commits to the encodings for the provided plaintext ranges.
|
/// Receives and commits to the encodings for the provided plaintext ranges.
|
||||||
@@ -166,9 +165,8 @@ pub(crate) async fn receive<M: MacStore>(
|
|||||||
let root = tree.root();
|
let root = tree.root();
|
||||||
|
|
||||||
ctx.io_mut().send(root.clone()).await?;
|
ctx.io_mut().send(root.clone()).await?;
|
||||||
let secret = ctx.io_mut().expect_next().await?;
|
|
||||||
|
|
||||||
let commitment = EncodingCommitment { root, secret };
|
let commitment = EncodingCommitment { root };
|
||||||
|
|
||||||
Ok((commitment, tree))
|
Ok((commitment, tree))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ pub(crate) async fn verify<T: Vm<Binary> + KeyStore + Send + Sync>(
|
|||||||
sent_proof.verify().map_err(VerifierError::verify)?;
|
sent_proof.verify().map_err(VerifierError::verify)?;
|
||||||
recv_proof.verify().map_err(VerifierError::verify)?;
|
recv_proof.verify().map_err(VerifierError::verify)?;
|
||||||
|
|
||||||
|
let mut encoder_secret = None;
|
||||||
if let Some(commit_config) = transcript_commit
|
if let Some(commit_config) = transcript_commit
|
||||||
&& let Some((sent, recv)) = commit_config.encoding()
|
&& let Some((sent, recv)) = commit_config.encoding()
|
||||||
{
|
{
|
||||||
@@ -147,7 +148,8 @@ pub(crate) async fn verify<T: Vm<Binary> + KeyStore + Send + Sync>(
|
|||||||
.index(recv)
|
.index(recv)
|
||||||
.expect("ranges were authenticated");
|
.expect("ranges were authenticated");
|
||||||
|
|
||||||
let commitment = encoding::transfer(ctx, vm, &sent_map, &recv_map).await?;
|
let (secret, commitment) = encoding::transfer(ctx, vm, &sent_map, &recv_map).await?;
|
||||||
|
encoder_secret = Some(secret);
|
||||||
transcript_commitments.push(TranscriptCommitment::Encoding(commitment));
|
transcript_commitments.push(TranscriptCommitment::Encoding(commitment));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +162,7 @@ pub(crate) async fn verify<T: Vm<Binary> + KeyStore + Send + Sync>(
|
|||||||
Ok(VerifierOutput {
|
Ok(VerifierOutput {
|
||||||
server_name,
|
server_name,
|
||||||
transcript: has_reveal.then_some(transcript),
|
transcript: has_reveal.then_some(transcript),
|
||||||
|
encoder_secret,
|
||||||
transcript_commitments,
|
transcript_commitments,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ use tlsn::{
|
|||||||
hash::{HashAlgId, HashProvider},
|
hash::{HashAlgId, HashProvider},
|
||||||
prover::{ProveConfig, Prover, ProverConfig, TlsConfig},
|
prover::{ProveConfig, Prover, ProverConfig, TlsConfig},
|
||||||
transcript::{
|
transcript::{
|
||||||
Direction, TranscriptCommitConfig, TranscriptCommitment, TranscriptCommitmentKind,
|
Direction, Transcript, TranscriptCommitConfig, TranscriptCommitment,
|
||||||
TranscriptSecret,
|
TranscriptCommitmentKind, TranscriptSecret,
|
||||||
},
|
},
|
||||||
verifier::{Verifier, VerifierConfig, VerifierOutput, VerifyConfig},
|
verifier::{Verifier, VerifierConfig, VerifierOutput, VerifyConfig},
|
||||||
};
|
};
|
||||||
|
use tlsn_core::ProverOutput;
|
||||||
use tlsn_server_fixture::bind;
|
use tlsn_server_fixture::bind;
|
||||||
use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
|
use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
|
||||||
|
|
||||||
@@ -34,11 +35,80 @@ async fn test() {
|
|||||||
|
|
||||||
let (socket_0, socket_1) = tokio::io::duplex(2 << 23);
|
let (socket_0, socket_1) = tokio::io::duplex(2 << 23);
|
||||||
|
|
||||||
tokio::join!(prover(socket_0), verifier(socket_1));
|
let ((full_transcript, prover_output), verifier_output) =
|
||||||
|
tokio::join!(prover(socket_0), verifier(socket_1));
|
||||||
|
|
||||||
|
let partial_transcript = verifier_output.transcript.unwrap();
|
||||||
|
let ServerName::Dns(server_name) = verifier_output.server_name.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(server_name.as_str(), SERVER_DOMAIN);
|
||||||
|
assert!(!partial_transcript.is_complete());
|
||||||
|
assert_eq!(
|
||||||
|
partial_transcript
|
||||||
|
.sent_authed()
|
||||||
|
.iter_ranges()
|
||||||
|
.next()
|
||||||
|
.unwrap(),
|
||||||
|
0..10
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
partial_transcript
|
||||||
|
.received_authed()
|
||||||
|
.iter_ranges()
|
||||||
|
.next()
|
||||||
|
.unwrap(),
|
||||||
|
0..10
|
||||||
|
);
|
||||||
|
|
||||||
|
let encoding_tree = prover_output
|
||||||
|
.transcript_secrets
|
||||||
|
.iter()
|
||||||
|
.find_map(|secret| {
|
||||||
|
if let TranscriptSecret::Encoding(tree) = secret {
|
||||||
|
Some(tree)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let encoding_commitment = prover_output
|
||||||
|
.transcript_commitments
|
||||||
|
.iter()
|
||||||
|
.find_map(|commitment| {
|
||||||
|
if let TranscriptCommitment::Encoding(commitment) = commitment {
|
||||||
|
Some(commitment)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let prove_sent = RangeSet::from(1..full_transcript.sent().len() - 1);
|
||||||
|
let prove_recv = RangeSet::from(1..full_transcript.received().len() - 1);
|
||||||
|
let idxs = [
|
||||||
|
(Direction::Sent, prove_sent.clone()),
|
||||||
|
(Direction::Received, prove_recv.clone()),
|
||||||
|
];
|
||||||
|
let proof = encoding_tree.proof(idxs.iter()).unwrap();
|
||||||
|
let (auth_sent, auth_recv) = proof
|
||||||
|
.verify_with_provider(
|
||||||
|
&HashProvider::default(),
|
||||||
|
&verifier_output.encoder_secret.unwrap(),
|
||||||
|
encoding_commitment,
|
||||||
|
full_transcript.sent(),
|
||||||
|
full_transcript.received(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(auth_sent, prove_sent);
|
||||||
|
assert_eq!(auth_recv, prove_recv);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(verifier_socket))]
|
#[instrument(skip(verifier_socket))]
|
||||||
async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(verifier_socket: T) {
|
async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||||
|
verifier_socket: T,
|
||||||
|
) -> (Transcript, ProverOutput) {
|
||||||
let (client_socket, server_socket) = tokio::io::duplex(2 << 16);
|
let (client_socket, server_socket) = tokio::io::duplex(2 << 16);
|
||||||
|
|
||||||
let server_task = tokio::spawn(bind(server_socket.compat()));
|
let server_task = tokio::spawn(bind(server_socket.compat()));
|
||||||
@@ -127,52 +197,13 @@ async fn prover<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(verifier_soc
|
|||||||
let output = prover.prove(&config).await.unwrap();
|
let output = prover.prove(&config).await.unwrap();
|
||||||
prover.close().await.unwrap();
|
prover.close().await.unwrap();
|
||||||
|
|
||||||
let encoding_tree = output
|
(transcript, output)
|
||||||
.transcript_secrets
|
|
||||||
.iter()
|
|
||||||
.find_map(|secret| {
|
|
||||||
if let TranscriptSecret::Encoding(tree) = secret {
|
|
||||||
Some(tree)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let encoding_commitment = output
|
|
||||||
.transcript_commitments
|
|
||||||
.iter()
|
|
||||||
.find_map(|commitment| {
|
|
||||||
if let TranscriptCommitment::Encoding(commitment) = commitment {
|
|
||||||
Some(commitment)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let prove_sent = RangeSet::from(1..sent_tx_len - 1);
|
|
||||||
let prove_recv = RangeSet::from(1..recv_tx_len - 1);
|
|
||||||
let idxs = [
|
|
||||||
(Direction::Sent, prove_sent.clone()),
|
|
||||||
(Direction::Received, prove_recv.clone()),
|
|
||||||
];
|
|
||||||
let proof = encoding_tree.proof(idxs.iter()).unwrap();
|
|
||||||
let (auth_sent, auth_recv) = proof
|
|
||||||
.verify_with_provider(
|
|
||||||
&HashProvider::default(),
|
|
||||||
encoding_commitment,
|
|
||||||
transcript.sent(),
|
|
||||||
transcript.received(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(auth_sent, prove_sent);
|
|
||||||
assert_eq!(auth_recv, prove_recv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(socket))]
|
#[instrument(skip(socket))]
|
||||||
async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(socket: T) {
|
async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(
|
||||||
|
socket: T,
|
||||||
|
) -> VerifierOutput {
|
||||||
let config_validator = ProtocolConfigValidator::builder()
|
let config_validator = ProtocolConfigValidator::builder()
|
||||||
.max_sent_data(MAX_SENT_DATA)
|
.max_sent_data(MAX_SENT_DATA)
|
||||||
.max_recv_data(MAX_RECV_DATA)
|
.max_recv_data(MAX_RECV_DATA)
|
||||||
@@ -197,30 +228,8 @@ async fn verifier<T: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>(soc
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let VerifierOutput {
|
let output = verifier.verify(&VerifyConfig::default()).await.unwrap();
|
||||||
server_name,
|
|
||||||
transcript,
|
|
||||||
transcript_commitments,
|
|
||||||
} = verifier.verify(&VerifyConfig::default()).await.unwrap();
|
|
||||||
|
|
||||||
verifier.close().await.unwrap();
|
verifier.close().await.unwrap();
|
||||||
|
|
||||||
let transcript = transcript.unwrap();
|
output
|
||||||
|
|
||||||
let ServerName::Dns(server_name) = server_name.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(server_name.as_str(), SERVER_DOMAIN);
|
|
||||||
assert!(!transcript.is_complete());
|
|
||||||
assert_eq!(
|
|
||||||
transcript.sent_authed().iter_ranges().next().unwrap(),
|
|
||||||
0..10
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
transcript.received_authed().iter_ranges().next().unwrap(),
|
|
||||||
0..10
|
|
||||||
);
|
|
||||||
assert!(matches!(
|
|
||||||
transcript_commitments[0],
|
|
||||||
TranscriptCommitment::Encoding(_)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user