1#![deny(missing_docs, unreachable_pub, unused_must_use)]
4#![deny(clippy::all)]
5#![forbid(unsafe_code)]
6
7pub(crate) mod config;
8mod error;
9pub mod state;
10
11use std::sync::Arc;
12
13pub use config::{VerifierConfig, VerifierConfigBuilder, VerifierConfigBuilderError};
14pub use error::VerifierError;
15pub use tlsn_core::{VerifierOutput, VerifyConfig, VerifyConfigBuilder, VerifyConfigBuilderError};
16
17use futures::{AsyncRead, AsyncWrite, TryFutureExt};
18use mpc_tls::{FollowerData, MpcTlsFollower, SessionKeys};
19use mpz_common::Context;
20use mpz_core::Block;
21use mpz_garble_core::Delta;
22use mpz_vm_core::prelude::*;
23use serio::{stream::IoStreamExt, SinkExt};
24use tls_core::msgs::enums::ContentType;
25use tlsn_common::{
26 commit::{commit_records, hash::verify_hash},
27 config::ProtocolConfig,
28 context::build_mt_context,
29 encoding,
30 mux::attach_mux,
31 tag::verify_tags,
32 transcript::{decode_transcript, verify_transcript, Record, TlsTranscript},
33 zk_aes_ctr::ZkAesCtr,
34 Role,
35};
36use tlsn_core::{
37 attestation::{Attestation, AttestationConfig},
38 connection::{ConnectionInfo, ServerName, TlsVersion, TranscriptLength},
39 request::Request,
40 transcript::TranscriptCommitment,
41 ProvePayload,
42};
43use tlsn_deap::Deap;
44use tokio::sync::Mutex;
45use web_time::{SystemTime, UNIX_EPOCH};
46
47use tracing::{debug, info, info_span, instrument, Span};
48
49pub(crate) type RCOTSender = mpz_ot::rcot::shared::SharedRCOTSender<
50 mpz_ot::ferret::Sender<mpz_ot::kos::Sender<mpz_ot::chou_orlandi::Receiver>>,
51 mpz_core::Block,
52>;
53pub(crate) type RCOTReceiver = mpz_ot::rcot::shared::SharedRCOTReceiver<
54 mpz_ot::kos::Receiver<mpz_ot::chou_orlandi::Sender>,
55 bool,
56 mpz_core::Block,
57>;
58pub(crate) type Mpc =
59 mpz_garble::protocol::semihonest::Evaluator<mpz_ot::cot::DerandCOTReceiver<RCOTReceiver>>;
60pub(crate) type Zk = mpz_zk::Verifier<RCOTSender>;
61
62#[derive(Debug)]
64pub struct SessionInfo {
65 pub server_name: ServerName,
67 pub connection_info: ConnectionInfo,
69}
70
71pub struct Verifier<T: state::VerifierState = state::Initialized> {
73 config: VerifierConfig,
74 span: Span,
75 state: T,
76}
77
78impl Verifier<state::Initialized> {
79 pub fn new(config: VerifierConfig) -> Self {
81 let span = info_span!("verifier");
82 Self {
83 config,
84 span,
85 state: state::Initialized,
86 }
87 }
88
89 #[instrument(parent = &self.span, level = "info", skip_all, err)]
97 pub async fn setup<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
98 self,
99 socket: S,
100 ) -> Result<Verifier<state::Setup>, VerifierError> {
101 let (mut mux_fut, mux_ctrl) = attach_mux(socket, Role::Verifier);
102 let mut mt = build_mt_context(mux_ctrl.clone());
103 let mut ctx = mux_fut.poll_with(mt.new_context()).await?;
104
105 let protocol_config = mux_fut
107 .poll_with(async {
108 let peer_configuration: ProtocolConfig = ctx.io_mut().expect_next().await?;
109 self.config
110 .protocol_config_validator()
111 .validate(&peer_configuration)?;
112
113 Ok::<_, VerifierError>(peer_configuration)
114 })
115 .await?;
116
117 let delta = Delta::random(&mut rand::rng());
118 let (vm, mut mpc_tls) = build_mpc_tls(&self.config, &protocol_config, delta, ctx);
119
120 let mut keys = mpc_tls.alloc()?;
122 translate_keys(&mut keys, &vm.try_lock().expect("VM is not locked"))?;
123
124 let mut zk_aes_ctr = ZkAesCtr::new(Role::Verifier);
126 zk_aes_ctr.set_key(keys.server_write_key, keys.server_write_iv);
127 zk_aes_ctr.alloc(
128 &mut (*vm.try_lock().expect("VM is not locked").zk()),
129 protocol_config.max_recv_data(),
130 )?;
131
132 debug!("setting up mpc-tls");
133
134 mux_fut.poll_with(mpc_tls.preprocess()).await?;
135
136 debug!("mpc-tls setup complete");
137
138 Ok(Verifier {
139 config: self.config,
140 span: self.span,
141 state: state::Setup {
142 mux_ctrl,
143 mux_fut,
144 delta,
145 mpc_tls,
146 zk_aes_ctr,
147 _keys: keys,
148 vm,
149 },
150 })
151 }
152
153 #[instrument(parent = &self.span, level = "info", skip_all, err)]
163 #[deprecated(
164 note = "attestation functionality will be removed from this API in future releases."
165 )]
166 pub async fn notarize<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
167 self,
168 socket: S,
169 config: &AttestationConfig,
170 ) -> Result<Attestation, VerifierError> {
171 let mut verifier = self.setup(socket).await?.run().await?;
172
173 #[allow(deprecated)]
174 let attestation = verifier.notarize(config).await?;
175
176 verifier.close().await?;
177
178 Ok(attestation)
179 }
180
181 #[instrument(parent = &self.span, level = "info", skip_all, err)]
190 pub async fn verify<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
191 self,
192 socket: S,
193 config: &VerifyConfig,
194 ) -> Result<VerifierOutput, VerifierError> {
195 let mut verifier = self.setup(socket).await?.run().await?;
196
197 let output = verifier.verify(config).await?;
198
199 verifier.close().await?;
200
201 Ok(output)
202 }
203}
204
205impl Verifier<state::Setup> {
206 #[instrument(parent = &self.span, level = "info", skip_all, err)]
208 pub async fn run(self) -> Result<Verifier<state::Committed>, VerifierError> {
209 let state::Setup {
210 mux_ctrl,
211 mut mux_fut,
212 delta,
213 mpc_tls,
214 mut zk_aes_ctr,
215 vm,
216 ..
217 } = self.state;
218
219 let start_time = SystemTime::now()
220 .duration_since(UNIX_EPOCH)
221 .expect("system time should be available")
222 .as_secs();
223
224 info!("starting MPC-TLS");
225
226 let (
227 mut ctx,
228 FollowerData {
229 server_key,
230 mut transcript,
231 keys,
232 ..
233 },
234 ) = mux_fut.poll_with(mpc_tls.run()).await?;
235
236 info!("finished MPC-TLS");
237
238 {
239 let mut vm = vm.try_lock().expect("VM should not be locked");
240
241 translate_transcript(&mut transcript, &vm)?;
242
243 debug!("finalizing mpc");
244
245 mux_fut
246 .poll_with(vm.finalize(&mut ctx))
247 .await
248 .map_err(VerifierError::mpc)?;
249
250 debug!("mpc finalized");
251 }
252
253 let (_, mut vm) = Arc::into_inner(vm)
255 .expect("vm should have only 1 reference")
256 .into_inner()
257 .into_inner();
258
259 let tag_proof = verify_tags(
262 &mut vm,
263 (keys.server_write_key, keys.server_write_iv),
264 keys.server_write_mac_key,
265 transcript.recv.clone(),
266 )
267 .map_err(VerifierError::zk)?;
268
269 let proof = commit_records(
271 &mut vm,
272 &mut zk_aes_ctr,
273 transcript
274 .recv
275 .iter_mut()
276 .filter(|record| record.typ == ContentType::ApplicationData),
277 )
278 .map_err(VerifierError::zk)?;
279
280 mux_fut
281 .poll_with(vm.execute_all(&mut ctx).map_err(VerifierError::zk))
282 .await?;
283
284 tag_proof.verify().map_err(VerifierError::zk)?;
288
289 proof.verify().map_err(VerifierError::zk)?;
291
292 let sent = transcript
293 .sent
294 .iter()
295 .filter(|record| record.typ == ContentType::ApplicationData)
296 .map(|record| record.ciphertext.len())
297 .sum::<usize>() as u32;
298 let received = transcript
299 .recv
300 .iter()
301 .filter(|record| record.typ == ContentType::ApplicationData)
302 .map(|record| record.ciphertext.len())
303 .sum::<usize>() as u32;
304
305 let transcript_refs = transcript
306 .to_transcript_refs()
307 .expect("transcript should be complete");
308
309 let connection_info = ConnectionInfo {
310 time: start_time,
311 version: TlsVersion::V1_2,
312 transcript_length: TranscriptLength { sent, received },
313 };
314
315 Ok(Verifier {
316 config: self.config,
317 span: self.span,
318 state: state::Committed {
319 mux_ctrl,
320 mux_fut,
321 delta,
322 ctx,
323 vm,
324 server_ephemeral_key: server_key
325 .try_into()
326 .expect("only supported key type should have been accepted"),
327 connection_info,
328 transcript_refs,
329 },
330 })
331 }
332}
333
334impl Verifier<state::Committed> {
335 pub fn connection_info(&self) -> &ConnectionInfo {
337 &self.state.connection_info
338 }
339
340 #[instrument(parent = &self.span, level = "info", skip_all, err)]
346 pub async fn verify(
347 &mut self,
348 #[allow(unused_variables)] config: &VerifyConfig,
349 ) -> Result<VerifierOutput, VerifierError> {
350 let state::Committed {
351 mux_fut,
352 ctx,
353 delta,
354 vm,
355 connection_info,
356 server_ephemeral_key,
357 transcript_refs,
358 ..
359 } = &mut self.state;
360
361 let ProvePayload {
362 server_identity,
363 transcript,
364 transcript_commit,
365 } = mux_fut
366 .poll_with(ctx.io_mut().expect_next().map_err(VerifierError::from))
367 .await?;
368
369 let server_name = if let Some((name, cert_data)) = server_identity {
370 cert_data
371 .verify_with_provider(
372 self.config.crypto_provider(),
373 connection_info.time,
374 server_ephemeral_key,
375 &name,
376 )
377 .map_err(VerifierError::verify)?;
378
379 Some(name)
380 } else {
381 None
382 };
383
384 if let Some(partial_transcript) = &transcript {
385 if partial_transcript.len_sent() != connection_info.transcript_length.sent as usize
387 || partial_transcript.len_received()
388 != connection_info.transcript_length.received as usize
389 {
390 return Err(VerifierError::verify(
391 "prover sent transcript with incorrect length",
392 ));
393 }
394
395 decode_transcript(
396 vm,
397 partial_transcript.sent_authed(),
398 partial_transcript.received_authed(),
399 transcript_refs,
400 )
401 .map_err(VerifierError::zk)?;
402 }
403
404 let mut transcript_commitments = Vec::new();
405 let mut hash_commitments = None;
406 if let Some(commit_config) = transcript_commit {
407 if commit_config.encoding() {
408 let commitment = mux_fut
409 .poll_with(encoding::transfer(
410 ctx,
411 transcript_refs,
412 delta,
413 |plaintext| vm.get_keys(plaintext).expect("reference is valid"),
414 ))
415 .await?;
416
417 transcript_commitments.push(TranscriptCommitment::Encoding(commitment));
418 }
419
420 if commit_config.has_hash() {
421 hash_commitments = Some(
422 verify_hash(vm, transcript_refs, commit_config.iter_hash().cloned())
423 .map_err(VerifierError::verify)?,
424 );
425 }
426 }
427
428 mux_fut
429 .poll_with(vm.execute_all(ctx).map_err(VerifierError::zk))
430 .await?;
431
432 if let Some(partial_transcript) = &transcript {
434 verify_transcript(vm, partial_transcript, transcript_refs)
435 .map_err(VerifierError::verify)?;
436 }
437
438 if let Some(hash_commitments) = hash_commitments {
439 for commitment in hash_commitments.try_recv().map_err(VerifierError::verify)? {
440 transcript_commitments.push(TranscriptCommitment::Hash(commitment));
441 }
442 }
443
444 Ok(VerifierOutput {
445 server_name,
446 transcript,
447 transcript_commitments,
448 })
449 }
450
451 #[instrument(parent = &self.span, level = "info", skip_all, err)]
457 #[deprecated(
458 note = "attestation functionality will be removed from this API in future releases."
459 )]
460 pub async fn notarize(
461 &mut self,
462 config: &AttestationConfig,
463 ) -> Result<Attestation, VerifierError> {
464 let VerifierOutput {
465 server_name,
466 transcript,
467 transcript_commitments,
468 } = self.verify(&VerifyConfig::default()).await?;
469
470 if server_name.is_some() {
471 return Err(VerifierError::attestation(
472 "server name can not be revealed to a notary",
473 ));
474 } else if transcript.is_some() {
475 return Err(VerifierError::attestation(
476 "transcript data can not be revealed to a notary",
477 ));
478 }
479
480 let state::Committed {
481 mux_fut,
482 ctx,
483 server_ephemeral_key,
484 connection_info,
485 ..
486 } = &mut self.state;
487
488 let request: Request = mux_fut
489 .poll_with(ctx.io_mut().expect_next().map_err(VerifierError::from))
490 .await?;
491
492 let mut builder = Attestation::builder(config)
493 .accept_request(request)
494 .map_err(VerifierError::attestation)?;
495
496 builder
497 .connection_info(connection_info.clone())
498 .server_ephemeral_key(server_ephemeral_key.clone())
499 .transcript_commitments(transcript_commitments);
500
501 let attestation = builder
502 .build(self.config.crypto_provider())
503 .map_err(VerifierError::attestation)?;
504
505 mux_fut
506 .poll_with(
507 ctx.io_mut()
508 .send(attestation.clone())
509 .map_err(VerifierError::from),
510 )
511 .await?;
512
513 info!("Sent attestation");
514
515 Ok(attestation)
516 }
517
518 #[instrument(parent = &self.span, level = "info", skip_all, err)]
520 pub async fn close(self) -> Result<(), VerifierError> {
521 let state::Committed {
522 mux_ctrl, mux_fut, ..
523 } = self.state;
524
525 if !mux_fut.is_complete() {
527 mux_ctrl.close();
528 mux_fut.await?;
529 }
530
531 Ok(())
532 }
533}
534
535fn build_mpc_tls(
536 config: &VerifierConfig,
537 protocol_config: &ProtocolConfig,
538 delta: Delta,
539 ctx: Context,
540) -> (Arc<Mutex<Deap<Mpc, Zk>>>, MpcTlsFollower) {
541 let mut rng = rand::rng();
542
543 let base_ot_send = mpz_ot::chou_orlandi::Sender::default();
544 let base_ot_recv = mpz_ot::chou_orlandi::Receiver::default();
545 let rcot_send = mpz_ot::kos::Sender::new(
546 mpz_ot::kos::SenderConfig::default(),
547 delta.into_inner(),
548 base_ot_recv,
549 );
550 let rcot_send = mpz_ot::ferret::Sender::new(
551 mpz_ot::ferret::FerretConfig::builder()
552 .lpn_type(mpz_ot::ferret::LpnType::Regular)
553 .build()
554 .expect("ferret config is valid"),
555 Block::random(&mut rng),
556 rcot_send,
557 );
558 let rcot_recv =
559 mpz_ot::kos::Receiver::new(mpz_ot::kos::ReceiverConfig::default(), base_ot_send);
560
561 let rcot_send = mpz_ot::rcot::shared::SharedRCOTSender::new(rcot_send);
562 let rcot_recv = mpz_ot::rcot::shared::SharedRCOTReceiver::new(rcot_recv);
563
564 let mpc = Mpc::new(mpz_ot::cot::DerandCOTReceiver::new(rcot_recv.clone()));
565
566 let zk = Zk::new(delta, rcot_send.clone());
567
568 let vm = Arc::new(Mutex::new(Deap::new(tlsn_deap::Role::Follower, mpc, zk)));
569
570 (
571 vm.clone(),
572 MpcTlsFollower::new(
573 config.build_mpc_tls_config(protocol_config),
574 ctx,
575 vm,
576 rcot_send,
577 (rcot_recv.clone(), rcot_recv.clone(), rcot_recv),
578 ),
579 )
580}
581
582fn translate_keys<Mpc, Zk>(
584 keys: &mut SessionKeys,
585 vm: &Deap<Mpc, Zk>,
586) -> Result<(), VerifierError> {
587 keys.client_write_key = vm
588 .translate(keys.client_write_key)
589 .map_err(VerifierError::mpc)?;
590 keys.client_write_iv = vm
591 .translate(keys.client_write_iv)
592 .map_err(VerifierError::mpc)?;
593 keys.server_write_key = vm
594 .translate(keys.server_write_key)
595 .map_err(VerifierError::mpc)?;
596 keys.server_write_iv = vm
597 .translate(keys.server_write_iv)
598 .map_err(VerifierError::mpc)?;
599 keys.server_write_mac_key = vm
600 .translate(keys.server_write_mac_key)
601 .map_err(VerifierError::mpc)?;
602
603 Ok(())
604}
605
606fn translate_transcript<Mpc, Zk>(
608 transcript: &mut TlsTranscript,
609 vm: &Deap<Mpc, Zk>,
610) -> Result<(), VerifierError> {
611 for Record { plaintext_ref, .. } in transcript.sent.iter_mut().chain(transcript.recv.iter_mut())
612 {
613 if let Some(plaintext_ref) = plaintext_ref.as_mut() {
614 *plaintext_ref = vm.translate(*plaintext_ref).map_err(VerifierError::mpc)?;
615 }
616 }
617
618 Ok(())
619}