tlsn_prover/
notarize.rs

1//! This module handles the notarization phase of the prover.
2//!
3//! The prover interacts with a TLS verifier who acts as a Notary, i.e. the
4//! verifier produces an attestation but does not verify transcript data.
5
6use super::{state::Notarize, Prover, ProverError};
7use serio::{stream::IoStreamExt as _, SinkExt as _};
8use tlsn_common::encoding;
9use tlsn_core::{
10    attestation::Attestation,
11    request::{Request, RequestConfig},
12    transcript::{encoding::EncodingTree, Transcript, TranscriptCommitConfig},
13    Secrets,
14};
15use tracing::{debug, instrument};
16
17impl Prover<Notarize> {
18    /// Returns the transcript.
19    pub fn transcript(&self) -> &Transcript {
20        &self.state.transcript
21    }
22
23    /// Configures transcript commitments.
24    pub fn transcript_commit(&mut self, config: TranscriptCommitConfig) {
25        self.state.transcript_commit_config = Some(config);
26    }
27
28    /// Finalizes the notarization.
29    #[instrument(parent = &self.span, level = "debug", skip_all, err)]
30    pub async fn finalize(
31        self,
32        config: &RequestConfig,
33    ) -> Result<(Attestation, Secrets), ProverError> {
34        let Notarize {
35            mux_ctrl,
36            mut mux_fut,
37            mut ctx,
38            vm,
39            connection_info,
40            server_cert_data,
41            transcript,
42            transcript_refs,
43            transcript_commit_config,
44            ..
45        } = self.state;
46
47        let sent_macs = transcript_refs
48            .sent()
49            .iter()
50            .flat_map(|plaintext| vm.get_macs(*plaintext).expect("reference is valid"))
51            .map(|mac| mac.as_block());
52        let recv_macs = transcript_refs
53            .recv()
54            .iter()
55            .flat_map(|plaintext| vm.get_macs(*plaintext).expect("reference is valid"))
56            .map(|mac| mac.as_block());
57
58        let encoding_provider = mux_fut
59            .poll_with(encoding::receive(&mut ctx, sent_macs, recv_macs))
60            .await?;
61
62        let provider = self.config.crypto_provider();
63
64        let hasher = provider
65            .hash
66            .get(config.hash_alg())
67            .map_err(ProverError::config)?;
68
69        let mut builder = Request::builder(config);
70
71        builder
72            .server_name(self.config.server_name().clone())
73            .server_cert_data(server_cert_data)
74            .transcript(transcript);
75
76        if let Some(config) = transcript_commit_config {
77            if config.has_encoding() {
78                builder.encoding_tree(
79                    EncodingTree::new(
80                        hasher,
81                        config.iter_encoding(),
82                        &encoding_provider,
83                        &connection_info.transcript_length,
84                    )
85                    .map_err(ProverError::commit)?,
86                );
87            }
88        }
89
90        let (request, secrets) = builder.build(provider).map_err(ProverError::attestation)?;
91
92        let attestation = mux_fut
93            .poll_with(async {
94                debug!("sending attestation request");
95
96                ctx.io_mut().send(request.clone()).await?;
97
98                let attestation: Attestation = ctx.io_mut().expect_next().await?;
99
100                Ok::<_, ProverError>(attestation)
101            })
102            .await?;
103
104        // Wait for the notary to correctly close the connection.
105        if !mux_fut.is_complete() {
106            mux_ctrl.close();
107            mux_fut.await?;
108        }
109
110        // Check the attestation is consistent with the Prover's view.
111        request
112            .validate(&attestation)
113            .map_err(ProverError::attestation)?;
114
115        Ok((attestation, secrets))
116    }
117}