Skip to content

Commit

Permalink
Rename PoseidonHasherChip to PoseidonHasher
Browse files Browse the repository at this point in the history
  • Loading branch information
nyunyunyunyu committed Aug 18, 2023
1 parent 3bacff7 commit 00e3ebc
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 122 deletions.
File renamed without changes.
116 changes: 116 additions & 0 deletions halo2-base/src/poseidon/hasher/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use std::mem;

use crate::{
gates::GateInstructions,
poseidon::hasher::{spec::OptimizedPoseidonSpec, state::PoseidonState},
AssignedValue, Context, ScalarField,
};

#[cfg(test)]
mod tests;

/// Module for maximum distance separable matrix operations.
pub mod mds;
/// Module for poseidon specification.
pub mod spec;
/// Module for poseidon states.
pub mod state;

/// Poseidon hasher. This is stateful.
pub struct PoseidonHasher<F: ScalarField, const T: usize, const RATE: usize> {
init_state: PoseidonState<F, T, RATE>,
state: PoseidonState<F, T, RATE>,
spec: OptimizedPoseidonSpec<F, T, RATE>,
absorbing: Vec<AssignedValue<F>>,
}

impl<F: ScalarField, const T: usize, const RATE: usize> PoseidonHasher<F, T, RATE> {
/// Create new Poseidon hasher.
pub fn new<const R_F: usize, const R_P: usize, const SECURE_MDS: usize>(
ctx: &mut Context<F>,
) -> Self {
let init_state = PoseidonState::default(ctx);
let state = init_state.clone();
Self {
init_state,
state,
spec: OptimizedPoseidonSpec::new::<R_F, R_P, SECURE_MDS>(),
absorbing: Vec::new(),
}
}

/// Initialize a poseidon hasher from an existing spec.
pub fn from_spec(ctx: &mut Context<F>, spec: OptimizedPoseidonSpec<F, T, RATE>) -> Self {
let init_state = PoseidonState::default(ctx);
Self { spec, state: init_state.clone(), init_state, absorbing: Vec::new() }
}

/// Reset state to default and clear the buffer.
pub fn clear(&mut self) {
self.state = self.init_state.clone();
self.absorbing.clear();
}

/// Store given `elements` into buffer.
pub fn update(&mut self, elements: &[AssignedValue<F>]) {
self.absorbing.extend_from_slice(elements);
}

/// Consume buffer and perform permutation, then output second element of
/// state.
pub fn squeeze(
&mut self,
ctx: &mut Context<F>,
gate: &impl GateInstructions<F>,
) -> AssignedValue<F> {
let input_elements = mem::take(&mut self.absorbing);
let exact = input_elements.len() % RATE == 0;

for chunk in input_elements.chunks(RATE) {
self.permutation(ctx, gate, chunk.to_vec());
}
if exact {
self.permutation(ctx, gate, vec![]);
}

self.state.s[1]
}

fn permutation(
&mut self,
ctx: &mut Context<F>,
gate: &impl GateInstructions<F>,
inputs: Vec<AssignedValue<F>>,
) {
let r_f = self.spec.r_f / 2;
let mds = &self.spec.mds_matrices.mds.0;
let pre_sparse_mds = &self.spec.mds_matrices.pre_sparse_mds.0;
let sparse_matrices = &self.spec.mds_matrices.sparse_matrices;

// First half of the full round
let constants = &self.spec.constants.start;
self.state.absorb_with_pre_constants(ctx, gate, inputs, &constants[0]);
for constants in constants.iter().skip(1).take(r_f - 1) {
self.state.sbox_full(ctx, gate, constants);
self.state.apply_mds(ctx, gate, mds);
}
self.state.sbox_full(ctx, gate, constants.last().unwrap());
self.state.apply_mds(ctx, gate, pre_sparse_mds);

// Partial rounds
let constants = &self.spec.constants.partial;
for (constant, sparse_mds) in constants.iter().zip(sparse_matrices.iter()) {
self.state.sbox_part(ctx, gate, constant);
self.state.apply_sparse_mds(ctx, gate, sparse_mds);
}

// Second half of the full rounds
let constants = &self.spec.constants.end;
for constants in constants.iter() {
self.state.sbox_full(ctx, gate, constants);
self.state.apply_mds(ctx, gate, mds);
}
self.state.sbox_full(ctx, gate, &[F::ZERO; T]);
self.state.apply_mds(ctx, gate, mds);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{poseidon::mds::*, utils::ScalarField};
use crate::{poseidon::hasher::mds::*, utils::ScalarField};

use poseidon_rs::poseidon::primitives::Spec as PoseidonSpec; // trait
use std::marker::PhantomData;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::iter;

use crate::{
gates::GateInstructions,
poseidon::mds::SparseMDSMatrix,
poseidon::hasher::mds::SparseMDSMatrix,
utils::ScalarField,
AssignedValue, Context,
QuantumCell::{Constant, Existing},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{cmp::max, iter::zip};
use crate::{
gates::{builder::GateThreadBuilder, GateChip},
halo2_proofs::halo2curves::bn256::Fr,
poseidon::PoseidonHasherChip,
poseidon::hasher::PoseidonHasher,
utils::ScalarField,
};
use pse_poseidon::Poseidon;
Expand Down Expand Up @@ -31,7 +31,7 @@ fn poseidon_compatiblity_verification<
// constructing native and in-circuit Poseidon sponges
let mut native_sponge = Poseidon::<F, T, RATE>::new(R_F, R_P);
// assuming SECURE_MDS = 0
let mut circuit_sponge = PoseidonHasherChip::<F, T, RATE>::new::<R_F, R_P, 0>(ctx);
let mut circuit_sponge = PoseidonHasher::<F, T, RATE>::new::<R_F, R_P, 0>(ctx);

// preparing to interleave absorptions and squeezings
let n_iterations = max(absorptions.len(), squeezings.len());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn test_poseidon_against_test_vectors() {
const T: usize = 3;
const RATE: usize = 2;

let mut hasher = PoseidonHasherChip::<Fr, T, RATE>::new::<R_F, R_P, 0>(ctx);
let mut hasher = PoseidonHasher::<Fr, T, RATE>::new::<R_F, R_P, 0>(ctx);

let state = [0u64, 1, 2];
hasher.state =
Expand All @@ -76,7 +76,7 @@ fn test_poseidon_against_test_vectors() {
const T: usize = 5;
const RATE: usize = 4;

let mut hasher = PoseidonHasherChip::<Fr, T, RATE>::new::<R_F, R_P, 0>(ctx);
let mut hasher = PoseidonHasher::<Fr, T, RATE>::new::<R_F, R_P, 0>(ctx);

let state = [0u64, 1, 2, 3, 4];
hasher.state =
Expand Down
118 changes: 2 additions & 116 deletions halo2-base/src/poseidon/mod.rs
Original file line number Diff line number Diff line change
@@ -1,116 +1,2 @@
use std::mem;

use crate::{
gates::GateInstructions,
poseidon::{spec::OptimizedPoseidonSpec, state::PoseidonState},
AssignedValue, Context, ScalarField,
};

#[cfg(test)]
mod tests;

/// Module for maximum distance separable matrix operations.
pub mod mds;
/// Module for poseidon specification.
pub mod spec;
/// Module for poseidon states.
pub mod state;

/// Chip for Poseidon hasher. The chip is stateful.
pub struct PoseidonHasherChip<F: ScalarField, const T: usize, const RATE: usize> {
init_state: PoseidonState<F, T, RATE>,
state: PoseidonState<F, T, RATE>,
spec: OptimizedPoseidonSpec<F, T, RATE>,
absorbing: Vec<AssignedValue<F>>,
}

impl<F: ScalarField, const T: usize, const RATE: usize> PoseidonHasherChip<F, T, RATE> {
/// Create new Poseidon hasher chip.
pub fn new<const R_F: usize, const R_P: usize, const SECURE_MDS: usize>(
ctx: &mut Context<F>,
) -> Self {
let init_state = PoseidonState::default(ctx);
let state = init_state.clone();
Self {
init_state,
state,
spec: OptimizedPoseidonSpec::new::<R_F, R_P, SECURE_MDS>(),
absorbing: Vec::new(),
}
}

/// Initialize a poseidon hasher from an existing spec.
pub fn from_spec(ctx: &mut Context<F>, spec: OptimizedPoseidonSpec<F, T, RATE>) -> Self {
let init_state = PoseidonState::default(ctx);
Self { spec, state: init_state.clone(), init_state, absorbing: Vec::new() }
}

/// Reset state to default and clear the buffer.
pub fn clear(&mut self) {
self.state = self.init_state.clone();
self.absorbing.clear();
}

/// Store given `elements` into buffer.
pub fn update(&mut self, elements: &[AssignedValue<F>]) {
self.absorbing.extend_from_slice(elements);
}

/// Consume buffer and perform permutation, then output second element of
/// state.
pub fn squeeze(
&mut self,
ctx: &mut Context<F>,
gate: &impl GateInstructions<F>,
) -> AssignedValue<F> {
let input_elements = mem::take(&mut self.absorbing);
let exact = input_elements.len() % RATE == 0;

for chunk in input_elements.chunks(RATE) {
self.permutation(ctx, gate, chunk.to_vec());
}
if exact {
self.permutation(ctx, gate, vec![]);
}

self.state.s[1]
}

fn permutation(
&mut self,
ctx: &mut Context<F>,
gate: &impl GateInstructions<F>,
inputs: Vec<AssignedValue<F>>,
) {
let r_f = self.spec.r_f / 2;
let mds = &self.spec.mds_matrices.mds.0;
let pre_sparse_mds = &self.spec.mds_matrices.pre_sparse_mds.0;
let sparse_matrices = &self.spec.mds_matrices.sparse_matrices;

// First half of the full round
let constants = &self.spec.constants.start;
self.state.absorb_with_pre_constants(ctx, gate, inputs, &constants[0]);
for constants in constants.iter().skip(1).take(r_f - 1) {
self.state.sbox_full(ctx, gate, constants);
self.state.apply_mds(ctx, gate, mds);
}
self.state.sbox_full(ctx, gate, constants.last().unwrap());
self.state.apply_mds(ctx, gate, pre_sparse_mds);

// Partial rounds
let constants = &self.spec.constants.partial;
for (constant, sparse_mds) in constants.iter().zip(sparse_matrices.iter()) {
self.state.sbox_part(ctx, gate, constant);
self.state.apply_sparse_mds(ctx, gate, sparse_mds);
}

// Second half of the full rounds
let constants = &self.spec.constants.end;
for constants in constants.iter() {
self.state.sbox_full(ctx, gate, constants);
self.state.apply_mds(ctx, gate, mds);
}
self.state.sbox_full(ctx, gate, &[F::ZERO; T]);
self.state.apply_mds(ctx, gate, mds);
}
}
/// Module for Poseidon hasher
pub mod hasher;

0 comments on commit 00e3ebc

Please sign in to comment.