1use fn_dsa_kgen::KeyPairGenerator;
5use ml_kem::{EncodedSizeUser, KemCore};
6use rand_core::CryptoRngCore;
7use time::OffsetDateTime;
8
9use reach_aliases::*;
10use reach_core::{
11 ParticipantPublicKeys, ParticipantType, RandomFromRng,
12 macros::digestible,
13 memory::{
14 Message, MessageChunk, MessageMetadata, MessageOrder, ReachingKeys, ReachingPublicKeys,
15 ReachingVerifyingKeys, ReplyData,
16 },
17 wire::Salts,
18};
19use reach_encryption::{Ciphertext, HintTaker, PublicKeyDecrypter, PublicKeyEncrypted};
20use reach_passphrase::{error::PassphraseError, passphrase_seeded_rng};
21use reach_proc_macros::*;
22use reach_signatures::{Sign, Signable, VerifyingKeys};
23
24#[derive(SigningKeys, VerifyingKeys)]
25pub struct ReachingSigningKeys {
26 pub ec_signing_key: Ed25519Signing,
27 pub pq_signing_key: FnDsaSigning,
28 pub pq_verifying_key: FnDsaVerifying,
29}
30
31impl ReachingSigningKeys {
32 pub fn from_passphrase<W>(
33 passphrase: &str,
34 wordlist: &W,
35 salts: &Salts,
36 ) -> Result<Self, PassphraseError>
37 where
38 W: AsRef<[&'static str]>,
39 {
40 let mut signing_keys_rng = passphrase_seeded_rng(
41 passphrase,
42 &salts.reaching_static,
43 &salts.reaching_static,
44 wordlist,
45 )?;
46
47 Ok(Self::random_from_rng(&mut signing_keys_rng))
48 }
49}
50
51impl VerifyingKeys<ReachingVerifyingKeys> for ReachingSigningKeys {}
52
53#[derive(ParticipantSecretKeys, SecretKeysRandomFromRng, UnsignedPublicKeys)]
54pub struct ReachingSecretKeys {
55 pub ec_secret_key: X25519Secret,
56 pub pq_secret_key: MlKemSecret,
57 pub pq_public_key: MlKemPublic,
58}
59
60impl<A> PublicKeyDecrypter<A> for ReachingSecretKeys where A: PublicKeyEncrypted + Ciphertext {}
61impl HintTaker for ReachingSecretKeys {}
62
63impl ReachingSecretKeys {
64 pub fn from_passphrase<W>(
65 passphrase: &str,
66 wordlist: &W,
67 salts: &Salts,
68 ) -> Result<(Self, Self), PassphraseError>
69 where
70 W: AsRef<[&'static str]>,
71 {
72 let mut current_rng = passphrase_seeded_rng(
73 passphrase,
74 &salts.reaching_static,
75 &salts.reaching_current,
76 wordlist,
77 )?;
78 let mut previous_rng = passphrase_seeded_rng(
79 passphrase,
80 &salts.reaching_static,
81 &salts.reaching_previous,
82 wordlist,
83 )?;
84
85 Ok((
86 Self::random_from_rng(&mut current_rng),
87 Self::random_from_rng(&mut previous_rng),
88 ))
89 }
90
91 pub fn unsigned_public_keys(&self) -> UnsignedReachingPublicKeys {
92 UnsignedReachingPublicKeys::from(self)
93 }
94}
95
96pub struct UnsignedReachingPublicKeys {
97 pub ec_public_key: X25519Public,
98 pub pq_public_key: MlKemPublic,
99}
100
101digestible!(UnsignedReachingPublicKeys, public_keys);
102
103impl ParticipantPublicKeys for UnsignedReachingPublicKeys {
104 fn ec_public_key(&self) -> &X25519Public {
105 &self.ec_public_key
106 }
107
108 fn pq_public_key(&self) -> &MlKemPublic {
109 &self.pq_public_key
110 }
111
112 fn participant_type(&self) -> ParticipantType {
113 ParticipantType::Reaching
114 }
115}
116
117impl Signable for UnsignedReachingPublicKeys {
118 type SignedType = ReachingPublicKeys;
119
120 fn with_signature(
121 self,
122 ec_signature: Ed25519Signature,
123 pq_signature: FnDsaSignature,
124 ) -> ReachingPublicKeys {
125 ReachingPublicKeys {
126 ec_public_key: self.ec_public_key,
127 pq_public_key: self.pq_public_key,
128 ec_signature,
129 pq_signature,
130 }
131 }
132}
133
134pub struct ReachingSecrets {
135 pub signing_keys: ReachingSigningKeys,
136 pub secret_keys_current: ReachingSecretKeys,
137 pub secret_keys_previous: ReachingSecretKeys,
138}
139
140impl ReachingSecrets {
141 pub fn from_passphrase<W>(
142 passphrase: &str,
143 wordlist: &W,
144 salts: &Salts,
145 ) -> Result<Self, PassphraseError>
146 where
147 W: AsRef<[&'static str]>,
148 {
149 let signing_keys = ReachingSigningKeys::from_passphrase(passphrase, wordlist, salts)?;
150 let (secret_keys_current, secret_keys_previous) =
151 ReachingSecretKeys::from_passphrase(passphrase, wordlist, salts)?;
152
153 Ok(Self {
154 signing_keys,
155 secret_keys_current,
156 secret_keys_previous,
157 })
158 }
159
160 pub fn reaching_keys(&self, csprng: &mut impl CryptoRngCore) -> ReachingKeys {
161 ReachingKeys {
162 verifying_keys: ReachingVerifyingKeys::from(&self.signing_keys),
163 public_keys: self
164 .signing_keys
165 .sign(self.secret_keys_current.unsigned_public_keys(), csprng),
166 }
167 }
168
169 pub fn previous_public_keys(&self) -> UnsignedReachingPublicKeys {
170 self.secret_keys_previous.unsigned_public_keys()
171 }
172}
173
174pub fn new_contact(content: String, language: String, reaching_keys: &ReachingKeys) -> Message {
175 let metadata = MessageMetadata {
176 order: MessageOrder::Datetime(
177 OffsetDateTime::now_local().unwrap_or(OffsetDateTime::now_utc()),
178 ),
179 reply_data: ReplyData::ReachingPublicKeys(Box::new(reaching_keys.public_keys.clone())),
180 envelope_link: None,
181 };
182
183 Message {
184 metadata,
185 chunk: MessageChunk::text_only(content, language),
186 additional_chunks: vec![],
187 }
188}