1#![allow(clippy::integer_arithmetic)]
33
34use crate::{
35 hash::{CryptoHash, CryptoHasher},
36 traits::*,
37};
38use anyhow::{anyhow, Result};
39use core::convert::TryFrom;
40use diem_crypto_derive::{DeserializeKey, SerializeKey, SilentDebug, SilentDisplay};
41use mirai_annotations::*;
42use serde::Serialize;
43use std::{cmp::Ordering, fmt};
44
45pub use ed25519_dalek;
46
47pub const ED25519_PRIVATE_KEY_LENGTH: usize = ed25519_dalek::SECRET_KEY_LENGTH;
49pub const ED25519_PUBLIC_KEY_LENGTH: usize = ed25519_dalek::PUBLIC_KEY_LENGTH;
51pub const ED25519_SIGNATURE_LENGTH: usize = ed25519_dalek::SIGNATURE_LENGTH;
53
54const L: [u8; 32] = [
56 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
58];
59
60#[derive(DeserializeKey, SerializeKey, SilentDebug, SilentDisplay)]
62pub struct Ed25519PrivateKey(ed25519_dalek::SecretKey);
63
64#[cfg(feature = "assert-private-keys-not-cloneable")]
65static_assertions::assert_not_impl_any!(Ed25519PrivateKey: Clone);
66
67#[cfg(any(test, feature = "cloneable-private-keys"))]
68impl Clone for Ed25519PrivateKey {
69 fn clone(&self) -> Self {
70 let serialized: &[u8] = &(self.to_bytes());
71 Ed25519PrivateKey::try_from(serialized).unwrap()
72 }
73}
74
75#[derive(DeserializeKey, Clone, SerializeKey)]
77pub struct Ed25519PublicKey(ed25519_dalek::PublicKey);
78
79#[cfg(mirai)]
80use crate::tags::ValidatedPublicKeyTag;
81#[cfg(not(mirai))]
82struct ValidatedPublicKeyTag {}
83
84#[derive(DeserializeKey, Clone, SerializeKey)]
86pub struct Ed25519Signature(ed25519_dalek::Signature);
87
88impl Ed25519PrivateKey {
89 pub const LENGTH: usize = ed25519_dalek::SECRET_KEY_LENGTH;
91
92 pub fn to_bytes(&self) -> [u8; ED25519_PRIVATE_KEY_LENGTH] {
94 self.0.to_bytes()
95 }
96
97 fn from_bytes_unchecked(
99 bytes: &[u8],
100 ) -> std::result::Result<Ed25519PrivateKey, CryptoMaterialError> {
101 match ed25519_dalek::SecretKey::from_bytes(bytes) {
102 Ok(dalek_secret_key) => Ok(Ed25519PrivateKey(dalek_secret_key)),
103 Err(_) => Err(CryptoMaterialError::DeserializationError),
104 }
105 }
106
107 fn sign_arbitrary_message(&self, message: &[u8]) -> Ed25519Signature {
110 let secret_key: &ed25519_dalek::SecretKey = &self.0;
111 let public_key: Ed25519PublicKey = self.into();
112 let expanded_secret_key: ed25519_dalek::ExpandedSecretKey =
113 ed25519_dalek::ExpandedSecretKey::from(secret_key);
114 let sig = expanded_secret_key.sign(message.as_ref(), &public_key.0);
115 Ed25519Signature(sig)
116 }
117}
118
119impl Ed25519PublicKey {
120 pub fn to_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_LENGTH] {
122 self.0.to_bytes()
123 }
124
125 pub(crate) fn from_bytes_unchecked(
127 bytes: &[u8],
128 ) -> std::result::Result<Ed25519PublicKey, CryptoMaterialError> {
129 match ed25519_dalek::PublicKey::from_bytes(bytes) {
130 Ok(dalek_public_key) => Ok(Ed25519PublicKey(dalek_public_key)),
131 Err(_) => Err(CryptoMaterialError::DeserializationError),
132 }
133 }
134
135 #[cfg(test)]
150 pub(crate) fn from_x25519_public_bytes(
151 x25519_bytes: &[u8],
152 negative: bool,
153 ) -> Result<Self, CryptoMaterialError> {
154 if x25519_bytes.len() != 32 {
155 return Err(CryptoMaterialError::DeserializationError);
156 }
157 let key_bits = {
158 let mut bits = [0u8; 32];
159 bits.copy_from_slice(x25519_bytes);
160 bits
161 };
162 let mtg_point = curve25519_dalek::montgomery::MontgomeryPoint(key_bits);
163 let sign = if negative { 1u8 } else { 0u8 };
164 let ed_point = mtg_point
165 .to_edwards(sign)
166 .ok_or(CryptoMaterialError::DeserializationError)?;
167 Ed25519PublicKey::try_from(&ed_point.compress().as_bytes()[..])
168 }
169}
170
171impl Ed25519Signature {
172 pub const LENGTH: usize = ed25519_dalek::SIGNATURE_LENGTH;
174
175 pub fn to_bytes(&self) -> [u8; ED25519_SIGNATURE_LENGTH] {
177 self.0.to_bytes()
178 }
179
180 pub(crate) fn from_bytes_unchecked(
183 bytes: &[u8],
184 ) -> std::result::Result<Ed25519Signature, CryptoMaterialError> {
185 match ed25519_dalek::Signature::try_from(bytes) {
186 Ok(dalek_signature) => Ok(Ed25519Signature(dalek_signature)),
187 Err(_) => Err(CryptoMaterialError::DeserializationError),
188 }
189 }
190
191 #[cfg(any(test, feature = "fuzzing"))]
193 pub fn dummy_signature() -> Self {
194 Self::from_bytes_unchecked(&[0u8; Self::LENGTH]).unwrap()
195 }
196
197 pub fn check_malleability(bytes: &[u8]) -> std::result::Result<(), CryptoMaterialError> {
215 if bytes.len() != ED25519_SIGNATURE_LENGTH {
216 return Err(CryptoMaterialError::WrongLengthError);
217 }
218 if !check_s_lt_l(&bytes[32..]) {
219 return Err(CryptoMaterialError::CanonicalRepresentationError);
220 }
221 Ok(())
222 }
223}
224
225impl PrivateKey for Ed25519PrivateKey {
230 type PublicKeyMaterial = Ed25519PublicKey;
231}
232
233impl SigningKey for Ed25519PrivateKey {
234 type VerifyingKeyMaterial = Ed25519PublicKey;
235 type SignatureMaterial = Ed25519Signature;
236
237 fn sign<T: CryptoHash + Serialize>(&self, message: &T) -> Ed25519Signature {
238 let mut bytes = <T::Hasher as CryptoHasher>::seed().to_vec();
239 bcs::serialize_into(&mut bytes, &message)
240 .map_err(|_| CryptoMaterialError::SerializationError)
241 .expect("Serialization of signable material should not fail.");
242 Ed25519PrivateKey::sign_arbitrary_message(self, bytes.as_ref())
243 }
244
245 #[cfg(any(test, feature = "fuzzing"))]
246 fn sign_arbitrary_message(&self, message: &[u8]) -> Ed25519Signature {
247 Ed25519PrivateKey::sign_arbitrary_message(self, message)
248 }
249}
250
251impl Uniform for Ed25519PrivateKey {
252 fn generate<R>(rng: &mut R) -> Self
253 where
254 R: ::rand::RngCore + ::rand::CryptoRng,
255 {
256 Ed25519PrivateKey(ed25519_dalek::SecretKey::generate(rng))
257 }
258}
259
260impl PartialEq<Self> for Ed25519PrivateKey {
261 fn eq(&self, other: &Self) -> bool {
262 self.to_bytes() == other.to_bytes()
263 }
264}
265
266impl Eq for Ed25519PrivateKey {}
267
268impl TryFrom<&[u8]> for Ed25519PrivateKey {
271 type Error = CryptoMaterialError;
272
273 fn try_from(bytes: &[u8]) -> std::result::Result<Ed25519PrivateKey, CryptoMaterialError> {
275 Ed25519PrivateKey::from_bytes_unchecked(bytes)
281 }
282}
283
284impl Length for Ed25519PrivateKey {
285 fn length(&self) -> usize {
286 Self::LENGTH
287 }
288}
289
290impl ValidCryptoMaterial for Ed25519PrivateKey {
291 fn to_bytes(&self) -> Vec<u8> {
292 self.to_bytes().to_vec()
293 }
294}
295
296impl Genesis for Ed25519PrivateKey {
297 fn genesis() -> Self {
298 let mut buf = [0u8; ED25519_PRIVATE_KEY_LENGTH];
299 buf[ED25519_PRIVATE_KEY_LENGTH - 1] = 1;
300 Self::try_from(buf.as_ref()).unwrap()
301 }
302}
303
304impl From<&Ed25519PrivateKey> for Ed25519PublicKey {
310 fn from(private_key: &Ed25519PrivateKey) -> Self {
311 let secret: &ed25519_dalek::SecretKey = &private_key.0;
312 let public: ed25519_dalek::PublicKey = secret.into();
313 Ed25519PublicKey(public)
314 }
315}
316
317impl PublicKey for Ed25519PublicKey {
319 type PrivateKeyMaterial = Ed25519PrivateKey;
320}
321
322impl std::hash::Hash for Ed25519PublicKey {
323 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
324 let encoded_pubkey = self.to_bytes();
325 state.write(&encoded_pubkey);
326 }
327}
328
329impl PartialEq for Ed25519PublicKey {
331 fn eq(&self, other: &Ed25519PublicKey) -> bool {
332 self.to_bytes() == other.to_bytes()
333 }
334}
335
336impl Eq for Ed25519PublicKey {}
337
338impl VerifyingKey for Ed25519PublicKey {
341 type SigningKeyMaterial = Ed25519PrivateKey;
342 type SignatureMaterial = Ed25519Signature;
343}
344
345impl fmt::Display for Ed25519PublicKey {
346 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347 write!(f, "{}", hex::encode(&self.0.as_bytes()))
348 }
349}
350
351impl fmt::Debug for Ed25519PublicKey {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 write!(f, "Ed25519PublicKey({})", self)
354 }
355}
356
357impl TryFrom<&[u8]> for Ed25519PublicKey {
358 type Error = CryptoMaterialError;
359
360 fn try_from(bytes: &[u8]) -> std::result::Result<Ed25519PublicKey, CryptoMaterialError> {
363 if bytes.len() != ED25519_PUBLIC_KEY_LENGTH {
366 return Err(CryptoMaterialError::WrongLengthError);
367 }
368
369 let mut bits = [0u8; ED25519_PUBLIC_KEY_LENGTH];
370 bits.copy_from_slice(&bytes[..ED25519_PUBLIC_KEY_LENGTH]);
371
372 let compressed = curve25519_dalek::edwards::CompressedEdwardsY(bits);
373 let point = compressed
374 .decompress()
375 .ok_or(CryptoMaterialError::DeserializationError)?;
376
377 if point.is_small_order() {
380 return Err(CryptoMaterialError::SmallSubgroupError);
381 }
382
383 let public_key = Ed25519PublicKey::from_bytes_unchecked(bytes)?;
387 add_tag!(&public_key, ValidatedPublicKeyTag); Ok(public_key)
389 }
390}
391
392impl Length for Ed25519PublicKey {
393 fn length(&self) -> usize {
394 ED25519_PUBLIC_KEY_LENGTH
395 }
396}
397
398impl ValidCryptoMaterial for Ed25519PublicKey {
399 fn to_bytes(&self) -> Vec<u8> {
400 self.0.to_bytes().to_vec()
401 }
402}
403
404impl Signature for Ed25519Signature {
409 type VerifyingKeyMaterial = Ed25519PublicKey;
410 type SigningKeyMaterial = Ed25519PrivateKey;
411
412 fn verify<T: CryptoHash + Serialize>(
416 &self,
417 message: &T,
418 public_key: &Ed25519PublicKey,
419 ) -> Result<()> {
420 precondition!(has_tag!(public_key, ValidatedPublicKeyTag));
422 let mut bytes = <T::Hasher as CryptoHasher>::seed().to_vec();
423 bcs::serialize_into(&mut bytes, &message)
424 .map_err(|_| CryptoMaterialError::SerializationError)?;
425 Self::verify_arbitrary_msg(self, &bytes, public_key)
426 }
427
428 fn verify_arbitrary_msg(&self, message: &[u8], public_key: &Ed25519PublicKey) -> Result<()> {
432 precondition!(has_tag!(public_key, ValidatedPublicKeyTag));
434 Ed25519Signature::check_malleability(&self.to_bytes())?;
435
436 public_key
437 .0
438 .verify_strict(message, &self.0)
439 .map_err(|e| anyhow!("{}", e))
440 .and(Ok(()))
441 }
442
443 fn to_bytes(&self) -> Vec<u8> {
444 self.0.to_bytes().to_vec()
445 }
446
447 #[cfg(feature = "batch")]
451 fn batch_verify<T: CryptoHash + Serialize>(
452 message: &T,
453 keys_and_signatures: Vec<(Self::VerifyingKeyMaterial, Self)>,
454 ) -> Result<()> {
455 for (_, sig) in keys_and_signatures.iter() {
456 Ed25519Signature::check_malleability(&sig.to_bytes())?
457 }
458 let mut message_bytes = <T::Hasher as CryptoHasher>::seed().to_vec();
459 bcs::serialize_into(&mut message_bytes, &message)
460 .map_err(|_| CryptoMaterialError::SerializationError)?;
461
462 let batch_argument = keys_and_signatures
463 .iter()
464 .map(|(key, signature)| (key.0, signature.0));
465 let (dalek_public_keys, dalek_signatures): (Vec<_>, Vec<_>) = batch_argument.unzip();
466 let message_ref = &(&message_bytes)[..];
467 let messages = vec![message_ref; dalek_signatures.len()];
471 ed25519_dalek::verify_batch(&messages[..], &dalek_signatures[..], &dalek_public_keys[..])
472 .map_err(|e| anyhow!("{}", e))?;
473 Ok(())
474 }
475}
476
477impl Length for Ed25519Signature {
478 fn length(&self) -> usize {
479 ED25519_SIGNATURE_LENGTH
480 }
481}
482
483impl ValidCryptoMaterial for Ed25519Signature {
484 fn to_bytes(&self) -> Vec<u8> {
485 self.to_bytes().to_vec()
486 }
487}
488
489impl std::hash::Hash for Ed25519Signature {
490 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
491 let encoded_signature = self.to_bytes();
492 state.write(&encoded_signature);
493 }
494}
495
496impl TryFrom<&[u8]> for Ed25519Signature {
497 type Error = CryptoMaterialError;
498
499 fn try_from(bytes: &[u8]) -> std::result::Result<Ed25519Signature, CryptoMaterialError> {
500 Ed25519Signature::check_malleability(bytes)?;
501 Ed25519Signature::from_bytes_unchecked(bytes)
502 }
503}
504
505impl PartialEq for Ed25519Signature {
507 fn eq(&self, other: &Ed25519Signature) -> bool {
508 self.to_bytes()[..] == other.to_bytes()[..]
509 }
510}
511
512impl Eq for Ed25519Signature {}
513
514impl fmt::Display for Ed25519Signature {
515 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
516 write!(f, "{}", hex::encode(&self.0.to_bytes()[..]))
517 }
518}
519
520impl fmt::Debug for Ed25519Signature {
521 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522 write!(f, "Ed25519Signature({})", self)
523 }
524}
525
526fn check_s_lt_l(s: &[u8]) -> bool {
528 for i in (0..32).rev() {
529 match s[i].cmp(&L[i]) {
530 Ordering::Less => return true,
531 Ordering::Greater => return false,
532 _ => {}
533 }
534 }
535 false
537}
538
539#[cfg(any(test, feature = "fuzzing"))]
540use crate::test_utils::{self, KeyPair};
541
542#[cfg(any(test, feature = "fuzzing"))]
544pub fn keypair_strategy() -> impl Strategy<Value = KeyPair<Ed25519PrivateKey, Ed25519PublicKey>> {
545 test_utils::uniform_keypair_strategy::<Ed25519PrivateKey, Ed25519PublicKey>()
546}
547
548#[cfg(any(test, feature = "fuzzing"))]
549use proptest::prelude::*;
550
551#[cfg(any(test, feature = "fuzzing"))]
552impl proptest::arbitrary::Arbitrary for Ed25519PublicKey {
553 type Parameters = ();
554 type Strategy = BoxedStrategy<Self>;
555
556 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
557 crate::test_utils::uniform_keypair_strategy::<Ed25519PrivateKey, Ed25519PublicKey>()
558 .prop_map(|v| v.public_key)
559 .boxed()
560 }
561}