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
1 change: 1 addition & 0 deletions light-client-verifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
5 changes: 3 additions & 2 deletions tendermint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
async-trait = { version = "0.1", default-features = false }
bytes = { version = "1.0", default-features = false, features = ["serde"] }
digest = { version = "0.10", default-features = false }
ed25519 = { version = "1.3", default-features = false }
ed25519-dalek = { version = "1", default-features = false, features = ["u64_backend"] }
futures = { version = "0.3", default-features = false }
Expand All @@ -51,14 +52,14 @@ tendermint-proto = { version = "0.25.0", default-features = false, path = "../pr
time = { version = "0.3", default-features = false, features = ["macros", "parsing"] }
zeroize = { version = "1.1", default-features = false, features = ["zeroize_derive", "alloc"] }
flex-error = { version = "0.4.4", default-features = false }
k256 = { version = "0.11", optional = true, default-features = false, features = ["ecdsa", "sha256"] }
k256 = { version = "0.11", default-features = false, features = ["ecdsa", "sha256"] }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having this one optional depends on whether CryptoProvider will be under a feature flag.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it now, we lock the signature type in CryptoProvider to the one defined by k256. If we cannot abstract this associated type to less specific rust-crypto bounds ("must be fixed array of 256 bits"?) and still keep it usable in generic code, then k256 should become a hard dependency. But I thought dependency management was the whole purpose of this rework.

ripemd160 = { version = "0.9", default-features = false, optional = true }

[features]
default = ["std"]
std = ["flex-error/std", "flex-error/eyre_tracer", "clock"]
clock = ["time/std"]
secp256k1 = ["k256", "ripemd160"]
secp256k1 = ["ripemd160"]

[dev-dependencies]
pretty_assertions = "1.3.0"
Expand Down
134 changes: 134 additions & 0 deletions tendermint/src/host_functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use crate::signature::Verifier;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a general thought, "host functions" that contains only a CryptoProvider trait still feels like YAGNI to me.

I would personally suggest putting it under a crypto module (which should probably have been created a long time ago, with all of the existing cryptography code in the tendermint crate factored into it).

use digest::FixedOutput;
use digest::{consts::U32, Digest};
use signature::Signer;

pub trait CryptoProvider {
type Sha256: Digest + FixedOutput<OutputSize = U32>;

type EcdsaSecp256k1Signer: Signer<k256::ecdsa::Signature>;
type EcdsaSecp256k1Verifier: Verifier<k256::ecdsa::Signature>;

// type Ed25519Signer: Signer<ed25519::Signature>;
// type Ed25519Verifier: Verifier<ed25519::Signature>;
}

#[cfg(test)]
mod tests {

/// A draft for an imlpementation of the HostFunctionManager for a specific chain (i.e. Polkadot/Substrate)
/// that uses the [`CryptoProvider`] trait
use core::marker::PhantomData;
use signature::{DigestSigner, DigestVerifier};

use super::*;
struct SubstrateHostFunctionsManager;
use k256::ecdsa::{SigningKey, VerifyingKey};

#[derive(Debug, Default)]
struct SubstrateSha256(sha2::Sha256);

struct SubstrateSigner<D> {
inner: SigningKey,
_d: PhantomData<D>,
}
#[derive(Debug)]
struct SubstrateSignatureVerifier<D> {
inner: VerifyingKey,
_d: PhantomData<D>,
}

impl<D: Digest + FixedOutput<OutputSize = U32>> SubstrateSignatureVerifier<D> {
fn from_bytes(public_key: &[u8]) -> Result<Self, ed25519::Error> {
Ok(Self {
inner: VerifyingKey::from_sec1_bytes(public_key)?,
_d: PhantomData::default(),
})
}
}

impl<D: Digest + FixedOutput<OutputSize = U32>, S: signature::Signature> DigestVerifier<D, S>
for SubstrateSignatureVerifier<D>
where
VerifyingKey: DigestVerifier<D, S>,
{
fn verify_digest(&self, digest: D, signature: &S) -> Result<(), ed25519::Error> {
self.inner.verify_digest(digest, signature)
}
}

impl<S: signature::PrehashSignature, D: Digest + FixedOutput<OutputSize = U32>> Verifier<S>
for SubstrateSignatureVerifier<D>
where
VerifyingKey: DigestVerifier<D, S>,
{
fn verify(&self, msg: &[u8], signature: &S) -> Result<(), ed25519::Error> {
let mut hasher = D::new();
Digest::update(&mut hasher, msg);
self.verify_digest(hasher, signature)
}
}

impl digest::OutputSizeUser for SubstrateSha256 {
type OutputSize = U32;
}

impl digest::HashMarker for SubstrateSha256 {}

impl digest::Update for SubstrateSha256 {
fn update(&mut self, data: &[u8]) {
use sha2::Digest;
self.0.update(data);
}
}

impl FixedOutput for SubstrateSha256 {
fn finalize_into(self, out: &mut digest::Output<Self>) {
use sha2::Digest;
*out = self.0.finalize();
}
}

impl<D: Digest, S: signature::Signature> Signer<S> for SubstrateSigner<D>
where
SigningKey: DigestSigner<D, S>,
{
fn try_sign(&self, msg: &[u8]) -> Result<S, ed25519::Error> {
let mut hasher = D::new();
Digest::update(&mut hasher, msg);
self.inner.try_sign_digest(hasher)
}
}

trait SubstrateHostFunctions: CryptoProvider {
fn sha2_256(preimage: &[u8]) -> [u8; 32];
fn ed25519_verify(sig: &[u8], msg: &[u8], pub_key: &[u8]) -> Result<(), ()>;
fn secp256k1_verify(sig: &[u8], message: &[u8], public: &[u8]) -> Result<(), ()>;
}

impl CryptoProvider for SubstrateHostFunctionsManager {
type Sha256 = SubstrateSha256;

type EcdsaSecp256k1Signer = SubstrateSigner<Self::Sha256>;
type EcdsaSecp256k1Verifier = SubstrateSignatureVerifier<Self::Sha256>;
}

impl SubstrateHostFunctions for SubstrateHostFunctionsManager {
fn sha2_256(preimage: &[u8]) -> [u8; 32] {
let mut hasher = Self::Sha256::new();
hasher.update(preimage);
let result = hasher.finalize().try_into().unwrap();
result
}
fn ed25519_verify(sig: &[u8], msg: &[u8], pub_key: &[u8]) -> Result<(), ()> {
let verifier =
<<Self as CryptoProvider>::EcdsaSecp256k1Verifier>::from_bytes(pub_key).unwrap();
let signature = k256::ecdsa::Signature::from_der(sig).unwrap();
Ok(verifier.verify(msg, &signature).unwrap())
}

fn secp256k1_verify(_sig: &[u8], _message: &[u8], _public: &[u8]) -> Result<(), ()> {
unimplemented!()
}
}
}
1 change: 1 addition & 0 deletions tendermint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub mod consensus;
pub mod evidence;
pub mod genesis;
pub mod hash;
pub mod host_functions;
pub mod merkle;
mod moniker;
pub mod node;
Expand Down