started adding some tests

This commit is contained in:
Balazs Komuves 2026-01-29 23:19:04 +01:00
parent b46a6dde66
commit f6c30ed6e0
No known key found for this signature in database
GPG Key ID: F63B7AEF18435562
8 changed files with 244 additions and 71 deletions

View File

@ -87,13 +87,13 @@ On modern 64-bit CPU-s, the 64-bit version would be preferred (TODO: implement i
### TODO
- [ ] clean up the code and make it more idiomatic
- [ ] optimize squaring to use less multiplications (?)
- [x] clean up the code and make it more idiomatic
- [x] implement `circomlib`-compatible Poseidon
- [x] benchmark RISC-V cycles
- [ ] add more Poseidon2 state widths (not just `t=3`)
- [x] implement `circomlib`-compatible Poseidon
- [ ] add a proper test-suite; in particular, more complete testing of the field operations
- [ ] add a 64 bit version
- [ ] further optimizations (?)
- [ ] implement the sponge construction
- [ ] optimize squaring to use less multiplications (?)
- [ ] investigate further optimization possibilities (?)

View File

@ -6,3 +6,5 @@ pub mod constant;
pub mod montgomery;
pub mod field;
#[cfg(test)]
mod test;

View File

@ -1,25 +1,16 @@
// "unstable" version
// "unstable" (in rust parlance) version
#![allow(dead_code)]
#![allow(non_snake_case)]
//------------------------------------------------------------------------------
const U32_MASK: u64 = 0x_FFFF_FFFF;
#[inline(always)]
pub fn boolToU32(c: bool) -> u32 {
if c { 1 } else { 0 }
}
#[inline(always)]
pub fn takeApart64(x: u64) -> (u32,u32) {
let lo: u32 = (x & U32_MASK) as u32;
let hi: u32 = (x >> 32 ) as u32;
(lo,hi)
}
//------------------------------------------------------------------------------
#[inline(always)]
@ -79,60 +70,3 @@ pub fn u64AddAdd32(xy: (u32,u32), a: u32, b: u32) -> (u32,u32) {
}
//------------------------------------------------------------------------------
// "portable" version
/*
pub fn addCarry32_(x: u32, y: u32) -> (u32,bool) {
let z: u32 = u32::wrapping_add(x, y);
let c: bool = z < x;
(z, c)
}
pub fn subBorrow32_(x: u32, y: u32) -> (u32,bool) {
let z: u32 = u32::wrapping_sub(x, y);
let c: bool = z > x;
(z, c)
}
pub fn addCarry32(x :u32, y: u32, cin: bool) -> (u32,bool) {
let z: u32 = u32::wrapping_add(u32::wrapping_add(x, y), boolToU32(cin));
let c: bool = if cin { z <= x } else { z < x };
(z, c)
}
pub fn subBorrow32(x: u32, y: u32, cin: bool) -> (u32,bool) {
let z: u32 = u32::wrapping_sub(u32::wrapping_sub(x, y), boolToU32(cin));
let c: bool = if cin { z >= x } else { z > x };
(z, c)
}
pub fn mulTrunc32(x: u32, y: u32) -> u32 {
u32::wrapping_mul(x,y)
}
pub fn mulExt32(x: u32, y: u32) -> (u32,u32) {
let z: u64 = (x as u64) * (y as u64);
let hi = (z >> 32) as u32;
let lo = (z & U32_MASK) as u32;
(lo, hi)
}
pub fn mulAdd32(x: u32, y: u32, a: u32) -> (u32,u32) {
let z: u64 = (x as u64) * (y as u64) + (a as u64);
let hi = (z >> 32) as u32;
let lo = (z & U32_MASK) as u32;
(lo, hi)
}
pub fn mulAddAdd32(x: u32, y: u32, a: u32, b: u32) -> (u32,u32) {
let z: u64 = (x as u64) * (y as u64) + (a as u64) + (b as u64);
let hi = (z >> 32) as u32;
let lo = (z & U32_MASK) as u32;
(lo, hi)
}
*/
//------------------------------------------------------------------------------

52
src/bn254/test/bigint.rs Normal file
View File

@ -0,0 +1,52 @@
// tests for bigints
#![allow(unused)]
use crate::bn254::bigint::*;
use crate::bn254::test::properties::*;
type Big = BigInt<8>;
//------------------------------------------------------------------------------
#[test]
fn zero_is_zero() {
assert!( Big::is_zero( Big::zero() ) )
}
#[test]
fn unit_to_decimal() {
let x: Big = Big::make( [ 0xff74e7f5 , 0x86ab86c2 , 0x7829f01b , 0x6dff3d9f , 0x7c6194d1 , 0x58fce839 , 0x1c3fc759 , 0x0ee7c7b9 ] );
assert_eq!( Big::to_decimal_string(x) , "6741899990217662167434591118162422674873486558668509109681649862022285027317" )
}
#[test]
fn unit_to_hex() {
let x: Big = Big::make( [ 0x5d8aa877 , 0x40b543d5 , 0x115812cd , 0x0563e2bd , 0x26c9552a , 0x1890edd6 , 0x803b772b , 0x1a12005c ] );
assert_eq!( Big::to_hex_string(x) , "0x1a12005c803b772b1890edd626c9552a0563e2bd115812cd40b543d55d8aa877" )
}
//------------------------------------------------------------------------------
fn prop_from_to_bytes_le<const N: usize>(x: BigInt<N>) -> bool where [(); 4*N]: {
let bs: [u8; 4*N] = BigInt::to_le_bytes(x);
BigInt::<N>::from_le_bytes(bs) == x
}
fn prop_to_from_bytes_le<const N: usize>(bs: [u8; 4*N]) -> bool {
let y: BigInt<N> = BigInt::from_le_bytes(bs);
BigInt::<N>::to_le_bytes(y) == bs
}
fn prop_from_to_bytes_be<const N: usize>(x: BigInt<N>) -> bool where [(); 4*N]: {
let bs: [u8; 4*N] = BigInt::to_be_bytes(x);
BigInt::<N>::from_be_bytes(bs) == x
}
fn prop_to_from_bytes_be<const N: usize>(bs: [u8; 4*N]) -> bool {
let y: BigInt<N> = BigInt::from_be_bytes(bs);
BigInt::<N>::to_be_bytes(y) == bs
}
//------------------------------------------------------------------------------

6
src/bn254/test/mod.rs Normal file
View File

@ -0,0 +1,6 @@
pub mod properties;
pub mod bigint;
// pub mod field;
// pub mod mont;

View File

@ -0,0 +1,113 @@
// field properties
#![allow(dead_code)]
#![allow(non_snake_case)]
use std::cmp::{Eq};
use std::ops::{Neg,Add,Sub,Mul,Div};
//------------------------------------------------------------------------------
pub trait Group = Copy + Clone + Default + From<u32> + Eq + Neg<Output=Self> + Add<Output=Self> + Sub<Output=Self>;
pub trait Ring = Group + Mul<Output=Self>;
pub trait Field = Ring + Div<Output=Self>;
//------------------------------------------------------------------------------
fn zero<A: Group>() -> A {
A::default()
}
fn small<A: Group>(x: u32) -> A {
A::from(x)
}
// wtf rust?
fn xneg<A: Neg<Output=A>>(x: A ) -> A {
-x
}
//------------------------------------------------------------------------------
pub fn prop_left_additive_unit<A: Group>(x: A) -> bool {
zero::<A>() + x == x
}
pub fn prop_right_additive_unit<A: Group>(x: A) -> bool {
x + zero::<A>() == x
}
pub fn prop_sub_zero<A: Group>(x: A) -> bool {
x - zero::<A>() == x
}
pub fn prop_zero_subo<A: Group>(x: A) -> bool {
zero::<A>() - x == xneg(x)
}
pub fn prop_add_commutative<A: Group>(x: A, y: A) -> bool {
x + y == y + x
}
pub fn prop_sub_anticommutative<A: Group>(x: A, y: A) -> bool {
x - y == xneg( y - x )
}
pub fn prop_neg_involutive<A: Group>(x: A) -> bool {
xneg( xneg(x) ) == x
}
pub fn prop_add_sub<A: Group>(x: A, y: A) -> bool {
(x + y) - y == x
}
pub fn prop_sub_add<A: Group>(x: A, y: A) -> bool {
(x - y) + y == x
}
pub fn prop_sub_neg_add<A: Group>(x: A, y: A) -> bool {
x - xneg(y) == x + y
}
pub fn prop_sub_add_neg<A: Group>(x: A, y: A) -> bool {
x - y == x + xneg(y)
}
//------------------------------------------------------------------------------
pub fn prop_twice<A: Ring>(x: A) -> bool {
x + x == x * small::<A>(2)
}
pub fn prop_thrice<A: Ring>(x: A) -> bool {
x + x + x == x * small::<A>(3)
}
//------------------------------------------------------------------------------
pub fn prop_left_multiplicative_unit<A: Ring>(x: A) -> bool {
small::<A>(1) * x == x
}
pub fn prop_right_multiplicative_unit<A: Ring>(x: A) -> bool {
x * small::<A>(1) == x
}
pub fn prop_mul_commutative<A: Ring>(x: A, y: A) -> bool {
x * y == y * x
}
pub fn prop_mul_neg<A: Ring>(x: A, y: A) -> bool {
xneg(x * y) == xneg(x) * y
}
pub fn prop_distributive_add<A: Ring>(x: A, y: A, z: A) -> bool {
(x + y) * z == x * z + y * z
}
pub fn prop_distributive_sub<A: Ring>(x: A, y: A, z: A) -> bool {
(x - y) * z == x * z - y * z
}
//------------------------------------------------------------------------------

View File

@ -167,4 +167,47 @@ pub fn hash4(a: Felt, b: Felt, c: Felt, d: Felt) -> Felt {
compress::<4>([ a, b, c, d ])
}
//==============================================================================
// *** TESTS
#[cfg(test)]
mod test {
use crate::bn254::field::*;
use super::*;
#[test]
fn hash1_kat() {
assert_eq!(
Felt::to_decimal_string( hash1( 1u32.into() ) ),
"18586133768512220936620570745912940619677854269274689475585506675881198879027"
);
}
#[test]
fn hash2_kat() {
assert_eq!(
Felt::to_decimal_string( hash2( 1u32.into(), 2u32.into() ) ),
"7853200120776062878684798364095072458815029376092732009249414926327459813530"
);
}
#[test]
fn hash3_kat() {
assert_eq!(
Felt::to_decimal_string( hash3( 1u32.into(), 2u32.into(), 3u32.into() ) ),
"6542985608222806190361240322586112750744169038454362455181422643027100751666"
);
}
#[test]
fn hash4_kat() {
assert_eq!(
Felt::to_decimal_string( hash4( 1u32.into(), 2u32.into(), 3u32.into(), 4u32.into() ) ),
"18821383157269793795438455681495246036402687001665670618754263018637548127333"
);
}
}
//------------------------------------------------------------------------------

View File

@ -83,4 +83,27 @@ pub fn permute_iterated(input: [Felt; 3], count: usize) -> [Felt; 3] {
out
}
//==============================================================================
// *** TESTS
#[cfg(test)]
mod test {
use crate::bn254::field::{Felt};
use super::*;
#[test]
fn permute3_kat() {
let out: [Felt; 3] = permute( [ 0u32.into() , 1u32.into() , 2u32.into() ] );
println!(" 0 -> {}" , out[0] );
println!(" 1 -> {}" , out[1] );
println!(" 2 -> {}" , out[2] );
assert_eq!( Felt::to_hex_string( out[0] ) , "0x30610a447b7dec194697fb50786aa7421494bd64c221ba4d3b1af25fb07bd103" );
assert_eq!( Felt::to_hex_string( out[1] ) , "0x13f731d6ffbad391be22d2ac364151849e19fa38eced4e761bcd21dbdc600288" );
assert_eq!( Felt::to_hex_string( out[2] ) , "0x1433e2c8f68382c447c5c14b8b3df7cbfd9273dd655fe52f1357c27150da786f" );
}
}
//------------------------------------------------------------------------------