Skip to content

Commit

Permalink
feat: add bls signature cache
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanosdev committed Jan 10, 2024
1 parent 48c4dae commit 6187cef
Show file tree
Hide file tree
Showing 9 changed files with 482 additions and 14 deletions.
126 changes: 121 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ base64 = "0.21"
http = "0.2"
flate2 = "1.0"
sha2 = "0.10"
urlencoding = "2.1.3"
urlencoding = "2.1"
rstest = "0.18"
tokio = { version = "1.24", features = ["full"] }
cached = "0.47"
lazy_static = "1.4"
parking_lot = "0.12"

serde_bytes = "0.11"
serde_cbor = "0.11"
Expand All @@ -73,7 +76,7 @@ wasm-bindgen-console-logger = "0.1"
# https://docs.rs/getrandom/latest/getrandom/#webassembly-support
rand = "0.8"
getrandom = { version = "0.2", features = ["js"] }

rand_chacha = "0.3"

ic-certification = { path = "./packages/ic-certification", default-features = false, version = "2.0.1" }
ic-http-certification = { path = "./packages/ic-http-certification", version = "2.0.1" }
Expand Down
6 changes: 6 additions & 0 deletions packages/ic-certificate-verification/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,16 @@ nom.workspace = true
miracl_core_bls12381.workspace = true
thiserror.workspace = true
leb128.workspace = true
cached.workspace = true
sha2.workspace = true
lazy_static.workspace = true
parking_lot.workspace = true

ic-certification = { workspace = true }
ic-cbor.workspace = true

[dev-dependencies]
ic-response-verification-test-utils.workspace = true
ic-certification-testing.workspace = true
rand.workspace = true
rand_chacha.workspace = true
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::error::{CertificateVerificationError, CertificateVerificationResult};
use crate::{
error::{CertificateVerificationError, CertificateVerificationResult},
signature_verification::verify_signature,
};
use candid::Principal;
use ic_cbor::{parse_cbor_principals_array, CertificateToCbor};
use ic_certification::{Certificate, Delegation, LookupResult};
use miracl_core_bls12381::bls12381::bls::{core_verify, BLS_OK};

const IC_STATE_ROOT_DOMAIN_SEPARATOR: &[u8; 14] = b"\x0Dic-state-root";
const DER_PREFIX: &[u8; 37] = b"\x30\x81\x82\x30\x1d\x06\x0d\x2b\x06\x01\x04\x01\x82\xdc\x7c\x05\x03\x01\x02\x01\x06\x0c\x2b\x06\x01\x04\x01\x82\xdc\x7c\x05\x03\x02\x01\x03\x61\x00";
Expand Down Expand Up @@ -63,12 +65,9 @@ impl VerifyCertificate<()> for Certificate {
Some(delegation) => delegation.verify(canister_id, root_public_key)?,
_ => root_public_key.into(),
};
let key = extract_der(der_key)?;
let pk = extract_der(der_key)?;

match core_verify(sig, &msg, &key) {
BLS_OK => Ok(()),
_ => Err(CertificateVerificationError::SignatureVerificationFailed),
}
verify_signature(&pk, sig, &msg)
}
}

Expand Down
2 changes: 2 additions & 0 deletions packages/ic-certificate-verification/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod signature_verification;

mod error;
pub use error::*;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use self::signature_cache::{SignatureCache, SignatureCacheEntry};
use crate::CertificateVerificationError;
use miracl_core_bls12381::bls12381::bls::{core_verify, BLS_OK};

mod signature_cache;

#[cfg(test)]
mod reproducible_rng;

#[cfg(test)]
mod tests;

pub fn verify_signature(
pk: &[u8],
sig: &[u8],
msg: &[u8],
) -> Result<(), CertificateVerificationError> {
let entry = SignatureCacheEntry::new(pk, sig, msg);

if SignatureCache::global().contains(&entry) {
return Ok(());
}

let result = core_verify(sig, msg, pk);

if !matches!(result, BLS_OK) {
return Err(CertificateVerificationError::SignatureVerificationFailed);
}

SignatureCache::global().insert(&entry);
Ok(())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use rand::{CryptoRng, Error, Rng, RngCore, SeedableRng};
use rand_chacha::ChaCha20Rng;

/// Byte length of the seed type used in [`ReproducibleRng`].
const SEED_LEN: usize = 32;

/// Provides a seeded RNG, where the randomly chosen seed is printed on standard output.
pub fn reproducible_rng() -> ReproducibleRng {
ReproducibleRng::new()
}

/// Wraps the logic of [`reproducible_rng`] into a separate struct.
///
/// This is needed when [`reproducible_rng`] cannot be used because its
/// return type `impl Rng + CryptoRng` can only be used as function parameter
/// or as return type
/// (See [impl trait type](https://doc.rust-lang.org/reference/types/impl-trait.html)).
pub struct ReproducibleRng {
rng: ChaCha20Rng,
seed: [u8; SEED_LEN],
}

impl ReproducibleRng {
/// Randomly generates a seed and prints it to `stdout`.
pub fn new() -> Self {
let mut seed = [0u8; SEED_LEN];
rand::thread_rng().fill(&mut seed);
let rng = Self::from_seed_internal(seed);
println!("{rng:?}");
rng
}

fn from_seed_internal(seed: [u8; SEED_LEN]) -> Self {
let rng = ChaCha20Rng::from_seed(seed);
Self { rng, seed }
}
}

impl std::fmt::Debug for ReproducibleRng {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Copy the seed below to reproduce the failed test.\n
let seed: [u8; 32] = {:?};",
self.seed
)
}
}

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

impl RngCore for ReproducibleRng {
fn next_u32(&mut self) -> u32 {
self.rng.next_u32()
}

fn next_u64(&mut self) -> u64 {
self.rng.next_u64()
}

fn fill_bytes(&mut self, dest: &mut [u8]) {
self.rng.fill(dest)
}

fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.rng.try_fill_bytes(dest)
}
}

impl CryptoRng for ReproducibleRng {}
Loading

0 comments on commit 6187cef

Please sign in to comment.