Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ethereum related signing changes #1668

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions core/src/proto/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use sha2::{Digest, Sha256};
use thiserror::Error;

use super::generated::types;
use crate::ledger::storage::{KeccakHasher, Sha256Hasher, StorageHasher};
#[cfg(any(feature = "tendermint", feature = "tendermint-abcipp"))]
use crate::tendermint_proto::abci::ResponseDeliverTx;
use crate::types::address::Address;
Expand Down Expand Up @@ -83,6 +84,10 @@ pub trait Signable<T> {
/// A byte vector containing the serialized data.
type Output: key::SignableBytes;

/// The hashing algorithm to use to sign serialized
/// data with.
type Hasher: 'static + StorageHasher;

/// Encodes `data` as a byte vector, with some arbitrary serialization
/// method.
///
Expand All @@ -103,6 +108,7 @@ pub struct SerializeWithBorsh;
pub struct SignableEthMessage;

impl<T: BorshSerialize> Signable<T> for SerializeWithBorsh {
type Hasher = Sha256Hasher;
type Output = Vec<u8>;

fn as_signable(data: &T) -> Vec<u8> {
Expand All @@ -112,6 +118,7 @@ impl<T: BorshSerialize> Signable<T> for SerializeWithBorsh {
}

impl Signable<KeccakHash> for SignableEthMessage {
type Hasher = KeccakHasher;
type Output = KeccakHash;

fn as_signable(hash: &KeccakHash) -> KeccakHash {
Expand Down Expand Up @@ -195,7 +202,8 @@ impl<T, S: Signable<T>> Signed<T, S> {
/// Initialize a new [`Signed`] instance.
pub fn new(keypair: &common::SecretKey, data: T) -> Self {
let to_sign = S::as_signable(&data);
let sig = common::SigScheme::sign(keypair, to_sign);
let sig =
common::SigScheme::sign_with_hasher::<S::Hasher>(keypair, to_sign);
Self::new_from(data, sig)
}

Expand All @@ -206,7 +214,11 @@ impl<T, S: Signable<T>> Signed<T, S> {
pk: &common::PublicKey,
) -> std::result::Result<(), VerifySigError> {
let signed_bytes = S::as_signable(&self.data);
common::SigScheme::verify_signature(pk, &signed_bytes, &self.sig)
common::SigScheme::verify_signature_with_hasher::<S::Hasher>(
pk,
&signed_bytes,
&self.sig,
)
}
}

Expand Down
38 changes: 23 additions & 15 deletions core/src/types/key/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ use super::{
ParseSignatureError, RefTo, SchemeType, SigScheme as SigSchemeTrait,
VerifySigError,
};
use crate::ledger::storage::DummyHasher;
use crate::types::ethereum_events::EthAddress;
use crate::types::key::SignableBytes;
use crate::types::key::{SignableBytes, StorageHasher};

/// Public key
#[derive(
Expand Down Expand Up @@ -305,7 +304,6 @@ impl super::Signature for Signature {
pub struct SigScheme;

impl super::SigScheme for SigScheme {
type Hasher = DummyHasher;
type PublicKey = PublicKey;
type SecretKey = SecretKey;
type Signature = Signature;
Expand All @@ -330,31 +328,41 @@ impl super::SigScheme for SigScheme {
);
}

fn sign(
fn sign_with_hasher<H>(
keypair: &SecretKey,
data: impl super::SignableBytes,
) -> Self::Signature {
) -> Self::Signature
where
H: 'static + StorageHasher,
{
match keypair {
SecretKey::Ed25519(kp) => {
Signature::Ed25519(ed25519::SigScheme::sign(kp, data))
}
SecretKey::Secp256k1(kp) => {
Signature::Secp256k1(secp256k1::SigScheme::sign(kp, data))
}
SecretKey::Ed25519(kp) => Signature::Ed25519(
ed25519::SigScheme::sign_with_hasher::<H>(kp, data),
),
SecretKey::Secp256k1(kp) => Signature::Secp256k1(
secp256k1::SigScheme::sign_with_hasher::<H>(kp, data),
),
}
}

fn verify_signature(
fn verify_signature_with_hasher<H>(
pk: &Self::PublicKey,
data: &impl SignableBytes,
sig: &Self::Signature,
) -> Result<(), VerifySigError> {
) -> Result<(), VerifySigError>
where
H: 'static + StorageHasher,
{
match (pk, sig) {
(PublicKey::Ed25519(pk), Signature::Ed25519(sig)) => {
ed25519::SigScheme::verify_signature(pk, data, sig)
ed25519::SigScheme::verify_signature_with_hasher::<H>(
pk, data, sig,
)
}
(PublicKey::Secp256k1(pk), Signature::Secp256k1(sig)) => {
secp256k1::SigScheme::verify_signature(pk, data, sig)
secp256k1::SigScheme::verify_signature_with_hasher::<H>(
pk, data, sig,
)
}
_ => Err(VerifySigError::MismatchedScheme),
}
Expand Down
22 changes: 15 additions & 7 deletions core/src/types/key/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use super::{
ParsePublicKeyError, ParseSecretKeyError, ParseSignatureError, RefTo,
SchemeType, SigScheme as SigSchemeTrait, SignableBytes, VerifySigError,
};
use crate::ledger::storage::Sha256Hasher;
use crate::types::key::StorageHasher;

const PUBLIC_KEY_LENGTH: usize = 32;
const SECRET_KEY_LENGTH: usize = 32;
Expand Down Expand Up @@ -323,7 +323,6 @@ impl PartialOrd for Signature {
pub struct SigScheme;

impl super::SigScheme for SigScheme {
type Hasher = Sha256Hasher;
type PublicKey = PublicKey;
type SecretKey = SecretKey;
type Signature = Signature;
Expand All @@ -342,16 +341,25 @@ impl super::SigScheme for SigScheme {
SecretKey(Box::new(ed25519_consensus::SigningKey::from(bytes)))
}

fn sign(keypair: &SecretKey, data: impl SignableBytes) -> Self::Signature {
Signature(keypair.0.sign(&data.signable_hash::<Self::Hasher>()))
fn sign_with_hasher<H>(
keypair: &SecretKey,
data: impl SignableBytes,
) -> Self::Signature
where
H: 'static + StorageHasher,
{
Signature(keypair.0.sign(&data.signable_hash::<H>()))
}

fn verify_signature(
fn verify_signature_with_hasher<H>(
pk: &Self::PublicKey,
data: &impl SignableBytes,
sig: &Self::Signature,
) -> Result<(), VerifySigError> {
pk.0.verify(&sig.0, &data.signable_hash::<Self::Hasher>())
) -> Result<(), VerifySigError>
where
H: 'static + StorageHasher,
{
pk.0.verify(&sig.0, &data.signable_hash::<H>())
.map_err(|err| VerifySigError::SigVerifyError(err.to_string()))
}
}
37 changes: 31 additions & 6 deletions core/src/types/key/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use thiserror::Error;

use super::address::Address;
use super::storage::{self, DbKeySeg, Key, KeySeg};
use crate::ledger::storage::StorageHasher;
use crate::ledger::storage::{Sha256Hasher, StorageHasher};
use crate::types::address;

const PK_STORAGE_KEY: &str = "public_key";
Expand Down Expand Up @@ -261,29 +261,54 @@ pub trait SigScheme: Eq + Ord + Debug + Serialize + Default {
type PublicKey: 'static + PublicKey;
/// Represents the secret key for this scheme
type SecretKey: 'static + SecretKey;
/// Represents the data hasher for this scheme
type Hasher: 'static + StorageHasher;
/// The scheme type of this implementation
const TYPE: SchemeType;

/// Generate a keypair.
#[cfg(feature = "rand")]
fn generate<R>(csprng: &mut R) -> Self::SecretKey
where
R: CryptoRng + RngCore;

/// Instantiate a secret key from the bytes.
fn from_bytes(bytes: [u8; 32]) -> Self::SecretKey;

/// Sign the data with a key.
fn sign(
fn sign_with_hasher<H>(
keypair: &Self::SecretKey,
data: impl SignableBytes,
) -> Self::Signature;
) -> Self::Signature
where
H: 'static + StorageHasher;

/// Check that the public key matches the signature on the given data.
fn verify_signature_with_hasher<H>(
pk: &Self::PublicKey,
data: &impl SignableBytes,
sig: &Self::Signature,
) -> Result<(), VerifySigError>
where
H: 'static + StorageHasher;

/// Sign the data with a key, using a SHA256 hasher.
#[inline]
fn sign(
keypair: &Self::SecretKey,
data: impl SignableBytes,
) -> Self::Signature {
Self::sign_with_hasher::<Sha256Hasher>(keypair, data)
}

/// Check that the public key matches the signature on the given data,
/// using a SHA256 hasher.
#[inline]
fn verify_signature(
pk: &Self::PublicKey,
data: &impl SignableBytes,
sig: &Self::Signature,
) -> Result<(), VerifySigError>;
) -> Result<(), VerifySigError> {
Self::verify_signature_with_hasher::<Sha256Hasher>(pk, data, sig)
}
}

/// Public key hash derived from `common::Key` borsh encoded bytes (hex string
Expand Down
35 changes: 19 additions & 16 deletions core/src/types/key/secp256k1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use super::{
use crate::hints;
use crate::types::eth_abi::Encode;
use crate::types::ethereum_events::EthAddress;
use crate::types::key::StorageHasher;

/// The provided constant is for a traditional
/// signature on this curve. For Ethereum, an extra byte is included
Expand Down Expand Up @@ -551,10 +552,6 @@ impl TryFrom<&[u8; 65]> for Signature {
pub struct SigScheme;

impl super::SigScheme for SigScheme {
#[cfg(any(test, feature = "secp256k1-sign-verify"))]
type Hasher = crate::ledger::storage::KeccakHasher;
#[cfg(not(any(test, feature = "secp256k1-sign-verify")))]
type Hasher = crate::ledger::storage::DummyHasher;
type PublicKey = PublicKey;
type SecretKey = SecretKey;
type Signature = Signature;
Expand All @@ -576,8 +573,13 @@ impl super::SigScheme for SigScheme {
))
}

/// Sign the data with a key
fn sign(keypair: &SecretKey, data: impl SignableBytes) -> Self::Signature {
fn sign_with_hasher<H>(
keypair: &SecretKey,
data: impl SignableBytes,
) -> Self::Signature
where
H: 'static + StorageHasher,
{
#[cfg(not(any(test, feature = "secp256k1-sign-verify")))]
{
// to avoid `unused-variables` warn
Expand All @@ -587,20 +589,22 @@ impl super::SigScheme for SigScheme {

#[cfg(any(test, feature = "secp256k1-sign-verify"))]
{
let message = libsecp256k1::Message::parse_slice(
&data.signable_hash::<Self::Hasher>(),
)
.expect("Message encoding should not fail");
let message =
libsecp256k1::Message::parse_slice(&data.signable_hash::<H>())
.expect("Message encoding should not fail");
let (sig, recovery_id) = libsecp256k1::sign(&message, &keypair.0);
Signature(sig, recovery_id)
}
}

fn verify_signature(
fn verify_signature_with_hasher<H>(
pk: &Self::PublicKey,
data: &impl SignableBytes,
sig: &Self::Signature,
) -> Result<(), VerifySigError> {
) -> Result<(), VerifySigError>
where
H: 'static + StorageHasher,
{
#[cfg(not(any(test, feature = "secp256k1-sign-verify")))]
{
// to avoid `unused-variables` warn
Expand All @@ -610,10 +614,9 @@ impl super::SigScheme for SigScheme {

#[cfg(any(test, feature = "secp256k1-sign-verify"))]
{
let message = libsecp256k1::Message::parse_slice(
&data.signable_hash::<Self::Hasher>(),
)
.expect("Message encoding should not fail");
let message =
libsecp256k1::Message::parse_slice(&data.signable_hash::<H>())
.expect("Message encoding should not fail");
let is_valid = libsecp256k1::verify(&message, &sig.0, &pk.0);
if is_valid {
Ok(())
Expand Down
2 changes: 2 additions & 0 deletions core/src/types/vote_extensions/validator_set_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ mod tag {
use super::{
epoch_to_token, Vext, VotingPowersMapExt, GOVERNANCE_CONTRACT_VERSION,
};
use crate::ledger::storage::KeccakHasher;
use crate::proto::Signable;
use crate::types::eth_abi::{AbiEncode, Encode, Token};
use crate::types::keccak::KeccakHash;
Expand All @@ -372,6 +373,7 @@ mod tag {
pub struct SerializeWithAbiEncode;

impl Signable<Vext> for SerializeWithAbiEncode {
type Hasher = KeccakHasher;
type Output = KeccakHash;

fn as_signable(ext: &Vext) -> Self::Output {
Expand Down