mirror of https://github.com/zcash/halo2.git
poseidon: Replace the `Duplex` struct with a `Sponge` struct
The `Sponge` struct's API correctly enforces the properties of a sponge: it can absorb an arbitrary number of elements, and then squeeze an arbitrary number of elements, but cannot absorb after it has squeezed. Co-authored-by: ying tong <yingtong@z.cash>
This commit is contained in:
parent
b827298d42
commit
9f654005c7
|
@ -3,6 +3,7 @@
|
||||||
use std::array;
|
use std::array;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use halo2::{
|
use halo2::{
|
||||||
arithmetic::FieldExt,
|
arithmetic::FieldExt,
|
||||||
|
@ -13,7 +14,9 @@ use halo2::{
|
||||||
mod pow5;
|
mod pow5;
|
||||||
pub use pow5::{Pow5Chip, Pow5Config, StateWord};
|
pub use pow5::{Pow5Chip, Pow5Config, StateWord};
|
||||||
|
|
||||||
use crate::primitives::poseidon::{ConstantLength, Domain, Spec, Sponge, SpongeRate, State};
|
use crate::primitives::poseidon::{
|
||||||
|
Absorbing, ConstantLength, Domain, Spec, SpongeMode, SpongeRate, Squeezing, State,
|
||||||
|
};
|
||||||
|
|
||||||
/// The set of circuit instructions required to use the Poseidon permutation.
|
/// The set of circuit instructions required to use the Poseidon permutation.
|
||||||
pub trait PoseidonInstructions<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize>:
|
pub trait PoseidonInstructions<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize>:
|
||||||
|
@ -30,10 +33,10 @@ pub trait PoseidonInstructions<F: FieldExt, S: Spec<F, T, RATE>, const T: usize,
|
||||||
) -> Result<State<Self::Word, T>, Error>;
|
) -> Result<State<Self::Word, T>, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The set of circuit instructions required to use the [`Duplex`] and [`Hash`] gadgets.
|
/// The set of circuit instructions required to use the [`Sponge`] and [`Hash`] gadgets.
|
||||||
///
|
///
|
||||||
/// [`Hash`]: self::Hash
|
/// [`Hash`]: self::Hash
|
||||||
pub trait PoseidonDuplexInstructions<
|
pub trait PoseidonSpongeInstructions<
|
||||||
F: FieldExt,
|
F: FieldExt,
|
||||||
S: Spec<F, T, RATE>,
|
S: Spec<F, T, RATE>,
|
||||||
const T: usize,
|
const T: usize,
|
||||||
|
@ -91,9 +94,9 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poseidon_duplex<
|
fn poseidon_sponge<
|
||||||
F: FieldExt,
|
F: FieldExt,
|
||||||
PoseidonChip: PoseidonDuplexInstructions<F, S, T, RATE>,
|
PoseidonChip: PoseidonSpongeInstructions<F, S, T, RATE>,
|
||||||
S: Spec<F, T, RATE>,
|
S: Spec<F, T, RATE>,
|
||||||
D: Domain<F, T, RATE>,
|
D: Domain<F, T, RATE>,
|
||||||
const T: usize,
|
const T: usize,
|
||||||
|
@ -110,30 +113,32 @@ fn poseidon_duplex<
|
||||||
Ok(PoseidonChip::get_output(state))
|
Ok(PoseidonChip::get_output(state))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Poseidon duplex sponge.
|
/// A Poseidon sponge.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Duplex<
|
pub struct Sponge<
|
||||||
F: FieldExt,
|
F: FieldExt,
|
||||||
PoseidonChip: PoseidonDuplexInstructions<F, S, T, RATE>,
|
PoseidonChip: PoseidonSpongeInstructions<F, S, T, RATE>,
|
||||||
S: Spec<F, T, RATE>,
|
S: Spec<F, T, RATE>,
|
||||||
|
M: SpongeMode,
|
||||||
D: Domain<F, T, RATE>,
|
D: Domain<F, T, RATE>,
|
||||||
const T: usize,
|
const T: usize,
|
||||||
const RATE: usize,
|
const RATE: usize,
|
||||||
> {
|
> {
|
||||||
chip: PoseidonChip,
|
chip: PoseidonChip,
|
||||||
sponge: Sponge<PoseidonChip::Word, RATE>,
|
mode: M,
|
||||||
state: State<PoseidonChip::Word, T>,
|
state: State<PoseidonChip::Word, T>,
|
||||||
domain: D,
|
domain: D,
|
||||||
|
_marker: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: FieldExt,
|
F: FieldExt,
|
||||||
PoseidonChip: PoseidonDuplexInstructions<F, S, T, RATE>,
|
PoseidonChip: PoseidonSpongeInstructions<F, S, T, RATE>,
|
||||||
S: Spec<F, T, RATE>,
|
S: Spec<F, T, RATE>,
|
||||||
D: Domain<F, T, RATE>,
|
D: Domain<F, T, RATE>,
|
||||||
const T: usize,
|
const T: usize,
|
||||||
const RATE: usize,
|
const RATE: usize,
|
||||||
> Duplex<F, PoseidonChip, S, D, T, RATE>
|
> Sponge<F, PoseidonChip, S, Absorbing<PoseidonChip::Word, RATE>, D, T, RATE>
|
||||||
{
|
{
|
||||||
/// Constructs a new duplex sponge for the given Poseidon specification.
|
/// Constructs a new duplex sponge for the given Poseidon specification.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
@ -142,9 +147,9 @@ impl<
|
||||||
domain: D,
|
domain: D,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
chip.initial_state(&mut layouter, &domain)
|
chip.initial_state(&mut layouter, &domain)
|
||||||
.map(|state| Duplex {
|
.map(|state| Sponge {
|
||||||
chip,
|
chip,
|
||||||
sponge: Sponge::Absorbing(
|
mode: Absorbing(
|
||||||
(0..RATE)
|
(0..RATE)
|
||||||
.map(|_| None)
|
.map(|_| None)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
@ -153,6 +158,7 @@ impl<
|
||||||
),
|
),
|
||||||
state,
|
state,
|
||||||
domain,
|
domain,
|
||||||
|
_marker: PhantomData::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,9 +168,7 @@ impl<
|
||||||
mut layouter: impl Layouter<F>,
|
mut layouter: impl Layouter<F>,
|
||||||
value: AssignedCell<F, F>,
|
value: AssignedCell<F, F>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match self.sponge {
|
for entry in self.mode.0.iter_mut() {
|
||||||
Sponge::Absorbing(ref mut input) => {
|
|
||||||
for entry in input.iter_mut() {
|
|
||||||
if entry.is_none() {
|
if entry.is_none() {
|
||||||
*entry = Some(value.into());
|
*entry = Some(value.into());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -172,74 +176,89 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
// We've already absorbed as many elements as we can
|
// We've already absorbed as many elements as we can
|
||||||
let _ = poseidon_duplex(
|
let _ = poseidon_sponge(
|
||||||
&self.chip,
|
&self.chip,
|
||||||
layouter.namespace(|| "PoseidonDuplex"),
|
layouter.namespace(|| "PoseidonSponge"),
|
||||||
&self.domain,
|
&self.domain,
|
||||||
&mut self.state,
|
&mut self.state,
|
||||||
input,
|
&self.mode.0,
|
||||||
)?;
|
)?;
|
||||||
self.sponge = Sponge::absorb(value.into());
|
self.mode = Absorbing::init_with(value.into());
|
||||||
}
|
|
||||||
Sponge::Squeezing(_) => {
|
|
||||||
// Drop the remaining output elements
|
|
||||||
self.sponge = Sponge::absorb(value.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transitions the sponge into its squeezing state.
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub fn finish_absorbing(
|
||||||
|
mut self,
|
||||||
|
mut layouter: impl Layouter<F>,
|
||||||
|
) -> Result<Sponge<F, PoseidonChip, S, Squeezing<PoseidonChip::Word, RATE>, D, T, RATE>, Error>
|
||||||
|
{
|
||||||
|
let mode = Squeezing(poseidon_sponge(
|
||||||
|
&self.chip,
|
||||||
|
layouter.namespace(|| "PoseidonSponge"),
|
||||||
|
&self.domain,
|
||||||
|
&mut self.state,
|
||||||
|
&self.mode.0,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
Ok(Sponge {
|
||||||
|
chip: self.chip,
|
||||||
|
mode,
|
||||||
|
state: self.state,
|
||||||
|
domain: self.domain,
|
||||||
|
_marker: PhantomData::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
F: FieldExt,
|
||||||
|
PoseidonChip: PoseidonSpongeInstructions<F, S, T, RATE>,
|
||||||
|
S: Spec<F, T, RATE>,
|
||||||
|
D: Domain<F, T, RATE>,
|
||||||
|
const T: usize,
|
||||||
|
const RATE: usize,
|
||||||
|
> Sponge<F, PoseidonChip, S, Squeezing<PoseidonChip::Word, RATE>, D, T, RATE>
|
||||||
|
{
|
||||||
/// Squeezes an element from the sponge.
|
/// Squeezes an element from the sponge.
|
||||||
pub fn squeeze(&mut self, mut layouter: impl Layouter<F>) -> Result<AssignedCell<F, F>, Error> {
|
pub fn squeeze(&mut self, mut layouter: impl Layouter<F>) -> Result<AssignedCell<F, F>, Error> {
|
||||||
loop {
|
loop {
|
||||||
match self.sponge {
|
for entry in self.mode.0.iter_mut() {
|
||||||
Sponge::Absorbing(ref input) => {
|
|
||||||
self.sponge = Sponge::Squeezing(poseidon_duplex(
|
|
||||||
&self.chip,
|
|
||||||
layouter.namespace(|| "PoseidonDuplex"),
|
|
||||||
&self.domain,
|
|
||||||
&mut self.state,
|
|
||||||
input,
|
|
||||||
)?);
|
|
||||||
}
|
|
||||||
Sponge::Squeezing(ref mut output) => {
|
|
||||||
for entry in output.iter_mut() {
|
|
||||||
if let Some(inner) = entry.take() {
|
if let Some(inner) = entry.take() {
|
||||||
return Ok(inner.into());
|
return Ok(inner.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We've already squeezed out all available elements
|
// We've already squeezed out all available elements
|
||||||
self.sponge = Sponge::Absorbing(
|
self.mode = Squeezing(poseidon_sponge(
|
||||||
(0..RATE)
|
&self.chip,
|
||||||
.map(|_| None)
|
layouter.namespace(|| "PoseidonSponge"),
|
||||||
.collect::<Vec<_>>()
|
&self.domain,
|
||||||
.try_into()
|
&mut self.state,
|
||||||
.unwrap(),
|
&self.mode.0,
|
||||||
);
|
)?);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Poseidon hash function, built around a duplex sponge.
|
/// A Poseidon hash function, built around a sponge.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Hash<
|
pub struct Hash<
|
||||||
F: FieldExt,
|
F: FieldExt,
|
||||||
PoseidonChip: PoseidonDuplexInstructions<F, S, T, RATE>,
|
PoseidonChip: PoseidonSpongeInstructions<F, S, T, RATE>,
|
||||||
S: Spec<F, T, RATE>,
|
S: Spec<F, T, RATE>,
|
||||||
D: Domain<F, T, RATE>,
|
D: Domain<F, T, RATE>,
|
||||||
const T: usize,
|
const T: usize,
|
||||||
const RATE: usize,
|
const RATE: usize,
|
||||||
> {
|
> {
|
||||||
duplex: Duplex<F, PoseidonChip, S, D, T, RATE>,
|
sponge: Sponge<F, PoseidonChip, S, Absorbing<PoseidonChip::Word, RATE>, D, T, RATE>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: FieldExt,
|
F: FieldExt,
|
||||||
PoseidonChip: PoseidonDuplexInstructions<F, S, T, RATE>,
|
PoseidonChip: PoseidonSpongeInstructions<F, S, T, RATE>,
|
||||||
S: Spec<F, T, RATE>,
|
S: Spec<F, T, RATE>,
|
||||||
D: Domain<F, T, RATE>,
|
D: Domain<F, T, RATE>,
|
||||||
const T: usize,
|
const T: usize,
|
||||||
|
@ -248,13 +267,13 @@ impl<
|
||||||
{
|
{
|
||||||
/// Initializes a new hasher.
|
/// Initializes a new hasher.
|
||||||
pub fn init(chip: PoseidonChip, layouter: impl Layouter<F>, domain: D) -> Result<Self, Error> {
|
pub fn init(chip: PoseidonChip, layouter: impl Layouter<F>, domain: D) -> Result<Self, Error> {
|
||||||
Duplex::new(chip, layouter, domain).map(|duplex| Hash { duplex })
|
Sponge::new(chip, layouter, domain).map(|sponge| Hash { sponge })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: FieldExt,
|
F: FieldExt,
|
||||||
PoseidonChip: PoseidonDuplexInstructions<F, S, T, RATE>,
|
PoseidonChip: PoseidonSpongeInstructions<F, S, T, RATE>,
|
||||||
S: Spec<F, T, RATE>,
|
S: Spec<F, T, RATE>,
|
||||||
const T: usize,
|
const T: usize,
|
||||||
const RATE: usize,
|
const RATE: usize,
|
||||||
|
@ -268,9 +287,11 @@ impl<
|
||||||
message: [AssignedCell<F, F>; L],
|
message: [AssignedCell<F, F>; L],
|
||||||
) -> Result<AssignedCell<F, F>, Error> {
|
) -> Result<AssignedCell<F, F>, Error> {
|
||||||
for (i, value) in array::IntoIter::new(message).enumerate() {
|
for (i, value) in array::IntoIter::new(message).enumerate() {
|
||||||
self.duplex
|
self.sponge
|
||||||
.absorb(layouter.namespace(|| format!("absorb_{}", i)), value)?;
|
.absorb(layouter.namespace(|| format!("absorb_{}", i)), value)?;
|
||||||
}
|
}
|
||||||
self.duplex.squeeze(layouter.namespace(|| "squeeze"))
|
self.sponge
|
||||||
|
.finish_absorbing(layouter.namespace(|| "finish absorbing"))?
|
||||||
|
.squeeze(layouter.namespace(|| "squeeze"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use halo2::{
|
||||||
poly::Rotation,
|
poly::Rotation,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{PoseidonDuplexInstructions, PoseidonInstructions};
|
use super::{PoseidonInstructions, PoseidonSpongeInstructions};
|
||||||
use crate::circuit::gadget::utilities::Var;
|
use crate::circuit::gadget::utilities::Var;
|
||||||
use crate::primitives::poseidon::{Domain, Mds, Spec, SpongeRate, State};
|
use crate::primitives::poseidon::{Domain, Mds, Spec, SpongeRate, State};
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize>
|
impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize>
|
||||||
PoseidonDuplexInstructions<F, S, WIDTH, RATE> for Pow5Chip<F, WIDTH, RATE>
|
PoseidonSpongeInstructions<F, S, WIDTH, RATE> for Pow5Chip<F, WIDTH, RATE>
|
||||||
{
|
{
|
||||||
fn initial_state(
|
fn initial_state(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -24,7 +24,7 @@ use grain::SboxType;
|
||||||
/// The type used to hold permutation state.
|
/// The type used to hold permutation state.
|
||||||
pub(crate) type State<F, const T: usize> = [F; T];
|
pub(crate) type State<F, const T: usize> = [F; T];
|
||||||
|
|
||||||
/// The type used to hold duplex sponge state.
|
/// The type used to hold sponge rate.
|
||||||
pub(crate) type SpongeRate<F, const RATE: usize> = [Option<F>; RATE];
|
pub(crate) type SpongeRate<F, const RATE: usize> = [Option<F>; RATE];
|
||||||
|
|
||||||
/// The type used to hold the MDS matrix and its inverse.
|
/// The type used to hold the MDS matrix and its inverse.
|
||||||
|
@ -124,7 +124,7 @@ pub(crate) fn permute<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RA
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poseidon_duplex<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize>(
|
fn poseidon_sponge<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize>(
|
||||||
state: &mut State<F, T>,
|
state: &mut State<F, T>,
|
||||||
input: &SpongeRate<F, RATE>,
|
input: &SpongeRate<F, RATE>,
|
||||||
pad_and_add: &dyn Fn(&mut State<F, T>, &SpongeRate<F, RATE>),
|
pad_and_add: &dyn Fn(&mut State<F, T>, &SpongeRate<F, RATE>),
|
||||||
|
@ -142,48 +142,65 @@ fn poseidon_duplex<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE:
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// The state of the [`Sponge`].
|
||||||
pub(crate) enum Sponge<F, const RATE: usize> {
|
// TODO: Seal this trait?
|
||||||
Absorbing(SpongeRate<F, RATE>),
|
pub trait SpongeMode {}
|
||||||
Squeezing(SpongeRate<F, RATE>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: fmt::Debug, const RATE: usize> Sponge<F, RATE> {
|
/// The absorbing state of the [`Sponge`].
|
||||||
pub(crate) fn absorb(val: F) -> Self {
|
#[derive(Debug)]
|
||||||
let mut input: [Option<F>; RATE] = (0..RATE)
|
pub struct Absorbing<F, const RATE: usize>(pub(crate) SpongeRate<F, RATE>);
|
||||||
.map(|_| None)
|
|
||||||
|
/// The squeezing state of the [`Sponge`].
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Squeezing<F, const RATE: usize>(pub(crate) SpongeRate<F, RATE>);
|
||||||
|
|
||||||
|
impl<F, const RATE: usize> SpongeMode for Absorbing<F, RATE> {}
|
||||||
|
impl<F, const RATE: usize> SpongeMode for Squeezing<F, RATE> {}
|
||||||
|
|
||||||
|
impl<F: fmt::Debug, const RATE: usize> Absorbing<F, RATE> {
|
||||||
|
pub(crate) fn init_with(val: F) -> Self {
|
||||||
|
Self(
|
||||||
|
iter::once(Some(val))
|
||||||
|
.chain((1..RATE).map(|_| None))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.try_into()
|
.try_into()
|
||||||
.unwrap();
|
.unwrap(),
|
||||||
input[0] = Some(val);
|
)
|
||||||
Sponge::Absorbing(input)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Poseidon duplex sponge.
|
/// A Poseidon sponge.
|
||||||
pub(crate) struct Duplex<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize> {
|
pub(crate) struct Sponge<
|
||||||
sponge: Sponge<F, RATE>,
|
F: FieldExt,
|
||||||
|
S: Spec<F, T, RATE>,
|
||||||
|
M: SpongeMode,
|
||||||
|
const T: usize,
|
||||||
|
const RATE: usize,
|
||||||
|
> {
|
||||||
|
mode: M,
|
||||||
state: State<F, T>,
|
state: State<F, T>,
|
||||||
pad_and_add: Box<dyn Fn(&mut State<F, T>, &SpongeRate<F, RATE>)>,
|
pad_and_add: Box<dyn Fn(&mut State<F, T>, &SpongeRate<F, RATE>)>,
|
||||||
mds_matrix: Mds<F, T>,
|
mds_matrix: Mds<F, T>,
|
||||||
round_constants: Vec<[F; T]>,
|
round_constants: Vec<[F; T]>,
|
||||||
_marker: PhantomData<S>,
|
_marker: PhantomData<(S, M)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize> Duplex<F, S, T, RATE> {
|
impl<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize>
|
||||||
/// Constructs a new duplex sponge for the given Poseidon specification.
|
Sponge<F, S, Absorbing<F, RATE>, T, RATE>
|
||||||
|
{
|
||||||
|
/// Constructs a new sponge for the given Poseidon specification.
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
initial_capacity_element: F,
|
initial_capacity_element: F,
|
||||||
pad_and_add: Box<dyn Fn(&mut State<F, T>, &SpongeRate<F, RATE>)>,
|
pad_and_add: Box<dyn Fn(&mut State<F, T>, &SpongeRate<F, RATE>)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (round_constants, mds_matrix, _) = S::constants();
|
let (round_constants, mds_matrix, _) = S::constants();
|
||||||
|
|
||||||
let input = [None; RATE];
|
let mode = Absorbing([None; RATE]);
|
||||||
let mut state = [F::zero(); T];
|
let mut state = [F::zero(); T];
|
||||||
state[RATE] = initial_capacity_element;
|
state[RATE] = initial_capacity_element;
|
||||||
|
|
||||||
Duplex {
|
Sponge {
|
||||||
sponge: Sponge::Absorbing(input),
|
mode,
|
||||||
state,
|
state,
|
||||||
pad_and_add,
|
pad_and_add,
|
||||||
mds_matrix,
|
mds_matrix,
|
||||||
|
@ -194,9 +211,7 @@ impl<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize> Duplex
|
||||||
|
|
||||||
/// Absorbs an element into the sponge.
|
/// Absorbs an element into the sponge.
|
||||||
pub(crate) fn absorb(&mut self, value: F) {
|
pub(crate) fn absorb(&mut self, value: F) {
|
||||||
match self.sponge {
|
for entry in self.mode.0.iter_mut() {
|
||||||
Sponge::Absorbing(ref mut input) => {
|
|
||||||
for entry in input.iter_mut() {
|
|
||||||
if entry.is_none() {
|
if entry.is_none() {
|
||||||
*entry = Some(value);
|
*entry = Some(value);
|
||||||
return;
|
return;
|
||||||
|
@ -204,46 +219,57 @@ impl<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize> Duplex
|
||||||
}
|
}
|
||||||
|
|
||||||
// We've already absorbed as many elements as we can
|
// We've already absorbed as many elements as we can
|
||||||
let _ = poseidon_duplex::<F, S, T, RATE>(
|
let _ = poseidon_sponge::<F, S, T, RATE>(
|
||||||
&mut self.state,
|
&mut self.state,
|
||||||
input,
|
&self.mode.0,
|
||||||
&self.pad_and_add,
|
&self.pad_and_add,
|
||||||
&self.mds_matrix,
|
&self.mds_matrix,
|
||||||
&self.round_constants,
|
&self.round_constants,
|
||||||
);
|
);
|
||||||
self.sponge = Sponge::absorb(value);
|
self.mode = Absorbing::init_with(value);
|
||||||
}
|
|
||||||
Sponge::Squeezing(_) => {
|
|
||||||
// Drop the remaining output elements
|
|
||||||
self.sponge = Sponge::absorb(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Squeezes an element from the sponge.
|
/// Transitions the sponge into its squeezing state.
|
||||||
pub(crate) fn squeeze(&mut self) -> F {
|
pub(crate) fn finish_absorbing(mut self) -> Sponge<F, S, Squeezing<F, RATE>, T, RATE> {
|
||||||
loop {
|
let mode = Squeezing(poseidon_sponge::<F, S, T, RATE>(
|
||||||
match self.sponge {
|
|
||||||
Sponge::Absorbing(ref input) => {
|
|
||||||
self.sponge = Sponge::Squeezing(poseidon_duplex::<F, S, T, RATE>(
|
|
||||||
&mut self.state,
|
&mut self.state,
|
||||||
input,
|
&self.mode.0,
|
||||||
&self.pad_and_add,
|
&self.pad_and_add,
|
||||||
&self.mds_matrix,
|
&self.mds_matrix,
|
||||||
&self.round_constants,
|
&self.round_constants,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
Sponge {
|
||||||
|
mode,
|
||||||
|
state: self.state,
|
||||||
|
pad_and_add: self.pad_and_add,
|
||||||
|
mds_matrix: self.mds_matrix,
|
||||||
|
round_constants: self.round_constants,
|
||||||
|
_marker: PhantomData::default(),
|
||||||
}
|
}
|
||||||
Sponge::Squeezing(ref mut output) => {
|
}
|
||||||
for entry in output.iter_mut() {
|
}
|
||||||
|
|
||||||
|
impl<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize>
|
||||||
|
Sponge<F, S, Squeezing<F, RATE>, T, RATE>
|
||||||
|
{
|
||||||
|
/// Squeezes an element from the sponge.
|
||||||
|
pub(crate) fn squeeze(&mut self) -> F {
|
||||||
|
loop {
|
||||||
|
for entry in self.mode.0.iter_mut() {
|
||||||
if let Some(e) = entry.take() {
|
if let Some(e) = entry.take() {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We've already squeezed out all available elements
|
// We've already squeezed out all available elements
|
||||||
self.sponge = Sponge::Absorbing([None; RATE]);
|
self.mode = Squeezing(poseidon_sponge::<F, S, T, RATE>(
|
||||||
}
|
&mut self.state,
|
||||||
}
|
&self.mode.0,
|
||||||
|
&self.pad_and_add,
|
||||||
|
&self.mds_matrix,
|
||||||
|
&self.round_constants,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,7 +327,7 @@ impl<F: FieldExt, const T: usize, const RATE: usize, const L: usize> Domain<F, T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Poseidon hash function, built around a duplex sponge.
|
/// A Poseidon hash function, built around a sponge.
|
||||||
pub struct Hash<
|
pub struct Hash<
|
||||||
F: FieldExt,
|
F: FieldExt,
|
||||||
S: Spec<F, T, RATE>,
|
S: Spec<F, T, RATE>,
|
||||||
|
@ -309,7 +335,7 @@ pub struct Hash<
|
||||||
const T: usize,
|
const T: usize,
|
||||||
const RATE: usize,
|
const RATE: usize,
|
||||||
> {
|
> {
|
||||||
duplex: Duplex<F, S, T, RATE>,
|
sponge: Sponge<F, S, Absorbing<F, RATE>, T, RATE>,
|
||||||
domain: D,
|
domain: D,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +369,7 @@ impl<
|
||||||
/// Initializes a new hasher.
|
/// Initializes a new hasher.
|
||||||
pub fn init(domain: D) -> Self {
|
pub fn init(domain: D) -> Self {
|
||||||
Hash {
|
Hash {
|
||||||
duplex: Duplex::new(domain.initial_capacity_element(), domain.pad_and_add()),
|
sponge: Sponge::new(domain.initial_capacity_element(), domain.pad_and_add()),
|
||||||
domain,
|
domain,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,9 +381,9 @@ impl<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize, const
|
||||||
/// Hashes the given input.
|
/// Hashes the given input.
|
||||||
pub fn hash(mut self, message: [F; L]) -> F {
|
pub fn hash(mut self, message: [F; L]) -> F {
|
||||||
for value in array::IntoIter::new(message) {
|
for value in array::IntoIter::new(message) {
|
||||||
self.duplex.absorb(value);
|
self.sponge.absorb(value);
|
||||||
}
|
}
|
||||||
self.duplex.squeeze()
|
self.sponge.finish_absorbing().squeeze()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue