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

Add crypto provider #1214

Closed
wants to merge 13 commits into from
3 changes: 2 additions & 1 deletion light-client-verifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ rustdoc-args = ["--cfg", "docsrs"]

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

rust-crypto = []
[dependencies]
tendermint = { version = "0.26.0", path = "../tendermint", default-features = false }

Expand All @@ -35,3 +35,4 @@ flex-error = { version = "0.4.4", default-features = false }

[dev-dependencies]
tendermint-testgen = { path = "../testgen", default-features = false }
sha2 = { version = "0.9", default-features = false }
mzabaluev marked this conversation as resolved.
Show resolved Hide resolved
111 changes: 75 additions & 36 deletions light-client-verifier/src/operations/commit_validator.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,25 @@
//! Provides an interface and default implementation for the `CommitValidator` operation

use core::marker::PhantomData;

use tendermint::block::CommitSig;
#[cfg(feature = "rust-crypto")]
use tendermint::crypto::DefaultHostFunctionsManager;

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 {
pub struct CommitValidator<C> {
hasher: ProdHasher,
_c: PhantomData<C>,
}

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(
impl<C> CommitValidator<C> {
pub fn validate(
&self,
signed_header: &SignedHeader,
validator_set: &ValidatorSet,
Expand Down Expand Up @@ -77,7 +50,7 @@ impl CommitValidator for ProdCommitValidator {
//
// It returns `ImplementationSpecific` error if it detects a signer
// that is not present in the validator set
fn validate_full(
pub fn validate_full(
&self,
signed_header: &SignedHeader,
validator_set: &ValidatorSet,
Expand All @@ -104,3 +77,69 @@ impl CommitValidator for ProdCommitValidator {
Ok(())
}
}

/// The batteries-included validator, for when you don't mind the dependencies on
/// the full rust-crypto stack.
#[cfg(feature = "rust-crypto")]
pub type ProdCommitValidator = CommitValidator<DefaultHostFunctionsManager>;

#[cfg(not(feature = "rust-crypto"))]
/// Production-ready implementation of a commit validator
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProdCommitValidator<C> {
inner: CommitValidator<C>,
}

#[cfg(not(feature = "rust-crypto"))]
impl<C> AsRef<CommitValidator<C>> for ProdCommitValidator<C> {
fn as_ref(&self) -> &CommitValidator<C> {
&self.inner
}
}

#[cfg(feature = "rust-crypto")]
impl AsRef<CommitValidator<DefaultHostFunctionsManager>> for ProdCommitValidator {
fn as_ref(&self) -> &CommitValidator<DefaultHostFunctionsManager> {
self
}
}

#[cfg(not(feature = "rust-crypto"))]
impl<C> ProdCommitValidator<C> {
/// 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 {
inner: CommitValidator {
hasher,
_c: PhantomData::default(),
},
}
}
}

#[cfg(feature = "rust-crypto")]
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 {
CommitValidator {
hasher,
_c: PhantomData::default(),
}
}
}

#[cfg(not(feature = "rust-crypto"))]
impl<C> Default for ProdCommitValidator<C> {
fn default() -> Self {
Self::new(ProdHasher::default())
}
}

#[cfg(feature = "rust-crypto")]
impl Default for ProdCommitValidator {
fn default() -> Self {
Self::new(ProdHasher::default())
}
}
38 changes: 30 additions & 8 deletions light-client-verifier/src/predicates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

use core::time::Duration;

use tendermint::{block::Height, hash::Hash};
use tendermint::{
block::Height,
crypto::{CryptoProvider, DefaultHostFunctionsManager},
hash::Hash,
};

use crate::{
errors::VerificationError,
Expand All @@ -15,7 +19,9 @@ use crate::{
/// of the `VerificationPredicates` trait.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct ProdPredicates;
impl VerificationPredicates for ProdPredicates {}
impl VerificationPredicates for ProdPredicates {
type CryptoProvider = DefaultHostFunctionsManager;
}

/// Defines the various predicates used to validate and verify light blocks.
///
Expand All @@ -24,6 +30,7 @@ impl VerificationPredicates for ProdPredicates {}
/// This enables test implementations to only override a single method rather than
/// have to re-define every predicate.
pub trait VerificationPredicates: Send + Sync {
type CryptoProvider: CryptoProvider;
/// Compare the provided validator_set_hash against the hash produced from hashing the validator
/// set.
fn validator_sets_match(
Expand Down Expand Up @@ -79,12 +86,27 @@ pub trait VerificationPredicates: Send + Sync {
}
}

#[cfg(not(feature = "rust-crypto"))]
/// Validate the commit using the given commit validator.
fn valid_commit(
&self,
signed_header: &SignedHeader,
validators: &ValidatorSet,
commit_validator: &CommitValidator<Self::CryptoProvider>,
) -> Result<(), VerificationError> {
commit_validator.validate(signed_header, validators)?;
commit_validator.validate_full(signed_header, validators)?;

Ok(())
}

#[cfg(feature = "rust-crypto")]
/// Validate the commit using the given commit validator.
fn valid_commit(
&self,
signed_header: &SignedHeader,
validators: &ValidatorSet,
commit_validator: &dyn CommitValidator,
commit_validator: &CommitValidator<DefaultHostFunctionsManager>,
) -> Result<(), VerificationError> {
commit_validator.validate(signed_header, validators)?;
commit_validator.validate_full(signed_header, validators)?;
Expand Down Expand Up @@ -471,15 +493,15 @@ mod tests {

// Test scenarios -->
// 1. valid commit - must result "Ok"
let mut result_ok = vp.valid_commit(&signed_header, &val_set, &commit_validator);
let mut result_ok = vp.valid_commit(&signed_header, &val_set, commit_validator.as_ref());

assert!(result_ok.is_ok());

// 2. no commit signatures - must return error
let signatures = signed_header.commit.signatures.clone();
signed_header.commit.signatures = vec![];

let mut result_err = vp.valid_commit(&signed_header, &val_set, &commit_validator);
let mut result_err = vp.valid_commit(&signed_header, &val_set, commit_validator.as_ref());

match result_err {
Err(VerificationError(VerificationErrorDetail::NoSignatureForCommit(_), _)) => {},
Expand All @@ -491,7 +513,7 @@ mod tests {
let mut bad_sigs = vec![signatures.clone().swap_remove(1)];
signed_header.commit.signatures = bad_sigs.clone();

result_err = vp.valid_commit(&signed_header, &val_set, &commit_validator);
result_err = vp.valid_commit(&signed_header, &val_set, commit_validator.as_ref());

match result_err {
Err(VerificationError(VerificationErrorDetail::MismatchPreCommitLength(e), _)) => {
Expand All @@ -504,7 +526,7 @@ mod tests {
// 4. commit.BlockIdFlagAbsent - should be "Ok"
bad_sigs.push(CommitSig::BlockIdFlagAbsent);
signed_header.commit.signatures = bad_sigs;
result_ok = vp.valid_commit(&signed_header, &val_set, &commit_validator);
result_ok = vp.valid_commit(&signed_header, &val_set, commit_validator.as_ref());
assert!(result_ok.is_ok());

// 5. faulty signer - must return error
Expand All @@ -523,7 +545,7 @@ mod tests {
result_err = vp.valid_commit(
&signed_header,
&val_set_with_faulty_signer,
&commit_validator,
commit_validator.as_ref(),
);

match result_err {
Expand Down
Loading