1use crate::{
14 ed25519::{
15 Ed25519PrivateKey, Ed25519PublicKey, Ed25519Signature,
16 ED25519_PRIVATE_KEY_LENGTH, ED25519_PUBLIC_KEY_LENGTH,
17 ED25519_SIGNATURE_LENGTH,
18 },
19 hash::{CryptoHash, CryptoHasher},
20 traits::*,
21};
22use anyhow::{anyhow, Result};
23use core::convert::TryFrom;
24use diem_crypto_derive::{
25 DeserializeKey, SerializeKey, SilentDebug, SilentDisplay,
26};
27use mirai_annotations::*;
28use rand::Rng;
29use serde::Serialize;
30use std::{convert::TryInto, fmt};
31
32const MAX_NUM_OF_KEYS: usize = 32;
33const BITMAP_NUM_OF_BYTES: usize = 4;
34
35#[derive(
38 DeserializeKey, Eq, PartialEq, SilentDisplay, SilentDebug, SerializeKey,
39)]
40pub struct MultiEd25519PrivateKey {
41 private_keys: Vec<Ed25519PrivateKey>,
42 threshold: u8,
43}
44
45#[cfg(feature = "assert-private-keys-not-cloneable")]
46static_assertions::assert_not_impl_any!(MultiEd25519PrivateKey: Clone);
47
48#[derive(Clone, DeserializeKey, Eq, PartialEq, SerializeKey)]
51pub struct MultiEd25519PublicKey {
52 public_keys: Vec<Ed25519PublicKey>,
53 threshold: u8,
54}
55
56#[cfg(mirai)]
57use crate::tags::ValidatedPublicKeyTag;
58#[cfg(not(mirai))]
59struct ValidatedPublicKeyTag {}
60
61#[derive(Clone, DeserializeKey, Eq, PartialEq, SerializeKey)]
68pub struct MultiEd25519Signature {
69 signatures: Vec<Ed25519Signature>,
70 bitmap: [u8; BITMAP_NUM_OF_BYTES],
71}
72
73impl MultiEd25519PrivateKey {
74 pub fn new(
76 private_keys: Vec<Ed25519PrivateKey>, threshold: u8,
77 ) -> std::result::Result<Self, CryptoMaterialError> {
78 let num_of_keys = private_keys.len();
79 if threshold == 0 || num_of_keys < threshold as usize {
80 Err(CryptoMaterialError::ValidationError)
81 } else if num_of_keys > MAX_NUM_OF_KEYS {
82 Err(CryptoMaterialError::WrongLengthError)
83 } else {
84 Ok(MultiEd25519PrivateKey {
85 private_keys,
86 threshold,
87 })
88 }
89 }
90
91 pub fn to_bytes(&self) -> Vec<u8> {
93 to_bytes(&self.private_keys, self.threshold)
94 }
95}
96
97impl MultiEd25519PublicKey {
98 pub fn new(
104 public_keys: Vec<Ed25519PublicKey>, threshold: u8,
105 ) -> std::result::Result<Self, CryptoMaterialError> {
106 let num_of_keys = public_keys.len();
107 if threshold == 0 || num_of_keys < threshold as usize {
108 Err(CryptoMaterialError::ValidationError)
109 } else if num_of_keys > MAX_NUM_OF_KEYS {
110 Err(CryptoMaterialError::WrongLengthError)
111 } else {
112 Ok(MultiEd25519PublicKey {
113 public_keys,
114 threshold,
115 })
116 }
117 }
118
119 pub fn public_keys(&self) -> &Vec<Ed25519PublicKey> { &self.public_keys }
121
122 pub fn threshold(&self) -> &u8 { &self.threshold }
124
125 pub fn to_bytes(&self) -> Vec<u8> {
127 to_bytes(&self.public_keys, self.threshold)
128 }
129}
130
131impl From<&Ed25519PrivateKey> for MultiEd25519PrivateKey {
138 fn from(ed_private_key: &Ed25519PrivateKey) -> Self {
139 MultiEd25519PrivateKey {
140 private_keys: vec![Ed25519PrivateKey::try_from(
141 &ed_private_key.to_bytes()[..],
142 )
143 .unwrap()],
144 threshold: 1u8,
145 }
146 }
147}
148
149impl PrivateKey for MultiEd25519PrivateKey {
150 type PublicKeyMaterial = MultiEd25519PublicKey;
151}
152
153impl SigningKey for MultiEd25519PrivateKey {
154 type SignatureMaterial = MultiEd25519Signature;
155 type VerifyingKeyMaterial = MultiEd25519PublicKey;
156
157 fn sign<T: CryptoHash + Serialize>(
158 &self, message: &T,
159 ) -> MultiEd25519Signature {
160 let mut bitmap = [0u8; BITMAP_NUM_OF_BYTES];
161 let signatures: Vec<Ed25519Signature> = self
162 .private_keys
163 .iter()
164 .take(self.threshold as usize)
165 .enumerate()
166 .map(|(i, item)| {
167 bitmap_set_bit(&mut bitmap, i);
168 item.sign(message)
169 })
170 .collect();
171
172 MultiEd25519Signature { signatures, bitmap }
173 }
174
175 #[cfg(any(test, feature = "fuzzing"))]
176 fn sign_arbitrary_message(&self, message: &[u8]) -> MultiEd25519Signature {
177 let mut signatures: Vec<Ed25519Signature> =
178 Vec::with_capacity(self.threshold as usize);
179 let mut bitmap = [0u8; BITMAP_NUM_OF_BYTES];
180 signatures.extend(
181 self.private_keys
182 .iter()
183 .take(self.threshold as usize)
184 .enumerate()
185 .map(|(i, item)| {
186 bitmap_set_bit(&mut bitmap, i);
187 item.sign_arbitrary_message(message)
188 }),
189 );
190 MultiEd25519Signature { signatures, bitmap }
191 }
192}
193
194impl Uniform for MultiEd25519PrivateKey {
196 fn generate<R>(rng: &mut R) -> Self
197 where R: ::rand::RngCore + ::rand::CryptoRng {
198 let num_of_keys = rng.gen_range(1..=MAX_NUM_OF_KEYS);
199 let mut private_keys: Vec<Ed25519PrivateKey> =
200 Vec::with_capacity(num_of_keys);
201 for _ in 0..num_of_keys {
202 private_keys.push(
203 Ed25519PrivateKey::try_from(
204 &ed25519_dalek::SecretKey::generate(rng).to_bytes()[..],
205 )
206 .unwrap(),
207 );
208 }
209 let threshold = rng.gen_range(1..=num_of_keys) as u8;
210 MultiEd25519PrivateKey {
211 private_keys,
212 threshold,
213 }
214 }
215}
216
217impl TryFrom<&[u8]> for MultiEd25519PrivateKey {
218 type Error = CryptoMaterialError;
219
220 fn try_from(
223 bytes: &[u8],
224 ) -> std::result::Result<MultiEd25519PrivateKey, CryptoMaterialError> {
225 if bytes.is_empty() {
226 return Err(CryptoMaterialError::WrongLengthError);
227 }
228 let threshold =
229 check_and_get_threshold(bytes, ED25519_PRIVATE_KEY_LENGTH)?;
230
231 let private_keys: Result<Vec<Ed25519PrivateKey>, _> = bytes
232 .chunks_exact(ED25519_PRIVATE_KEY_LENGTH)
233 .map(Ed25519PrivateKey::try_from)
234 .collect();
235
236 private_keys.map(|private_keys| MultiEd25519PrivateKey {
237 private_keys,
238 threshold,
239 })
240 }
241}
242
243impl Length for MultiEd25519PrivateKey {
244 fn length(&self) -> usize {
245 self.private_keys.len() * ED25519_PRIVATE_KEY_LENGTH + 1
246 }
247}
248
249impl ValidCryptoMaterial for MultiEd25519PrivateKey {
250 fn to_bytes(&self) -> Vec<u8> { self.to_bytes() }
251}
252
253impl Genesis for MultiEd25519PrivateKey {
254 fn genesis() -> Self {
255 let mut buf = [0u8; ED25519_PRIVATE_KEY_LENGTH];
256 buf[ED25519_PRIVATE_KEY_LENGTH - 1] = 1u8;
257 MultiEd25519PrivateKey {
258 private_keys: vec![
259 Ed25519PrivateKey::try_from(buf.as_ref()).unwrap()
260 ],
261 threshold: 1u8,
262 }
263 }
264}
265
266impl From<Ed25519PublicKey> for MultiEd25519PublicKey {
273 fn from(ed_public_key: Ed25519PublicKey) -> Self {
274 MultiEd25519PublicKey {
275 public_keys: vec![ed_public_key],
276 threshold: 1u8,
277 }
278 }
279}
280
281impl From<&MultiEd25519PrivateKey> for MultiEd25519PublicKey {
284 fn from(private_key: &MultiEd25519PrivateKey) -> Self {
285 let public_keys = private_key
286 .private_keys
287 .iter()
288 .map(PrivateKey::public_key)
289 .collect();
290 MultiEd25519PublicKey {
291 public_keys,
292 threshold: private_key.threshold,
293 }
294 }
295}
296
297impl PublicKey for MultiEd25519PublicKey {
299 type PrivateKeyMaterial = MultiEd25519PrivateKey;
300}
301
302#[allow(clippy::derive_hash_xor_eq)]
303impl std::hash::Hash for MultiEd25519PublicKey {
304 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
305 let encoded_pubkey = self.to_bytes();
306 state.write(&encoded_pubkey);
307 }
308}
309
310impl TryFrom<&[u8]> for MultiEd25519PublicKey {
311 type Error = CryptoMaterialError;
312
313 fn try_from(
317 bytes: &[u8],
318 ) -> std::result::Result<MultiEd25519PublicKey, CryptoMaterialError> {
319 if bytes.is_empty() {
320 return Err(CryptoMaterialError::WrongLengthError);
321 }
322 let threshold =
323 check_and_get_threshold(bytes, ED25519_PUBLIC_KEY_LENGTH)?;
324 let public_keys: Result<Vec<Ed25519PublicKey>, _> = bytes
325 .chunks_exact(ED25519_PUBLIC_KEY_LENGTH)
326 .map(Ed25519PublicKey::try_from)
327 .collect();
328 public_keys.map(|public_keys| {
329 let public_key = MultiEd25519PublicKey {
330 public_keys,
331 threshold,
332 };
333 add_tag!(&public_key, ValidatedPublicKeyTag);
334 public_key
335 })
336 }
337}
338
339impl VerifyingKey for MultiEd25519PublicKey {
342 type SignatureMaterial = MultiEd25519Signature;
343 type SigningKeyMaterial = MultiEd25519PrivateKey;
344}
345
346impl fmt::Display for MultiEd25519PublicKey {
347 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348 write!(f, "{}", hex::encode(&self.to_bytes()))
349 }
350}
351
352impl fmt::Debug for MultiEd25519PublicKey {
353 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354 write!(f, "MultiEd25519PublicKey({})", self)
355 }
356}
357
358impl Length for MultiEd25519PublicKey {
359 fn length(&self) -> usize {
360 self.public_keys.len() * ED25519_PUBLIC_KEY_LENGTH + 1
361 }
362}
363
364impl ValidCryptoMaterial for MultiEd25519PublicKey {
365 fn to_bytes(&self) -> Vec<u8> { self.to_bytes() }
366}
367
368impl MultiEd25519Signature {
369 pub fn new(
371 signatures: Vec<(Ed25519Signature, u8)>,
372 ) -> std::result::Result<Self, CryptoMaterialError> {
373 let num_of_sigs = signatures.len();
374 if num_of_sigs == 0 || num_of_sigs > MAX_NUM_OF_KEYS {
375 return Err(CryptoMaterialError::ValidationError);
376 }
377
378 let mut sorted_signatures = signatures;
379 sorted_signatures.sort_by(|a, b| a.1.cmp(&b.1));
380
381 let mut bitmap = [0u8; BITMAP_NUM_OF_BYTES];
382
383 let (sigs, indexes): (Vec<_>, Vec<_>) =
385 sorted_signatures.iter().cloned().unzip();
386 for i in indexes {
387 if i < MAX_NUM_OF_KEYS as u8 {
389 if bitmap_get_bit(bitmap, i as usize) {
392 return Err(CryptoMaterialError::BitVecError(
393 "Duplicate signature index".to_string(),
394 ));
395 } else {
396 bitmap_set_bit(&mut bitmap, i as usize);
397 }
398 } else {
399 return Err(CryptoMaterialError::BitVecError(
400 "Signature index is out of range".to_string(),
401 ));
402 }
403 }
404 Ok(MultiEd25519Signature {
405 signatures: sigs,
406 bitmap,
407 })
408 }
409
410 pub fn signatures(&self) -> &Vec<Ed25519Signature> { &self.signatures }
412
413 pub fn bitmap(&self) -> &[u8; BITMAP_NUM_OF_BYTES] { &self.bitmap }
415
416 pub fn to_bytes(&self) -> Vec<u8> {
419 let mut bytes: Vec<u8> = self
420 .signatures
421 .iter()
422 .flat_map(|sig| sig.to_bytes().to_vec())
423 .collect();
424 bytes.extend(&self.bitmap[..]);
425 bytes
426 }
427}
428
429impl TryFrom<&[u8]> for MultiEd25519Signature {
434 type Error = CryptoMaterialError;
435
436 fn try_from(
439 bytes: &[u8],
440 ) -> std::result::Result<MultiEd25519Signature, CryptoMaterialError> {
441 let length = bytes.len();
442 let bitmap_num_of_bytes = length % ED25519_SIGNATURE_LENGTH;
443 let num_of_sigs = length / ED25519_SIGNATURE_LENGTH;
444
445 if num_of_sigs == 0
446 || num_of_sigs > MAX_NUM_OF_KEYS
447 || bitmap_num_of_bytes != BITMAP_NUM_OF_BYTES
448 {
449 return Err(CryptoMaterialError::WrongLengthError);
450 }
451
452 let bitmap = match bytes[length - BITMAP_NUM_OF_BYTES..].try_into() {
453 Ok(bitmap) => bitmap,
454 Err(_) => return Err(CryptoMaterialError::DeserializationError),
455 };
456 if bitmap_count_ones(bitmap) != num_of_sigs as u32 {
457 return Err(CryptoMaterialError::DeserializationError);
458 }
459
460 let signatures: Result<Vec<Ed25519Signature>, _> = bytes
461 .chunks_exact(ED25519_SIGNATURE_LENGTH)
462 .map(Ed25519Signature::try_from)
463 .collect();
464 signatures
465 .map(|signatures| MultiEd25519Signature { signatures, bitmap })
466 }
467}
468
469impl Length for MultiEd25519Signature {
470 fn length(&self) -> usize {
471 self.signatures.len() * ED25519_SIGNATURE_LENGTH + BITMAP_NUM_OF_BYTES
472 }
473}
474
475#[allow(clippy::derive_hash_xor_eq)]
476impl std::hash::Hash for MultiEd25519Signature {
477 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
478 let encoded_signature = self.to_bytes();
479 state.write(&encoded_signature);
480 }
481}
482
483impl fmt::Display for MultiEd25519Signature {
484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485 write!(f, "{}", hex::encode(&self.to_bytes()[..]))
486 }
487}
488
489impl fmt::Debug for MultiEd25519Signature {
490 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
491 write!(f, "MultiEd25519Signature({})", self)
492 }
493}
494
495impl ValidCryptoMaterial for MultiEd25519Signature {
496 fn to_bytes(&self) -> Vec<u8> { self.to_bytes() }
497}
498
499impl Signature for MultiEd25519Signature {
500 type SigningKeyMaterial = MultiEd25519PrivateKey;
501 type VerifyingKeyMaterial = MultiEd25519PublicKey;
502
503 fn verify<T: CryptoHash + Serialize>(
504 &self, message: &T, public_key: &MultiEd25519PublicKey,
505 ) -> Result<()> {
506 precondition!(has_tag!(public_key, ValidatedPublicKeyTag));
509 let mut bytes = <T as CryptoHash>::Hasher::seed().to_vec();
510 bcs::serialize_into(&mut bytes, &message)
511 .map_err(|_| CryptoMaterialError::SerializationError)?;
512 Self::verify_arbitrary_msg(self, &bytes, public_key)
513 }
514
515 fn verify_arbitrary_msg(
519 &self, message: &[u8], public_key: &MultiEd25519PublicKey,
520 ) -> Result<()> {
521 precondition!(has_tag!(public_key, ValidatedPublicKeyTag));
524 match bitmap_last_set_bit(self.bitmap) {
525 Some(last_bit) if last_bit as usize <= public_key.length() => (),
526 _ => {
527 return Err(anyhow!(
528 "{}",
529 CryptoMaterialError::BitVecError(
530 "Signature index is out of range".to_string()
531 )
532 ))
533 }
534 };
535 if bitmap_count_ones(self.bitmap) < public_key.threshold as u32 {
536 return Err(anyhow!(
537 "{}",
538 CryptoMaterialError::BitVecError(
539 "Not enough signatures to meet the threshold".to_string()
540 )
541 ));
542 }
543 let mut bitmap_index = 0;
544 for sig in &self.signatures {
546 while !bitmap_get_bit(self.bitmap, bitmap_index) {
547 bitmap_index += 1;
548 }
549 sig.verify_arbitrary_msg(
550 message,
551 &public_key.public_keys[bitmap_index as usize],
552 )?;
553 bitmap_index += 1;
554 }
555 Ok(())
556 }
557}
558
559impl From<Ed25519Signature> for MultiEd25519Signature {
560 fn from(ed_signature: Ed25519Signature) -> Self {
561 MultiEd25519Signature {
562 signatures: vec![ed_signature],
563 bitmap: [0b1000_0000u8, 0u8, 0u8, 0u8],
565 }
566 }
567}
568
569fn to_bytes<T: ValidCryptoMaterial>(keys: &[T], threshold: u8) -> Vec<u8> {
575 let mut bytes: Vec<u8> = keys
576 .iter()
577 .flat_map(ValidCryptoMaterial::to_bytes)
578 .collect();
579 bytes.push(threshold);
580 bytes
581}
582
583fn check_and_get_threshold(
585 bytes: &[u8], key_size: usize,
586) -> std::result::Result<u8, CryptoMaterialError> {
587 let payload_length = bytes.len();
588 if bytes.is_empty() {
589 return Err(CryptoMaterialError::WrongLengthError);
590 }
591 let threshold_num_of_bytes = payload_length % key_size;
592 let num_of_keys = payload_length / key_size;
593 let threshold_byte = bytes[bytes.len() - 1];
594
595 if num_of_keys == 0
596 || num_of_keys > MAX_NUM_OF_KEYS
597 || threshold_num_of_bytes != 1
598 {
599 Err(CryptoMaterialError::WrongLengthError)
600 } else if threshold_byte == 0 || threshold_byte > num_of_keys as u8 {
601 Err(CryptoMaterialError::ValidationError)
602 } else {
603 Ok(threshold_byte)
604 }
605}
606
607fn bitmap_set_bit(input: &mut [u8; BITMAP_NUM_OF_BYTES], index: usize) {
608 let bucket = index / 8;
609 let bucket_pos = index - (bucket * 8);
612 input[bucket] |= 128 >> bucket_pos as u8;
613}
614
615fn bitmap_get_bit(input: [u8; BITMAP_NUM_OF_BYTES], index: usize) -> bool {
617 let bucket = index / 8;
618 let bucket_pos = index - (bucket * 8);
621 (input[bucket] & (128 >> bucket_pos as u8)) != 0
622}
623
624fn bitmap_count_ones(input: [u8; BITMAP_NUM_OF_BYTES]) -> u32 {
626 input.iter().map(|a| a.count_ones()).sum()
627}
628
629fn bitmap_last_set_bit(input: [u8; BITMAP_NUM_OF_BYTES]) -> Option<u8> {
631 input
632 .iter()
633 .rev()
634 .enumerate()
635 .find(|(_, byte)| byte != &&0u8)
636 .map(|(i, byte)| {
637 (8 * (BITMAP_NUM_OF_BYTES - i) - byte.trailing_zeros() as usize - 1)
638 as u8
639 })
640}
641
642#[test]
643fn bitmap_tests() {
644 let mut bitmap = [0b0100_0000u8, 0b1111_1111u8, 0u8, 0b1000_0000u8];
645 assert!(!bitmap_get_bit(bitmap, 0));
646 assert!(bitmap_get_bit(bitmap, 1));
647 for i in 8..16 {
648 assert!(bitmap_get_bit(bitmap, i));
649 }
650 for i in 16..24 {
651 assert!(!bitmap_get_bit(bitmap, i));
652 }
653 assert!(bitmap_get_bit(bitmap, 24));
654 assert!(!bitmap_get_bit(bitmap, 31));
655 assert_eq!(bitmap_last_set_bit(bitmap), Some(24));
656
657 bitmap_set_bit(&mut bitmap, 30);
658 assert!(bitmap_get_bit(bitmap, 30));
659 assert_eq!(bitmap_last_set_bit(bitmap), Some(30));
660}