reach_core/wire/
reach.rs

1// SPDX-FileCopyrightText: 2023—2025 eaon <eaon@posteo.net>
2// SPDX-License-Identifier: EUPL-1.2
3
4use ml_kem::EncodedSizeUser;
5#[cfg(any(debug_assertions, feature = "server"))]
6use rand_core::CryptoRngCore;
7
8#[cfg(debug_assertions)]
9use ecdh_omr::Decoy;
10use reach_aliases::*;
11#[cfg(any(feature = "reaching", feature = "reachable"))]
12use reach_proc_macros::ParticipantPublicKeys;
13use reach_proc_macros::{Verifier, communicable, prosted};
14#[cfg(debug_assertions)]
15use reach_signatures::FN_DSA_SIGNATURE_EMPTY;
16use reach_signatures::{Signatures, Verifiable, Verifies};
17
18#[cfg(any(feature = "reaching", feature = "reachable"))]
19use crate::error::WireError;
20use crate::macros::*;
21#[cfg(any(feature = "reachable", feature = "attestant"))]
22use crate::storage::Storable;
23#[cfg(any(feature = "reachable", feature = "server", debug_assertions))]
24use crate::traits::*;
25use crate::wire::{Response, proto};
26#[cfg(any(feature = "reachable", feature = "server", feature = "attestant"))]
27use crate::{
28    communication::MatchResponse,
29    wire::{ReachOk, Request},
30};
31
32#[cfg(any(feature = "reachable", feature = "server"))]
33mod reachable_server {
34    use super::*;
35
36    #[communicable(Request::RemoveReachablePublicKeys)]
37    #[prosted(proto::RemoveReachablePublicKeys, Decode, Encode, ProstTraits)]
38    pub struct RemoveReachablePublicKeys {
39        pub ec_public_key: X25519Public,
40        pub pq_public_key: MlKemPublic,
41    }
42}
43
44#[cfg(any(feature = "reachable", feature = "server"))]
45pub use reachable_server::*;
46
47#[prosted(proto::AttestantVerifyingKeys, Decode, Encode, ProstTraits)]
48#[derive(Verifier, Debug, Clone, Copy)]
49pub struct AttestantVerifyingKeys {
50    pub ec_verifying_key: Ed25519Verifying,
51    pub pq_verifying_key: FnDsaVerifying,
52}
53
54#[cfg(feature = "server")]
55impl AuditAuthenticationAssurance for AttestantVerifyingKeys {}
56
57#[cfg(any(feature = "reachable", feature = "attestant"))]
58impl Storable for AttestantVerifyingKeys {}
59
60digestible!(AttestantVerifyingKeys, verifying_keys);
61
62#[cfg(any(feature = "reaching", feature = "reachable"))]
63pub fn verify_signature_chains(
64    attestant_verifying_keys: &AttestantVerifyingKeys,
65    reachable_signed_keys: &[ReachableSignedKeys],
66) -> Result<(), WireError> {
67    for item in reachable_signed_keys {
68        if !item.verifying_keys.verify(attestant_verifying_keys) {
69            return Err(WireError::Verification);
70        }
71        if !item.public_keys.verify(&item.verifying_keys) {
72            return Err(WireError::Verification);
73        }
74    }
75
76    Ok(())
77}
78
79impl Verifies<ReachableVerifyingKeys> for AttestantVerifyingKeys {}
80
81#[cfg(any(feature = "attestant", feature = "reachable", feature = "server"))]
82mod attestant_reachable_server {
83    use super::*;
84
85    #[derive(Clone, Copy)]
86    #[communicable(Response::AuthenticationChallenge)]
87    #[prosted(proto::AuthenticationChallenge, Decode, Encode, ProstTraits)]
88    pub struct AuthenticationChallenge {
89        pub authentication_challenge: ThreeTwo,
90    }
91
92    #[cfg(feature = "server")]
93    impl RandomFromRng for AuthenticationChallenge {
94        fn random_from_rng(csprng: &mut impl CryptoRngCore) -> Self {
95            Self {
96                authentication_challenge: ThreeTwo::random_from_rng(csprng),
97            }
98        }
99    }
100
101    #[communicable(Request::AuthenticationAssurance)]
102    #[prosted(proto::AuthenticationAssurance, Decode, Encode, ProstTraits)]
103    pub struct AuthenticationAssurance {
104        pub authenticator_id: SixFour,
105        pub ec_signature: Ed25519Signature,
106        pub pq_signature: FnDsaSignature,
107    }
108
109    impl Signatures for AuthenticationAssurance {
110        fn ec_signature(&self) -> &Ed25519Signature {
111            &self.ec_signature
112        }
113
114        fn pq_signature(&self) -> &FnDsaSignature {
115            &self.pq_signature
116        }
117    }
118
119    impl MatchResponse<Request> for AuthenticationAssurance {
120        type Resp = ReachOk;
121    }
122}
123
124#[cfg(any(feature = "attestant", feature = "reachable", feature = "server"))]
125pub use attestant_reachable_server::*;
126
127#[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
128mod reaching_reachable_server {
129    #[cfg(any(feature = "reaching", feature = "reachable"))]
130    use reach_proc_macros::prosted;
131
132    use super::*;
133
134    use crate::ParticipantType;
135
136    #[prosted(proto::ReachableSignedKeys, Decode, Encode, EncodeOwned)]
137    pub struct ReachableSignedKeys {
138        pub verifying_keys: ReachableVerifyingKeys,
139        pub public_keys: ReachablePublicKeys,
140    }
141
142    nested_participant_keys!(ReachableSignedKeys);
143
144    #[communicable(Response::Reach, owned)]
145    #[prosted(proto::Reach, Decode, EncodeOwned, ProstTraitsOwned)]
146    pub struct Reach {
147        pub reachable_signed_keys: Vec<ReachableSignedKeys>,
148        pub envelope_id_hints: EnvelopeIdHints,
149    }
150}
151
152#[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
153pub use reaching_reachable_server::*;
154
155#[derive(Debug, Clone)]
156#[prosted(proto::ReachablePublicKeys, Decode, Encode, EncodeOwned, ProstTraits)]
157#[cfg_attr(
158    any(feature = "reaching", feature = "reachable"),
159    derive(ParticipantPublicKeys)
160)]
161pub struct ReachablePublicKeys {
162    pub ec_public_key: X25519Public,
163    pub pq_public_key: MlKemPublic,
164    pub ec_signature: Ed25519Signature,
165    pub pq_signature: FnDsaSignature,
166}
167
168digestible!(ReachablePublicKeys, public_keys);
169
170impl Signatures for ReachablePublicKeys {
171    fn ec_signature(&self) -> &Ed25519Signature {
172        &self.ec_signature
173    }
174
175    fn pq_signature(&self) -> &FnDsaSignature {
176        &self.pq_signature
177    }
178}
179
180impl Verifies<ReachablePublicKeys> for ReachableVerifyingKeys {}
181
182impl Verifiable for ReachablePublicKeys {}
183
184#[cfg(any(feature = "reachable", feature = "server"))]
185impl AuditAuthenticationAssurance for ReachableVerifyingKeys {}
186
187#[prosted(proto::SharedVerifyingKeys, Decode, Encode, ProstTraits)]
188#[cfg_attr(
189    any(feature = "reaching", feature = "reachable", feature = "attestant"),
190    derive(Verifier, Clone)
191)]
192pub struct SharedVerifyingKeys {
193    pub ec_verifying_key: Ed25519Verifying,
194    pub pq_verifying_key: FnDsaVerifying,
195    pub attestant_ec_signature: Ed25519Signature,
196    pub attestant_pq_signature: FnDsaSignature,
197}
198
199impl Signatures for SharedVerifyingKeys {
200    fn ec_signature(&self) -> &Ed25519Signature {
201        &self.attestant_ec_signature
202    }
203
204    fn pq_signature(&self) -> &FnDsaSignature {
205        &self.attestant_pq_signature
206    }
207}
208
209impl Verifies<SharedVerifyingKeys> for AttestantVerifyingKeys {}
210
211digestible!(SharedVerifyingKeys, verifying_keys);
212
213impl Verifiable for SharedVerifyingKeys {}
214
215#[cfg(debug_assertions)]
216impl Decoy for SharedVerifyingKeys {
217    fn random_decoy(csprng: &mut impl CryptoRngCore) -> Self {
218        let mut attestant_pq_signature = FN_DSA_SIGNATURE_EMPTY;
219        csprng.fill_bytes(&mut attestant_pq_signature);
220        let mut pq_verifying_key = FN_DSA_VERIFYING_EMPTY;
221        csprng.fill_bytes(&mut pq_verifying_key);
222
223        Self {
224            ec_verifying_key: Ed25519Verifying::from(&Ed25519Signing::generate(csprng)),
225            pq_verifying_key,
226            attestant_ec_signature: Ed25519Signature::from_bytes(&SixFour::random_from_rng(csprng)),
227            attestant_pq_signature,
228        }
229    }
230}
231
232#[cfg(any(feature = "reachable", feature = "attestant"))]
233impl Storable for SharedVerifyingKeys {}
234
235#[prosted(proto::SharedPublicKeys, Decode, Encode, ProstTraits)]
236#[derive(Debug)]
237pub struct SharedPublicKeys {
238    pub ec_public_key: X25519Public,
239    pub pq_public_key: MlKemPublic,
240    pub attestant_ec_signature: Ed25519Signature,
241    pub attestant_pq_signature: FnDsaSignature,
242}
243
244impl Signatures for SharedPublicKeys {
245    fn ec_signature(&self) -> &Ed25519Signature {
246        &self.attestant_ec_signature
247    }
248
249    fn pq_signature(&self) -> &FnDsaSignature {
250        &self.attestant_pq_signature
251    }
252}
253
254impl Verifies<SharedPublicKeys> for AttestantVerifyingKeys {}
255
256#[cfg(any(feature = "reachable", feature = "attestant"))]
257impl Storable for SharedPublicKeys {}
258
259#[cfg_attr(
260    any(feature = "reachable", feature = "server", feature = "attestant"),
261    communicable(Request::ReachableVerifyingKeys)
262)]
263#[prosted(
264    proto::ReachableVerifyingKeys,
265    Decode,
266    EncodeOwned,
267    Encode,
268    ProstTraits
269)]
270#[derive(Debug, Verifier, Clone)]
271pub struct ReachableVerifyingKeys {
272    pub ec_verifying_key: Ed25519Verifying,
273    pub pq_verifying_key: FnDsaVerifying,
274    pub attestant_ec_signature: Ed25519Signature,
275    pub attestant_pq_signature: FnDsaSignature,
276}
277
278impl Signatures for ReachableVerifyingKeys {
279    fn ec_signature(&self) -> &Ed25519Signature {
280        &self.attestant_ec_signature
281    }
282
283    fn pq_signature(&self) -> &FnDsaSignature {
284        &self.attestant_pq_signature
285    }
286}
287
288digestible!(ReachableVerifyingKeys, verifying_keys);
289
290impl Verifiable for ReachableVerifyingKeys {}
291
292#[cfg(any(feature = "reachable", feature = "attestant"))]
293impl Storable for ReachableVerifyingKeys {}
294
295#[cfg(any(feature = "attestant", feature = "server"))]
296mod attestant_server {
297    use super::*;
298
299    #[prosted(proto::RemoveReachableVerifyingKeys, Decode, Encode)]
300    pub struct RemoveReachableVerifyingKeys {
301        pub reachable_id: ThreeTwo,
302        pub attestant_timed_ec_signature: Ed25519Signature,
303        pub attestant_timed_pq_signature: FnDsaSignature,
304    }
305
306    impl MatchResponse<Request> for RemoveReachableVerifyingKeys {
307        type Resp = ReachOk;
308    }
309}
310
311#[cfg(any(feature = "attestant", feature = "server"))]
312pub use attestant_server::*;
313
314#[cfg(any(feature = "attestant", feature = "server", feature = "reachable"))]
315impl MatchResponse<Request> for ReachableVerifyingKeys {
316    type Resp = ReachOk;
317}