minor improvements (README, bench)

This commit is contained in:
Balazs Komuves 2026-01-27 14:24:28 +01:00
parent 49e10423d0
commit 37d424c319
No known key found for this signature in database
GPG Key ID: F63B7AEF18435562
4 changed files with 59 additions and 26 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.DS_Store
target/
Cargo.lock
tmp/

View File

@ -70,26 +70,30 @@ Some approximate benchmark numbers below.
On RV32IM (the primary target as of now), we have approximately the following cycle counts:
Poseidon2:
- Poseidon: about 900k cycles for a single `t=3` permutation
- Poseidon2: about 350k cycles for a single `t=3` permutation
- 350k cycles for a single `t=3` permutation
Note: Poseidon is about 2.5x slower, simply because there are about 2.5x more
field multiplications involved (which absolutely dominate the runtime).
#### Modern CPUs
On modern 64-bit CPU-s, the 64-bit version is preferred (TODO: implement it).
On modern 64-bit CPU-s, the 64-bit version would be preferred (TODO: implement it).
32 bit version, running on an M2 macbook pro:
32 bit version, running on an M2 macbook pro (single threaded):
- 155 msec for 10k `t=3` permutations
- Poseidon: 320 msec for 10,000 `t=3` permutations
- Poseidon2: 140 msec for 10,000 `t=3` permutations
### TODO
- [ ] clean up the code and make it more idiomatic
- [ ] optimize squaring to use less multiplications (?)
- [ ] benchmark RISC-V cycles
- [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
- [ ] further optimizations (?)
- [ ] implement the sponge construction

View File

@ -1,50 +1,76 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use criterion::{criterion_group, criterion_main, Criterion};
use std::hint::{black_box};
use rust_poseidon_bn254_pure::bn254::field::*;
use rust_poseidon_bn254_pure::poseidon2::permutation::*;
use rust_poseidon_bn254_pure::bn254::montgomery::{Mont};
use rust_poseidon_bn254_pure::poseidon;
use rust_poseidon_bn254_pure::poseidon2;
//------------------------------------------------------------------------------
type State = (Felt,Felt,Felt);
type Triple = (Felt,Felt,Felt);
fn initial_state() -> State {
fn initial_triple() -> Triple {
( Felt::from_u32(0)
, Felt::from_u32(1)
, Felt::from_u32(2)
)
}
fn iterate_perm(n: usize) -> State {
let mut state: State = initial_state();
fn initial_vector() -> [Felt; 3] {
[ Felt::from_u32(0)
, Felt::from_u32(1)
, Felt::from_u32(2)
]
}
pub fn poseidon1_permute_felt(input: [Felt; 3]) -> [Felt; 3] {
let mut state: [Mont; 3] =
[ Felt::to_mont(&input[0])
, Felt::to_mont(&input[1])
, Felt::to_mont(&input[2])
];
state = poseidon::permutation::permute_mont_T3(state);
let out: [Felt; 3] =
[ Felt::from_mont(&state[0])
, Felt::from_mont(&state[1])
, Felt::from_mont(&state[2])
];
out
}
fn iterate_poseidon1(n: usize) -> [Felt; 3] {
let mut state: [Felt; 3] = initial_vector();
for _i in 0..n {
state = permute_felt(&state);
state = poseidon1_permute_felt(state);
}
state
}
// for a Merkle tree update with depth 20, we need 20 permutation calls
fn twenty_permutations() -> State {
let mut state: State = initial_state();
iterate_perm(20);
fn iterate_poseidon2(n: usize) -> Triple {
let mut state: Triple = initial_triple();
for _i in 0..n {
state = poseidon2::permutation::permute_felt(&state);
}
state
}
fn bench_iterated_perm(c: &mut Criterion , n: usize) {
let msg = format!("Poseidon2 permutation iterated {} times", n);
c.bench_function(&msg, |b| b.iter(|| iterate_perm(black_box(n)) ));
fn bench_iterated_poseidon1(c: &mut Criterion , n: usize) {
let msg = format!("Poseidon1 permutation iterated {} times", n);
c.bench_function(&msg, |b| b.iter(|| iterate_poseidon1(black_box(n)) ));
}
fn bench_twenty(c: &mut Criterion) {
let msg = format!("Poseidon2 permutation iterated 20 times");
c.bench_function(&msg, |b| b.iter(|| twenty_permutations() ));
fn bench_iterated_poseidon2(c: &mut Criterion , n: usize) {
let msg = format!("Poseidon2 permutation iterated {} times", n);
c.bench_function(&msg, |b| b.iter(|| iterate_poseidon2(black_box(n)) ));
}
//------------------------------------------------------------------------------
fn bench_permutations(c: &mut Criterion) {
bench_iterated_perm(c, 1000);
bench_twenty(c);
bench_iterated_poseidon1(c, 10000);
bench_iterated_poseidon2(c, 10000);
}
//------------------------------------------------------------------------------

View File

@ -1,4 +1,6 @@
#![allow(unused)]
use std::time::Instant;
use rust_poseidon_bn254_pure::bn254::bigint::*;