Skip to content

Commit

Permalink
changed method of ran group element generation
Browse files Browse the repository at this point in the history
  • Loading branch information
trbritt committed Nov 11, 2024
1 parent 649313f commit 8b0bfa4
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 7 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ serde_json = "1.0.127"
sha2 = "0.11.0-pre.4"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
paste = "1.0.15"

[[bench]]
name = "mod"
Expand Down
21 changes: 19 additions & 2 deletions src/groups/g1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::fields::fp::{FieldExtensionTrait, Fp};
use crate::groups::group::{GroupAffine, GroupError, GroupProjective, GroupTrait};
use crate::hasher::Expander;
use crate::svdw::{MapError, SvdW, SvdWTrait};
use crate::Fr;
use crypto_bigint::rand_core::CryptoRngCore;
use num_traits::{One, Zero};
use std::sync::OnceLock;
Expand Down Expand Up @@ -292,9 +293,25 @@ impl GroupTrait<1, 1, Fp> for G1Projective {
Self::generator()
}

/// Generates a random point in the 𝔾₁ group
/// Generates a random point in the 𝔾₁ group, using a pseudo-random
/// function according to formulation in §4.1.7.4 of the Moon Math Manual,
/// see <https://github.com/LeastAuthority/moonmath-manual/releases/latest/download/main-moonmath.pdf>
fn rand<R: CryptoRngCore>(rng: &mut R) -> Self {
Self::generator() * <Fp as FieldExtensionTrait<1, 1>>::rand(rng)
const K: usize = 10;
let a_i = (0..K)
.into_iter()
.map(|_| Fp::new(Fr::rand(rng).value()))
.collect::<Vec<_>>();
let b_i = (0..(K - 1))
.into_iter()
.map(|_| Fp::new(Fr::rand(rng).value()))
.collect::<Vec<_>>();
let mut random_scalar = Fp::ONE;
(1..K).into_iter().for_each(|i| {
random_scalar = random_scalar * a_i[i] * b_i[i - 1];
});
random_scalar = random_scalar * a_i[0];
Self::generator() * random_scalar
}

/// Hashes a message to a point on the 𝔾₁ group
Expand Down
23 changes: 19 additions & 4 deletions src/groups/g2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,9 @@ impl GroupTrait<2, 2, Fp2> for G2Projective {
/// This function first generates a random point on the twist curve E'(𝔽ₚ²),
/// then applies cofactor clearing to ensure the result is in the r-torsion subgroup.
/// It is then passed through the `new` function to ensure it passes the curve and
/// subgroup checks.
/// subgroup checks. It generates the random scalar to create a pseudo-random
/// function according to formulation in §4.1.7.4 of the Moon Math Manual,
/// see <https://github.com/LeastAuthority/moonmath-manual/releases/latest/download/main-moonmath.pdf>
///
/// # Examples
///
Expand All @@ -228,9 +230,22 @@ impl GroupTrait<2, 2, Fp2> for G2Projective {
0,
0,
]));
let rando = Fp::new(Fr::rand(rng).value());
let mut tmp = Self::generator() * rando;
tracing::trace!(?rando, ?tmp, "G2Projective::rand");
const K: usize = 10;
let a_i = (0..K)
.into_iter()
.map(|_| Fp::new(Fr::rand(rng).value()))
.collect::<Vec<_>>();
let b_i = (0..(K - 1))
.into_iter()
.map(|_| Fp::new(Fr::rand(rng).value()))
.collect::<Vec<_>>();
let mut random_scalar = Fp::ONE;
(1..K).into_iter().for_each(|i| {
random_scalar = random_scalar * a_i[i] * b_i[i - 1];
});
random_scalar = random_scalar * a_i[0];
let mut tmp = Self::generator() * random_scalar;
tracing::trace!(?random_scalar, ?tmp, "G2Projective::rand");

