diff --git a/Code/common/Cargo.toml b/Code/common/Cargo.toml index 7fad66bf0..37a2afea2 100644 --- a/Code/common/Cargo.toml +++ b/Code/common/Cargo.toml @@ -5,4 +5,5 @@ edition = "2021" publish = false [dependencies] +secrecy = "0.8.0" signature = "2.1.0" diff --git a/Code/common/src/consensus.rs b/Code/common/src/consensus.rs index 0c4e1e24d..7666c2eb1 100644 --- a/Code/common/src/consensus.rs +++ b/Code/common/src/consensus.rs @@ -1,6 +1,6 @@ use crate::{ - Address, Height, PrivateKey, Proposal, PublicKey, Round, Signature, SignedVote, Validator, - ValidatorSet, Value, ValueId, Vote, + Address, Height, PrivateKey, Proposal, PublicKey, Round, Signature, SignedVote, SigningScheme, + Validator, ValidatorSet, Value, ValueId, Vote, }; /// This trait allows to abstract over the various datatypes @@ -12,21 +12,22 @@ where type Address: Address; type Height: Height; type Proposal: Proposal; - type PrivateKey: PrivateKey; - type PublicKey: PublicKey>; type Validator: Validator; type ValidatorSet: ValidatorSet; type Value: Value; type Vote: Vote; + type SigningScheme: SigningScheme; // TODO: Do we need to support multiple signing schemes? // FIXME: Remove altogether const DUMMY_VALUE: Self::Value; /// Sign the given vote using the given private key. - fn sign_vote(vote: &Self::Vote, private_key: &Self::PrivateKey) -> Signature; + /// TODO: Maybe move this as concrete methods in `SignedVote`? + fn sign_vote(vote: &Self::Vote, private_key: &PrivateKey) -> Signature; /// Verify the given vote's signature using the given public key. - fn verify_signed_vote(signed_vote: &SignedVote, public_key: &Self::PublicKey) -> bool; + /// TODO: Maybe move this as concrete methods in `SignedVote`? + fn verify_signed_vote(signed_vote: &SignedVote, public_key: &PublicKey) -> bool; /// Build a new proposal for the given value at the given height, round and POL round. fn new_proposal( diff --git a/Code/common/src/lib.rs b/Code/common/src/lib.rs index adef2b18a..9a0b76501 100644 --- a/Code/common/src/lib.rs +++ b/Code/common/src/lib.rs @@ -22,16 +22,21 @@ mod validator_set; mod value; mod vote; +// Re-export `signature` crate for convenience +pub use ::signature; + /// Type alias to make it easier to refer the `ValueId` type of a given `Consensus` engine. pub type ValueId = <::Value as Value>::Id; -pub type Signature = <::PrivateKey as PrivateKey>::Signature; +pub type PublicKey = <::SigningScheme as SigningScheme>::PublicKey; +pub type PrivateKey = <::SigningScheme as SigningScheme>::PrivateKey; +pub type Signature = <::SigningScheme as SigningScheme>::Signature; pub use consensus::Consensus; pub use height::Height; pub use proposal::Proposal; pub use round::Round; pub use signed_vote::SignedVote; -pub use signing::{PrivateKey, PublicKey}; +pub use signing::SigningScheme; pub use timeout::{Timeout, TimeoutStep}; pub use validator_set::{Address, Validator, ValidatorSet, VotingPower}; pub use value::Value; diff --git a/Code/common/src/signed_vote.rs b/Code/common/src/signed_vote.rs index a59e729a5..adfd4a268 100644 --- a/Code/common/src/signed_vote.rs +++ b/Code/common/src/signed_vote.rs @@ -1,4 +1,4 @@ -use crate::{Consensus, PublicKey}; +use crate::{Consensus, Signature}; // TODO: Do we need to abstract over `SignedVote` as well? @@ -9,18 +9,14 @@ where { pub vote: C::Vote, pub address: C::Address, - pub signature: ::Signature, + pub signature: Signature, } impl SignedVote where C: Consensus, { - pub fn new( - vote: C::Vote, - address: C::Address, - signature: ::Signature, - ) -> Self { + pub fn new(vote: C::Vote, address: C::Address, signature: Signature) -> Self { Self { vote, address, diff --git a/Code/common/src/signing.rs b/Code/common/src/signing.rs index 7808f0c5c..07abc4ae5 100644 --- a/Code/common/src/signing.rs +++ b/Code/common/src/signing.rs @@ -1,22 +1,20 @@ use core::fmt::Debug; -use signature::{Signer, Verifier}; +use secrecy::{CloneableSecret, DebugSecret, Zeroize}; +use signature::{Keypair, Signer, Verifier}; -/// Defines the requirements for a private key type. -pub trait PrivateKey +pub trait SigningScheme where - Self: Clone + Debug + Signer, + Self: Clone + Debug + Eq, { - type Signature: Clone + Debug + PartialEq + Eq; - type PublicKey: PublicKey; + type Signature: Clone + Debug + Eq; - fn public_key(&self) -> Self::PublicKey; -} + type PublicKey: Clone + Debug + Eq + Verifier; -/// Defines the requirements for a public key type. -pub trait PublicKey -where - Self: Clone + Debug + PartialEq + Eq + Verifier, -{ - type Signature: Clone + Debug + PartialEq + Eq; + type PrivateKey: Clone + + Signer + + Keypair + + Zeroize + + DebugSecret + + CloneableSecret; } diff --git a/Code/common/src/validator_set.rs b/Code/common/src/validator_set.rs index db3756e56..29b9b8c50 100644 --- a/Code/common/src/validator_set.rs +++ b/Code/common/src/validator_set.rs @@ -1,6 +1,6 @@ use core::fmt::Debug; -use crate::Consensus; +use crate::{Consensus, PublicKey}; /// Voting power held by a validator. /// @@ -26,7 +26,7 @@ where fn address(&self) -> &C::Address; /// The public key of the validator, used to verify signatures. - fn public_key(&self) -> &C::PublicKey; + fn public_key(&self) -> &PublicKey; /// The voting power held by the validaror. fn voting_power(&self) -> VotingPower; @@ -46,7 +46,7 @@ where fn get_proposer(&self) -> C::Validator; /// Get the validator with the given public key. - fn get_by_public_key(&self, public_key: &C::PublicKey) -> Option<&C::Validator>; + fn get_by_public_key(&self, public_key: &PublicKey) -> Option<&C::Validator>; /// Get the validator with the given address. fn get_by_address(&self, address: &C::Address) -> Option<&C::Validator>; diff --git a/Code/consensus/Cargo.toml b/Code/consensus/Cargo.toml index 90fda0325..01b40c00a 100644 --- a/Code/consensus/Cargo.toml +++ b/Code/consensus/Cargo.toml @@ -8,3 +8,4 @@ publish = false malachite-common = { version = "0.1.0", path = "../common" } malachite-round = { version = "0.1.0", path = "../round" } malachite-vote = { version = "0.1.0", path = "../vote" } +secrecy = "0.8.0" diff --git a/Code/consensus/src/executor.rs b/Code/consensus/src/executor.rs index d004e6df5..54496e892 100644 --- a/Code/consensus/src/executor.rs +++ b/Code/consensus/src/executor.rs @@ -1,5 +1,8 @@ use std::collections::BTreeMap; +use secrecy::{ExposeSecret, Secret}; + +use malachite_common::signature::Keypair; use malachite_common::{ Consensus, PrivateKey, Proposal, Round, SignedVote, Timeout, TimeoutStep, Validator, ValidatorSet, Value, Vote, VoteType, @@ -18,7 +21,7 @@ where C: Consensus, { height: C::Height, - key: C::PrivateKey, + key: Secret>, validator_set: C::ValidatorSet, round: Round, votes: VoteKeeper, @@ -29,7 +32,7 @@ impl Executor where C: Consensus, { - pub fn new(height: C::Height, validator_set: C::ValidatorSet, key: C::PrivateKey) -> Self { + pub fn new(height: C::Height, validator_set: C::ValidatorSet, key: PrivateKey) -> Self { let votes = VoteKeeper::new( height.clone(), Round::INITIAL, @@ -38,7 +41,7 @@ where Self { height, - key, + key: Secret::new(key), validator_set, round: Round::INITIAL, votes, @@ -75,11 +78,11 @@ where RoundMessage::Vote(vote) => { let address = self .validator_set - .get_by_public_key(&self.key.public_key())? + .get_by_public_key(&self.key.expose_secret().verifying_key())? .address() .clone(); - let signature = C::sign_vote(&vote, &self.key); + let signature = C::sign_vote(&vote, self.key.expose_secret()); let signed_vote = SignedVote::new(vote, address, signature); Some(Message::Vote(signed_vote)) @@ -109,7 +112,7 @@ where fn apply_new_round(&mut self, round: Round) -> Option> { let proposer = self.validator_set.get_proposer(); - let event = if proposer.public_key() == &self.key.public_key() { + let event = if proposer.public_key() == &self.key.expose_secret().verifying_key() { let value = self.get_value(); RoundEvent::NewRoundProposer(value) } else { diff --git a/Code/test/Cargo.toml b/Code/test/Cargo.toml index 536932fdb..6e1e33b87 100644 --- a/Code/test/Cargo.toml +++ b/Code/test/Cargo.toml @@ -13,3 +13,4 @@ ed25519-consensus = "2.1.0" signature = "2.1.0" rand = { version = "0.8.5", features = ["std_rng"] } sha2 = "0.10.8" +secrecy = "0.8.0" diff --git a/Code/test/src/consensus.rs b/Code/test/src/consensus.rs index ecccbc810..80abb1035 100644 --- a/Code/test/src/consensus.rs +++ b/Code/test/src/consensus.rs @@ -4,7 +4,7 @@ use malachite_common::SignedVote; use crate::height::*; use crate::proposal::*; -use crate::public_key::{Ed25519PrivateKey, Ed25519PublicKey, Ed25519Signature}; +use crate::signing::{Ed25519, PrivateKey, PublicKey, Signature}; use crate::validator_set::*; use crate::value::*; use crate::vote::*; @@ -16,21 +16,20 @@ impl Consensus for TestConsensus { type Address = Address; type Height = Height; type Proposal = Proposal; - type PublicKey = Ed25519PublicKey; - type PrivateKey = Ed25519PrivateKey; type ValidatorSet = ValidatorSet; type Validator = Validator; type Value = Value; type Vote = Vote; + type SigningScheme = Ed25519; const DUMMY_VALUE: Self::Value = Value::new(9999); - fn sign_vote(vote: &Self::Vote, private_key: &Self::PrivateKey) -> Ed25519Signature { + fn sign_vote(vote: &Self::Vote, private_key: &PrivateKey) -> Signature { use signature::Signer; private_key.sign(&vote.to_bytes()) } - fn verify_signed_vote(signed_vote: &SignedVote, public_key: &Ed25519PublicKey) -> bool { + fn verify_signed_vote(signed_vote: &SignedVote, public_key: &PublicKey) -> bool { use signature::Verifier; public_key .verify(&signed_vote.vote.to_bytes(), &signed_vote.signature) diff --git a/Code/test/src/lib.rs b/Code/test/src/lib.rs index c08d0d1de..9da94495e 100644 --- a/Code/test/src/lib.rs +++ b/Code/test/src/lib.rs @@ -4,7 +4,7 @@ mod consensus; mod height; mod proposal; -mod public_key; +mod signing; mod validator_set; mod value; mod vote; @@ -12,7 +12,7 @@ mod vote; pub use crate::consensus::*; pub use crate::height::*; pub use crate::proposal::*; -pub use crate::public_key::*; +pub use crate::signing::*; pub use crate::validator_set::*; pub use crate::value::*; pub use crate::vote::*; diff --git a/Code/test/src/public_key.rs b/Code/test/src/public_key.rs deleted file mode 100644 index 51a35b8a6..000000000 --- a/Code/test/src/public_key.rs +++ /dev/null @@ -1,68 +0,0 @@ -use ed25519_consensus::{Signature, SigningKey, VerificationKey}; - -use malachite_common::{PrivateKey, PublicKey}; -use rand::{CryptoRng, RngCore}; -use signature::{Signer, Verifier}; - -pub type Ed25519Signature = Signature; - -#[derive(Clone, Debug)] -pub struct Ed25519PrivateKey(SigningKey); - -impl Ed25519PrivateKey { - pub fn generate(rng: R) -> Self - where - R: RngCore + CryptoRng, - { - let signing_key = SigningKey::new(rng); - - Self(signing_key) - } - - pub fn public_key(&self) -> Ed25519PublicKey { - Ed25519PublicKey::new(self.0.verification_key()) - } -} - -impl PrivateKey for Ed25519PrivateKey { - type Signature = Signature; - type PublicKey = Ed25519PublicKey; - - fn public_key(&self) -> Self::PublicKey { - self.public_key() - } -} - -impl Signer for Ed25519PrivateKey { - fn try_sign(&self, msg: &[u8]) -> Result { - Ok(self.0.sign(msg)) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct Ed25519PublicKey(VerificationKey); - -impl Ed25519PublicKey { - pub fn new(key: impl Into) -> Self { - Self(key.into()) - } - - pub fn hash(&self) -> [u8; 32] { - use sha2::{Digest, Sha256}; - let mut hasher = Sha256::new(); - hasher.update(self.0.as_bytes()); - hasher.finalize().into() - } -} - -impl PublicKey for Ed25519PublicKey { - type Signature = Signature; -} - -impl Verifier for Ed25519PublicKey { - fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), signature::Error> { - self.0 - .verify(signature, msg) - .map_err(|_| signature::Error::new()) - } -} diff --git a/Code/test/src/signing.rs b/Code/test/src/signing.rs new file mode 100644 index 000000000..af120d071 --- /dev/null +++ b/Code/test/src/signing.rs @@ -0,0 +1,89 @@ +use malachite_common::SigningScheme; +use rand::{CryptoRng, RngCore}; +use secrecy::{CloneableSecret, DebugSecret, Zeroize}; +use signature::{Keypair, Signer, Verifier}; + +pub use ed25519_consensus::Signature; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Ed25519; + +impl Ed25519 { + pub fn generate_keypair(rng: R) -> PrivateKey + where + R: RngCore + CryptoRng, + { + PrivateKey::generate(rng) + } +} + +impl SigningScheme for Ed25519 { + type Signature = Signature; + type PublicKey = PublicKey; + type PrivateKey = PrivateKey; +} + +#[derive(Clone, Debug)] +pub struct PrivateKey(ed25519_consensus::SigningKey); + +impl PrivateKey { + pub fn generate(rng: R) -> Self + where + R: RngCore + CryptoRng, + { + let signing_key = ed25519_consensus::SigningKey::new(rng); + + Self(signing_key) + } + + pub fn public_key(&self) -> PublicKey { + PublicKey::new(self.0.verification_key()) + } +} + +impl Signer for PrivateKey { + fn try_sign(&self, msg: &[u8]) -> Result { + Ok(self.0.sign(msg)) + } +} + +impl Keypair for PrivateKey { + type VerifyingKey = PublicKey; + + fn verifying_key(&self) -> Self::VerifyingKey { + self.public_key() + } +} + +impl Zeroize for PrivateKey { + fn zeroize(&mut self) { + self.0.zeroize() + } +} + +impl DebugSecret for PrivateKey {} +impl CloneableSecret for PrivateKey {} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct PublicKey(ed25519_consensus::VerificationKey); + +impl PublicKey { + pub fn new(key: impl Into) -> Self { + Self(key.into()) + } + + pub fn hash(&self) -> [u8; 32] { + use sha2::{Digest, Sha256}; + let mut hasher = Sha256::new(); + hasher.update(self.0.as_bytes()); + hasher.finalize().into() + } +} + +impl Verifier for PublicKey { + fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), signature::Error> { + self.0 + .verify(signature, msg) + .map_err(|_| signature::Error::new()) + } +} diff --git a/Code/test/src/validator_set.rs b/Code/test/src/validator_set.rs index 841042678..985da7d23 100644 --- a/Code/test/src/validator_set.rs +++ b/Code/test/src/validator_set.rs @@ -2,7 +2,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use malachite_common::VotingPower; -use crate::{Ed25519PublicKey, TestConsensus}; +use crate::{signing::PublicKey, TestConsensus}; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Address([u8; Self::LENGTH]); @@ -14,7 +14,7 @@ impl Address { Self(value) } - pub fn from_public_key(public_key: &Ed25519PublicKey) -> Self { + pub fn from_public_key(public_key: &PublicKey) -> Self { let hash = public_key.hash(); let mut address = [0; Self::LENGTH]; address.copy_from_slice(&hash[..Self::LENGTH]); @@ -28,12 +28,12 @@ impl malachite_common::Address for Address {} #[derive(Clone, Debug, PartialEq, Eq)] pub struct Validator { pub address: Address, - pub public_key: Ed25519PublicKey, + pub public_key: PublicKey, pub voting_power: VotingPower, } impl Validator { - pub fn new(public_key: Ed25519PublicKey, voting_power: VotingPower) -> Self { + pub fn new(public_key: PublicKey, voting_power: VotingPower) -> Self { Self { address: Address::from_public_key(&public_key), public_key, @@ -47,7 +47,7 @@ impl malachite_common::Validator for Validator { &self.address } - fn public_key(&self) -> &Ed25519PublicKey { + fn public_key(&self) -> &PublicKey { &self.public_key } @@ -113,7 +113,7 @@ impl ValidatorSet { self.validators.iter().find(|v| &v.address == address) } - pub fn get_by_public_key(&self, public_key: &Ed25519PublicKey) -> Option<&Validator> { + pub fn get_by_public_key(&self, public_key: &PublicKey) -> Option<&Validator> { self.validators.iter().find(|v| &v.public_key == public_key) } @@ -147,7 +147,7 @@ impl malachite_common::ValidatorSet for ValidatorSet { self.total_voting_power() } - fn get_by_public_key(&self, public_key: &Ed25519PublicKey) -> Option<&Validator> { + fn get_by_public_key(&self, public_key: &PublicKey) -> Option<&Validator> { self.get_by_public_key(public_key) } @@ -167,18 +167,18 @@ mod tests { use super::*; - use crate::Ed25519PrivateKey; + use crate::PrivateKey; #[test] fn add_update_remove() { let mut rng = StdRng::seed_from_u64(0x42); - let sk1 = Ed25519PrivateKey::generate(&mut rng); - let sk2 = Ed25519PrivateKey::generate(&mut rng); - let sk3 = Ed25519PrivateKey::generate(&mut rng); - let sk4 = Ed25519PrivateKey::generate(&mut rng); - let sk5 = Ed25519PrivateKey::generate(&mut rng); - let sk6 = Ed25519PrivateKey::generate(&mut rng); + let sk1 = PrivateKey::generate(&mut rng); + let sk2 = PrivateKey::generate(&mut rng); + let sk3 = PrivateKey::generate(&mut rng); + let sk4 = PrivateKey::generate(&mut rng); + let sk5 = PrivateKey::generate(&mut rng); + let sk6 = PrivateKey::generate(&mut rng); let v1 = Validator::new(sk1.public_key(), 1); let v2 = Validator::new(sk2.public_key(), 2); diff --git a/Code/test/src/vote.rs b/Code/test/src/vote.rs index 9532b6123..5601b8a7e 100644 --- a/Code/test/src/vote.rs +++ b/Code/test/src/vote.rs @@ -1,7 +1,7 @@ use malachite_common::{Round, SignedVote, VoteType}; use signature::Signer; -use crate::{Address, Ed25519PrivateKey, TestConsensus, ValueId}; +use crate::{Address, PrivateKey, TestConsensus, ValueId}; /// A vote for a value in a round #[derive(Clone, Debug, PartialEq, Eq)] @@ -46,7 +46,7 @@ impl Vote { bytes } - pub fn signed(self, private_key: &Ed25519PrivateKey) -> SignedVote { + pub fn signed(self, private_key: &PrivateKey) -> SignedVote { let address = Address::from_public_key(&private_key.public_key()); let signature = private_key.sign(&self.to_bytes()); diff --git a/Code/test/tests/consensus_executor.rs b/Code/test/tests/consensus_executor.rs index 71cff7c76..e617ece38 100644 --- a/Code/test/tests/consensus_executor.rs +++ b/Code/test/tests/consensus_executor.rs @@ -3,9 +3,7 @@ use malachite_consensus::executor::Executor; use malachite_consensus::message::Message; use malachite_round::state::{RoundValue, State, Step}; -use malachite_test::{ - Ed25519PrivateKey, Height, Proposal, TestConsensus, Validator, ValidatorSet, Vote, -}; +use malachite_test::{Height, PrivateKey, Proposal, TestConsensus, Validator, ValidatorSet, Vote}; use rand::rngs::StdRng; use rand::SeedableRng; @@ -23,9 +21,9 @@ fn executor_steps_proposer() { let mut rng = StdRng::seed_from_u64(0x42); - let sk1 = Ed25519PrivateKey::generate(&mut rng); - let sk2 = Ed25519PrivateKey::generate(&mut rng); - let sk3 = Ed25519PrivateKey::generate(&mut rng); + let sk1 = PrivateKey::generate(&mut rng); + let sk2 = PrivateKey::generate(&mut rng); + let sk3 = PrivateKey::generate(&mut rng); let v1 = Validator::new(sk1.public_key(), 1); let v2 = Validator::new(sk2.public_key(), 2); @@ -208,9 +206,9 @@ fn executor_steps_not_proposer() { let mut rng = StdRng::seed_from_u64(0x42); - let sk1 = Ed25519PrivateKey::generate(&mut rng); - let sk2 = Ed25519PrivateKey::generate(&mut rng); - let sk3 = Ed25519PrivateKey::generate(&mut rng); + let sk1 = PrivateKey::generate(&mut rng); + let sk2 = PrivateKey::generate(&mut rng); + let sk3 = PrivateKey::generate(&mut rng); let v1 = Validator::new(sk1.public_key(), 1); let v2 = Validator::new(sk2.public_key(), 2); @@ -391,9 +389,9 @@ fn executor_steps_not_proposer_timeout() { let mut rng = StdRng::seed_from_u64(0x42); - let sk1 = Ed25519PrivateKey::generate(&mut rng); - let sk2 = Ed25519PrivateKey::generate(&mut rng); - let sk3 = Ed25519PrivateKey::generate(&mut rng); + let sk1 = PrivateKey::generate(&mut rng); + let sk2 = PrivateKey::generate(&mut rng); + let sk3 = PrivateKey::generate(&mut rng); let v1 = Validator::new(sk1.public_key(), 1); let v2 = Validator::new(sk2.public_key(), 1);