tlsn_core/request/
builder.rs

1use crate::{
2    connection::{ServerCertData, ServerCertOpening, ServerName},
3    index::Index,
4    request::{Request, RequestConfig},
5    secrets::Secrets,
6    transcript::{encoding::EncodingTree, Transcript},
7    CryptoProvider,
8};
9
10/// Builder for [`Request`].
11pub struct RequestBuilder<'a> {
12    config: &'a RequestConfig,
13    server_name: Option<ServerName>,
14    server_cert_data: Option<ServerCertData>,
15    encoding_tree: Option<EncodingTree>,
16    transcript: Option<Transcript>,
17}
18
19impl<'a> RequestBuilder<'a> {
20    /// Creates a new request builder.
21    pub fn new(config: &'a RequestConfig) -> Self {
22        Self {
23            config,
24            server_name: None,
25            server_cert_data: None,
26            encoding_tree: None,
27            transcript: None,
28        }
29    }
30
31    /// Sets the server name.
32    pub fn server_name(&mut self, name: ServerName) -> &mut Self {
33        self.server_name = Some(name);
34        self
35    }
36
37    /// Sets the server identity data.
38    pub fn server_cert_data(&mut self, data: ServerCertData) -> &mut Self {
39        self.server_cert_data = Some(data);
40        self
41    }
42
43    /// Sets the tree to commit to the transcript encodings.
44    pub fn encoding_tree(&mut self, tree: EncodingTree) -> &mut Self {
45        self.encoding_tree = Some(tree);
46        self
47    }
48
49    /// Sets the transcript.
50    pub fn transcript(&mut self, transcript: Transcript) -> &mut Self {
51        self.transcript = Some(transcript);
52        self
53    }
54
55    /// Builds the attestation request and returns the corresponding secrets.
56    pub fn build(
57        self,
58        provider: &CryptoProvider,
59    ) -> Result<(Request, Secrets), RequestBuilderError> {
60        let Self {
61            config,
62            server_name,
63            server_cert_data,
64            encoding_tree,
65            transcript,
66        } = self;
67
68        let signature_alg = *config.signature_alg();
69        let hash_alg = *config.hash_alg();
70
71        let hasher = provider.hash.get(&hash_alg).map_err(|_| {
72            RequestBuilderError::new(format!("unsupported hash algorithm: {hash_alg}"))
73        })?;
74
75        let server_name =
76            server_name.ok_or_else(|| RequestBuilderError::new("server name is missing"))?;
77
78        let server_cert_opening = ServerCertOpening::new(
79            server_cert_data
80                .ok_or_else(|| RequestBuilderError::new("server identity data is missing"))?,
81        );
82
83        let transcript =
84            transcript.ok_or_else(|| RequestBuilderError::new("transcript is missing"))?;
85
86        let server_cert_commitment = server_cert_opening.commit(hasher);
87
88        let encoding_commitment_root = encoding_tree.as_ref().map(|tree| tree.root());
89
90        let extensions = config.extensions().to_vec();
91
92        let request = Request {
93            signature_alg,
94            hash_alg,
95            server_cert_commitment,
96            encoding_commitment_root,
97            extensions,
98        };
99
100        let secrets = Secrets {
101            server_name,
102            server_cert_opening,
103            encoding_tree,
104            plaintext_hashes: Index::default(),
105            transcript,
106        };
107
108        Ok((request, secrets))
109    }
110}
111
112/// Error for [`RequestBuilder`].
113#[derive(Debug, thiserror::Error)]
114#[error("request builder error: {message}")]
115pub struct RequestBuilderError {
116    message: String,
117}
118
119impl RequestBuilderError {
120    fn new(message: impl Into<String>) -> Self {
121        Self {
122            message: message.into(),
123        }
124    }
125}