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

Make crypto implementations replaceable #1238

Merged
merged 51 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
62dda70
define CryptoProvider trait
blasrodri Oct 17, 2022
b7920c3
wip
blasrodri Oct 17, 2022
c4b52de
implement CryptoProvider for Substrate (WIP)
blasrodri Oct 19, 2022
a35c105
comment issues
blasrodri Oct 19, 2022
47b56bf
ed25519_verify implementation for SubstrateHostFunctionsManager
blasrodri Oct 19, 2022
2d0fc38
introduce EcdsaSecp256k1Signer
blasrodri Oct 19, 2022
6cbcbb3
doc a bit
blasrodri Oct 19, 2022
e6edade
move CryptoProvider to tendermint crate instead
blasrodri Oct 20, 2022
bcd6be0
rename host_functions module to crypto
blasrodri Oct 31, 2022
7f5e812
tendermint: Remove ED25519_SIGNATURE_SIZE
mzabaluev Nov 17, 2022
3fecdef
tendermint: clean up mod crypto
mzabaluev Nov 17, 2022
4a511c5
Disentangle CryptoProvider from k256 crate
mzabaluev Nov 17, 2022
9575852
Add DefaultCryptoProvider
mzabaluev Nov 17, 2022
3573ef0
tendermint: reorg mod crypto
mzabaluev Nov 18, 2022
2baed4f
tendermint: generalize hash methods
mzabaluev Nov 18, 2022
a032364
tendermint: eliminate get_split_point helper
mzabaluev Nov 18, 2022
f264742
light-client: eliminate Hasher
mzabaluev Nov 20, 2022
f0eee32
fix no_std
mzabaluev Nov 21, 2022
ce146c8
Fix the tools build
mzabaluev Nov 23, 2022
4a65669
Fix wasm-light-client build
mzabaluev Nov 23, 2022
d39148d
kvstore-test: No need to copy vec-of-vecs
mzabaluev Nov 24, 2022
4503794
Merge branch 'main' into mikhail/add-crypto-provider
mzabaluev Nov 28, 2022
f1d9593
Merge branch 'main' into mikhail/add-crypto-provider
mzabaluev Dec 1, 2022
ec3cf88
Break down CryptoProvider into functional traits
mzabaluev Dec 1, 2022
5a2dfe5
alt_crypto test: Roll our own signature type
mzabaluev Dec 1, 2022
58c113a
Fix the wasm build
mzabaluev Dec 1, 2022
dcabd56
Fix a clippy lint
mzabaluev Dec 1, 2022
76a3fce
Fix a clippy lint in alt_crypto test
mzabaluev Dec 1, 2022
a9c86f2
Disentangle CommitValidator from the hasher
mzabaluev Dec 2, 2022
79af98a
light-client: Enable shrinking in backward test
mzabaluev Dec 2, 2022
c5ec595
light-client: update edition to rust2021
mzabaluev Dec 2, 2022
4f73378
Recover LightClient::verify_backward
mzabaluev Dec 2, 2022
41efc0b
Fix light-client-js build, record technical debt
mzabaluev Dec 5, 2022
6365d49
tendermint: Make sha2 an optional dependency
mzabaluev Dec 7, 2022
58425b5
Redesign crypto::Sha256, add MerkleHash trait
mzabaluev Dec 13, 2022
1bb92a9
Fix all-features build
mzabaluev Dec 14, 2022
079ec41
chore: fix clippy lints
mzabaluev Dec 14, 2022
1133fd9
tendermint: "rust-crypto" does not imply "k256"
mzabaluev Dec 14, 2022
4a38c73
rpc: require tendermint/rust-crypto
mzabaluev Dec 15, 2022
374303c
Merge branch 'main' into mikhail/add-crypto-provider
mzabaluev Dec 15, 2022
adb6327
Remove a bogus lint override
mzabaluev Dec 15, 2022
eac7b5a
Changelog entry for #1238
mzabaluev Dec 15, 2022
24573b9
Merge branch 'main' into mikhail/add-crypto-provider
mzabaluev Jan 9, 2023
2a7f441
Merge branch 'main' into mikhail/add-crypto-provider
mzabaluev Jan 19, 2023
d525562
tendermint: crypto::signature::Verifier trait
mzabaluev Jan 23, 2023
672db2d
tendermint: fix secp256k1 verification tests
mzabaluev Jan 24, 2023
3d7ee0a
Guard public key extraction with rust-crypto
mzabaluev Jan 24, 2023
3acfa23
tendermint: remove re-exports from signature crate
mzabaluev Jan 24, 2023
2b49f63
tendermint: rework signature in alt_crypto test
mzabaluev Jan 24, 2023
3741884
Updated the changelog entry for #1238
mzabaluev Jan 25, 2023
5ef4502
Merge branch 'main' into mikhail/add-crypto-provider
romac Jan 31, 2023
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
- `[tendermint]` Make implementations of cryptographic primitives replaceable
([#1238](https://github.com/informalsystems/tendermint-rs/pull/1238)).
* Provide a `Sha256` trait in module `crypto` and make digest hashing
implementations available through it.
* Provide a `Verifier` trait in module `crypto::signature` to enable
alternative implementations of signature verification available through it.
An `Error` enum is defined in the same module, representing the error cases
that can arise in the implementation in a deliberately opaque way.
* The module `crypto::default` provides pure Rust implementations of the
cryptographic traits. The module is made available by a
new `rust-crypto` feature, enabled by default.
* `merkle::simple_hash_from_byte_vectors` is made generic over an
implementation of the new `MerkleHash` trait. Implementations for
Rust-Crypto conformant digest objects and the non-incremental
`crypto::Sha256` API are provided in the crate.
* The `Header::hash` and `ValidatorSet::hash` methods are gated by the
`rust-crypto` feature. Generic hashing methods not dependent on
the default crypto implementations are added for both types,
named `hash_with`.
* Conversions to `account::Id` and `node::Id` from `PublicKey` and
curve-specific key types are gated by the `rust-crypto` feature.
* The `validator::Info::new` method is gated by the `rust-crypto` feature.
* Remove a deprecated constant `signature::ED25519_SIGNATURE_SIZE`.

- `[tendermint-light-client-verifier]` Changes for the new Tendermint crypto API
([#1238](https://github.com/informalsystems/tendermint-rs/pull/1238)).
* The `rust-crypto` feature, enabled by default, guards the
batteries-included implementation types: `ProdVerifier`, `ProdPredicates`,
`ProdVotingPowerCalculator`.
* Remove the `operations::hasher` API (`Hasher` and `ProdHasher`),
made unnecessary by the new crypto abstractions in the `tendermint` crate.
* The `VerificationPredicates` trait features a `Sha256` associated type
to represent the hasher implementation, replacing the `&dyn Hasher`
parameter passed to methods.
* Change the type of the `VerificationErrorDetail::FaultySigner` field
`validator_set` to `ValidatorSet`. This removes a hasher dependency from
`CommitValidator`, and `ProdCommitValidator` is now an empty dummy type.

- `[tendermint-light-client]` Changes for the new Tendermint crypto API
([#1238](https://github.com/informalsystems/tendermint-rs/pull/1238)).
* The `rust-crypto` feature enables the default crypto implementations,
and is required by the `rpc-client` and `unstable` features.
`ProdForkDetector` is guarded by this feature, and is made a specific
type alias to the hasher-generic `ProvidedForkDetector` type.
* `LightClientBuilder` gets another type parameter for the Merkle hasher.
Its generic constructors lose the `Hasher` parameter.
2 changes: 1 addition & 1 deletion config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
tendermint = { version = "0.28.0", default-features = false, path = "../tendermint" }
tendermint = { version = "0.28.0", default-features = false, features = ["rust-crypto"], path = "../tendermint" }
flex-error = { version = "0.4.4", default-features = false }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Expand Down
2 changes: 1 addition & 1 deletion config/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ fn priv_validator_json_parser() {
let raw_priv_validator_key = read_fixture("priv_validator_key.json");
let priv_validator_key = PrivValidatorKey::parse_json(raw_priv_validator_key).unwrap();
assert_eq!(
priv_validator_key.consensus_pubkey().to_hex(),
priv_validator_key.consensus_pubkey().public_key().to_hex(),
"F26BF4B2A2E84CEB7A53C3F1AE77408779B20064782FBADBDF0E365959EE4534"
);
}
Expand Down
2 changes: 1 addition & 1 deletion light-client-js/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ default = ["console_error_panic_hook"]
serde = { version = "1.0", default-features = false, features = [ "derive" ] }
serde_json = { version = "1.0", default-features = false }
tendermint = { version = "0.28.0", default-features = false, path = "../tendermint" }
tendermint-light-client-verifier = { version = "0.28.0", default-features = false, path = "../light-client-verifier" }
tendermint-light-client-verifier = { version = "0.28.0", features = ["rust-crypto"], default-features = false, path = "../light-client-verifier" }
wasm-bindgen = { version = "0.2.63", default-features = false, features = [ "serde-serialize" ] }
serde-wasm-bindgen = { version = "0.4.5", default-features = false }

Expand Down
6 changes: 5 additions & 1 deletion light-client-js/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ use tendermint::Time;
use tendermint_light_client_verifier::{
options::Options,
types::{LightBlock, TrustThreshold},
ProdVerifier, Verifier,
Verifier,
};
use wasm_bindgen::{prelude::*, JsValue};

// TODO: Use Web Crypto API for cryptographic routines.
// https://github.com/informalsystems/tendermint-rs/issues/1241
use tendermint_light_client_verifier::ProdVerifier;

/// Check whether a given untrusted block can be trusted.
#[wasm_bindgen]
pub fn verify(untrusted: JsValue, trusted: JsValue, options: JsValue, now: JsValue) -> JsValue {
Expand Down
4 changes: 3 additions & 1 deletion light-client-verifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[features]
default = ["flex-error/std", "flex-error/eyre_tracer"]
default = ["rust-crypto", "flex-error/std", "flex-error/eyre_tracer"]
rust-crypto = ["tendermint/rust-crypto"]

[dependencies]
tendermint = { version = "0.28.0", path = "../tendermint", default-features = false }
Expand All @@ -35,3 +36,4 @@ flex-error = { version = "0.4.4", default-features = false }

[dev-dependencies]
tendermint-testgen = { path = "../testgen", default-features = false }
sha2 = { version = "0.10", default-features = false }
7 changes: 3 additions & 4 deletions light-client-verifier/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use tendermint::{account::Id, Error as TendermintError};
use crate::{
operations::voting_power::VotingPowerTally,
prelude::*,
types::{Hash, Height, Time, Validator, ValidatorAddress},
types::{Hash, Height, Time, Validator, ValidatorAddress, ValidatorSet},
};

define_error! {
Expand Down Expand Up @@ -161,13 +161,12 @@ define_error! {
FaultySigner
{
signer: Id,
validator_set: Hash
validator_set: ValidatorSet
}
| e | {
format_args!(
"Found a faulty signer ({}) not present in the validator set ({})",
"Found a faulty signer ({}) not present in the validator set",
e.signer,
e.validator_set
)
},

Expand Down
5 changes: 4 additions & 1 deletion light-client-verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ pub mod predicates;
pub mod types;
mod verifier;

pub use verifier::{PredicateVerifier, ProdVerifier, Verdict, Verifier};
pub use verifier::{PredicateVerifier, Verdict, Verifier};

#[cfg(feature = "rust-crypto")]
pub use verifier::ProdVerifier;
3 changes: 0 additions & 3 deletions light-client-verifier/src/operations.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
//! Crypto function traits allowing mocking out during testing
pub mod hasher;
pub use self::hasher::*;

pub mod voting_power;
pub use self::voting_power::*;

Expand Down
51 changes: 8 additions & 43 deletions light-client-verifier/src/operations/commit_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,12 @@ use tendermint::block::CommitSig;

use crate::{
errors::VerificationError,
operations::{Hasher, ProdHasher},
types::{SignedHeader, ValidatorSet},
};

/// Validates the commit associated with a header against a validator set
pub trait CommitValidator: Send + Sync {
/// Perform basic validation
fn validate(
&self,
signed_header: &SignedHeader,
validators: &ValidatorSet,
) -> Result<(), VerificationError>;

/// Perform full validation, only necessary if we do full verification (2/3)
fn validate_full(
&self,
signed_header: &SignedHeader,
validator_set: &ValidatorSet,
) -> Result<(), VerificationError>;
}

/// Production-ready implementation of a commit validator
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProdCommitValidator {
hasher: ProdHasher,
}

impl ProdCommitValidator {
/// Create a new commit validator using the given [`Hasher`]
/// to compute the hash of headers and validator sets.
pub fn new(hasher: ProdHasher) -> Self {
Self { hasher }
}
}

impl Default for ProdCommitValidator {
fn default() -> Self {
Self::new(ProdHasher::default())
}
}

impl CommitValidator for ProdCommitValidator {
fn validate(
&self,
signed_header: &SignedHeader,
Expand All @@ -71,12 +35,7 @@ impl CommitValidator for ProdCommitValidator {
Ok(())
}

// This check is only necessary if we do full verification (2/3)
//
// See https://github.com/informalsystems/tendermint-rs/issues/281
//
// It returns `ImplementationSpecific` error if it detects a signer
// that is not present in the validator set
/// Perform full validation, only necessary if we do full verification (2/3)
fn validate_full(
&self,
signed_header: &SignedHeader,
Expand All @@ -96,11 +55,17 @@ impl CommitValidator for ProdCommitValidator {
if validator_set.validator(*validator_address).is_none() {
return Err(VerificationError::faulty_signer(
*validator_address,
self.hasher.hash_validator_set(validator_set),
validator_set.clone(),
));
}
}

Ok(())
}
}

/// Production-ready implementation of a commit validator.
#[derive(Copy, Clone, Default, Debug)]
pub struct ProdCommitValidator;

impl CommitValidator for ProdCommitValidator {}
24 changes: 0 additions & 24 deletions light-client-verifier/src/operations/hasher.rs

This file was deleted.

33 changes: 27 additions & 6 deletions light-client-verifier/src/operations/voting_power.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//! Provides an interface and default implementation for the `VotingPower` operation
use alloc::collections::BTreeSet as HashSet;
use core::{convert::TryFrom, fmt};
use core::{convert::TryFrom, fmt, marker::PhantomData};

use serde::{Deserialize, Serialize};
use tendermint::{
block::CommitSig,
crypto::signature,
trust_threshold::TrustThreshold as _,
vote::{SignedVote, ValidatorIndex, Vote},
};
Expand Down Expand Up @@ -98,11 +99,31 @@ pub trait VotingPowerCalculator: Send + Sync {
) -> Result<VotingPowerTally, VerificationError>;
}

/// Default implementation of a `VotingPowerCalculator`
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct ProdVotingPowerCalculator;
/// Default implementation of a `VotingPowerCalculator`, parameterized with
/// the signature verification trait.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ProvidedVotingPowerCalculator<V> {
_verifier: PhantomData<V>,
}

// Safety: the only member is phantom data
unsafe impl<V> Send for ProvidedVotingPowerCalculator<V> {}
unsafe impl<V> Sync for ProvidedVotingPowerCalculator<V> {}

impl<V> Default for ProvidedVotingPowerCalculator<V> {
fn default() -> Self {
Self {
_verifier: PhantomData,
}
}
}

/// Default implementation of a `VotingPowerCalculator`.
#[cfg(feature = "rust-crypto")]
pub type ProdVotingPowerCalculator =
ProvidedVotingPowerCalculator<tendermint::crypto::default::signature::Verifier>;

impl VotingPowerCalculator for ProdVotingPowerCalculator {
impl<V: signature::Verifier> VotingPowerCalculator for ProvidedVotingPowerCalculator<V> {
fn voting_power_in(
&self,
signed_header: &SignedHeader,
Expand Down Expand Up @@ -146,7 +167,7 @@ impl VotingPowerCalculator for ProdVotingPowerCalculator {
// Check vote is valid
let sign_bytes = signed_vote.sign_bytes();
if validator
.verify_signature(&sign_bytes, signed_vote.signature())
.verify_signature::<V>(&sign_bytes, signed_vote.signature())
.is_err()
{
return Err(VerificationError::invalid_signature(
Expand Down
Loading