1#![deny(missing_docs, unreachable_pub, unused_must_use)]
4#![deny(clippy::all)]
5#![forbid(unsafe_code)]
6
7pub(crate) mod config;
8mod error;
9mod notarize;
10pub mod state;
11mod verify;
12
13use std::sync::Arc;
14
15pub use config::{VerifierConfig, VerifierConfigBuilder, VerifierConfigBuilderError};
16pub use error::VerifierError;
17
18use futures::{AsyncRead, AsyncWrite};
19use mpc_tls::{FollowerData, MpcTlsFollower, SessionKeys};
20use mpz_common::Context;
21use mpz_core::Block;
22use mpz_garble_core::Delta;
23use serio::stream::IoStreamExt;
24use state::{Notarize, Verify};
25use tls_core::msgs::enums::ContentType;
26use tlsn_common::{
27 commit::commit_records,
28 config::ProtocolConfig,
29 context::build_mt_context,
30 mux::attach_mux,
31 transcript::{Record, TlsTranscript},
32 zk_aes::ZkAesCtr,
33 Role,
34};
35use tlsn_core::{
36 attestation::{Attestation, AttestationConfig},
37 connection::{ConnectionInfo, ServerName, TlsVersion, TranscriptLength},
38 transcript::PartialTranscript,
39};
40use tlsn_deap::Deap;
41use tokio::sync::Mutex;
42use web_time::{SystemTime, UNIX_EPOCH};
43
44use tracing::{debug, info, info_span, instrument, Span};
45
46pub(crate) type RCOTSender = mpz_ot::rcot::shared::SharedRCOTSender<
47 mpz_ot::ferret::Sender<mpz_ot::kos::Sender<mpz_ot::chou_orlandi::Receiver>>,
48 mpz_core::Block,
49>;
50pub(crate) type RCOTReceiver = mpz_ot::rcot::shared::SharedRCOTReceiver<
51 mpz_ot::kos::Receiver<mpz_ot::chou_orlandi::Sender>,
52 bool,
53 mpz_core::Block,
54>;
55pub(crate) type Mpc =
56 mpz_garble::protocol::semihonest::Evaluator<mpz_ot::cot::DerandCOTReceiver<RCOTReceiver>>;
57pub(crate) type Zk = mpz_zk::Verifier<RCOTSender>;
58
59#[derive(Debug)]
61pub struct SessionInfo {
62 pub server_name: ServerName,
64 pub connection_info: ConnectionInfo,
66}
67
68pub struct Verifier<T: state::VerifierState> {
70 config: VerifierConfig,
71 span: Span,
72 state: T,
73}
74
75impl Verifier<state::Initialized> {
76 pub fn new(config: VerifierConfig) -> Self {
78 let span = info_span!("verifier");
79 Self {
80 config,
81 span,
82 state: state::Initialized,
83 }
84 }
85
86 #[instrument(parent = &self.span, level = "info", skip_all, err)]
94 pub async fn setup<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
95 self,
96 socket: S,
97 ) -> Result<Verifier<state::Setup>, VerifierError> {
98 let (mut mux_fut, mux_ctrl) = attach_mux(socket, Role::Verifier);
99 let mut mt = build_mt_context(mux_ctrl.clone());
100 let mut ctx = mux_fut.poll_with(mt.new_context()).await?;
101
102 let protocol_config = mux_fut
104 .poll_with(async {
105 let peer_configuration: ProtocolConfig = ctx.io_mut().expect_next().await?;
106 self.config
107 .protocol_config_validator()
108 .validate(&peer_configuration)?;
109
110 Ok::<_, VerifierError>(peer_configuration)
111 })
112 .await?;
113
114 let delta = Delta::random(&mut rand::rng());
115 let (vm, mut mpc_tls) = build_mpc_tls(&self.config, &protocol_config, delta, ctx);
116
117 let mut keys = mpc_tls.alloc()?;
119 translate_keys(&mut keys, &vm.try_lock().expect("VM is not locked"))?;
120
121 let mut zk_aes = ZkAesCtr::new(Role::Verifier);
123 zk_aes.set_key(keys.server_write_key, keys.server_write_iv);
124 zk_aes.alloc(
125 &mut (*vm.try_lock().expect("VM is not locked").zk()),
126 protocol_config.max_recv_data(),
127 )?;
128
129 debug!("setting up mpc-tls");
130
131 mux_fut.poll_with(mpc_tls.preprocess()).await?;
132
133 debug!("mpc-tls setup complete");
134
135 Ok(Verifier {
136 config: self.config,
137 span: self.span,
138 state: state::Setup {
139 mux_ctrl,
140 mux_fut,
141 mt,
142 delta,
143 mpc_tls,
144 zk_aes,
145 _keys: keys,
146 vm,
147 },
148 })
149 }
150
151 #[instrument(parent = &self.span, level = "info", skip_all, err)]
161 pub async fn notarize<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
162 self,
163 socket: S,
164 config: &AttestationConfig,
165 ) -> Result<Attestation, VerifierError> {
166 self.setup(socket)
167 .await?
168 .run()
169 .await?
170 .start_notarize()
171 .finalize(config)
172 .await
173 }
174
175 #[instrument(parent = &self.span, level = "info", skip_all, err)]
184 pub async fn verify<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
185 self,
186 socket: S,
187 ) -> Result<(PartialTranscript, SessionInfo), VerifierError> {
188 let mut verifier = self.setup(socket).await?.run().await?.start_verify();
189 let transcript = verifier.receive().await?;
190
191 let session_info = verifier.finalize().await?;
192 Ok((transcript, session_info))
193 }
194}
195
196impl Verifier<state::Setup> {
197 #[instrument(parent = &self.span, level = "info", skip_all, err)]
199 pub async fn run(self) -> Result<Verifier<state::Closed>, VerifierError> {
200 let state::Setup {
201 mux_ctrl,
202 mut mux_fut,
203 mt,
204 delta,
205 mpc_tls,
206 mut zk_aes,
207 vm,
208 ..
209 } = self.state;
210
211 let start_time = SystemTime::now()
212 .duration_since(UNIX_EPOCH)
213 .expect("system time should be available")
214 .as_secs();
215
216 info!("starting MPC-TLS");
217
218 let (
219 mut ctx,
220 FollowerData {
221 server_key,
222 mut transcript,
223 keys,
224 },
225 ) = mux_fut.poll_with(mpc_tls.run()).await?;
226
227 info!("finished MPC-TLS");
228
229 {
230 let mut vm = vm.try_lock().expect("VM should not be locked");
231
232 translate_transcript(&mut transcript, &vm)?;
233
234 let proof = commit_records(
236 &mut (*vm.zk()),
237 &mut zk_aes,
238 transcript
239 .recv
240 .iter_mut()
241 .filter(|record| record.typ == ContentType::ApplicationData),
242 )
243 .map_err(VerifierError::zk)?;
244
245 debug!("finalizing mpc");
246
247 mux_fut
249 .poll_with(vm.finalize(&mut ctx))
250 .await
251 .map_err(VerifierError::mpc)?;
252
253 debug!("mpc finalized");
254
255 proof.verify().map_err(VerifierError::zk)?;
257 }
258
259 let sent = transcript
260 .sent
261 .iter()
262 .filter(|record| record.typ == ContentType::ApplicationData)
263 .map(|record| record.ciphertext.len())
264 .sum::<usize>() as u32;
265 let received = transcript
266 .recv
267 .iter()
268 .filter(|record| record.typ == ContentType::ApplicationData)
269 .map(|record| record.ciphertext.len())
270 .sum::<usize>() as u32;
271
272 let transcript_refs = transcript
273 .to_transcript_refs()
274 .expect("transcript should be complete");
275
276 let connection_info = ConnectionInfo {
277 time: start_time,
278 version: TlsVersion::V1_2,
279 transcript_length: TranscriptLength { sent, received },
280 };
281
282 let (_, vm) = Arc::into_inner(vm)
284 .expect("vm should have only 1 reference")
285 .into_inner()
286 .into_inner();
287
288 Ok(Verifier {
289 config: self.config,
290 span: self.span,
291 state: state::Closed {
292 mux_ctrl,
293 mux_fut,
294 mt,
295 delta,
296 ctx,
297 keys,
298 vm,
299 server_ephemeral_key: server_key
300 .try_into()
301 .expect("only supported key type should have been accepted"),
302 connection_info,
303 transcript_refs,
304 },
305 })
306 }
307}
308
309impl Verifier<state::Closed> {
310 pub fn start_notarize(self) -> Verifier<Notarize> {
316 Verifier {
317 config: self.config,
318 span: self.span,
319 state: self.state.into(),
320 }
321 }
322
323 pub fn start_verify(self) -> Verifier<Verify> {
328 Verifier {
329 config: self.config,
330 span: self.span,
331 state: self.state.into(),
332 }
333 }
334}
335
336fn build_mpc_tls(
337 config: &VerifierConfig,
338 protocol_config: &ProtocolConfig,
339 delta: Delta,
340 ctx: Context,
341) -> (Arc<Mutex<Deap<Mpc, Zk>>>, MpcTlsFollower) {
342 let mut rng = rand::rng();
343
344 let base_ot_send = mpz_ot::chou_orlandi::Sender::default();
345 let base_ot_recv = mpz_ot::chou_orlandi::Receiver::default();
346 let rcot_send = mpz_ot::kos::Sender::new(
347 mpz_ot::kos::SenderConfig::default(),
348 delta.into_inner(),
349 base_ot_recv,
350 );
351 let rcot_send = mpz_ot::ferret::Sender::new(
352 mpz_ot::ferret::FerretConfig::builder()
353 .lpn_type(mpz_ot::ferret::LpnType::Regular)
354 .build()
355 .expect("ferret config is valid"),
356 Block::random(&mut rng),
357 rcot_send,
358 );
359 let rcot_recv =
360 mpz_ot::kos::Receiver::new(mpz_ot::kos::ReceiverConfig::default(), base_ot_send);
361
362 let rcot_send = mpz_ot::rcot::shared::SharedRCOTSender::new(rcot_send);
363 let rcot_recv = mpz_ot::rcot::shared::SharedRCOTReceiver::new(rcot_recv);
364
365 let mpc = Mpc::new(mpz_ot::cot::DerandCOTReceiver::new(rcot_recv.clone()));
366
367 let zk = Zk::new(delta, rcot_send.clone());
368
369 let vm = Arc::new(Mutex::new(Deap::new(tlsn_deap::Role::Follower, mpc, zk)));
370
371 (
372 vm.clone(),
373 MpcTlsFollower::new(
374 config.build_mpc_tls_config(protocol_config),
375 ctx,
376 vm,
377 rcot_send,
378 (rcot_recv.clone(), rcot_recv.clone(), rcot_recv),
379 ),
380 )
381}
382
383fn translate_keys<Mpc, Zk>(
385 keys: &mut SessionKeys,
386 vm: &Deap<Mpc, Zk>,
387) -> Result<(), VerifierError> {
388 keys.client_write_key = vm
389 .translate(keys.client_write_key)
390 .map_err(VerifierError::mpc)?;
391 keys.client_write_iv = vm
392 .translate(keys.client_write_iv)
393 .map_err(VerifierError::mpc)?;
394 keys.server_write_key = vm
395 .translate(keys.server_write_key)
396 .map_err(VerifierError::mpc)?;
397 keys.server_write_iv = vm
398 .translate(keys.server_write_iv)
399 .map_err(VerifierError::mpc)?;
400
401 Ok(())
402}
403
404fn translate_transcript<Mpc, Zk>(
406 transcript: &mut TlsTranscript,
407 vm: &Deap<Mpc, Zk>,
408) -> Result<(), VerifierError> {
409 for Record { plaintext_ref, .. } in transcript.sent.iter_mut().chain(transcript.recv.iter_mut())
410 {
411 if let Some(plaintext_ref) = plaintext_ref.as_mut() {
412 *plaintext_ref = vm.translate(*plaintext_ref).map_err(VerifierError::mpc)?;
413 }
414 }
415
416 Ok(())
417}