1use rand_core::CryptoRngCore;
5#[cfg(any(feature = "reachable", feature = "server", feature = "attestant"))]
6use sha3::{Digest, Sha3_512};
7
8use reach_aliases::*;
9#[cfg(feature = "reachable")]
10use reach_signatures::Signatures;
11#[cfg(any(feature = "reachable", feature = "server", feature = "attestant"))]
12use reach_signatures::Verifier;
13#[cfg(any(feature = "reachable", feature = "server"))]
14use reach_signatures::verify_digest;
15#[cfg(any(feature = "reachable", feature = "attestant"))]
16use reach_signatures::{Digestible, Sign, VerifyingKeys};
17
18use crate::error;
19#[cfg(any(feature = "reachable", feature = "server", feature = "attestant"))]
20use crate::wire::{AuthenticationAssurance, AuthenticationChallenge};
21
22pub trait RandomFromRng {
23 fn random_from_rng(csprng: &mut impl CryptoRngCore) -> Self;
24}
25
26macro_rules! byte_array_random_from_rng {
27 ($length:tt) => {
28 impl RandomFromRng for [u8; $length] {
29 fn random_from_rng(csprng: &mut impl CryptoRngCore) -> Self {
30 let mut byte_array = [0u8; $length];
31 csprng.fill_bytes(&mut byte_array);
32
33 byte_array
34 }
35 }
36 };
37}
38
39byte_array_random_from_rng!(16);
40byte_array_random_from_rng!(24);
41byte_array_random_from_rng!(32);
42byte_array_random_from_rng!(64);
43
44#[cfg(any(feature = "reaching", feature = "reachable"))]
45mod reaching_reachable {
46 use std::ops::Deref;
47
48 use crate::ParticipantType;
49
50 use super::*;
51
52 pub trait ParticipantPublicKeys {
53 fn ec_public_key(&self) -> &X25519Public;
54 fn pq_public_key(&self) -> &MlKemPublic;
55 fn participant_type(&self) -> ParticipantType;
56 }
57
58 impl ParticipantPublicKeys for Box<&dyn ParticipantPublicKeys> {
59 fn ec_public_key(&self) -> &X25519Public {
60 self.deref().ec_public_key()
61 }
62
63 fn pq_public_key(&self) -> &MlKemPublic {
64 self.deref().pq_public_key()
65 }
66
67 fn participant_type(&self) -> ParticipantType {
68 self.deref().participant_type()
69 }
70 }
71}
72
73#[cfg(any(feature = "reaching", feature = "reachable"))]
74pub use reaching_reachable::*;
75
76pub trait ProstEncode
77where
78 <Self as ProstEncode>::EncodedType: ProstMessage + for<'a> From<&'a Self>,
79{
80 type EncodedType;
81
82 fn encode<B>(&self, buf: &mut B) -> Result<(), error::EncodeError>
83 where
84 B: bytes::BufMut,
85 {
86 Self::EncodedType::from(self)
87 .encode(buf)
88 .map_err(error::EncodeError::from)
89 }
90
91 fn encode_to_vec(&self) -> Vec<u8> {
92 Self::EncodedType::from(self).encode_to_vec()
93 }
94}
95
96pub trait ProstEncodeOwned: Sized
97where
98 <Self as ProstEncodeOwned>::EncodedType: ProstMessage + From<Self>,
99{
100 type EncodedType;
101
102 fn encode<B>(self, buf: &mut B) -> Result<(), error::EncodeError>
103 where
104 B: bytes::BufMut,
105 {
106 Self::EncodedType::from(self)
107 .encode(buf)
108 .map_err(error::EncodeError::from)
109 }
110
111 fn encode_to_vec(self) -> Vec<u8> {
112 Self::EncodedType::from(self).encode_to_vec()
113 }
114}
115
116pub trait ProstDecode
117where
118 Self: Sized + TryFrom<Self::EncodedType, Error = error::DecodeError>,
119 <Self as ProstDecode>::EncodedType: ProstMessage + Default,
120{
121 type EncodedType;
122
123 fn decode<M>(message: M) -> Result<Self, error::DecodeError>
124 where
125 M: AsRef<[u8]>,
126 {
127 Self::try_from(Self::EncodedType::decode(message.as_ref())?)
128 }
129}
130
131#[cfg(any(feature = "reachable", feature = "attestant"))]
132pub trait AssureAuthentication {
133 fn assure_authentication<V>(
134 &self,
135 verifier: &V,
136 authentication_challenge: &AuthenticationChallenge,
137 csprng: &mut impl CryptoRngCore,
138 ) -> AuthenticationAssurance
139 where
140 V: Verifier + Digestible,
141 Self: Sign + VerifyingKeys<V>,
142 {
143 let epoch_timeframe = time::OffsetDateTime::now_utc().unix_timestamp() / 30;
144
145 let mut hasher = <Sha3_512 as Digest>::new();
146 hasher.update(authentication_challenge.authentication_challenge.as_slice());
147 hasher.update(epoch_timeframe.to_le_bytes().as_slice());
148
149 let (ec_signature, pq_signature) =
150 self.sign_digest(b"Authentication Assurance", hasher, csprng);
151
152 AuthenticationAssurance {
153 authenticator_id: verifier.finalized_digest(),
154 ec_signature,
155 pq_signature,
156 }
157 }
158}
159
160#[cfg(any(feature = "reachable", feature = "server"))]
161pub trait AuditAuthenticationAssurance {
162 fn audit_authentication_assurance(
163 &self,
164 authentication_assurance: &AuthenticationAssurance,
165 authentication_challenge: &AuthenticationChallenge,
166 ) -> bool
167 where
168 Self: Verifier,
169 {
170 let epoch_timeframe = time::OffsetDateTime::now_utc().unix_timestamp() / 30;
171
172 for i in 0..2 {
175 let mut hasher = <Sha3_512 as Digest>::new();
176 hasher.update(authentication_challenge.authentication_challenge);
177 hasher.update((epoch_timeframe + i).to_le_bytes());
178
179 if verify_digest(
180 self,
181 b"Authentication Assurance",
182 hasher,
183 authentication_assurance.ec_signature(),
184 authentication_assurance.pq_signature(),
185 ) {
186 return true;
187 }
188 }
189
190 false
191 }
192}