ed448_goldilocks_plus/sign/
signing_key.rs1use crate::curve::edwards::extended::PointBytes;
5use crate::sign::expanded::ExpandedSecretKey;
6use crate::{
7 Context, Scalar, ScalarBytes, Signature, VerifyingKey, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH,
8};
9use core::fmt::{self, Debug, Formatter};
10use crypto_signature::Error;
11use sha3::{
12 digest::{
13 consts::U64, crypto_common::BlockSizeUser, typenum::IsEqual, ExtendableOutput, FixedOutput,
14 FixedOutputReset, HashMarker, Update, XofReader,
15 },
16 Digest,
17};
18use subtle::{Choice, ConstantTimeEq};
19use zeroize::{Zeroize, ZeroizeOnDrop};
20
21pub type SecretKey = ScalarBytes;
25
26pub trait PreHash {
28 fn fill_bytes(&mut self, out: &mut [u8]);
30}
31
32#[derive(Debug)]
34pub struct PreHasherXmd<HashT>
35where
36 HashT: BlockSizeUser + Default + FixedOutput + FixedOutputReset + Update + HashMarker,
37 HashT::OutputSize: IsEqual<U64>,
38{
39 hasher: HashT,
40}
41
42impl<HashT> From<HashT> for PreHasherXmd<HashT>
43where
44 HashT: BlockSizeUser + Default + FixedOutput + FixedOutputReset + Update + HashMarker,
45 HashT::OutputSize: IsEqual<U64>,
46{
47 fn from(hasher: HashT) -> Self {
48 Self::new(hasher)
49 }
50}
51
52impl<HashT> PreHasherXmd<HashT>
53where
54 HashT: BlockSizeUser + Default + FixedOutput + FixedOutputReset + Update + HashMarker,
55 HashT::OutputSize: IsEqual<U64>,
56{
57 pub fn new(hasher: HashT) -> Self {
59 Self { hasher }
60 }
61}
62
63impl<HashT> PreHash for PreHasherXmd<HashT>
64where
65 HashT: BlockSizeUser + Default + FixedOutput + FixedOutputReset + Update + HashMarker,
66 HashT::OutputSize: IsEqual<U64>,
67{
68 fn fill_bytes(&mut self, out: &mut [u8]) {
69 out.copy_from_slice(self.hasher.finalize_reset().as_slice());
70 }
71}
72
73pub struct PreHasherXof<HashT>
75where
76 HashT: Default + ExtendableOutput + Update,
77{
78 reader: <HashT as ExtendableOutput>::Reader,
79}
80
81impl<HashT> Debug for PreHasherXof<HashT>
82where
83 HashT: Default + ExtendableOutput + Update,
84{
85 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
86 f.debug_struct("SigningPreHasherXof")
87 .finish_non_exhaustive()
88 }
89}
90
91impl<HashT> PreHash for PreHasherXof<HashT>
92where
93 HashT: Default + ExtendableOutput + Update,
94{
95 fn fill_bytes(&mut self, out: &mut [u8]) {
96 self.reader.read(out);
97 }
98}
99
100impl<HashT> From<HashT> for PreHasherXof<HashT>
101where
102 HashT: Default + ExtendableOutput + Update,
103{
104 fn from(hasher: HashT) -> Self {
105 Self::new(hasher)
106 }
107}
108
109impl<HashT> PreHasherXof<HashT>
110where
111 HashT: Default + ExtendableOutput + Update,
112{
113 pub fn new(hasher: HashT) -> Self {
115 Self {
116 reader: hasher.finalize_xof(),
117 }
118 }
119}
120
121#[derive(Clone)]
123pub struct SigningKey {
124 pub(crate) secret: ExpandedSecretKey,
125}
126
127impl Debug for SigningKey {
128 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
129 f.debug_struct("SigningKey")
130 .field("verifying_key", &self.secret.public_key)
131 .finish_non_exhaustive()
132 }
133}
134
135impl Zeroize for SigningKey {
136 fn zeroize(&mut self) {
137 self.secret.zeroize();
138 }
139}
140
141impl Drop for SigningKey {
142 fn drop(&mut self) {
143 self.secret.zeroize();
144 }
145}
146
147impl ZeroizeOnDrop for SigningKey {}
148
149impl ConstantTimeEq for SigningKey {
150 fn ct_eq(&self, other: &Self) -> Choice {
151 self.secret.seed.ct_eq(&other.secret.seed)
152 }
153}
154
155impl Eq for SigningKey {}
156
157impl PartialEq for SigningKey {
158 fn eq(&self, other: &Self) -> bool {
159 self.ct_eq(other).into()
160 }
161}
162
163impl From<SecretKey> for SigningKey {
164 fn from(secret_scalar: SecretKey) -> Self {
165 Self::from(&secret_scalar)
166 }
167}
168
169impl From<&SecretKey> for SigningKey {
170 fn from(secret_scalar: &SecretKey) -> Self {
171 Self {
172 secret: ExpandedSecretKey::from(secret_scalar),
173 }
174 }
175}
176
177#[cfg(any(feature = "alloc", feature = "std"))]
178impl TryFrom<Vec<u8>> for SigningKey {
179 type Error = &'static str;
180
181 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
182 Self::try_from(value.as_slice())
183 }
184}
185
186#[cfg(any(feature = "alloc", feature = "std"))]
187impl TryFrom<&Vec<u8>> for SigningKey {
188 type Error = &'static str;
189
190 fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
191 Self::try_from(value.as_slice())
192 }
193}
194
195impl TryFrom<&[u8]> for SigningKey {
196 type Error = &'static str;
197
198 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
199 if value.len() != SECRET_KEY_LENGTH {
200 return Err("Invalid length for a signing key");
201 }
202 Ok(Self::from(ScalarBytes::from_slice(value)))
203 }
204}
205
206#[cfg(any(feature = "alloc", feature = "std"))]
207impl TryFrom<Box<[u8]>> for SigningKey {
208 type Error = &'static str;
209
210 fn try_from(value: Box<[u8]>) -> Result<Self, Self::Error> {
211 Self::try_from(value.as_ref())
212 }
213}
214
215impl<D> crypto_signature::DigestSigner<D, Signature> for SigningKey
216where
217 D: Digest,
218{
219 fn try_sign_digest(&self, digest: D) -> Result<Signature, Error> {
220 let mut prehashed_message = [0u8; 64];
221 prehashed_message.copy_from_slice(digest.finalize().as_slice());
222 let sig = self.secret.sign_prehashed(&[], &prehashed_message)?;
223 Ok(sig.into())
224 }
225}
226
227impl crypto_signature::hazmat::PrehashSigner<Signature> for SigningKey {
228 fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature, Error> {
229 let sig = self.secret.sign_prehashed(&[], prehash)?;
230 Ok(sig.into())
231 }
232}
233
234impl crypto_signature::Signer<Signature> for SigningKey {
235 fn try_sign(&self, msg: &[u8]) -> Result<Signature, Error> {
236 let sig = self.secret.sign_raw(msg)?;
237 Ok(sig.into())
238 }
239}
240
241impl<D> crypto_signature::DigestSigner<D, Signature> for Context<'_, '_, SigningKey>
242where
243 D: Digest,
244{
245 fn try_sign_digest(&self, digest: D) -> Result<Signature, Error> {
246 let mut prehashed_message = [0u8; 64];
247 prehashed_message.copy_from_slice(digest.finalize().as_slice());
248 let sig = self
249 .key
250 .secret
251 .sign_prehashed(self.value, &prehashed_message)?;
252 Ok(sig.into())
253 }
254}
255
256impl crypto_signature::hazmat::PrehashSigner<Signature> for Context<'_, '_, SigningKey> {
257 fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature, Error> {
258 let sig = self.key.secret.sign_prehashed(self.value, prehash)?;
259 Ok(sig.into())
260 }
261}
262
263impl crypto_signature::Signer<Signature> for Context<'_, '_, SigningKey> {
264 fn try_sign(&self, msg: &[u8]) -> Result<Signature, Error> {
265 let sig = self.key.secret.sign_ctx(self.value, msg)?;
266 Ok(sig.into())
267 }
268}
269
270impl<D> crypto_signature::DigestVerifier<D, Signature> for SigningKey
271where
272 D: Digest,
273{
274 fn verify_digest(&self, msg: D, signature: &Signature) -> Result<(), Error> {
275 <VerifyingKey as crypto_signature::DigestVerifier<D, Signature>>::verify_digest(
276 &self.secret.public_key,
277 msg,
278 signature,
279 )
280 }
281}
282
283impl crypto_signature::Verifier<Signature> for SigningKey {
284 fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> {
285 self.secret.public_key.verify_raw(signature, msg)
286 }
287}
288
289#[cfg(all(any(feature = "alloc", feature = "std"), feature = "pkcs8"))]
290impl pkcs8::EncodePrivateKey for SigningKey {
291 fn to_pkcs8_der(&self) -> pkcs8::Result<pkcs8::SecretDocument> {
292 KeypairBytes::from(self).to_pkcs8_der()
293 }
294}
295
296#[cfg(all(any(feature = "alloc", feature = "std"), feature = "pkcs8"))]
297impl pkcs8::spki::DynSignatureAlgorithmIdentifier for SigningKey {
298 fn signature_algorithm_identifier(
299 &self,
300 ) -> pkcs8::spki::Result<pkcs8::spki::AlgorithmIdentifierOwned> {
301 Ok(pkcs8::spki::AlgorithmIdentifier {
303 oid: super::ALGORITHM_OID,
304 parameters: None,
305 })
306 }
307}
308
309#[cfg(feature = "pkcs8")]
310#[derive(Clone, Copy, Debug, Eq, PartialEq)]
312pub struct KeypairBytes {
313 pub secret_key: PointBytes,
315 pub verifying_key: Option<PointBytes>,
317}
318
319#[cfg(all(any(feature = "alloc", feature = "std"), feature = "pkcs8"))]
320impl pkcs8::EncodePrivateKey for KeypairBytes {
321 fn to_pkcs8_der(&self) -> pkcs8::Result<pkcs8::SecretDocument> {
322 let mut private_key = [0u8; 2 + SECRET_KEY_LENGTH];
323 private_key[0] = 0x04;
324 private_key[1] = SECRET_KEY_LENGTH as u8;
325 private_key[2..].copy_from_slice(self.secret_key.as_ref());
326
327 let private_key_info = pkcs8::PrivateKeyInfo {
328 algorithm: super::ALGORITHM_ID,
329 private_key: &private_key,
330 public_key: self.verifying_key.as_ref().map(|v| v.as_ref()),
331 };
332 let result = pkcs8::SecretDocument::encode_msg(&private_key_info)?;
333
334 #[cfg(feature = "zeroize")]
335 private_key.zeroize();
336
337 Ok(result)
338 }
339}
340
341#[cfg(feature = "pkcs8")]
342impl TryFrom<pkcs8::PrivateKeyInfo<'_>> for KeypairBytes {
343 type Error = pkcs8::Error;
344
345 fn try_from(value: pkcs8::PrivateKeyInfo<'_>) -> Result<Self, Self::Error> {
346 if value.algorithm.oid != super::ALGORITHM_OID {
347 return Err(pkcs8::Error::KeyMalformed);
348 }
349 if value.private_key.len() != SECRET_KEY_LENGTH {
350 return Err(pkcs8::Error::KeyMalformed);
351 }
352 let mut secret_key = [0u8; SECRET_KEY_LENGTH];
353 secret_key.copy_from_slice(value.private_key);
354 let verifying_key = if let Some(public_key) = value.public_key {
355 if public_key.len() != PUBLIC_KEY_LENGTH {
356 return Err(pkcs8::Error::KeyMalformed);
357 }
358 let mut bytes = [0u8; PUBLIC_KEY_LENGTH];
359 bytes.copy_from_slice(public_key);
360 Some(bytes)
361 } else {
362 None
363 };
364 Ok(KeypairBytes {
365 secret_key,
366 verifying_key,
367 })
368 }
369}
370
371#[cfg(feature = "pkcs8")]
372impl TryFrom<KeypairBytes> for SigningKey {
373 type Error = pkcs8::Error;
374
375 fn try_from(value: KeypairBytes) -> Result<Self, Self::Error> {
376 Self::try_from(&value)
377 }
378}
379
380#[cfg(feature = "pkcs8")]
381impl TryFrom<&KeypairBytes> for SigningKey {
382 type Error = pkcs8::Error;
383
384 fn try_from(value: &KeypairBytes) -> Result<Self, Self::Error> {
385 let signing_key = SigningKey::from(SecretKey::from_slice(value.secret_key.as_ref()));
386
387 if let Some(public_bytes) = value.verifying_key {
388 let verifying_key =
389 VerifyingKey::from_bytes(&public_bytes).map_err(|_| pkcs8::Error::KeyMalformed)?;
390 if signing_key.verifying_key() != verifying_key {
391 return Err(pkcs8::Error::KeyMalformed);
392 }
393 }
394 Ok(signing_key)
395 }
396}
397
398#[cfg(feature = "pkcs8")]
399impl From<&SigningKey> for KeypairBytes {
400 fn from(signing_key: &SigningKey) -> Self {
401 KeypairBytes {
402 secret_key: PointBytes::from(signing_key.to_bytes()),
403 verifying_key: Some(PointBytes::from(signing_key.verifying_key().to_bytes())),
404 }
405 }
406}
407
408#[cfg(feature = "pkcs8")]
409impl TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey {
410 type Error = pkcs8::Error;
411
412 fn try_from(value: pkcs8::PrivateKeyInfo<'_>) -> Result<Self, Self::Error> {
413 KeypairBytes::try_from(value)?.try_into()
414 }
415}
416
417#[cfg(feature = "serde")]
418impl serdect::serde::Serialize for SigningKey {
419 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
420 where
421 S: serdect::serde::Serializer,
422 {
423 serdect::array::serialize_hex_lower_or_bin(&self.secret.seed, s)
424 }
425}
426
427#[cfg(feature = "serde")]
428impl<'de> serdect::serde::Deserialize<'de> for SigningKey {
429 fn deserialize<D>(d: D) -> Result<Self, D::Error>
430 where
431 D: serdect::serde::Deserializer<'de>,
432 {
433 let mut bytes = SecretKey::default();
434 serdect::array::deserialize_hex_or_bin(&mut bytes, d)?;
435 Ok(SigningKey::from(bytes))
436 }
437}
438
439impl SigningKey {
440 pub fn generate(mut rng: impl rand_core::CryptoRngCore) -> Self {
442 let mut secret_scalar = SecretKey::default();
443 rng.fill_bytes(secret_scalar.as_mut());
444 assert!(!secret_scalar.iter().all(|&v| v == 0));
445 Self {
446 secret: ExpandedSecretKey::from(&secret_scalar),
447 }
448 }
449
450 pub fn to_bytes(&self) -> SecretKey {
452 self.secret.seed
453 }
454
455 pub fn as_bytes(&self) -> &SecretKey {
457 &self.secret.seed
458 }
459
460 pub fn to_scalar(&self) -> Scalar {
465 self.secret.scalar
466 }
467
468 pub fn verifying_key(&self) -> VerifyingKey {
470 self.secret.public_key
471 }
472
473 pub fn with_context<'k, 'v>(&'k self, context: &'v [u8]) -> Context<'k, 'v, Self> {
476 Context {
477 key: self,
478 value: context,
479 }
480 }
481
482 pub fn sign_raw(&self, message: &[u8]) -> Signature {
485 let sig = self
486 .secret
487 .sign_raw(message)
488 .expect("to succeed since no context is provided");
489 sig.into()
490 }
491
492 pub fn sign_ctx(&self, context: &[u8], message: &[u8]) -> Result<Signature, Error> {
495 let sig = self.secret.sign_ctx(context, message)?;
496 Ok(sig.into())
497 }
498
499 pub fn sign_prehashed<D>(
502 &self,
503 context: Option<&[u8]>,
504 mut prehashed_message: D,
505 ) -> Result<Signature, Error>
506 where
507 D: PreHash,
508 {
509 let mut m = [0u8; 64];
510 prehashed_message.fill_bytes(&mut m);
511 let sig = self
512 .secret
513 .sign_prehashed(context.unwrap_or_default(), &m)?;
514 Ok(sig.into())
515 }
516}
517#[cfg(feature = "serde")]
518#[test]
519fn serialization() {
520 use rand_chacha::ChaCha8Rng;
521 use rand_core::SeedableRng;
522
523 let mut rng = ChaCha8Rng::from_seed([0u8; 32]);
524 let signing_key = SigningKey::generate(&mut rng);
525
526 let bytes = serde_bare::to_vec(&signing_key).unwrap();
527 let signing_key2: SigningKey = serde_bare::from_slice(&bytes).unwrap();
528 assert_eq!(signing_key, signing_key2);
529
530 let string = serde_json::to_string(&signing_key).unwrap();
531 let signing_key3: SigningKey = serde_json::from_str(&string).unwrap();
532 assert_eq!(signing_key, signing_key3);
533}