// multiplying an element of the larger base field by the cofactor of a prime-ordered
// subgroup will return an element in the prime-order subgroup, see
Expand Down
133 changes: 132 additions & 1 deletion src/groups/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ mod tests {
use crate::fields::fp::{FieldExtensionTrait, Fp};
use crate::fields::fp2::Fp2;
use crate::groups::g1::{G1Affine, G1Projective};
use crate::groups::g2::G2Projective;
use crate::groups::g2::{G2Affine, G2Projective};

#[derive(Serialize, Deserialize, Clone)]
struct _G2Coords {
Expand Down Expand Up @@ -871,4 +871,135 @@ mod tests {
}
}
}
mod random {
use super::*;
use crate::GroupTrait;
use rand_core::OsRng;

/// This is the monobit test, which is a simplified version of NIST SP 800-22
#[test]
fn g1_monobit_test() {
const SAMPLE_SIZE: usize = 1000;
let mut x_coordinates = Vec::with_capacity(SAMPLE_SIZE);
let mut y_coordinates = Vec::with_capacity(SAMPLE_SIZE);

// Generate sample points
for _ in 0..SAMPLE_SIZE {
let affine = G1Affine::rand(&mut OsRng);
x_coordinates.push(affine.x);
y_coordinates.push(affine.y);
}
// Convert coordinates to bits and count 1s
let total_bits = SAMPLE_SIZE * 256; // Each Fp is 256 bits
for coords in [x_coordinates, y_coordinates] {
let mut total_ones = 0;
for coord in coords {
let bits = coord.to_be_bytes();
for byte in bits {
total_ones += byte.count_ones() as usize;
}
}
// For truly random bits, we expect approximately 50% ones
let proportion_ones = total_ones as f64 / total_bits as f64;
assert!(
(proportion_ones - 0.5).abs() < 0.01,
"Bit distribution shows bias: {}",
proportion_ones
);
}
}
#[test]
fn g2_monobit_test() {
const SAMPLE_SIZE: usize = 1000;
let mut x_coordinates = Vec::with_capacity(SAMPLE_SIZE);
let mut y_coordinates = Vec::with_capacity(SAMPLE_SIZE);

// Generate sample points
for _ in 0..SAMPLE_SIZE {
let affine = G2Affine::rand(&mut OsRng);
x_coordinates.push(affine.x);
y_coordinates.push(affine.y);
}
// Convert coordinates to bits and count 1s
let total_bits = SAMPLE_SIZE * 256 * 2; // Each Fp is 256 bits
for coords in [x_coordinates, y_coordinates] {
let mut total_ones = 0;
for coord in coords {
for inner_coord in coord.0 {
let bits = inner_coord.to_be_bytes();
for byte in bits {
total_ones += byte.count_ones() as usize;
}
}
}
// For truly random bits, we expect approximately 50% ones
let proportion_ones = total_ones as f64 / total_bits as f64;
assert!(
(proportion_ones - 0.5).abs() < 0.01,
"Bit distribution shows bias: {}",
proportion_ones
);
}
}
}
/// These tests are mainly for line coverage to assert the correct unimplemented behaviour in
/// real usage scenarios encountered at runtime
mod unimplemented {
use super::*;
use crate::{Fp12, GroupTrait, Gt, XMDExpander};
use rand_core::OsRng;
use sha3::Keccak256;

mod gt {
use super::*;
#[test]
#[should_panic]
fn test_endo() {
let _ = Gt::identity().endomorphism();
}

#[test]
#[should_panic]
fn test_hash_to_curve() {
let expander = XMDExpander::<Keccak256>::new(&[0xAA; 32], 180);
let _ = Gt::hash_to_curve(&expander, &[0x0F; 32]);
}

#[test]
#[should_panic]
fn test_sign_message() {
let expander = XMDExpander::<Keccak256>::new(&[0xAA; 32], 180);
let _ = Gt::sign_message(&expander, &[0x0F; 32], Fp12::rand(&mut OsRng));
}
}

mod g2 {
use super::*;
macro_rules! g2_panic_tests {
($type:ty) => {
paste::paste! {
#[test]
#[should_panic]
fn [<test_ $type:snake _hash_to_curve>]() {
let expander = XMDExpander::<Keccak256>::new(&[0xAA; 32], 180);
let _ = <$type>::hash_to_curve(&expander, &[0x0F; 32]);
}

#[test]
#[should_panic]
fn [<test_ $type:snake _sign_message>]() {
let expander = XMDExpander::<Keccak256>::new(&[0xAA; 32], 180);
let _ = <$type>::sign_message(
&expander,
&[0x0F; 32],
<Fp2 as FieldExtensionTrait<2, 2>>::rand(&mut OsRng),
);
}
}
};
}
g2_panic_tests!(G2Affine);
g2_panic_tests!(G2Projective);
}
}
}

0 comments on commit 8b0bfa4

Please sign in to comment.