diem_types/
validator_signer.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8use crate::{
9    account_address::AccountAddress,
10    validator_config::{
11        ConsensusPrivateKey, ConsensusPublicKey, ConsensusSignature,
12        ConsensusVRFPrivateKey, ConsensusVRFPublicKey,
13    },
14};
15use diem_crypto::{
16    hash::CryptoHash, test_utils::TEST_SEED, PrivateKey, SigningKey, Uniform,
17};
18use rand::{rngs::StdRng, SeedableRng};
19use serde::ser::Serialize;
20use std::convert::TryFrom;
21
22/// ValidatorSigner associates an author with public and private keys with
23/// helpers for signing and validating. This struct can be used for all signing
24/// operations including block and network signing, respectively.
25#[cfg_attr(any(test, feature = "fuzzing"), derive(Clone, Debug))]
26pub struct ValidatorSigner {
27    author: AccountAddress,
28    private_key: ConsensusPrivateKey,
29    // If it's `Some`, the generated block will also set `vrf_proof` to `Some`.
30    vrf_private_key: Option<ConsensusVRFPrivateKey>,
31}
32
33impl ValidatorSigner {
34    pub fn new(
35        author: AccountAddress, private_key: ConsensusPrivateKey,
36        vrf_private_key: Option<ConsensusVRFPrivateKey>,
37    ) -> Self {
38        ValidatorSigner {
39            author,
40            private_key,
41            vrf_private_key,
42        }
43    }
44
45    /// Constructs a signature for `message` using `private_key`.
46    pub fn sign<T: Serialize + CryptoHash>(
47        &self, message: &T,
48    ) -> ConsensusSignature {
49        self.private_key.sign(message)
50    }
51
52    /// Returns the author associated with this signer.
53    pub fn author(&self) -> AccountAddress { self.author }
54
55    /// Returns the public key associated with this signer.
56    pub fn public_key(&self) -> ConsensusPublicKey {
57        self.private_key.public_key()
58    }
59
60    pub fn vrf_public_key(&self) -> Option<ConsensusVRFPublicKey> {
61        self.vrf_private_key.as_ref().map(|sk| sk.public_key())
62    }
63
64    /// Returns the private key associated with this signer. Only available for
65    /// testing purposes.
66    #[cfg(any(test, feature = "fuzzing"))]
67    pub fn private_key(&self) -> &ConsensusPrivateKey { &self.private_key }
68}
69
70impl ValidatorSigner {
71    /// Generate a random set of public and private keys and author
72    /// information.
73    /// This takes an optional seed, which it initializes to
74    /// `test_utils::TEST_SEED` if passed `None`
75    pub fn random(opt_rng_seed: impl for<'a> Into<Option<[u8; 32]>>) -> Self {
76        let mut rng =
77            StdRng::from_seed(opt_rng_seed.into().unwrap_or(TEST_SEED));
78        Self::new(
79            AccountAddress::random(),
80            ConsensusPrivateKey::generate(&mut rng),
81            Some(ConsensusVRFPrivateKey::generate(&mut rng)),
82        )
83    }
84
85    /// For test only - makes signer with nicely looking account address that
86    /// has specified integer as fist byte, and rest are zeroes
87    pub fn from_int(num: u8) -> Self {
88        let mut address = [0; AccountAddress::LENGTH];
89        address[0] = num;
90        let private_key = ConsensusPrivateKey::generate_for_testing();
91        let vrf_private_key = ConsensusVRFPrivateKey::generate_for_testing();
92        Self::new(
93            AccountAddress::try_from(&address[..]).unwrap(),
94            private_key,
95            Some(vrf_private_key),
96        )
97    }
98}
99
100#[cfg(any(test, feature = "fuzzing"))]
101pub mod proptests {
102    use super::*;
103    use diem_crypto::Genesis;
104    use proptest::{prelude::*, sample, strategy::LazyJust};
105
106    #[allow(clippy::redundant_closure)]
107    pub fn arb_signing_key() -> impl Strategy<Value = ConsensusPrivateKey> {
108        prop_oneof![
109            // The no_shrink here reflects that particular keypair choices out
110            // of random options are irrelevant.
111            LazyJust::new(|| ConsensusPrivateKey::generate_for_testing()),
112            LazyJust::new(|| ConsensusPrivateKey::genesis()),
113        ]
114    }
115
116    pub fn signer_strategy(
117        signing_key_strategy: impl Strategy<Value = ConsensusPrivateKey>,
118    ) -> impl Strategy<Value = ValidatorSigner> {
119        signing_key_strategy.prop_map(|signing_key| {
120            ValidatorSigner::new(AccountAddress::random(), signing_key, None)
121        })
122    }
123
124    #[allow(clippy::redundant_closure)]
125    pub fn rand_signer() -> impl Strategy<Value = ValidatorSigner> {
126        signer_strategy(arb_signing_key())
127    }
128
129    #[allow(clippy::redundant_closure)]
130    pub fn arb_signer() -> impl Strategy<Value = ValidatorSigner> {
131        prop_oneof![
132            rand_signer(),
133            LazyJust::new(|| {
134                let genesis_key = ConsensusPrivateKey::genesis();
135                ValidatorSigner::new(
136                    AccountAddress::random(),
137                    genesis_key,
138                    None,
139                )
140            })
141        ]
142    }
143
144    fn select_keypair(
145        keys: Vec<ConsensusPrivateKey>,
146    ) -> impl Strategy<Value = ConsensusPrivateKey> {
147        sample::select(keys)
148    }
149
150    pub fn mostly_in_keypair_pool(
151        keys: Vec<ConsensusPrivateKey>,
152    ) -> impl Strategy<Value = ValidatorSigner> {
153        prop::strategy::Union::new_weighted(vec![
154            (9, signer_strategy(select_keypair(keys)).boxed()),
155            (1, arb_signer().boxed()),
156        ])
157    }
158
159    proptest! {
160        #[test]
161        fn test_new_signer(signing_key in arb_signing_key()){
162            let public_key = signing_key.public_key();
163            let signer = ValidatorSigner::new(AccountAddress::random(), signing_key, None);
164            prop_assert_eq!(public_key, signer.public_key());
165        }
166
167    }
168}