mirror of
https://github.com/vacp2p/zerokit.git
synced 2026-01-09 13:47:58 -05:00
Compare commits
11 Commits
benchmark-
...
poseidon_h
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0649e22d0 | ||
|
|
9bb8246b6a | ||
|
|
96bc791047 | ||
|
|
a0cefd50bd | ||
|
|
63a0472466 | ||
|
|
b65433ba99 | ||
|
|
80b393568f | ||
|
|
4d93b592bc | ||
|
|
602c923296 | ||
|
|
f9bf41b69d | ||
|
|
9a5ab32d0d |
50
Cargo.lock
generated
50
Cargo.lock
generated
@@ -1226,6 +1226,18 @@ version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
|
||||
|
||||
[[package]]
|
||||
name = "light-poseidon"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39e3d87542063daaccbfecd78b60f988079b6ec4e089249658b9455075c78d42"
|
||||
dependencies = [
|
||||
"ark-bn254",
|
||||
"ark-ff 0.5.0",
|
||||
"num-bigint",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "litrs"
|
||||
version = "0.4.1"
|
||||
@@ -1415,7 +1427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror",
|
||||
"thiserror 2.0.12",
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
@@ -1564,13 +1576,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.0"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
"zerocopy 0.8.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1706,7 +1717,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sled",
|
||||
"thiserror",
|
||||
"thiserror 2.0.12",
|
||||
"tiny-keccak",
|
||||
"zerokit_utils",
|
||||
]
|
||||
@@ -1770,7 +1781,7 @@ dependencies = [
|
||||
"primitive-types",
|
||||
"proptest",
|
||||
"rand 0.8.5",
|
||||
"rand 0.9.0",
|
||||
"rand 0.9.1",
|
||||
"rlp",
|
||||
"ruint-macro",
|
||||
"serde",
|
||||
@@ -2008,13 +2019,33 @@ version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2537,8 +2568,13 @@ dependencies = [
|
||||
"hex",
|
||||
"hex-literal",
|
||||
"lazy_static",
|
||||
"light-poseidon",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"rand 0.9.1",
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
"rln",
|
||||
"serde",
|
||||
"sled",
|
||||
"tiny-keccak",
|
||||
|
||||
2
Makefile
2
Makefile
@@ -26,7 +26,7 @@ endif
|
||||
[ -s "$$NVM_DIR/nvm.sh" ] && \. "$$NVM_DIR/nvm.sh" && \
|
||||
nvm install 22.14.0 && \
|
||||
nvm use 22.14.0'
|
||||
@curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
@cargo install wasm-pack
|
||||
@echo "\033[1;32m>>> Now run this command to activate Node.js 22.14.0: \033[1;33msource $$HOME/.nvm/nvm.sh && nvm use 22.14.0\033[0m"
|
||||
|
||||
build: .pre-build
|
||||
|
||||
23
flake.lock
generated
23
flake.lock
generated
@@ -18,7 +18,28 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1745289264,
|
||||
"narHash": "sha256-7nt+UJ7qaIUe2J7BdnEEph9n2eKEwxUwKS/QIr091uA=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "3b7171858c20d5293360042936058fb0c4cb93a9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
25
flake.nix
25
flake.nix
@@ -4,9 +4,13 @@
|
||||
inputs = {
|
||||
# Version 24.11
|
||||
nixpkgs.url = "github:NixOS/nixpkgs?rev=f44bd8ca21e026135061a0a57dcf3d0775b67a49";
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs }:
|
||||
outputs = { self, nixpkgs, rust-overlay }:
|
||||
let
|
||||
stableSystems = [
|
||||
"x86_64-linux" "aarch64-linux"
|
||||
@@ -15,7 +19,8 @@
|
||||
"i686-windows"
|
||||
];
|
||||
forAllSystems = nixpkgs.lib.genAttrs stableSystems;
|
||||
pkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgsFor = forAllSystems (system: import nixpkgs { inherit system overlays; });
|
||||
in rec
|
||||
{
|
||||
packages = forAllSystems (system: let
|
||||
@@ -29,9 +34,21 @@
|
||||
pkgs = pkgsFor.${system};
|
||||
in {
|
||||
default = pkgs.mkShell {
|
||||
inputsFrom = [
|
||||
packages.${system}.default
|
||||
buildInputs = with pkgs; [
|
||||
git
|
||||
cmake
|
||||
rustup
|
||||
cargo-make
|
||||
gnuplot
|
||||
xz
|
||||
wasm-pack
|
||||
rust-bin.stable.latest.default
|
||||
];
|
||||
# Shared library liblzma.so.5 used by wasm-pack
|
||||
shellHook = ''
|
||||
xz_lib=$(nix-store -q --references $(which xz) | grep xz)
|
||||
export LD_LIBRARY_PATH=$xz_lib/lib:$LD_LIBRARY_PATH
|
||||
'';
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@ sled = "0.34.7"
|
||||
serde = "1.0"
|
||||
lazy_static = "1.5.0"
|
||||
hex = "0.4"
|
||||
light-poseidon = "0.3.0"
|
||||
|
||||
[dev-dependencies]
|
||||
ark-bn254 = { version = "0.5.0", features = ["std"] }
|
||||
@@ -31,6 +32,10 @@ num-traits = "0.2.19"
|
||||
hex-literal = "1.0.0"
|
||||
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
|
||||
criterion = { version = "0.4.0", features = ["html_reports"] }
|
||||
rand = "0.9.1"
|
||||
rand_chacha = "0.9.0"
|
||||
rand_core = "0.9.3"
|
||||
rln = { path = "../rln", default-features = false }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -2,7 +2,14 @@ use ark_bn254::Fr;
|
||||
use criterion::{
|
||||
black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput,
|
||||
};
|
||||
use zerokit_utils::Poseidon;
|
||||
use light_poseidon::{
|
||||
PoseidonHasher as LPoseidonHasher, PoseidonParameters as LPoseidonParameters,
|
||||
};
|
||||
use rand::RngCore;
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
use rand_core::SeedableRng;
|
||||
use rln::utils::bytes_le_to_fr;
|
||||
use zerokit_utils::{Poseidon, RoundParameters};
|
||||
|
||||
const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [
|
||||
(2, 8, 56, 0),
|
||||
@@ -15,42 +22,81 @@ const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [
|
||||
(9, 8, 63, 0),
|
||||
];
|
||||
|
||||
struct U256Stream {
|
||||
rng: ChaCha8Rng,
|
||||
}
|
||||
impl U256Stream {
|
||||
fn seeded_stream(seed: u64) -> Self {
|
||||
let rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
Self { rng }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for U256Stream {
|
||||
type Item = [u8; 32];
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut res = [0; 32];
|
||||
self.rng.fill_bytes(&mut res);
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn poseidon_benchmark(c: &mut Criterion) {
|
||||
let hasher = Poseidon::<Fr>::from(&ROUND_PARAMS);
|
||||
let mut group = c.benchmark_group("poseidon Fr");
|
||||
|
||||
for size in [10u32, 100, 1000].iter() {
|
||||
// group.measurement_time(std::time::Duration::from_secs(30));
|
||||
for size in [1u32, 2].iter() {
|
||||
group.throughput(Throughput::Elements(*size as u64));
|
||||
let vals = U256Stream::seeded_stream(*size as u64)
|
||||
.take(*size as usize)
|
||||
.map(|b| bytes_le_to_fr(&b).0)
|
||||
.collect::<Vec<_>>();
|
||||
let RoundParameters {
|
||||
t,
|
||||
n_rounds_full,
|
||||
n_rounds_partial,
|
||||
skip_matrices: _,
|
||||
ark_consts,
|
||||
mds,
|
||||
} = hasher.select_params(&vals).unwrap();
|
||||
|
||||
group.bench_with_input(BenchmarkId::new("Array hash", size), size, |b, &size| {
|
||||
group.bench_function(BenchmarkId::new("Array hash light", size), |b| {
|
||||
b.iter_batched(
|
||||
// Setup: create values for each benchmark iteration
|
||||
// setup
|
||||
|| {
|
||||
let mut values = Vec::with_capacity(size as usize);
|
||||
for i in 0..size {
|
||||
values.push([Fr::from(i)]);
|
||||
}
|
||||
values
|
||||
// this needs to be done here due to move/copy/etc issues.
|
||||
let l_params = LPoseidonParameters {
|
||||
ark: ark_consts.clone(),
|
||||
mds: mds.clone(),
|
||||
full_rounds: *n_rounds_full,
|
||||
partial_rounds: *n_rounds_partial,
|
||||
width: *t,
|
||||
alpha: 5,
|
||||
};
|
||||
|
||||
light_poseidon::Poseidon::<Fr>::new(l_params)
|
||||
},
|
||||
// Actual benchmark
|
||||
|values| {
|
||||
for v in values.iter() {
|
||||
let _ = hasher.hash(black_box(&v[..]));
|
||||
}
|
||||
},
|
||||
|mut light_hasher| black_box(light_hasher.hash(&vals)),
|
||||
BatchSize::SmallInput,
|
||||
)
|
||||
});
|
||||
group.bench_function(BenchmarkId::new("Array hash ift", size), |b| {
|
||||
b.iter(|| black_box(hasher.hash(&vals)))
|
||||
});
|
||||
group.bench_function(BenchmarkId::new("Array hash light_circom", size), |b| {
|
||||
b.iter_batched(
|
||||
// setup
|
||||
|| light_poseidon::Poseidon::<Fr>::new_circom(*size as usize).unwrap(),
|
||||
// Actual benchmark
|
||||
|mut light_hasher_circom| black_box(light_hasher_circom.hash(&vals)),
|
||||
BatchSize::SmallInput,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
// Benchmark single hash operation separately
|
||||
group.bench_function("Single hash", |b| {
|
||||
let input = [Fr::from(u64::MAX)];
|
||||
b.iter(|| {
|
||||
let _ = hasher.hash(black_box(&input[..]));
|
||||
})
|
||||
});
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
|
||||
@@ -225,37 +225,43 @@ pub fn find_poseidon_ark_and_mds<F: PrimeField>(
|
||||
partial_rounds,
|
||||
);
|
||||
|
||||
let mut ark = Vec::<F>::with_capacity((full_rounds + partial_rounds) as usize);
|
||||
for _ in 0..(full_rounds + partial_rounds) {
|
||||
let values = lfsr.get_field_elements_rejection_sampling::<F>(rate);
|
||||
for el in values {
|
||||
ark.push(el);
|
||||
let ark = {
|
||||
let mut res = Vec::<F>::with_capacity((full_rounds + partial_rounds) as usize);
|
||||
for _ in 0..(full_rounds + partial_rounds) {
|
||||
let values = lfsr.get_field_elements_rejection_sampling::<F>(rate);
|
||||
for el in values {
|
||||
res.push(el);
|
||||
}
|
||||
}
|
||||
}
|
||||
res
|
||||
};
|
||||
|
||||
let mut mds = Vec::<Vec<F>>::with_capacity(rate);
|
||||
mds.resize(rate, vec![F::zero(); rate]);
|
||||
let mds = {
|
||||
let mut res = Vec::<Vec<F>>::with_capacity(rate);
|
||||
res.resize(rate, vec![F::zero(); rate]);
|
||||
|
||||
// Note that we build the MDS matrix generating 2*rate elements. If the matrix built is not secure (see checks with algorithm 1, 2, 3 in reference implementation)
|
||||
// it has to be skipped. Since here we do not implement such algorithm we allow to pass a parameter to skip generations of elements giving unsecure matrixes.
|
||||
// At the moment, the skip_matrices parameter has to be generated from the reference implementation and passed to this function
|
||||
for _ in 0..skip_matrices {
|
||||
let _ = lfsr.get_field_elements_mod_p::<F>(2 * (rate));
|
||||
}
|
||||
|
||||
// a qualifying matrix must satisfy the following requirements
|
||||
// - there is no duplication among the elements in x or y
|
||||
// - there is no i and j such that x[i] + y[j] = p
|
||||
// - the resultant MDS passes all the three tests
|
||||
|
||||
let xs = lfsr.get_field_elements_mod_p::<F>(rate);
|
||||
let ys = lfsr.get_field_elements_mod_p::<F>(rate);
|
||||
|
||||
for i in 0..(rate) {
|
||||
for (j, ys_item) in ys.iter().enumerate().take(rate) {
|
||||
mds[i][j] = (xs[i] + ys_item).inverse().unwrap();
|
||||
// Note that we build the MDS matrix generating 2*rate elements. If the matrix built is not secure (see checks with algorithm 1, 2, 3 in reference implementation)
|
||||
// it has to be skipped. Since here we do not implement such algorithm we allow to pass a parameter to skip generations of elements giving unsecure matrixes.
|
||||
// At the moment, the skip_matrices parameter has to be generated from the reference implementation and passed to this function
|
||||
for _ in 0..skip_matrices {
|
||||
let _ = lfsr.get_field_elements_mod_p::<F>(2 * (rate));
|
||||
}
|
||||
}
|
||||
|
||||
// a qualifying matrix must satisfy the following requirements
|
||||
// - there is no duplication among the elements in x or y
|
||||
// - there is no i and j such that x[i] + y[j] = p
|
||||
// - the resultant MDS passes all the three tests
|
||||
|
||||
let xs = lfsr.get_field_elements_mod_p::<F>(rate);
|
||||
let ys = lfsr.get_field_elements_mod_p::<F>(rate);
|
||||
|
||||
for i in 0..(rate) {
|
||||
for (j, ys_item) in ys.iter().enumerate().take(rate) {
|
||||
res[i][j] = (xs[i] + ys_item).inverse().unwrap();
|
||||
}
|
||||
}
|
||||
res
|
||||
};
|
||||
|
||||
(ark, mds)
|
||||
}
|
||||
|
||||
@@ -8,49 +8,80 @@ use ark_ff::PrimeField;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct RoundParameters<F: PrimeField> {
|
||||
// confirm: Is this "rate"? does this correlate with light-poseidon "width" parameter?
|
||||
pub t: usize,
|
||||
pub n_rounds_f: usize,
|
||||
pub n_rounds_p: usize,
|
||||
pub n_rounds_full: usize,
|
||||
pub n_rounds_partial: usize,
|
||||
pub skip_matrices: usize,
|
||||
pub c: Vec<F>,
|
||||
pub m: Vec<Vec<F>>,
|
||||
pub ark_consts: Vec<F>,
|
||||
pub mds: Vec<Vec<F>>,
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct RoundParameVec<F: PrimeField> {
|
||||
pub inner: Vec<RoundParameters<F>>,
|
||||
}
|
||||
|
||||
// Dev artifact: helps grok internal params against light-poseidon approach to params
|
||||
// /// Parameters for the Poseidon hash algorithm.
|
||||
// pub struct PoseidonParameters<F: PrimeField> {
|
||||
// /// Round constants.
|
||||
// pub ark: Vec<F>,
|
||||
// /// MDS matrix.
|
||||
// pub mds: Vec<Vec<F>>,
|
||||
// /// Number of full rounds (where S-box is applied to all elements of the
|
||||
// /// state).
|
||||
// pub full_rounds: usize,
|
||||
// /// Number of partial rounds (where S-box is applied only to the first
|
||||
// /// element of the state).
|
||||
// pub partial_rounds: usize,
|
||||
// /// Number of prime fields in the state.
|
||||
// pub width: usize,
|
||||
// /// Exponential used in S-box to power elements of the state.
|
||||
// pub alpha: u64,
|
||||
// }
|
||||
|
||||
pub struct Poseidon<F: PrimeField> {
|
||||
round_params: Vec<RoundParameters<F>>,
|
||||
}
|
||||
impl<F: PrimeField> Poseidon<F> {
|
||||
// Loads round parameters and generates round constants
|
||||
// poseidon_params is a vector containing tuples (t, RF, RP, skip_matrices)
|
||||
// where: t is the rate (input length + 1), RF is the number of full rounds, RP is the number of partial rounds
|
||||
// and skip_matrices is a (temporary) parameter used to generate secure MDS matrices (see comments in the description of find_poseidon_ark_and_mds)
|
||||
// TODO: implement automatic generation of round parameters
|
||||
pub fn from(poseidon_params: &[(usize, usize, usize, usize)]) -> Self {
|
||||
|
||||
impl<F: PrimeField> RoundParameVec<F> {
|
||||
fn make_param_vec(poseidon_params: &[(usize, usize, usize, usize)]) -> Self {
|
||||
let mut read_params = Vec::<RoundParameters<F>>::with_capacity(poseidon_params.len());
|
||||
|
||||
for &(t, n_rounds_f, n_rounds_p, skip_matrices) in poseidon_params {
|
||||
for &(t, n_rounds_full, n_rounds_partial, skip_matrices) in poseidon_params {
|
||||
let (ark, mds) = find_poseidon_ark_and_mds::<F>(
|
||||
1, // is_field = 1
|
||||
0, // is_sbox_inverse = 0
|
||||
F::MODULUS_BIT_SIZE as u64,
|
||||
t,
|
||||
n_rounds_f as u64,
|
||||
n_rounds_p as u64,
|
||||
n_rounds_full as u64,
|
||||
n_rounds_partial as u64,
|
||||
skip_matrices,
|
||||
);
|
||||
let rp = RoundParameters {
|
||||
t,
|
||||
n_rounds_p,
|
||||
n_rounds_f,
|
||||
n_rounds_partial,
|
||||
n_rounds_full,
|
||||
skip_matrices,
|
||||
c: ark,
|
||||
m: mds,
|
||||
ark_consts: ark,
|
||||
mds,
|
||||
};
|
||||
read_params.push(rp);
|
||||
}
|
||||
|
||||
Self { inner: read_params }
|
||||
}
|
||||
}
|
||||
impl<F: PrimeField> Poseidon<F> {
|
||||
// Loads round parameters and generates round constants
|
||||
// poseidon_params is a vector containing tuples (t, n_rounds_full, n_rounds_partial, skip_matrices)
|
||||
// where t is the rate (input length + 1)
|
||||
// and skip_matrices is a (temporary) parameter used to generate secure MDS matrices (see comments in the description of find_poseidon_ark_and_mds)
|
||||
// TODO: implement automatic generation of round parameters
|
||||
pub fn from(poseidon_params: &[(usize, usize, usize, usize)]) -> Self {
|
||||
let param_vec = RoundParameVec::make_param_vec(poseidon_params);
|
||||
// dbg!(¶m_vec.inner);
|
||||
Poseidon {
|
||||
round_params: read_params,
|
||||
round_params: param_vec.inner,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,38 +123,29 @@ impl<F: PrimeField> Poseidon<F> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hash(&self, inp: &[F]) -> Result<F, String> {
|
||||
pub fn select_params(&self, inp: &[F]) -> Result<&RoundParameters<F>, String> {
|
||||
if inp.is_empty() {
|
||||
return Err("Attempt to hash empty data input".to_string());
|
||||
}
|
||||
// Note that the rate t becomes input length + 1; hence for length N we pick parameters with T = N + 1
|
||||
let t = inp.len() + 1;
|
||||
self.round_params
|
||||
.iter()
|
||||
.find(|el| el.t == t)
|
||||
.ok_or("No parameters found for inputs length".to_string())
|
||||
}
|
||||
|
||||
// We seek the index (Poseidon's round_params is an ordered vector) for the parameters corresponding to t
|
||||
let param_index = self.round_params.iter().position(|el| el.t == t);
|
||||
pub fn hash(&self, inp: &[F]) -> Result<F, String> {
|
||||
let params = self.select_params(inp)?;
|
||||
let mut state = Vec::with_capacity(inp.len() + 1);
|
||||
state.push(F::ZERO);
|
||||
state.extend_from_slice(inp);
|
||||
let mut state_2 = vec![F::ZERO; inp.len() + 1];
|
||||
|
||||
if inp.is_empty() || param_index.is_none() {
|
||||
return Err("No parameters found for inputs length".to_string());
|
||||
}
|
||||
|
||||
let param_index = param_index.unwrap();
|
||||
|
||||
let mut state = vec![F::ZERO; t];
|
||||
let mut state_2 = state.clone();
|
||||
state[1..].clone_from_slice(inp);
|
||||
|
||||
for i in 0..(self.round_params[param_index].n_rounds_f
|
||||
+ self.round_params[param_index].n_rounds_p)
|
||||
{
|
||||
self.ark(
|
||||
&mut state,
|
||||
&self.round_params[param_index].c,
|
||||
i * self.round_params[param_index].t,
|
||||
);
|
||||
self.sbox(
|
||||
self.round_params[param_index].n_rounds_f,
|
||||
self.round_params[param_index].n_rounds_p,
|
||||
&mut state,
|
||||
i,
|
||||
);
|
||||
self.mix_2(&state, &self.round_params[param_index].m, &mut state_2);
|
||||
for i in 0..(params.n_rounds_full + params.n_rounds_partial) {
|
||||
self.ark(&mut state, ¶ms.ark_consts, i * params.t);
|
||||
self.sbox(params.n_rounds_full, params.n_rounds_partial, &mut state, i);
|
||||
self.mix_2(&state, ¶ms.mds, &mut state_2);
|
||||
std::mem::swap(&mut state, &mut state_2);
|
||||
}
|
||||
|
||||
@@ -140,3 +162,41 @@ where
|
||||
Self::from(&[])
|
||||
}
|
||||
}
|
||||
|
||||
// WIP artifact
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use ark_bn254::Fr;
|
||||
|
||||
use super::*;
|
||||
const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [
|
||||
(2, 8, 56, 0),
|
||||
(3, 8, 57, 0),
|
||||
(4, 8, 56, 0),
|
||||
(5, 8, 60, 0),
|
||||
(6, 8, 60, 0),
|
||||
(7, 8, 63, 0),
|
||||
(8, 8, 64, 0),
|
||||
(9, 8, 63, 0),
|
||||
];
|
||||
// #[test]
|
||||
// fn see_params() {
|
||||
// let mut param_vec = RoundParameVec::<Fr>::make_param_vec(&ROUND_PARAMS);
|
||||
// let stats /* (rate, fulls, partual, sm, ark_n, mds_n) */ = param_vec.inner.into_iter().map(|RoundParameters { rate, n_rounds_full, n_rounds_partial, skip_matrices, ark_consts, mds }| (rate, n_rounds_full, n_rounds_partial, skip_matrices, ark_consts.len(), mds.len())).collect::<Vec<_>>();
|
||||
// println!("r f p s cl ml");
|
||||
// for s in stats.iter() {
|
||||
// println!("{:?}", s);
|
||||
// }
|
||||
// panic!();
|
||||
// }
|
||||
// #[test]
|
||||
// fn see_data() {
|
||||
// let size = 10;
|
||||
// let mut param_vec = RoundParameVec::<Fr>::make_param_vec(&ROUND_PARAMS);
|
||||
// let mut values = Vec::with_capacity(size as usize);
|
||||
// for i in 0..size {
|
||||
// values.push([Fr::from(u128::MAX - i)]);
|
||||
// }
|
||||
// panic!("{:?}", values);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -3533,8 +3533,8 @@ mod test {
|
||||
let poseidon_hasher = Poseidon::<Fr>::from(&ROUND_PARAMS);
|
||||
let poseidon_parameters = poseidon_hasher.get_parameters();
|
||||
for i in 0..poseidon_parameters.len() {
|
||||
assert_eq!(loaded_c[i], poseidon_parameters[i].c);
|
||||
assert_eq!(loaded_m[i], poseidon_parameters[i].m);
|
||||
assert_eq!(loaded_c[i], poseidon_parameters[i].ark_consts);
|
||||
assert_eq!(loaded_m[i], poseidon_parameters[i].mds);
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
|
||||
Reference in New Issue
Block a user