static_dh_ecdh/ecdh/
ecdh.rs1use core::ops::{Mul};
4use core::{convert::TryInto};
5
6use num_bigint_dig::{BigInt, BigUint, Sign};
7use rand_chacha::rand_core::{RngCore, SeedableRng};
8use rand_chacha::ChaCha20Rng;
9
10use generic_array::{
11 typenum::{self, Unsigned},
12 ArrayLength, GenericArray,
13};
14
15use elliptic_curve::sec1::EncodedPoint as PubKey;
16use elliptic_curve::{sec1::UncompressedPointSize, Curve};
17use p256::{AffinePoint, NistP256, NonZeroScalar, PublicKey, Scalar};
18use p384::{NistP384, SecretKey as P384Secret};
19
20use super::affine_math::{APTypes, EncodedTypes, MyAffinePoint};
21
22use crate::{constants, dh::dh};
23use crate::{CryptoError, Result};
24
25pub trait ToBytes {
27 type OutputSize: ArrayLength<u8>;
29
30 fn to_bytes(&self) -> GenericArray<u8, Self::OutputSize>;
32
33 fn size() -> usize {
35 Self::OutputSize::to_usize()
36 }
37}
38pub trait FromBytes: ToBytes + Sized {
40 fn from_bytes(bytes: &[u8]) -> Result<Self>;
42}
43#[derive(Clone)]
45pub struct SkP256(NonZeroScalar);
46#[derive(Debug, Clone, PartialEq)]
48pub struct PkP256(p256::PublicKey);
49
50impl ToBytes for PkP256 {
52 type OutputSize = UncompressedPointSize<NistP256>;
54
55 fn to_bytes(&self) -> GenericArray<u8, Self::OutputSize> {
56 let bytes = p256::EncodedPoint::encode(self.0, false);
58 GenericArray::clone_from_slice(bytes.as_bytes())
59 }
60}
61
62impl FromBytes for PkP256 {
64 fn from_bytes(bytes: &[u8]) -> Result<Self> {
65 if bytes.len() != Self::OutputSize::to_usize() {
68 return Err(CryptoError::InvalidEncoding);
69 }
70 let parsed =
74 p256::PublicKey::from_sec1_bytes(bytes).map_err(|_| CryptoError::InvalidEncoding)?;
75 Ok(PkP256(parsed))
76 }
77}
78
79impl ToBytes for SkP256 {
80 type OutputSize = <NistP256 as Curve>::FieldSize;
82
83 fn to_bytes(&self) -> GenericArray<u8, Self::OutputSize> {
84 self.0.into()
88 }
90}
91
92impl FromBytes for SkP256 {
93 fn from_bytes(bytes: &[u8]) -> Result<Self> {
94 if bytes.len() != Self::OutputSize::to_usize() {
96 return Err(CryptoError::InvalidEncoding);
97 }
98 let arr = GenericArray::<u8, Self::OutputSize>::clone_from_slice(bytes);
100 let scalar = Scalar::from_bytes_reduced(&arr);
103 let nonzero_scalar = NonZeroScalar::new(scalar).ok_or(CryptoError::InvalidEncoding)?;
104
105 Ok(SkP256(nonzero_scalar))
106 }
107}
108
109#[derive(Debug, Clone, PartialEq)]
111pub struct SharedSecretP256(pub AffinePoint);
112
113impl ToBytes for SharedSecretP256 {
115 type OutputSize = typenum::U32;
116
117 fn to_bytes(&self) -> GenericArray<u8, Self::OutputSize> {
118 let bytes = p256::EncodedPoint::from(self.0);
120 GenericArray::<u8, Self::OutputSize>::clone_from_slice(bytes.x().unwrap())
121 }
122}
123pub trait KeyExchange {
125 type SKey: Clone + ToBytes + FromBytes;
127 type PubKey: Clone + ToBytes + FromBytes;
129 type CompSecret: ToBytes;
131
132 fn generate_private_key(seed: [u8; 32]) -> Self::SKey;
134 fn generate_public_key(sk: &Self::SKey) -> Self::PubKey;
136 fn generate_shared_secret(sk: &Self::SKey, pk: &Self::PubKey) -> Result<Self::CompSecret>;
138}
139pub struct ECDHNISTP256;
141
142impl KeyExchange for ECDHNISTP256 {
143 type SKey = SkP256;
144 type PubKey = PkP256;
145 type CompSecret = SharedSecretP256;
146
147 fn generate_private_key(seed: [u8; 32]) -> Self::SKey {
148 let mut rng = ChaCha20Rng::from_seed(seed); let mut dest = [0; 32];
150 rng.fill_bytes(&mut dest);
151 let arr = GenericArray::<u8, _>::clone_from_slice(&dest);
152 SkP256(NonZeroScalar::from_repr(arr).expect("Private scalar value initialization failed"))
153 }
154
155 fn generate_public_key(sk: &Self::SKey) -> Self::PubKey {
156 let affine_pub_key = AffinePoint::generator().mul(sk.0);
157 PkP256(PublicKey::from_affine(affine_pub_key).expect("Failed to derive public key"))
158 }
159
160 fn generate_shared_secret(
161 sk: &Self::SKey,
162 others_pk: &Self::PubKey,
163 ) -> Result<Self::CompSecret> {
164 let shared_secret = others_pk.0.as_affine().mul(sk.0);
165 Ok(SharedSecretP256(shared_secret))
166 }
167}
168
169#[derive(Debug, Clone)]
171pub struct SkP384(P384Secret);
172#[derive(Debug, Clone, PartialEq)]
174pub struct PkP384(pub PubKey<NistP384>);
175#[derive(Debug, Clone, PartialEq)]
177pub struct SharedSecretP384(pub PubKey<NistP384>);
178
179impl ToBytes for PkP384 {
181 type OutputSize = UncompressedPointSize<NistP384>;
183
184 fn to_bytes(&self) -> GenericArray<u8, Self::OutputSize> {
185 GenericArray::clone_from_slice(self.0.as_bytes())
187 }
188}
189
190impl FromBytes for PkP384 {
192 fn from_bytes(bytes: &[u8]) -> Result<Self> {
193 if bytes.len() != Self::OutputSize::to_usize() {
196 return Err(CryptoError::InvalidEncoding);
197 }
198 let parsed = PubKey::from_bytes(bytes).map_err(|_| CryptoError::InvalidEncoding)?;
202 Ok(PkP384(parsed))
203 }
204}
205
206impl ToBytes for SkP384 {
207 type OutputSize = <NistP384 as Curve>::FieldSize;
209
210 fn to_bytes(&self) -> GenericArray<u8, Self::OutputSize> {
211 self.0.to_bytes()
215 }
217}
218
219impl FromBytes for SkP384 {
220 fn from_bytes(bytes: &[u8]) -> Result<Self> {
221 if bytes.len() != Self::OutputSize::to_usize() {
223 return Err(CryptoError::InvalidEncoding);
224 }
225
226 Ok(SkP384(
227 P384Secret::from_bytes(bytes).expect("Failed to deserialize raw private scalar"),
228 ))
229 }
230}
231
232impl ToBytes for SharedSecretP384 {
234 type OutputSize = typenum::U48;
235
236 fn to_bytes(&self) -> GenericArray<u8, Self::OutputSize> {
237 let bytes = p384::EncodedPoint::from(self.0);
239 GenericArray::<u8, Self::OutputSize>::clone_from_slice(bytes.x().unwrap())
240 }
241}
242
243pub struct ECDHNISTP384<const N: usize>;
245
246impl<const N: usize> KeyExchange for ECDHNISTP384<N> {
247 type SKey = SkP384;
248 type PubKey = PkP384;
249 type CompSecret = SharedSecretP384;
250
251 fn generate_private_key(seed: [u8; 32]) -> Self::SKey {
252 let mut rng = ChaCha20Rng::from_seed(seed); let mut dest = [0; N];
254 rng.fill_bytes(&mut dest);
255 SkP384(P384Secret::from_bytes(&dest).expect("Failed to generate a `P384` private key"))
256 }
257
258 fn generate_public_key(sk: &Self::SKey) -> Self::PubKey {
259 let mod_prime =
260 dh::unhexlify_to_bytearray::<N>(&constants::ECDH_NIST_384_MODP.replace("0x", ""));
261 let b_val =
262 dh::unhexlify_to_bytearray::<N>(&constants::ECDH_NIST_384_B_VAL.replace("0x", ""));
263
264 let a = BigInt::from(-3);
265 let b = BigInt::from_bytes_be(Sign::Plus, &b_val);
266 let modp = BigInt::from_bytes_be(Sign::Plus, &mod_prime);
267
268 let gen = MyAffinePoint::<N>::generator();
269 let pk = match gen {
270 APTypes::P384(gen) => {
271 let pub_key = MyAffinePoint::<48>::double_and_add(
272 gen,
273 BigUint::from_bytes_be(sk.clone().to_bytes().as_slice()),
274 &a,
275 &b,
276 &modp,
277 );
278 if let EncodedTypes::EncodedTypeP384(pubkey) = pub_key.to_uncompressed_bytes(false) {
279 pubkey
280 } else {
281 unreachable!() }
283 }
284 _ => unreachable!(),
285 };
286 pk
287 }
288
289 fn generate_shared_secret(
290 sk: &Self::SKey,
291 others_pk: &Self::PubKey,
292 ) -> Result<Self::CompSecret> {
293 let mod_prime =
294 dh::unhexlify_to_bytearray::<N>(&constants::ECDH_NIST_384_MODP.replace("0x", ""));
295 let b_val =
296 dh::unhexlify_to_bytearray::<N>(&constants::ECDH_NIST_384_B_VAL.replace("0x", ""));
297
298 let a = BigInt::from(-3);
299 let b = BigInt::from_bytes_be(Sign::Plus, &b_val);
300 let modp = BigInt::from_bytes_be(Sign::Plus, &mod_prime);
301
302 if others_pk.0.as_bytes().len() != 97 {
303 panic!()
304 };
305 let pk: [u8; 97] = others_pk
306 .0
307 .as_bytes()
308 .try_into()
309 .expect("failed to serialize `EncodedPoint`");
310 let affine_pt = MyAffinePoint {
311 x: BigInt::from_bytes_be(Sign::Plus, &pk[1..N + 1]),
312 y: BigInt::from_bytes_be(Sign::Plus, &pk[N + 1..97]),
313 infinity: false,
314 };
315
316 let shared_secret = MyAffinePoint::<48>::double_and_add(
317 affine_pt,
318 BigUint::from_bytes_be(sk.clone().to_bytes().as_slice()),
319 &a,
320 &b,
321 &modp,
322 );
323 if let EncodedTypes::EncodedTypeP384_SS(sharedsecret) = shared_secret.to_uncompressed_bytes(true)
324 {
325 Ok(sharedsecret)
326 } else {
327 unreachable!() }
329 }
330}
331