From b46a6dde66ef69f688c130c9d6355178a0d3a060 Mon Sep 17 00:00:00 2001 From: Balazs Komuves Date: Thu, 29 Jan 2026 22:03:52 +0100 Subject: [PATCH] add random number / field element generation support --- src/bin/testmain.rs | 26 ++++++++++++++++++--- src/bn254/bigint.rs | 50 ++++++++++++++++++++++++++++++++++++++++- src/bn254/field.rs | 17 +++++++++++++- src/bn254/montgomery.rs | 20 ++++++++++++++++- src/lib.rs | 3 +++ 5 files changed, 110 insertions(+), 6 deletions(-) diff --git a/src/bin/testmain.rs b/src/bin/testmain.rs index 7180580..488ebb1 100644 --- a/src/bin/testmain.rs +++ b/src/bin/testmain.rs @@ -1,8 +1,12 @@ #![allow(unused)] +#![feature(random)] use std::time::Instant; +use std::ops::{RangeFull}; +use std::random::{Distribution,DefaultRandomSource,random}; + use rust_poseidon_bn254_pure::bn254::bigint::*; use rust_poseidon_bn254_pure::bn254::constant::*; use rust_poseidon_bn254_pure::bn254::montgomery::*; @@ -153,6 +157,7 @@ fn main() { //---------------------------------------------------------------------------- +/* println!(""); println!("sanity checking comparison with the prime"); let one : Big = BigInt::from_u32(1); @@ -166,9 +171,11 @@ fn main() { BigInt::is_lt_prime(a) , BigInt::is_lt_prime(b) , BigInt::is_lt_prime(c) ); +*/ //---------------------------------------------------------------------------- +/* { println!(""); println!("conversion to/from bytes"); @@ -188,14 +195,25 @@ fn main() { println!("b = {}",b); println!("be = {:?}",ys); } +*/ //---------------------------------------------------------------------------- -/* + println!(""); println!("underlying repr = {:?} ", MONT1); - println!("in hex = {}", MONT1); + println!("in hex = {}", Mont::to_hex_string (MONT1)); println!("in dec = {}", Mont::to_decimal_string(MONT1)); -*/ + + //---------------------------------------------------------------------------- + + println!(""); + println!("20 random field elements"); + for i in 0..20 { + let x: Felt = random(..); + println!(" - {} {} {}", x, Felt::to_bigint(x) < FIELD_PRIME , Felt::is_valid(x) ); + } + + //---------------------------------------------------------------------------- // expected results: // @@ -204,6 +222,8 @@ fn main() { // compress3 = 6542985608222806190361240322586112750744169038454362455181422643027100751666 // compress4 = 18821383157269793795438455681495246036402687001665670618754263018637548127333 + println!(""); + let out1 = poseidon::hash1( Felt::from_u32(1) ); println!("compress(1) = {}", Felt::to_decimal_string(out1) ); diff --git a/src/bn254/bigint.rs b/src/bn254/bigint.rs index 9e1295e..0b1f5c6 100644 --- a/src/bn254/bigint.rs +++ b/src/bn254/bigint.rs @@ -1,4 +1,5 @@ + // // big integers, represented as little-endian arrays of u32-s // @@ -10,7 +11,9 @@ use std::fmt; use std::cmp::{Ordering,min}; -use std::ops::{Add,Sub}; +use std::ops::{Add,Sub,RangeFull}; + +use std::random::{RandomSource,Distribution}; use unroll::unroll_for_loops; @@ -87,6 +90,15 @@ impl From for BigInt { fn from(x: u32) -> Self { Self::from_u32(x) } } +//------------------------------------------------------------------------------ +// random trait + +impl Distribution> for RangeFull { + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> BigInt { + BigInt::sample(source) + } +} + //------------------------------------------------------------------------------ // internal implementations @@ -176,6 +188,10 @@ impl BigInt { str::from_utf8(&digits).unwrap().to_string() } + pub fn to_hex_string(input: BigInt) -> String { + format!("{}", input) + } + //------------------------------------ pub fn truncate1(big: BigInt<{N+1}>) -> BigInt { @@ -380,6 +396,17 @@ impl BigInt { BigInt::multiply(big,big) } + //------------------------------------ + // random + + pub fn sample(source: &mut (impl RandomSource + ?Sized)) -> BigInt { + let mut xs: [u32; N] = [0; N]; + for i in 0..N { + xs[i] = RangeFull.sample(source); + } + BigInt::make(xs) + } + } // ----------------------------------------------------------------------------- @@ -447,6 +474,27 @@ impl BigInt256 { } } + //------------------------------------ + // ramndom + + fn sample_masked(source: &mut (impl RandomSource + ?Sized)) -> BigInt256 { + let mut xs: [u32; 8] = [0; 8]; + for i in 0..8 { + xs[i] = RangeFull.sample(source); + } + xs[7] = xs[7] & 0x_3FFF_FFFF; + BigInt::make(xs) + } + + // rejection sampling + pub fn sample_mod_prime(source: &mut (impl RandomSource + ?Sized)) -> BigInt256 { + let mut x: BigInt256 = BigInt256::sample_masked(source); + while( !BigInt256::is_lt_prime(x) ) { + x = BigInt256::sample_masked(source); + } + x + } + } diff --git a/src/bn254/field.rs b/src/bn254/field.rs index 72f9819..e1f4249 100644 --- a/src/bn254/field.rs +++ b/src/bn254/field.rs @@ -10,7 +10,9 @@ #![allow(non_snake_case)] use std::fmt; -use std::ops::{Neg,Add,Sub,Mul}; +use std::ops::{Neg,Add,Sub,Mul,RangeFull}; + +use std::random::{RandomSource,Distribution}; use crate::bn254::bigint::*; use crate::bn254::constant::*; @@ -90,6 +92,15 @@ impl From for Felt { fn from(x: u32) -> Self { Self::from_u32(x) } } +//------------------------------------------------------------------------------ +// random trait + +impl Distribution for RangeFull { + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> Felt { + Felt(BigInt::sample_mod_prime(source)) + } +} + //------------------------------------------------------------------------------ // internal implementations @@ -122,6 +133,10 @@ impl Felt { BigInt::to_decimal_string(input.0) } + pub fn to_hex_string(input: Felt) -> String { + BigInt::to_hex_string(input.0) + } + //------------------------------------ // conversion to/from bytes diff --git a/src/bn254/montgomery.rs b/src/bn254/montgomery.rs index 0829b43..9ce7dcf 100644 --- a/src/bn254/montgomery.rs +++ b/src/bn254/montgomery.rs @@ -7,7 +7,9 @@ #![allow(non_snake_case)] use std::fmt; -use std::ops::{Neg,Add,Sub,Mul}; +use std::ops::{Neg,Add,Sub,Mul,RangeFull}; + +use std::random::{RandomSource,Distribution}; use unroll::unroll_for_loops; @@ -81,6 +83,15 @@ impl From for Mont { fn from(x: u32) -> Self { Self::convert_from_u32(x) } } +//------------------------------------------------------------------------------ +// random trait + +impl Distribution for RangeFull { + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> Mont { + Mont(BigInt::sample_mod_prime(source)) + } +} + //------------------------------------------------------------------------------ // internal implementations @@ -125,10 +136,17 @@ impl Mont { Mont(big) } + //------------------------------------ + // to string + pub fn to_decimal_string(input: Mont) -> String { BigInt::to_decimal_string(Mont::convert_to_big(input)) } + pub fn to_hex_string(input: Mont) -> String { + BigInt::to_hex_string(Mont::convert_to_big(input)) + } + //------------------------------------ #[inline(always)] diff --git a/src/lib.rs b/src/lib.rs index be1885a..ca047d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,10 @@ #![allow(incomplete_features)] + #![feature(bigint_helper_methods)] #![feature(generic_const_exprs)] +#![feature(random)] +#![feature(trait_alias)] pub mod bn254; pub mod poseidon;