diff --git a/node/Cargo.lock b/node/Cargo.lock index d0737747..07ce3a74 100644 --- a/node/Cargo.lock +++ b/node/Cargo.lock @@ -52,18 +52,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ahash" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.2" @@ -133,123 +121,6 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" -[[package]] -name = "ark-bn254" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" -dependencies = [ - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", - "num-traits", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "digest", - "itertools 0.10.5", - "num-bigint", - "num-traits", - "paste", - "rustc_version", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-poly" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", -] - -[[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" -dependencies = [ - "ark-serialize-derive", - "ark-std", - "digest", - "num-bigint", -] - -[[package]] -name = "ark-serialize-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" -dependencies = [ - "num-traits", - "rand", -] - [[package]] name = "assert_matches" version = "1.5.0" @@ -712,17 +583,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "diff" version = "0.1.13" @@ -764,7 +624,7 @@ checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ "curve25519-dalek", "ed25519", - "rand_core", + "rand_core 0.6.4", "serde", "sha2", "zeroize", @@ -807,6 +667,34 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "ff_ce" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b538e4231443a5b9c507caee3356f016d832cf7393d2d90f03ea3180d4e3fbc" +dependencies = [ + "byteorder", + "ff_derive_ce", + "hex", + "rand 0.4.6", + "serde", +] + +[[package]] +name = "ff_derive_ce" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96fbccd88dbb1fac4ee4a07c2fcc4ca719a74ffbd9d2b9d41d8c8eb073d8b20" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + [[package]] name = "fiat-crypto" version = "0.2.3" @@ -825,6 +713,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "futures-channel" version = "0.3.29" @@ -907,15 +801,6 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - [[package]] name = "hashbrown" version = "0.14.2" @@ -1013,7 +898,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" dependencies = [ "bitmaps", - "rand_core", + "rand_core 0.6.4", "rand_xoshiro", "sized-chunks", "typenum", @@ -1027,7 +912,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown", ] [[package]] @@ -1412,6 +1297,18 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "pairing_ce" +version = "0.28.5" +source = "git+https://github.com/matter-labs/pairing.git?rev=f55393f#f55393fd366596eac792d78525d26e9c4d6ed1ca" +dependencies = [ + "byteorder", + "cfg-if", + "ff_ce", + "rand 0.4.6", + "serde", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1435,12 +1332,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - [[package]] name = "peeking_take_while" version = "0.1.2" @@ -1741,6 +1632,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + [[package]] name = "rand" version = "0.8.5" @@ -1749,7 +1653,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1759,9 +1663,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", ] +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.4" @@ -1777,7 +1696,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1800,6 +1719,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -2028,9 +1956,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "snow" @@ -2042,7 +1970,7 @@ dependencies = [ "blake2", "chacha20poly1305", "curve25519-dalek", - "rand_core", + "rand_core 0.6.4", "rustc_version", "sha2", "subtle", @@ -2220,9 +2148,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -2239,9 +2167,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", @@ -2611,26 +2539,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" -[[package]] -name = "zerocopy" -version = "0.7.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - [[package]] name = "zeroize" version = "1.6.0" @@ -2658,7 +2566,7 @@ dependencies = [ "anyhow", "once_cell", "pin-project", - "rand", + "rand 0.8.5", "sha3", "thiserror", "time", @@ -2674,7 +2582,7 @@ version = "0.1.0" dependencies = [ "anyhow", "once_cell", - "rand", + "rand 0.8.5", "thiserror", "tokio", "tracing", @@ -2693,15 +2601,14 @@ name = "zksync_consensus_crypto" version = "0.1.0" dependencies = [ "anyhow", - "ark-bn254", - "ark-ec", - "ark-serialize", "blst", "criterion", "ed25519-dalek", + "ff_ce", "hex", - "num-traits", - "rand", + "pairing_ce", + "rand 0.4.6", + "rand 0.8.5", "sha3", "thiserror", "tracing", @@ -2713,7 +2620,7 @@ version = "0.1.0" dependencies = [ "anyhow", "prost", - "rand", + "rand 0.8.5", "tokio", "tracing", "vise", @@ -2740,7 +2647,7 @@ dependencies = [ "pin-project", "pretty_assertions", "prost", - "rand", + "rand 0.8.5", "snow", "test-casing", "thiserror", @@ -2763,7 +2670,7 @@ dependencies = [ "bit-vec", "hex", "prost", - "rand", + "rand 0.8.5", "serde", "tracing", "zksync_concurrency", @@ -2781,7 +2688,7 @@ dependencies = [ "assert_matches", "async-trait", "prost", - "rand", + "rand 0.8.5", "rocksdb", "tempfile", "test-casing", @@ -2801,7 +2708,7 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "rand", + "rand 0.8.5", "test-casing", "thiserror", "tokio", @@ -2819,7 +2726,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", - "rand", + "rand 0.8.5", "tokio", "tracing", "tracing-subscriber", @@ -2852,7 +2759,7 @@ dependencies = [ "prost", "prost-reflect", "quick-protobuf", - "rand", + "rand 0.8.5", "serde", "serde_json", "tokio", diff --git a/node/Cargo.toml b/node/Cargo.toml index 705f86b4..c998681b 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -40,10 +40,8 @@ assert_matches = "1.5.0" async-trait = "0.1.71" bit-vec = "0.6" blst = "0.3.10" -ark-bn254 = "0.4.0" -ark-ec = "0.4.2" -ark-serialize = { version = "0.4.2", features = ["std"] } -num-traits = "0.2.17" +pairing = { package = "pairing_ce", git = "https://github.com/matter-labs/pairing.git", rev = "f55393f" } +ff_ce = "0.14.3" clap = { version = "4.3.3", features = ["derive"] } heck = "0.4.1" ed25519-dalek = { version = "2.0.0", features = ["rand_core"] } @@ -61,6 +59,7 @@ pretty_assertions = "1.4.0" quick-protobuf = "0.8.1" quote = "1.0.33" rand = "0.8.0" +rand04 = { package = "rand", version = "0.4" } rocksdb = "0.21.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.95" diff --git a/node/deny.toml b/node/deny.toml index 129c4ddf..4806b4d4 100644 --- a/node/deny.toml +++ b/node/deny.toml @@ -55,12 +55,11 @@ skip = [ { name = "regex-syntax", version = "=0.6.29" }, # Old versions required by hyper. - { name = "socket2", version = "0.4.10" }, + { name = "socket2", version = "=0.4.10" }, - # Old versions required by ark-bn254. - { name = "syn", version = "=1.0.109" }, - { name = "hashbrown", version = "=0.13.2" }, - { name = "itertools", version = "=0.10.5" } + # Old versions required by pairing_ce & ff_ce. + { name = "rand", version = "0.4" }, + { name = "syn", version = "1.0" }, ] [sources] diff --git a/node/libs/crypto/Cargo.toml b/node/libs/crypto/Cargo.toml index 91eda71f..417ab7f5 100644 --- a/node/libs/crypto/Cargo.toml +++ b/node/libs/crypto/Cargo.toml @@ -9,16 +9,15 @@ license.workspace = true [dependencies] anyhow.workspace = true blst.workspace = true -ark-bn254.workspace = true -ark-ec.workspace = true -ark-serialize.workspace = true -num-traits.workspace = true +pairing.workspace = true ed25519-dalek.workspace = true hex.workspace = true rand.workspace = true sha3.workspace = true +rand04.workspace = true thiserror.workspace = true tracing.workspace = true +ff_ce.workspace = true [dev-dependencies] criterion = "0.5.1" diff --git a/node/libs/crypto/src/bn254/hash.rs b/node/libs/crypto/src/bn254/hash.rs index e6b93eb9..53d89f54 100644 --- a/node/libs/crypto/src/bn254/hash.rs +++ b/node/libs/crypto/src/bn254/hash.rs @@ -1,11 +1,13 @@ //! Hash operations. -use ark_bn254::{G1Affine, G1Projective}; -use ark_ec::AffineRepr as _; +use pairing::{ + bn256::{G1Affine, G1Compressed}, + EncodedPoint, +}; use sha3::Digest as _; /// Hashes an arbitrary message and maps it to an elliptic curve point in G1. -pub(crate) fn hash_to_g1(msg: &[u8]) -> G1Projective { +pub(crate) fn hash_to_g1(msg: &[u8]) -> G1Affine { for i in 0..256 { // Hash the message with the index as suffix. let bytes: [u8; 32] = sha3::Keccak256::new() @@ -15,10 +17,9 @@ pub(crate) fn hash_to_g1(msg: &[u8]) -> G1Projective { .into(); // Try to get a G1 point from the hash. The probability that this works is around 1/8. - let p = G1Affine::from_random_bytes(&bytes); - - if let Some(p) = p { - return p.into(); + let p = G1Compressed::from_fixed_bytes(bytes).into_affine(); + if let Ok(p) = p { + return p; } } // It should be statistically infeasible to finish the loop without finding a point. diff --git a/node/libs/crypto/src/bn254/mod.rs b/node/libs/crypto/src/bn254/mod.rs index 533509e9..622553c7 100644 --- a/node/libs/crypto/src/bn254/mod.rs +++ b/node/libs/crypto/src/bn254/mod.rs @@ -4,16 +4,19 @@ //! hence it does not protect the secret key from side-channel attacks. use crate::ByteFmt; -use anyhow::Context as _; -use ark_bn254::{Bn254, Fr, G1Projective as G1, G2Projective as G2}; -use ark_ec::{ - pairing::{Pairing as _, PairingOutput}, - Group as _, -}; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; pub use error::Error; -use num_traits::Zero as _; -use std::collections::HashMap; +use ff_ce::Field as _; +use pairing::{ + bn256::{Bn256, Fq12, Fr, FrRepr, G1Affine, G1Compressed, G2Affine, G2Compressed, G1, G2}, + ff::{PrimeField, PrimeFieldRepr}, + CurveAffine as _, CurveProjective as _, EncodedPoint as _, Engine as _, +}; +use std::{ + collections::HashMap, + fmt::{Debug, Formatter}, + hash::{Hash, Hasher}, + io::Cursor, +}; #[doc(hidden)] pub mod error; @@ -30,47 +33,72 @@ pub struct SecretKey(Fr); impl SecretKey { /// Gets the corresponding [`PublicKey`] for this [`SecretKey`] pub fn public(&self) -> PublicKey { - let p = G2::generator() * self.0; + let p = G2Affine::one().mul(self.0); PublicKey(p) } /// Produces a signature using this [`SecretKey`] pub fn sign(&self, msg: &[u8]) -> Signature { let hash_point = hash::hash_to_g1(msg); - let sig = hash_point * self.0; + let sig = hash_point.mul(self.0); Signature(sig) } } impl ByteFmt for SecretKey { fn decode(bytes: &[u8]) -> anyhow::Result { - Fr::deserialize_compressed(bytes) - .map(Self) - .context("failed to decode secret key") + let mut fr_repr = FrRepr::default(); + fr_repr.read_be(Cursor::new(bytes))?; + let fr = Fr::from_repr(fr_repr)?; + Ok(SecretKey(fr)) } fn encode(&self) -> Vec { let mut buf = Vec::new(); - self.0.serialize_compressed(&mut buf).unwrap(); + self.0.into_repr().write_be(&mut buf).unwrap(); buf } } +impl Debug for SecretKey { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "SecretKey({:?})", self.public()) + } +} + +impl PartialEq for SecretKey { + fn eq(&self, other: &Self) -> bool { + self.public() == other.public() + } +} + /// Type safety wrapper around G2. -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct PublicKey(G2); +impl Default for PublicKey { + fn default() -> Self { + PublicKey(G2::zero()) + } +} + +impl Hash for PublicKey { + fn hash(&self, state: &mut H) { + state.write(&self.encode()); + } +} + impl ByteFmt for PublicKey { fn decode(bytes: &[u8]) -> anyhow::Result { - G2::deserialize_compressed(bytes) - .map(Self) - .context("failed to decode public key") + let arr: [u8; 64] = bytes.try_into()?; + let p = G2Compressed::from_fixed_bytes(arr) + .into_affine()? + .into_projective(); + Ok(PublicKey(p)) } fn encode(&self) -> Vec { - let mut buf = Vec::new(); - self.0.serialize_compressed(&mut buf).unwrap(); - buf + self.0.into_affine().into_compressed().as_ref().to_vec() } } @@ -100,9 +128,9 @@ impl Signature { let hash_point = hash::hash_to_g1(msg); // First pair: e(H(m): G1, pk: G2) - let a = Bn254::pairing(hash_point, pk.0); + let a = Bn256::pairing(hash_point, pk.0); // Second pair: e(sig: G1, generator: G2) - let b = Bn254::pairing(self.0, G2::generator()); + let b = Bn256::pairing(self.0, G2Affine::one()); if a == b { Ok(()) @@ -114,14 +142,15 @@ impl Signature { impl ByteFmt for Signature { fn decode(bytes: &[u8]) -> anyhow::Result { - G1::deserialize_compressed(bytes) - .map(Self) - .context("failed to decode signature") + let arr: [u8; 32] = bytes.try_into()?; + let p = G1Compressed::from_fixed_bytes(arr) + .into_affine()? + .into_projective(); + Ok(Signature(p)) } + fn encode(&self) -> Vec { - let mut buf = Vec::new(); - self.0.serialize_compressed(&mut buf).unwrap(); - buf + self.0.into_affine().into_compressed().as_ref().to_vec() } } @@ -136,6 +165,7 @@ impl Ord for Signature { ByteFmt::encode(self).cmp(&ByteFmt::encode(other)) } } + /// Type safety wrapper around [Signature] indicating that it is an aggregated signature. #[derive(Clone, Debug, PartialEq, Eq)] pub struct AggregateSignature(G1); @@ -143,9 +173,9 @@ pub struct AggregateSignature(G1); impl AggregateSignature { /// Generates an aggregate signature from a list of signatures. pub fn aggregate<'a>(sigs: impl IntoIterator) -> Self { - let mut agg = G1::zero(); + let mut agg = G1Affine::zero().into_projective(); for sig in sigs { - agg += sig.0 + agg.add_assign(&sig.0) } AggregateSignature(agg) @@ -157,17 +187,17 @@ impl AggregateSignature { fn verify_raw(&self, msgs_and_pks: &[(&[u8], &PublicKey)]) -> Result<(), Error> { // Aggregate public keys if they are signing the same hash. Each public key aggregated // is one fewer pairing to calculate. - let mut pairs: HashMap<&[u8], G2> = HashMap::new(); + let mut pairs: HashMap<&[u8], PublicKey> = HashMap::new(); for (msg, pk) in msgs_and_pks { - *pairs.entry(msg).or_default() += pk.0; + pairs.entry(msg).or_default().0.add_assign(&pk.0); } // First pair: e(sig: G1, generator: G2) - let a = Bn254::pairing(self.0, G2::generator()); + let a = Bn256::pairing(self.0, G2::one()); // Second pair: e(H(m1): G1, pk1: G2) * ... * e(H(m1000): G1, pk1000: G2) - let mut b = PairingOutput::zero(); + let mut b = Fq12::one(); for (msg, pk) in pairs { - b += Bn254::pairing(hash::hash_to_g1(msg), pk); + b.mul_assign(&Bn256::pairing(hash::hash_to_g1(msg), pk.0)) } if a == b { @@ -190,15 +220,15 @@ impl AggregateSignature { impl ByteFmt for AggregateSignature { fn decode(bytes: &[u8]) -> anyhow::Result { - G1::deserialize_compressed(bytes) - .map(Self) - .context("failed to decode aggregate signature") + let arr: [u8; 32] = bytes.try_into()?; + let p = G1Compressed::from_fixed_bytes(arr) + .into_affine()? + .into_projective(); + Ok(AggregateSignature(p)) } fn encode(&self) -> Vec { - let mut buf = Vec::new(); - self.0.serialize_compressed(&mut buf).unwrap(); - buf + self.0.into_affine().into_compressed().as_ref().to_vec() } } diff --git a/node/libs/crypto/src/bn254/testonly.rs b/node/libs/crypto/src/bn254/testonly.rs index a4af1c1d..dd7bb4a1 100644 --- a/node/libs/crypto/src/bn254/testonly.rs +++ b/node/libs/crypto/src/bn254/testonly.rs @@ -1,33 +1,50 @@ //! Random key generation, intended for use in testing use super::{AggregateSignature, PublicKey, SecretKey, Signature}; -use rand::{distributions::Standard, prelude::Distribution, Rng}; +use pairing::bn256::{Fr, G1, G2}; +use rand::{distributions::Standard, prelude::Distribution, Rng, RngCore}; +use rand04::Rand; + +struct RngWrapper(R); + +impl rand04::Rng for RngWrapper { + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } +} /// Generates a random SecretKey. This is meant for testing purposes. impl Distribution for Standard { fn sample(&self, rng: &mut R) -> SecretKey { - let rand = ark_bn254::Fr::new(rng.gen()); - SecretKey(rand) + let scalar = Fr::rand(&mut RngWrapper(rng)); + SecretKey(scalar) } } /// Generates a random PublicKey. This is meant for testing purposes. impl Distribution for Standard { fn sample(&self, rng: &mut R) -> PublicKey { - PublicKey(rng.gen()) + let p = G2::rand(&mut RngWrapper(rng)); + PublicKey(p) } } /// Generates a random Signature. This is meant for testing purposes. impl Distribution for Standard { fn sample(&self, rng: &mut R) -> Signature { - Signature(rng.gen()) + let p = G1::rand(&mut RngWrapper(rng)); + Signature(p) } } /// Generates a random AggregateSignature. This is meant for testing purposes. impl Distribution for Standard { fn sample(&self, rng: &mut R) -> AggregateSignature { - AggregateSignature(rng.gen()) + let p = G1::rand(&mut RngWrapper(rng)); + AggregateSignature(p) } } diff --git a/node/libs/crypto/src/bn254/tests.rs b/node/libs/crypto/src/bn254/tests.rs index d07afbfa..90030e11 100644 --- a/node/libs/crypto/src/bn254/tests.rs +++ b/node/libs/crypto/src/bn254/tests.rs @@ -1,4 +1,7 @@ -use crate::bn254::{AggregateSignature, PublicKey, SecretKey, Signature}; +use crate::{ + bn254::{AggregateSignature, PublicKey, SecretKey, Signature}, + ByteFmt, +}; use rand::{rngs::StdRng, Rng, SeedableRng}; use std::iter::repeat_with; @@ -85,3 +88,28 @@ fn aggregate_signature_failure_smoke() { assert!(agg.verify(pks.iter().map(|pk| (&msg[..], pk))).is_err()) } + +#[test] +fn byte_fmt_correctness() { + let mut rng = rand::thread_rng(); + + let sk: SecretKey = rng.gen(); + let bytes = sk.encode(); + let sk_decoded = SecretKey::decode(&bytes).unwrap(); + assert_eq!(sk, sk_decoded); + + let pk: PublicKey = rng.gen(); + let bytes = pk.encode(); + let pk_decoded = PublicKey::decode(&bytes).unwrap(); + assert_eq!(pk, pk_decoded); + + let sig: Signature = rng.gen(); + let bytes = sig.encode(); + let sig_decoded = Signature::decode(&bytes).unwrap(); + assert_eq!(sig, sig_decoded); + + let agg: AggregateSignature = rng.gen(); + let bytes = agg.encode(); + let agg_decoded = AggregateSignature::decode(&bytes).unwrap(); + assert_eq!(agg, agg_decoded); +}