-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
iqkms-signing: refactor into multiple modules (#30)
Factors each major type into its own module. Also adds some additional lints.
- Loading branch information
1 parent
8697013
commit 9c8b1e0
Showing
8 changed files
with
180 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use crate::{Error, Result, SigningKey, VerifyingKey}; | ||
use crypto::signature::ecdsa; | ||
use std::{ | ||
collections::BTreeMap as Map, | ||
fmt::{self, Debug}, | ||
}; | ||
|
||
#[cfg(feature = "ethereum")] | ||
use types::ethereum; | ||
|
||
/// Keys for producing digital signatures. | ||
#[derive(Default)] | ||
pub struct Keyring { | ||
/// Signing keys. | ||
keys: Map<VerifyingKey, SigningKey>, | ||
|
||
/// Ethereum address index. | ||
#[cfg(feature = "ethereum")] | ||
eth_index: Map<ethereum::Address, VerifyingKey>, | ||
} | ||
|
||
impl Keyring { | ||
/// Create a new key ring. | ||
pub fn new() -> Self { | ||
Self::default() | ||
} | ||
|
||
/// Add a key to the ring. | ||
pub fn add(&mut self, signing_key: SigningKey) -> Result<()> { | ||
let verifying_key = signing_key.verifying_key(); | ||
|
||
#[cfg(feature = "ethereum")] | ||
#[allow(irrefutable_let_patterns)] | ||
if let VerifyingKey::EcdsaSecp256k1(vk) = &verifying_key { | ||
self.eth_index.insert(vk.try_into()?, verifying_key.clone()); | ||
} | ||
|
||
if self.keys.insert(verifying_key, signing_key).is_some() { | ||
Err(Error) | ||
} else { | ||
Ok(()) | ||
} | ||
} | ||
|
||
/// Find a key by its Ethereum address. | ||
#[cfg(feature = "ethereum")] | ||
#[cfg_attr(docsrs, doc(cfg(feature = "ethereum")))] | ||
pub fn find_by_eth_address( | ||
&self, | ||
addr: ðereum::Address, | ||
) -> Result<&ecdsa::secp256k1::SigningKey> { | ||
let signing_key = self | ||
.eth_index | ||
.get(addr) | ||
.and_then(|vk| self.keys.get(vk)) | ||
.ok_or(Error)?; | ||
|
||
match signing_key { | ||
SigningKey::EcdsaSecp256k1(key) => Ok(key), | ||
#[allow(unreachable_patterns)] | ||
_ => Err(Error), | ||
} | ||
} | ||
} | ||
|
||
impl Debug for Keyring { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_struct("Keyring").finish_non_exhaustive() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
use crate::{Error, Result, VerifyingKey}; | ||
use crypto::{ | ||
digest::{sha2::Sha256, Digest}, | ||
rand::{OsRng, RngCore}, | ||
signature::{ecdsa, hazmat::PrehashSigner}, | ||
}; | ||
use std::fmt::{self, Debug}; | ||
|
||
/// Signing key. | ||
pub enum SigningKey { | ||
/// ECDSA/secp256k1 | ||
#[cfg(feature = "secp256k1")] | ||
#[cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))] | ||
EcdsaSecp256k1(ecdsa::secp256k1::SigningKey), | ||
} | ||
|
||
impl SigningKey { | ||
/// Generate a random ECDSA/secp256k1 key. | ||
// TODO(tarcieri): unified `generate` method with algorithm parameter | ||
#[cfg(feature = "secp256k1")] | ||
#[cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))] | ||
pub fn generate_secp256k1() -> Self { | ||
let mut bytes = [0u8; 32]; | ||
|
||
loop { | ||
OsRng.fill_bytes(&mut bytes); | ||
|
||
if let Ok(signing_key) = ecdsa::secp256k1::SigningKey::from_bytes(&bytes) { | ||
// TODO(tarcieri): zeroize bytes | ||
return signing_key.into(); | ||
} | ||
} | ||
} | ||
|
||
/// Sign the given message with this key. | ||
// TODO(tarcieri): support for customizing hash function used | ||
pub fn sign(&self, msg: &[u8]) -> Result<Vec<u8>> { | ||
self.sign_digest(&Sha256::digest(msg)) | ||
} | ||
|
||
/// Sign the given prehashed message digest with this key. | ||
pub fn sign_digest(&self, msg_digest: &[u8]) -> Result<Vec<u8>> { | ||
match self { | ||
#[cfg(feature = "secp256k1")] | ||
Self::EcdsaSecp256k1(sk) => { | ||
PrehashSigner::<ecdsa::secp256k1::Signature>::sign_prehash(sk, msg_digest) | ||
.map(|sig| sig.to_vec()) | ||
.map_err(|_| Error) | ||
} | ||
} | ||
} | ||
|
||
/// Get the [`VerifyingKey`] that corresponds to this signing key. | ||
pub fn verifying_key(&self) -> VerifyingKey { | ||
match self { | ||
#[cfg(feature = "secp256k1")] | ||
SigningKey::EcdsaSecp256k1(sk) => VerifyingKey::EcdsaSecp256k1(sk.verifying_key()), | ||
} | ||
} | ||
} | ||
|
||
impl Debug for SigningKey { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_struct("SigningKey") | ||
.field("verifying_key", &self.verifying_key()) | ||
.finish_non_exhaustive() | ||
} | ||
} | ||
|
||
#[cfg(feature = "secp256k1")] | ||
#[cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))] | ||
impl From<ecdsa::secp256k1::SigningKey> for SigningKey { | ||
#[inline] | ||
fn from(key: ecdsa::secp256k1::SigningKey) -> SigningKey { | ||
SigningKey::EcdsaSecp256k1(key) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
use crypto::signature::ecdsa; | ||
|
||
/// Verifying key. | ||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] | ||
pub enum VerifyingKey { | ||
/// ECDSA/secp256k1 | ||
#[cfg(feature = "secp256k1")] | ||
#[cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))] | ||
EcdsaSecp256k1(ecdsa::secp256k1::VerifyingKey), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters