1mod builder;
34mod config;
35mod extension;
36mod proof;
37
38use std::fmt;
39
40use rand::distr::{Distribution, StandardUniform};
41use serde::{Deserialize, Serialize};
42
43use crate::{
44 connection::{ConnectionInfo, ServerCertCommitment, ServerEphemKey},
45 hash::{impl_domain_separator, Hash, HashAlgorithm, HashAlgorithmExt, TypedHash},
46 merkle::MerkleTree,
47 presentation::PresentationBuilder,
48 signing::{Signature, VerifyingKey},
49 transcript::TranscriptCommitment,
50 CryptoProvider,
51};
52
53pub use builder::{AttestationBuilder, AttestationBuilderError};
54pub use config::{AttestationConfig, AttestationConfigBuilder, AttestationConfigError};
55pub use extension::{Extension, InvalidExtension};
56pub use proof::{AttestationError, AttestationProof};
57
58pub const VERSION: Version = Version(0);
60
61#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
63pub struct Uid(pub [u8; 16]);
64
65impl From<[u8; 16]> for Uid {
66 fn from(id: [u8; 16]) -> Self {
67 Self(id)
68 }
69}
70
71impl Distribution<Uid> for StandardUniform {
72 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Uid {
73 Uid(self.sample(rng))
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
79pub struct Version(u32);
80
81impl_domain_separator!(Version);
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct Field<T> {
86 pub id: FieldId,
88 pub data: T,
90}
91
92#[derive(
94 Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
95)]
96pub struct FieldId(pub u32);
97
98impl FieldId {
99 pub(crate) fn next<T>(&mut self, data: T) -> Field<T> {
100 let id = *self;
101 self.0 += 1;
102
103 Field { id, data }
104 }
105}
106
107impl fmt::Display for FieldId {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 write!(f, "{}", self.0)
110 }
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
115#[repr(u8)]
116pub enum FieldKind {
117 ConnectionInfo = 0x01,
119 ServerEphemKey = 0x02,
121 ServerIdentityCommitment = 0x03,
123 EncodingCommitment = 0x04,
125 PlaintextHash = 0x05,
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
133pub struct Header {
134 pub id: Uid,
136 pub version: Version,
138 pub root: TypedHash,
140}
141
142impl_domain_separator!(Header);
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct Body {
149 verifying_key: Field<VerifyingKey>,
150 connection_info: Field<ConnectionInfo>,
151 server_ephemeral_key: Field<ServerEphemKey>,
152 cert_commitment: Field<ServerCertCommitment>,
153 extensions: Vec<Field<Extension>>,
154 transcript_commitments: Vec<Field<TranscriptCommitment>>,
155}
156
157impl Body {
158 pub fn extensions(&self) -> impl Iterator<Item = &Extension> {
160 self.extensions.iter().map(|field| &field.data)
161 }
162
163 pub fn verifying_key(&self) -> &VerifyingKey {
165 &self.verifying_key.data
166 }
167
168 pub(crate) fn root(&self, hasher: &dyn HashAlgorithm) -> TypedHash {
172 let mut tree = MerkleTree::new(hasher.id());
173 let fields = self
174 .hash_fields(hasher)
175 .into_iter()
176 .map(|(_, hash)| hash)
177 .collect::<Vec<_>>();
178 tree.insert(hasher, fields);
179 tree.root()
180 }
181
182 pub(crate) fn hash_fields(&self, hasher: &dyn HashAlgorithm) -> Vec<(FieldId, Hash)> {
191 let Self {
194 verifying_key,
195 connection_info: conn_info,
196 server_ephemeral_key,
197 cert_commitment,
198 extensions,
199 transcript_commitments,
200 } = self;
201
202 let mut fields: Vec<(FieldId, Hash)> = vec![
203 (verifying_key.id, hasher.hash_separated(&verifying_key.data)),
204 (conn_info.id, hasher.hash_separated(&conn_info.data)),
205 (
206 server_ephemeral_key.id,
207 hasher.hash_separated(&server_ephemeral_key.data),
208 ),
209 (
210 cert_commitment.id,
211 hasher.hash_separated(&cert_commitment.data),
212 ),
213 ];
214
215 for field in extensions.iter() {
216 fields.push((field.id, hasher.hash_separated(&field.data)));
217 }
218
219 for field in transcript_commitments.iter() {
220 fields.push((field.id, hasher.hash_separated(&field.data)));
221 }
222
223 fields.sort_by_key(|(id, _)| *id);
224 fields
225 }
226
227 pub(crate) fn connection_info(&self) -> &ConnectionInfo {
229 &self.connection_info.data
230 }
231
232 pub(crate) fn server_ephemeral_key(&self) -> &ServerEphemKey {
234 &self.server_ephemeral_key.data
235 }
236
237 pub(crate) fn cert_commitment(&self) -> &ServerCertCommitment {
239 &self.cert_commitment.data
240 }
241
242 pub(crate) fn transcript_commitments(&self) -> impl Iterator<Item = &TranscriptCommitment> {
244 self.transcript_commitments.iter().map(|field| &field.data)
245 }
246}
247
248#[derive(Debug, Clone, Serialize, Deserialize)]
252pub struct Attestation {
253 pub signature: Signature,
255 pub header: Header,
257 pub body: Body,
259}
260
261impl Attestation {
262 pub fn builder(config: &AttestationConfig) -> AttestationBuilder<'_> {
264 AttestationBuilder::new(config)
265 }
266
267 pub fn presentation_builder<'a>(
269 &'a self,
270 provider: &'a CryptoProvider,
271 ) -> PresentationBuilder<'a> {
272 PresentationBuilder::new(provider, self)
273 }
274}