Skip to content

Commit

Permalink
Update from upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
slowli committed Nov 13, 2023
2 parents 3321d41 + fefb04a commit f4b1e14
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 272 deletions.
311 changes: 109 additions & 202 deletions node/Cargo.lock

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand All @@ -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"
Expand Down
9 changes: 4 additions & 5 deletions node/deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
7 changes: 3 additions & 4 deletions node/libs/crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
15 changes: 8 additions & 7 deletions node/libs/crypto/src/bn254/hash.rs
Original file line number Diff line number Diff line change
@@ -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()
Expand All @@ -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.
Expand Down
116 changes: 73 additions & 43 deletions node/libs/crypto/src/bn254/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Self> {
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<u8> {
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<H: Hasher>(&self, state: &mut H) {
state.write(&self.encode());
}
}

impl ByteFmt for PublicKey {
fn decode(bytes: &[u8]) -> anyhow::Result<Self> {
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<u8> {
let mut buf = Vec::new();
self.0.serialize_compressed(&mut buf).unwrap();
buf
self.0.into_affine().into_compressed().as_ref().to_vec()
}
}

Expand Down Expand Up @@ -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(())
Expand All @@ -114,14 +142,15 @@ impl Signature {

impl ByteFmt for Signature {
fn decode(bytes: &[u8]) -> anyhow::Result<Self> {
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<u8> {
let mut buf = Vec::new();
self.0.serialize_compressed(&mut buf).unwrap();
buf
self.0.into_affine().into_compressed().as_ref().to_vec()
}
}

Expand All @@ -136,16 +165,17 @@ 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);

impl AggregateSignature {
/// Generates an aggregate signature from a list of signatures.
pub fn aggregate<'a>(sigs: impl IntoIterator<Item = &'a Signature>) -> 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)
Expand All @@ -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 {
Expand All @@ -190,15 +220,15 @@ impl AggregateSignature {

impl ByteFmt for AggregateSignature {
fn decode(bytes: &[u8]) -> anyhow::Result<Self> {
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<u8> {
let mut buf = Vec::new();
self.0.serialize_compressed(&mut buf).unwrap();
buf
self.0.into_affine().into_compressed().as_ref().to_vec()
}
}

Expand Down
29 changes: 23 additions & 6 deletions node/libs/crypto/src/bn254/testonly.rs
Original file line number Diff line number Diff line change
@@ -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>(R);

impl<R: RngCore> rand04::Rng for RngWrapper<R> {
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<SecretKey> for Standard {
fn sample<R: Rng + ?Sized>(&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<PublicKey> for Standard {
fn sample<R: Rng + ?Sized>(&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<Signature> for Standard {
fn sample<R: Rng + ?Sized>(&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<AggregateSignature> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> AggregateSignature {
AggregateSignature(rng.gen())
let p = G1::rand(&mut RngWrapper(rng));
AggregateSignature(p)
}
}
30 changes: 29 additions & 1 deletion node/libs/crypto/src/bn254/tests.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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);
}

0 comments on commit f4b1e14

Please sign in to comment.