1use crate::{account_address::AccountAddress, on_chain_config::ValidatorSet};
9use diem_crypto::{
10 bls::deserialize_bls_public_key_unchecked, hash::CryptoHash, Signature,
11 VRFPublicKey, VerifyingKey,
12};
13use serde::{Deserialize, Serialize};
14use std::{collections::BTreeMap, fmt};
15use thiserror::Error;
16
17use crate::{
18 on_chain_config::OnChainConfig,
19 validator_config::{
20 ConsensusPublicKey, ConsensusSignature, ConsensusVRFProof,
21 ConsensusVRFPublicKey,
22 },
23};
24#[cfg(any(test, feature = "fuzzing"))]
25use anyhow::{ensure, Result};
26#[cfg(any(test, feature = "fuzzing"))]
27use proptest_derive::Arbitrary;
28
29#[derive(Debug, Error, PartialEq)]
31pub enum VerifyError {
32 #[error("Author is unknown")]
33 UnknownAuthor,
35 #[error(
36 "The voting power ({}) is less than quorum voting power ({})",
37 voting_power,
38 quorum_voting_power
39 )]
40 TooLittleVotingPower {
41 voting_power: u64,
42 quorum_voting_power: u64,
43 },
44 #[error(
45 "The number of signatures ({}) is greater than total number of authors ({})",
46 num_of_signatures,
47 num_of_authors
48 )]
49 TooManySignatures {
50 num_of_signatures: usize,
51 num_of_authors: usize,
52 },
53 #[error("Signature is invalid")]
54 InvalidSignature,
56 #[error("Invalid VRF proof")]
57 InvalidVrfProof,
58}
59
60#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
62#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
63pub struct ValidatorConsensusInfo {
64 #[serde(deserialize_with = "deserialize_bls_public_key_unchecked")]
68 public_key: ConsensusPublicKey,
69 vrf_public_key: Option<ConsensusVRFPublicKey>,
71 voting_power: u64,
72}
73
74impl ValidatorConsensusInfo {
75 pub fn new(
76 public_key: ConsensusPublicKey,
77 vrf_public_key: Option<ConsensusVRFPublicKey>, voting_power: u64,
78 ) -> Self {
79 ValidatorConsensusInfo {
80 public_key,
81 vrf_public_key,
82 voting_power,
83 }
84 }
85
86 pub fn voting_power(&self) -> u64 { self.voting_power }
87
88 pub fn public_key(&self) -> &ConsensusPublicKey { &self.public_key }
89
90 pub fn vrf_public_key(&self) -> &Option<ConsensusVRFPublicKey> {
91 &self.vrf_public_key
92 }
93}
94
95#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
99#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
100pub struct ValidatorVerifier {
101 address_to_validator_info: BTreeMap<AccountAddress, ValidatorConsensusInfo>,
104 quorum_voting_power: u64,
106 total_voting_power: u64,
109}
110
111impl ValidatorVerifier {
112 pub fn new(
116 address_to_validator_info: BTreeMap<
117 AccountAddress,
118 ValidatorConsensusInfo,
119 >,
120 ) -> Self {
121 let total_voting_power = sum_voting_power(&address_to_validator_info);
122 let quorum_voting_power = if address_to_validator_info.is_empty() {
123 0
124 } else {
125 total_voting_power * 2 / 3 + 1
126 };
127 ValidatorVerifier {
128 address_to_validator_info,
129 quorum_voting_power,
130 total_voting_power,
131 }
132 }
133
134 #[cfg(any(test, feature = "fuzzing"))]
136 pub fn new_with_quorum_voting_power(
137 address_to_validator_info: BTreeMap<
138 AccountAddress,
139 ValidatorConsensusInfo,
140 >,
141 quorum_voting_power: u64,
142 ) -> Result<Self> {
143 let total_voting_power = sum_voting_power(&address_to_validator_info);
144 ensure!(
145 quorum_voting_power <= total_voting_power,
146 "Quorum voting power is greater than the sum of all voting power of authors: {}, \
147 quorum_size: {}.",
148 quorum_voting_power,
149 total_voting_power
150 );
151 Ok(ValidatorVerifier {
152 address_to_validator_info,
153 quorum_voting_power,
154 total_voting_power,
155 })
156 }
157
158 #[cfg(any(test, feature = "fuzzing"))]
161 pub fn new_for_testing(
164 address_to_validator_info: BTreeMap<
165 AccountAddress,
166 ValidatorConsensusInfo,
167 >,
168 quorum_voting_power: u64, total_voting_power: u64,
169 ) -> Self {
170 ValidatorVerifier {
171 address_to_validator_info,
172 quorum_voting_power,
173 total_voting_power,
174 }
175 }
176
177 pub fn new_single(
180 author: AccountAddress, public_key: ConsensusPublicKey,
181 vrf_public_key: Option<ConsensusVRFPublicKey>,
182 ) -> Self {
183 let mut author_to_validator_info = BTreeMap::new();
184 author_to_validator_info.insert(
185 author,
186 ValidatorConsensusInfo::new(public_key, vrf_public_key, 1),
187 );
188 Self::new(author_to_validator_info)
189 }
190
191 pub fn verify<T: Serialize + CryptoHash>(
193 &self, author: AccountAddress, message: &T,
194 signature: &ConsensusSignature,
195 ) -> std::result::Result<(), VerifyError> {
196 match self.get_public_key(&author) {
197 Some(public_key) => {
198 if public_key
199 .verify_struct_signature(message, signature)
200 .is_err()
201 {
202 Err(VerifyError::InvalidSignature)
203 } else {
204 Ok(())
205 }
206 }
207 None => Err(VerifyError::UnknownAuthor),
208 }
209 }
210
211 pub fn verify_vrf(
213 &self, author: AccountAddress, seed: &[u8], proof: &ConsensusVRFProof,
214 ) -> std::result::Result<(), VerifyError> {
215 match self.get_vrf_public_key(&author) {
216 Some(Some(public_key)) => {
217 if public_key.verify_proof(seed, proof).is_err() {
218 Err(VerifyError::InvalidVrfProof)
219 } else {
220 Ok(())
221 }
222 }
223 _ => Err(VerifyError::UnknownAuthor),
224 }
225 }
226
227 pub fn verify_aggregated_struct_signature<T: CryptoHash + Serialize>(
234 &self, message: &T,
235 aggregated_signature: &BTreeMap<AccountAddress, ConsensusSignature>,
236 ) -> std::result::Result<(), VerifyError> {
237 self.check_num_of_signatures(aggregated_signature)?;
238 self.check_voting_power(aggregated_signature.keys())?;
239 for (author, signature) in aggregated_signature {
240 self.verify(*author, message, &signature.clone())?;
241 }
242 Ok(())
243 }
244
245 pub fn batch_verify_aggregated_signatures<T: CryptoHash + Serialize>(
248 &self, message: &T,
249 aggregated_signature: &BTreeMap<AccountAddress, ConsensusSignature>,
250 ) -> std::result::Result<(), VerifyError> {
251 self.check_num_of_signatures(aggregated_signature)?;
252 self.check_voting_power(aggregated_signature.keys())?;
253 let keys_and_signatures: Vec<(ConsensusPublicKey, ConsensusSignature)> =
254 aggregated_signature
255 .iter()
256 .flat_map(|(address, signature)| {
257 let sig = signature.clone();
258 self.get_public_key(&address).map(|pub_key| (pub_key, sig))
259 })
260 .collect();
261 if ConsensusSignature::batch_verify(message, keys_and_signatures)
264 .is_err()
265 {
266 self.verify_aggregated_struct_signature(
267 message,
268 aggregated_signature,
269 )?
270 }
271 Ok(())
272 }
273
274 fn check_num_of_signatures(
277 &self,
278 aggregated_signature: &BTreeMap<AccountAddress, ConsensusSignature>,
279 ) -> std::result::Result<(), VerifyError> {
280 let num_of_signatures = aggregated_signature.len();
281 if num_of_signatures > self.len() {
282 return Err(VerifyError::TooManySignatures {
283 num_of_signatures,
284 num_of_authors: self.len(),
285 });
286 }
287 Ok(())
288 }
289
290 pub fn check_voting_power<'a>(
294 &self, authors: impl Iterator<Item = &'a AccountAddress>,
295 ) -> std::result::Result<(), VerifyError> {
296 let mut aggregated_voting_power = 0;
299 for account_address in authors {
300 match self.get_voting_power(&account_address) {
301 Some(voting_power) => aggregated_voting_power += voting_power,
302 None => return Err(VerifyError::UnknownAuthor),
303 }
304 }
305
306 if aggregated_voting_power < self.quorum_voting_power {
307 return Err(VerifyError::TooLittleVotingPower {
308 voting_power: aggregated_voting_power,
309 quorum_voting_power: self.quorum_voting_power,
310 });
311 }
312 Ok(())
313 }
314
315 pub fn get_public_key(
317 &self, author: &AccountAddress,
318 ) -> Option<ConsensusPublicKey> {
319 self.address_to_validator_info
320 .get(&author)
321 .map(|validator_info| validator_info.public_key.clone())
322 }
323
324 pub fn get_vrf_public_key(
326 &self, author: &AccountAddress,
327 ) -> Option<Option<ConsensusVRFPublicKey>> {
328 self.address_to_validator_info
329 .get(&author)
330 .map(|validator_info| validator_info.vrf_public_key.clone())
331 }
332
333 pub fn get_voting_power(&self, author: &AccountAddress) -> Option<u64> {
335 self.address_to_validator_info
336 .get(&author)
337 .map(|validator_info| validator_info.voting_power)
338 }
339
340 pub fn get_ordered_account_addresses_iter(
342 &self,
343 ) -> impl Iterator<Item = AccountAddress> + '_ {
344 self.address_to_validator_info.keys().copied()
347 }
348
349 pub fn len(&self) -> usize { self.address_to_validator_info.len() }
351
352 pub fn is_empty(&self) -> bool { self.len() == 0 }
354
355 pub fn quorum_voting_power(&self) -> u64 { self.quorum_voting_power }
357
358 pub fn total_voting_power(&self) -> u64 { self.total_voting_power }
360
361 pub fn address_to_validator_info(
362 &self,
363 ) -> &BTreeMap<AccountAddress, ValidatorConsensusInfo> {
364 &self.address_to_validator_info
365 }
366
367 pub fn extra_vote_count<'a>(
369 &self, signers: impl Iterator<Item = &'a AccountAddress>,
370 ) -> anyhow::Result<u64> {
371 let mut total_count = 0;
372 for signer in signers {
373 total_count += self
374 .get_voting_power(signer)
375 .ok_or(anyhow::anyhow!("Signer is not a validator"))?;
376 }
377 total_count.checked_sub(self.quorum_voting_power).ok_or(
378 anyhow::anyhow!("counted voting power overflows total power"),
379 )
380 }
381}
382
383impl OnChainConfig for ValidatorVerifier {
384 const IDENTIFIER: &'static str = "DiemSystem";
385}
386
387fn sum_voting_power(
390 address_to_validator_info: &BTreeMap<
391 AccountAddress,
392 ValidatorConsensusInfo,
393 >,
394) -> u64 {
395 address_to_validator_info.values().fold(0, |sum, x| {
396 sum.checked_add(x.voting_power)
397 .expect("sum of all voting power is greater than u64::max")
398 })
399}
400
401impl fmt::Display for ValidatorVerifier {
402 fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
403 write!(f, "ValidatorSet: [")?;
404 for (addr, info) in &self.address_to_validator_info {
405 write!(
406 f,
407 "{}: {}, ",
408 addr.short_str_lossless(),
409 info.voting_power
410 )?;
411 }
412 write!(f, "]")
413 }
414}
415
416impl From<&ValidatorSet> for ValidatorVerifier {
417 fn from(validator_set: &ValidatorSet) -> Self {
418 ValidatorVerifier::new(validator_set.payload().iter().fold(
419 BTreeMap::new(),
420 |mut map, validator| {
421 map.insert(
422 *validator.account_address(),
423 ValidatorConsensusInfo::new(
424 validator.consensus_public_key().clone(),
425 validator.vrf_public_key().clone(),
426 validator.consensus_voting_power(),
427 ),
428 );
429 map
430 },
431 ))
432 }
433}
434
435#[cfg(any(test, feature = "fuzzing"))]
436impl From<&ValidatorVerifier> for ValidatorSet {
437 fn from(verifier: &ValidatorVerifier) -> Self {
438 ValidatorSet::new(
439 verifier
440 .get_ordered_account_addresses_iter()
441 .map(|addr| {
442 crate::validator_info::ValidatorInfo::new_with_test_network_keys(
443 addr,
444 verifier.get_public_key(&addr).unwrap(),
445 verifier.get_vrf_public_key(&addr).unwrap(),
446 verifier.get_voting_power(&addr).unwrap(),
447 )
448 })
449 .collect(),
450 )
451 }
452}
453
454#[cfg(any(test, feature = "fuzzing"))]
459pub fn random_validator_verifier(
460 count: usize, custom_voting_power_quorum: Option<u64>,
461 pseudo_random_account_address: bool,
462) -> (
463 Vec<crate::validator_signer::ValidatorSigner>,
464 ValidatorVerifier,
465) {
466 let mut signers = Vec::new();
467 let mut account_address_to_validator_info = BTreeMap::new();
468 for i in 0..count {
469 let random_signer = if pseudo_random_account_address {
470 crate::validator_signer::ValidatorSigner::from_int(i as u8)
471 } else {
472 crate::validator_signer::ValidatorSigner::random([i as u8; 32])
473 };
474 account_address_to_validator_info.insert(
475 random_signer.author(),
476 crate::validator_verifier::ValidatorConsensusInfo::new(
477 random_signer.public_key(),
478 random_signer.vrf_public_key(),
479 1,
480 ),
481 );
482 signers.push(random_signer);
483 }
484 (
485 signers,
486 match custom_voting_power_quorum {
487 Some(custom_voting_power_quorum) => {
488 ValidatorVerifier::new_with_quorum_voting_power(
489 account_address_to_validator_info,
490 custom_voting_power_quorum,
491 )
492 .expect("Unable to create testing validator verifier")
493 }
494 None => ValidatorVerifier::new(account_address_to_validator_info),
495 },
496 )
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502 use crate::validator_signer::ValidatorSigner;
503 use diem_crypto::test_utils::{TestDiemCrypto, TEST_SEED};
504 use std::collections::BTreeMap;
505
506 #[test]
507 fn test_check_voting_power() {
508 let (validator_signers, validator_verifier) =
509 random_validator_verifier(2, None, false);
510 let mut author_to_signature_map = BTreeMap::new();
511
512 assert_eq!(
513 validator_verifier
514 .check_voting_power(author_to_signature_map.keys())
515 .unwrap_err(),
516 VerifyError::TooLittleVotingPower {
517 voting_power: 0,
518 quorum_voting_power: 2,
519 }
520 );
521
522 let dummy_struct = TestDiemCrypto("Hello, World".to_string());
523 for validator in validator_signers.iter() {
524 author_to_signature_map
525 .insert(validator.author(), validator.sign(&dummy_struct));
526 }
527
528 assert_eq!(
529 validator_verifier
530 .check_voting_power(author_to_signature_map.keys()),
531 Ok(())
532 );
533 }
534
535 #[test]
536 fn test_validator() {
537 let validator_signer = ValidatorSigner::random(TEST_SEED);
538 let dummy_struct = TestDiemCrypto("Hello, World".to_string());
539 let signature = validator_signer.sign(&dummy_struct);
540 let validator = ValidatorVerifier::new_single(
541 validator_signer.author(),
542 validator_signer.public_key(),
543 validator_signer.vrf_public_key(),
544 );
545 assert_eq!(
546 validator.verify(
547 validator_signer.author(),
548 &dummy_struct,
549 &signature
550 ),
551 Ok(())
552 );
553 let unknown_validator_signer = ValidatorSigner::random([1; 32]);
554 let unknown_signature = unknown_validator_signer.sign(&dummy_struct);
555 assert_eq!(
556 validator.verify(
557 unknown_validator_signer.author(),
558 &dummy_struct,
559 &unknown_signature
560 ),
561 Err(VerifyError::UnknownAuthor)
562 );
563 assert_eq!(
564 validator.verify(
565 validator_signer.author(),
566 &dummy_struct,
567 &unknown_signature
568 ),
569 Err(VerifyError::InvalidSignature)
570 );
571 }
572
573 #[test]
574 fn test_equal_vote_quorum_validators() {
575 const NUM_SIGNERS: u8 = 7;
576 let validator_signers: Vec<ValidatorSigner> = (0..NUM_SIGNERS)
578 .map(|i| ValidatorSigner::random([i; 32]))
579 .collect();
580 let dummy_struct = TestDiemCrypto("Hello, World".to_string());
581
582 let mut author_to_public_key_map = BTreeMap::new();
584 for validator in validator_signers.iter() {
585 author_to_public_key_map.insert(
586 validator.author(),
587 ValidatorConsensusInfo::new(
588 validator.public_key(),
589 validator.vrf_public_key(),
590 1,
591 ),
592 );
593 }
594
595 let mut author_to_signature_map = BTreeMap::new();
597 for validator in validator_signers.iter() {
598 author_to_signature_map
599 .insert(validator.author(), validator.sign(&dummy_struct));
600 }
601
602 let validator_verifier =
605 ValidatorVerifier::new_with_quorum_voting_power(
606 author_to_public_key_map,
607 5,
608 )
609 .expect("Incorrect quorum size.");
610
611 assert_eq!(
613 validator_verifier.batch_verify_aggregated_signatures(
614 &dummy_struct,
615 &author_to_signature_map
616 ),
617 Ok(())
618 );
619
620 let unknown_validator_signer =
622 ValidatorSigner::random([NUM_SIGNERS + 1; 32]);
623 let unknown_signature = unknown_validator_signer.sign(&dummy_struct);
624 author_to_signature_map.insert(
625 unknown_validator_signer.author(),
626 unknown_signature.clone(),
627 );
628 assert_eq!(
629 validator_verifier.batch_verify_aggregated_signatures(
630 &dummy_struct,
631 &author_to_signature_map
632 ),
633 Err(VerifyError::TooManySignatures {
634 num_of_signatures: 8,
635 num_of_authors: 7
636 })
637 );
638
639 author_to_signature_map.clear();
641 for validator in validator_signers.iter().take(5) {
642 author_to_signature_map
643 .insert(validator.author(), validator.sign(&dummy_struct));
644 }
645 assert_eq!(
646 validator_verifier.batch_verify_aggregated_signatures(
647 &dummy_struct,
648 &author_to_signature_map
649 ),
650 Ok(())
651 );
652
653 author_to_signature_map.insert(
656 unknown_validator_signer.author(),
657 unknown_signature.clone(),
658 );
659 assert_eq!(
660 validator_verifier.batch_verify_aggregated_signatures(
661 &dummy_struct,
662 &author_to_signature_map
663 ),
664 Err(VerifyError::UnknownAuthor)
665 );
666
667 author_to_signature_map.clear();
670 for validator in validator_signers.iter().take(4) {
671 author_to_signature_map
672 .insert(validator.author(), validator.sign(&dummy_struct));
673 }
674 assert_eq!(
675 validator_verifier.batch_verify_aggregated_signatures(
676 &dummy_struct,
677 &author_to_signature_map
678 ),
679 Err(VerifyError::TooLittleVotingPower {
680 voting_power: 4,
681 quorum_voting_power: 5
682 })
683 );
684
685 author_to_signature_map
688 .insert(unknown_validator_signer.author(), unknown_signature);
689 assert_eq!(
690 validator_verifier.batch_verify_aggregated_signatures(
691 &dummy_struct,
692 &author_to_signature_map
693 ),
694 Err(VerifyError::UnknownAuthor)
695 );
696 }
697
698 #[test]
699 #[should_panic]
700 fn test_very_unequal_vote_quorum_validators() {
701 const NUM_SIGNERS: u8 = 4;
702 let validator_signers: Vec<ValidatorSigner> = (0..NUM_SIGNERS)
704 .map(|i| ValidatorSigner::random([i; 32]))
705 .collect();
706 let dummy_struct = TestDiemCrypto("Hello, World".to_string());
707
708 let mut author_to_public_key_map = BTreeMap::new();
711 let mut author_to_signature_map = BTreeMap::new();
712 for (i, validator_signer) in validator_signers.iter().enumerate() {
713 let mut voting_power: u64 = i as u64;
714 if i == 3 {
715 voting_power = u64::max_value()
716 }
717 author_to_public_key_map.insert(
718 validator_signer.author(),
719 ValidatorConsensusInfo::new(
720 validator_signer.public_key(),
721 validator_signer.vrf_public_key(),
722 voting_power,
723 ),
724 );
725 author_to_signature_map.insert(
726 validator_signer.author(),
727 validator_signer.sign(&dummy_struct),
728 );
729 }
730
731 let _validator_verifier =
733 ValidatorVerifier::new(author_to_public_key_map);
734 }
735
736 #[test]
737 fn test_unequal_vote_quorum_validators() {
738 const NUM_SIGNERS: u8 = 4;
739 let validator_signers: Vec<ValidatorSigner> = (0..NUM_SIGNERS)
741 .map(|i| ValidatorSigner::random([i; 32]))
742 .collect();
743 let dummy_struct = TestDiemCrypto("Hello, World".to_string());
744
745 let mut author_to_public_key_map = BTreeMap::new();
748 let mut author_to_signature_map = BTreeMap::new();
749 for (i, validator_signer) in validator_signers.iter().enumerate() {
750 author_to_public_key_map.insert(
751 validator_signer.author(),
752 ValidatorConsensusInfo::new(
753 validator_signer.public_key(),
754 validator_signer.vrf_public_key(),
755 i as u64,
756 ),
757 );
758 author_to_signature_map.insert(
759 validator_signer.author(),
760 validator_signer.sign(&dummy_struct),
761 );
762 }
763
764 let validator_verifier =
767 ValidatorVerifier::new_with_quorum_voting_power(
768 author_to_public_key_map,
769 5,
770 )
771 .expect("Incorrect quorum size.");
772
773 assert_eq!(
775 validator_verifier.batch_verify_aggregated_signatures(
776 &dummy_struct,
777 &author_to_signature_map
778 ),
779 Ok(())
780 );
781
782 let unknown_validator_signer =
784 ValidatorSigner::random([NUM_SIGNERS + 1; 32]);
785 let unknown_signature = unknown_validator_signer.sign(&dummy_struct);
786 author_to_signature_map.insert(
787 unknown_validator_signer.author(),
788 unknown_signature.clone(),
789 );
790 assert_eq!(
791 validator_verifier.batch_verify_aggregated_signatures(
792 &dummy_struct,
793 &author_to_signature_map
794 ),
795 Err(VerifyError::TooManySignatures {
796 num_of_signatures: 5,
797 num_of_authors: 4
798 })
799 );
800
801 author_to_signature_map.clear();
804 for validator in validator_signers.iter().skip(2) {
805 author_to_signature_map
806 .insert(validator.author(), validator.sign(&dummy_struct));
807 }
808 assert_eq!(
809 validator_verifier.batch_verify_aggregated_signatures(
810 &dummy_struct,
811 &author_to_signature_map
812 ),
813 Ok(())
814 );
815
816 author_to_signature_map.insert(
819 unknown_validator_signer.author(),
820 unknown_signature.clone(),
821 );
822 assert_eq!(
823 validator_verifier.batch_verify_aggregated_signatures(
824 &dummy_struct,
825 &author_to_signature_map
826 ),
827 Err(VerifyError::UnknownAuthor)
828 );
829
830 author_to_signature_map.clear();
833 for validator in validator_signers.iter().take(3) {
834 author_to_signature_map
835 .insert(validator.author(), validator.sign(&dummy_struct));
836 }
837 assert_eq!(
838 validator_verifier.batch_verify_aggregated_signatures(
839 &dummy_struct,
840 &author_to_signature_map
841 ),
842 Err(VerifyError::TooLittleVotingPower {
843 voting_power: 3,
844 quorum_voting_power: 5
845 })
846 );
847
848 author_to_signature_map
851 .insert(unknown_validator_signer.author(), unknown_signature);
852 assert_eq!(
853 validator_verifier.batch_verify_aggregated_signatures(
854 &dummy_struct,
855 &author_to_signature_map
856 ),
857 Err(VerifyError::UnknownAuthor)
858 );
859 }
860}