1#![allow(clippy::integer_arithmetic)]
38
39use crate::{
40 hash::{CryptoHash, CryptoHasher},
41 traits::*,
42};
43use anyhow::{anyhow, Result};
44use core::convert::TryFrom;
45use diem_crypto_derive::{
46 DeserializeKey, SerializeKey, SilentDebug, SilentDisplay,
47};
48use mirai_annotations::*;
49use serde::Serialize;
50use std::{cmp::Ordering, fmt};
51
52pub const ED25519_PRIVATE_KEY_LENGTH: usize = ed25519_dalek::SECRET_KEY_LENGTH;
54pub const ED25519_PUBLIC_KEY_LENGTH: usize = ed25519_dalek::PUBLIC_KEY_LENGTH;
56pub const ED25519_SIGNATURE_LENGTH: usize = ed25519_dalek::SIGNATURE_LENGTH;
58
59const L: [u8; 32] = [
61 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2,
62 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
64];
65
66#[derive(DeserializeKey, SerializeKey, SilentDebug, SilentDisplay)]
68pub struct Ed25519PrivateKey(ed25519_dalek::SecretKey);
69
70#[cfg(feature = "assert-private-keys-not-cloneable")]
71static_assertions::assert_not_impl_any!(Ed25519PrivateKey: Clone);
72
73#[cfg(any(test, feature = "cloneable-private-keys"))]
74impl Clone for Ed25519PrivateKey {
75 fn clone(&self) -> Self {
76 let serialized: &[u8] = &(self.to_bytes());
77 Ed25519PrivateKey::try_from(serialized).unwrap()
78 }
79}
80
81#[derive(DeserializeKey, Clone, SerializeKey)]
83pub struct Ed25519PublicKey(ed25519_dalek::PublicKey);
84
85#[cfg(mirai)]
86use crate::tags::ValidatedPublicKeyTag;
87#[cfg(not(mirai))]
88struct ValidatedPublicKeyTag {}
89
90#[derive(DeserializeKey, Clone, SerializeKey)]
92pub struct Ed25519Signature(ed25519_dalek::Signature);
93
94impl Ed25519PrivateKey {
95 pub const LENGTH: usize = ed25519_dalek::SECRET_KEY_LENGTH;
97
98 pub fn to_bytes(&self) -> [u8; ED25519_PRIVATE_KEY_LENGTH] {
100 self.0.to_bytes()
101 }
102
103 fn from_bytes_unchecked(
106 bytes: &[u8],
107 ) -> std::result::Result<Ed25519PrivateKey, CryptoMaterialError> {
108 match ed25519_dalek::SecretKey::from_bytes(bytes) {
109 Ok(dalek_secret_key) => Ok(Ed25519PrivateKey(dalek_secret_key)),
110 Err(_) => Err(CryptoMaterialError::DeserializationError),
111 }
112 }
113
114 fn sign_arbitrary_message(&self, message: &[u8]) -> Ed25519Signature {
117 let secret_key: &ed25519_dalek::SecretKey = &self.0;
118 let public_key: Ed25519PublicKey = self.into();
119 let expanded_secret_key: ed25519_dalek::ExpandedSecretKey =
120 ed25519_dalek::ExpandedSecretKey::from(secret_key);
121 let sig = expanded_secret_key.sign(message.as_ref(), &public_key.0);
122 Ed25519Signature(sig)
123 }
124}
125
126impl Ed25519PublicKey {
127 pub fn to_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_LENGTH] {
129 self.0.to_bytes()
130 }
131
132 pub(crate) fn from_bytes_unchecked(
135 bytes: &[u8],
136 ) -> std::result::Result<Ed25519PublicKey, CryptoMaterialError> {
137 match ed25519_dalek::PublicKey::from_bytes(bytes) {
138 Ok(dalek_public_key) => Ok(Ed25519PublicKey(dalek_public_key)),
139 Err(_) => Err(CryptoMaterialError::DeserializationError),
140 }
141 }
142
143 #[cfg(test)]
157 pub(crate) fn from_x25519_public_bytes(
158 x25519_bytes: &[u8], negative: bool,
159 ) -> Result<Self, CryptoMaterialError> {
160 if x25519_bytes.len() != 32 {
161 return Err(CryptoMaterialError::DeserializationError);
162 }
163 let key_bits = {
164 let mut bits = [0u8; 32];
165 bits.copy_from_slice(x25519_bytes);
166 bits
167 };
168 let mtg_point = curve25519_dalek::montgomery::MontgomeryPoint(key_bits);
169 let sign = if negative { 1u8 } else { 0u8 };
170 let ed_point = mtg_point
171 .to_edwards(sign)
172 .ok_or(CryptoMaterialError::DeserializationError)?;
173 Ed25519PublicKey::try_from(&ed_point.compress().as_bytes()[..])
174 }
175}
176
177impl Ed25519Signature {
178 pub const LENGTH: usize = ed25519_dalek::SIGNATURE_LENGTH;
180
181 pub fn to_bytes(&self) -> [u8; ED25519_SIGNATURE_LENGTH] {
183 self.0.to_bytes()
184 }
185
186 pub(crate) fn from_bytes_unchecked(
189 bytes: &[u8],
190 ) -> std::result::Result<Ed25519Signature, CryptoMaterialError> {
191 match ed25519_dalek::Signature::try_from(bytes) {
192 Ok(dalek_signature) => Ok(Ed25519Signature(dalek_signature)),
193 Err(_) => Err(CryptoMaterialError::DeserializationError),
194 }
195 }
196
197 #[cfg(any(test, feature = "fuzzing"))]
199 pub fn dummy_signature() -> Self {
200 Self::from_bytes_unchecked(&[0u8; Self::LENGTH]).unwrap()
201 }
202
203 pub fn check_malleability(
224 bytes: &[u8],
225 ) -> std::result::Result<(), CryptoMaterialError> {
226 if bytes.len() != ED25519_SIGNATURE_LENGTH {
227 return Err(CryptoMaterialError::WrongLengthError);
228 }
229 if !check_s_lt_l(&bytes[32..]) {
230 return Err(CryptoMaterialError::CanonicalRepresentationError);
231 }
232 Ok(())
233 }
234}
235
236impl PrivateKey for Ed25519PrivateKey {
241 type PublicKeyMaterial = Ed25519PublicKey;
242}
243
244impl SigningKey for Ed25519PrivateKey {
245 type SignatureMaterial = Ed25519Signature;
246 type VerifyingKeyMaterial = Ed25519PublicKey;
247
248 fn sign<T: CryptoHash + Serialize>(&self, message: &T) -> Ed25519Signature {
249 let mut bytes = <T::Hasher as CryptoHasher>::seed().to_vec();
250 bcs::serialize_into(&mut bytes, &message)
251 .map_err(|_| CryptoMaterialError::SerializationError)
252 .expect("Serialization of signable material should not fail.");
253 Ed25519PrivateKey::sign_arbitrary_message(&self, bytes.as_ref())
254 }
255
256 #[cfg(any(test, feature = "fuzzing"))]
257 fn sign_arbitrary_message(&self, message: &[u8]) -> Ed25519Signature {
258 Ed25519PrivateKey::sign_arbitrary_message(self, message)
259 }
260}
261
262impl Uniform for Ed25519PrivateKey {
263 fn generate<R>(rng: &mut R) -> Self
264 where R: ::rand::RngCore + ::rand::CryptoRng {
265 Ed25519PrivateKey(ed25519_dalek::SecretKey::generate(rng))
266 }
267}
268
269impl PartialEq<Self> for Ed25519PrivateKey {
270 fn eq(&self, other: &Self) -> bool { self.to_bytes() == other.to_bytes() }
271}
272
273impl Eq for Ed25519PrivateKey {}
274
275impl TryFrom<&[u8]> for Ed25519PrivateKey {
278 type Error = CryptoMaterialError;
279
280 fn try_from(
283 bytes: &[u8],
284 ) -> std::result::Result<Ed25519PrivateKey, CryptoMaterialError> {
285 Ed25519PrivateKey::from_bytes_unchecked(bytes)
293 }
294}
295
296impl Length for Ed25519PrivateKey {
297 fn length(&self) -> usize { Self::LENGTH }
298}
299
300impl ValidCryptoMaterial for Ed25519PrivateKey {
301 fn to_bytes(&self) -> Vec<u8> { self.to_bytes().to_vec() }
302}
303
304impl Genesis for Ed25519PrivateKey {
305 fn genesis() -> Self {
306 let mut buf = [0u8; ED25519_PRIVATE_KEY_LENGTH];
307 buf[ED25519_PRIVATE_KEY_LENGTH - 1] = 1;
308 Self::try_from(buf.as_ref()).unwrap()
309 }
310}
311
312impl From<&Ed25519PrivateKey> for Ed25519PublicKey {
319 fn from(private_key: &Ed25519PrivateKey) -> Self {
320 let secret: &ed25519_dalek::SecretKey = &private_key.0;
321 let public: ed25519_dalek::PublicKey = secret.into();
322 Ed25519PublicKey(public)
323 }
324}
325
326impl PublicKey for Ed25519PublicKey {
328 type PrivateKeyMaterial = Ed25519PrivateKey;
329}
330
331impl std::hash::Hash for Ed25519PublicKey {
332 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
333 let encoded_pubkey = self.to_bytes();
334 state.write(&encoded_pubkey);
335 }
336}
337
338impl PartialEq for Ed25519PublicKey {
340 fn eq(&self, other: &Ed25519PublicKey) -> bool {
341 self.to_bytes() == other.to_bytes()
342 }
343}
344
345impl Eq for Ed25519PublicKey {}
346
347impl VerifyingKey for Ed25519PublicKey {
350 type SignatureMaterial = Ed25519Signature;
351 type SigningKeyMaterial = Ed25519PrivateKey;
352}
353
354impl fmt::Display for Ed25519PublicKey {
355 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356 write!(f, "{}", hex::encode(&self.0.as_bytes()))
357 }
358}
359
360impl fmt::Debug for Ed25519PublicKey {
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 write!(f, "Ed25519PublicKey({})", self)
363 }
364}
365
366impl TryFrom<&[u8]> for Ed25519PublicKey {
367 type Error = CryptoMaterialError;
368
369 fn try_from(
373 bytes: &[u8],
374 ) -> std::result::Result<Ed25519PublicKey, CryptoMaterialError> {
375 if bytes.len() != ED25519_PUBLIC_KEY_LENGTH {
379 return Err(CryptoMaterialError::WrongLengthError);
380 }
381
382 let mut bits = [0u8; ED25519_PUBLIC_KEY_LENGTH];
383 bits.copy_from_slice(&bytes[..ED25519_PUBLIC_KEY_LENGTH]);
384
385 let compressed = curve25519_dalek::edwards::CompressedEdwardsY(bits);
386 let point = compressed
387 .decompress()
388 .ok_or(CryptoMaterialError::DeserializationError)?;
389
390 if point.is_small_order() {
393 return Err(CryptoMaterialError::SmallSubgroupError);
394 }
395
396 let public_key = Ed25519PublicKey::from_bytes_unchecked(bytes)?;
400 add_tag!(&public_key, ValidatedPublicKeyTag); Ok(public_key)
402 }
403}
404
405impl Length for Ed25519PublicKey {
406 fn length(&self) -> usize { ED25519_PUBLIC_KEY_LENGTH }
407}
408
409impl ValidCryptoMaterial for Ed25519PublicKey {
410 fn to_bytes(&self) -> Vec<u8> { self.0.to_bytes().to_vec() }
411}
412
413impl Signature for Ed25519Signature {
418 type SigningKeyMaterial = Ed25519PrivateKey;
419 type VerifyingKeyMaterial = Ed25519PublicKey;
420
421 fn verify<T: CryptoHash + Serialize>(
426 &self, message: &T, public_key: &Ed25519PublicKey,
427 ) -> Result<()> {
428 precondition!(has_tag!(public_key, ValidatedPublicKeyTag));
431 let mut bytes = <T::Hasher as CryptoHasher>::seed().to_vec();
432 bcs::serialize_into(&mut bytes, &message)
433 .map_err(|_| CryptoMaterialError::SerializationError)?;
434 Self::verify_arbitrary_msg(self, &bytes, public_key)
435 }
436
437 fn verify_arbitrary_msg(
441 &self, message: &[u8], public_key: &Ed25519PublicKey,
442 ) -> Result<()> {
443 precondition!(has_tag!(public_key, ValidatedPublicKeyTag));
446 Ed25519Signature::check_malleability(&self.to_bytes())?;
447
448 public_key
449 .0
450 .verify_strict(message, &self.0)
451 .map_err(|e| anyhow!("{}", e))
452 .and(Ok(()))
453 }
454
455 #[cfg(feature = "batch")]
460 fn batch_verify<T: CryptoHash + Serialize>(
461 message: &T,
462 keys_and_signatures: Vec<(Self::VerifyingKeyMaterial, Self)>,
463 ) -> Result<()> {
464 for (_, sig) in keys_and_signatures.iter() {
465 Ed25519Signature::check_malleability(&sig.to_bytes())?
466 }
467 let mut message_bytes = <T::Hasher as CryptoHasher>::seed().to_vec();
468 bcs::serialize_into(&mut message_bytes, &message)
469 .map_err(|_| CryptoMaterialError::SerializationError)?;
470
471 let batch_argument = keys_and_signatures
472 .iter()
473 .map(|(key, signature)| (key.0, signature.0));
474 let (dalek_public_keys, dalek_signatures): (Vec<_>, Vec<_>) =
475 batch_argument.unzip();
476 let message_ref = &(&message_bytes)[..];
477 let messages = vec![message_ref; dalek_signatures.len()];
482 ed25519_dalek::verify_batch(
483 &messages[..],
484 &dalek_signatures[..],
485 &dalek_public_keys[..],
486 )
487 .map_err(|e| anyhow!("{}", e))?;
488 Ok(())
489 }
490}
491
492impl Length for Ed25519Signature {
493 fn length(&self) -> usize { ED25519_SIGNATURE_LENGTH }
494}
495
496impl ValidCryptoMaterial for Ed25519Signature {
497 fn to_bytes(&self) -> Vec<u8> { self.to_bytes().to_vec() }
498}
499
500impl std::hash::Hash for Ed25519Signature {
501 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
502 let encoded_signature = self.to_bytes();
503 state.write(&encoded_signature);
504 }
505}
506
507impl TryFrom<&[u8]> for Ed25519Signature {
508 type Error = CryptoMaterialError;
509
510 fn try_from(
511 bytes: &[u8],
512 ) -> std::result::Result<Ed25519Signature, CryptoMaterialError> {
513 Ed25519Signature::check_malleability(bytes)?;
514 Ed25519Signature::from_bytes_unchecked(bytes)
515 }
516}
517
518impl PartialEq for Ed25519Signature {
520 fn eq(&self, other: &Ed25519Signature) -> bool {
521 self.to_bytes()[..] == other.to_bytes()[..]
522 }
523}
524
525impl Eq for Ed25519Signature {}
526
527impl fmt::Display for Ed25519Signature {
528 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529 write!(f, "{}", hex::encode(&self.0.to_bytes()[..]))
530 }
531}
532
533impl fmt::Debug for Ed25519Signature {
534 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
535 write!(f, "Ed25519Signature({})", self)
536 }
537}
538
539fn check_s_lt_l(s: &[u8]) -> bool {
541 for i in (0..32).rev() {
542 match s[i].cmp(&L[i]) {
543 Ordering::Less => return true,
544 Ordering::Greater => return false,
545 _ => {}
546 }
547 }
548 false
550}
551
552#[cfg(any(test, feature = "fuzzing"))]
553use crate::test_utils::{self, KeyPair};
554
555#[cfg(any(test, feature = "fuzzing"))]
557pub fn keypair_strategy(
558) -> impl Strategy<Value = KeyPair<Ed25519PrivateKey, Ed25519PublicKey>> {
559 test_utils::uniform_keypair_strategy::<Ed25519PrivateKey, Ed25519PublicKey>(
560 )
561}
562
563#[cfg(any(test, feature = "fuzzing"))]
564use proptest::prelude::*;
565
566#[cfg(any(test, feature = "fuzzing"))]
567impl proptest::arbitrary::Arbitrary for Ed25519PublicKey {
568 type Parameters = ();
569 type Strategy = BoxedStrategy<Self>;
570
571 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
572 crate::test_utils::uniform_keypair_strategy::<
573 Ed25519PrivateKey,
574 Ed25519PublicKey,
575 >()
576 .prop_map(|v| v.public_key)
577 .boxed()
578 }
579}