mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-07 16:23:12 +00:00
Merge pull request #407 from mir-protocol/challenger_outer_hash
Use the outer hash in the challenger
This commit is contained in:
commit
a452da523b
@ -135,7 +135,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
|||||||
pub(crate) fn open_plonk(
|
pub(crate) fn open_plonk(
|
||||||
commitments: &[&Self; 4],
|
commitments: &[&Self; 4],
|
||||||
zeta: F::Extension,
|
zeta: F::Extension,
|
||||||
challenger: &mut Challenger<F, C::InnerHasher>,
|
challenger: &mut Challenger<F, C::Hasher>,
|
||||||
common_data: &CommonCircuitData<F, C, D>,
|
common_data: &CommonCircuitData<F, C, D>,
|
||||||
timing: &mut TimingTree,
|
timing: &mut TimingTree,
|
||||||
) -> (FriProof<F, C::Hasher, D>, OpeningSet<F, D>) {
|
) -> (FriProof<F, C::Hasher, D>, OpeningSet<F, D>) {
|
||||||
|
|||||||
@ -21,7 +21,7 @@ pub fn fri_proof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const
|
|||||||
lde_polynomial_coeffs: PolynomialCoeffs<F::Extension>,
|
lde_polynomial_coeffs: PolynomialCoeffs<F::Extension>,
|
||||||
// Evaluation of the polynomial on the large domain.
|
// Evaluation of the polynomial on the large domain.
|
||||||
lde_polynomial_values: PolynomialValues<F::Extension>,
|
lde_polynomial_values: PolynomialValues<F::Extension>,
|
||||||
challenger: &mut Challenger<F, C::InnerHasher>,
|
challenger: &mut Challenger<F, C::Hasher>,
|
||||||
common_data: &CommonCircuitData<F, C, D>,
|
common_data: &CommonCircuitData<F, C, D>,
|
||||||
timing: &mut TimingTree,
|
timing: &mut TimingTree,
|
||||||
) -> FriProof<F, C::Hasher, D> {
|
) -> FriProof<F, C::Hasher, D> {
|
||||||
@ -63,7 +63,7 @@ pub fn fri_proof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const
|
|||||||
fn fri_committed_trees<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
fn fri_committed_trees<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||||
mut coeffs: PolynomialCoeffs<F::Extension>,
|
mut coeffs: PolynomialCoeffs<F::Extension>,
|
||||||
mut values: PolynomialValues<F::Extension>,
|
mut values: PolynomialValues<F::Extension>,
|
||||||
challenger: &mut Challenger<F, C::InnerHasher>,
|
challenger: &mut Challenger<F, C::Hasher>,
|
||||||
common_data: &CommonCircuitData<F, C, D>,
|
common_data: &CommonCircuitData<F, C, D>,
|
||||||
) -> (
|
) -> (
|
||||||
Vec<MerkleTree<F, C::Hasher>>,
|
Vec<MerkleTree<F, C::Hasher>>,
|
||||||
@ -140,7 +140,7 @@ fn fri_prover_query_rounds<
|
|||||||
>(
|
>(
|
||||||
initial_merkle_trees: &[&MerkleTree<F, C::Hasher>],
|
initial_merkle_trees: &[&MerkleTree<F, C::Hasher>],
|
||||||
trees: &[MerkleTree<F, C::Hasher>],
|
trees: &[MerkleTree<F, C::Hasher>],
|
||||||
challenger: &mut Challenger<F, C::InnerHasher>,
|
challenger: &mut Challenger<F, C::Hasher>,
|
||||||
n: usize,
|
n: usize,
|
||||||
common_data: &CommonCircuitData<F, C, D>,
|
common_data: &CommonCircuitData<F, C, D>,
|
||||||
) -> Vec<FriQueryRound<F, C::Hasher, D>> {
|
) -> Vec<FriQueryRound<F, C::Hasher, D>> {
|
||||||
@ -156,7 +156,7 @@ fn fri_prover_query_round<
|
|||||||
>(
|
>(
|
||||||
initial_merkle_trees: &[&MerkleTree<F, C::Hasher>],
|
initial_merkle_trees: &[&MerkleTree<F, C::Hasher>],
|
||||||
trees: &[MerkleTree<F, C::Hasher>],
|
trees: &[MerkleTree<F, C::Hasher>],
|
||||||
challenger: &mut Challenger<F, C::InnerHasher>,
|
challenger: &mut Challenger<F, C::Hasher>,
|
||||||
n: usize,
|
n: usize,
|
||||||
common_data: &CommonCircuitData<F, C, D>,
|
common_data: &CommonCircuitData<F, C, D>,
|
||||||
) -> FriQueryRound<F, C::Hasher, D> {
|
) -> FriQueryRound<F, C::Hasher, D> {
|
||||||
|
|||||||
@ -1,7 +1,15 @@
|
|||||||
|
use plonky2_field::extension_field::Extendable;
|
||||||
use plonky2_field::field_types::Field;
|
use plonky2_field::field_types::Field;
|
||||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||||
use unroll::unroll_for_loops;
|
use unroll::unroll_for_loops;
|
||||||
|
|
||||||
|
use crate::gates::gmimc::GMiMCGate;
|
||||||
|
use crate::hash::hash_types::{HashOut, RichField};
|
||||||
|
use crate::hash::hashing::{compress, hash_n_to_hash, PlonkyPermutation, SPONGE_WIDTH};
|
||||||
|
use crate::iop::target::{BoolTarget, Target};
|
||||||
|
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::plonk::config::{AlgebraicHasher, Hasher};
|
||||||
|
|
||||||
pub(crate) const NUM_ROUNDS: usize = 101;
|
pub(crate) const NUM_ROUNDS: usize = 101;
|
||||||
|
|
||||||
pub trait GMiMC<const WIDTH: usize>: Field
|
pub trait GMiMC<const WIDTH: usize>: Field
|
||||||
@ -85,6 +93,61 @@ impl GMiMC<12> for GoldilocksField {
|
|||||||
const ROUND_CONSTANTS: [u64; NUM_ROUNDS] = GOLDILOCKS_ROUND_CONSTANTS;
|
const ROUND_CONSTANTS: [u64; NUM_ROUNDS] = GOLDILOCKS_ROUND_CONSTANTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct GMiMCPermutation;
|
||||||
|
impl<F: RichField> PlonkyPermutation<F> for GMiMCPermutation {
|
||||||
|
fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] {
|
||||||
|
F::gmimc_permute(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct GMiMCHash;
|
||||||
|
impl<F: RichField> Hasher<F> for GMiMCHash {
|
||||||
|
const HASH_SIZE: usize = 4 * 8;
|
||||||
|
type Hash = HashOut<F>;
|
||||||
|
type Permutation = GMiMCPermutation;
|
||||||
|
|
||||||
|
fn hash(input: Vec<F>, pad: bool) -> Self::Hash {
|
||||||
|
hash_n_to_hash::<F, Self::Permutation>(input, pad)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash {
|
||||||
|
compress::<F, Self::Permutation>(left, right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: RichField> AlgebraicHasher<F> for GMiMCHash {
|
||||||
|
fn permute_swapped<const D: usize>(
|
||||||
|
inputs: [Target; SPONGE_WIDTH],
|
||||||
|
swap: BoolTarget,
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
) -> [Target; SPONGE_WIDTH]
|
||||||
|
where
|
||||||
|
F: RichField + Extendable<D>,
|
||||||
|
{
|
||||||
|
let gate_type = GMiMCGate::<F, D, SPONGE_WIDTH>::new();
|
||||||
|
let gate = builder.add_gate(gate_type, vec![]);
|
||||||
|
|
||||||
|
let swap_wire = GMiMCGate::<F, D, SPONGE_WIDTH>::WIRE_SWAP;
|
||||||
|
let swap_wire = Target::wire(gate, swap_wire);
|
||||||
|
builder.connect(swap.target, swap_wire);
|
||||||
|
|
||||||
|
// Route input wires.
|
||||||
|
for i in 0..SPONGE_WIDTH {
|
||||||
|
let in_wire = GMiMCGate::<F, D, SPONGE_WIDTH>::wire_input(i);
|
||||||
|
let in_wire = Target::wire(gate, in_wire);
|
||||||
|
builder.connect(inputs[i], in_wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect output wires.
|
||||||
|
(0..SPONGE_WIDTH)
|
||||||
|
.map(|i| Target::wire(gate, GMiMCGate::<F, D, SPONGE_WIDTH>::wire_output(i)))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||||
|
|||||||
@ -97,19 +97,6 @@ pub trait PlonkyPermutation<F: RichField> {
|
|||||||
fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH];
|
fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PoseidonPermutation;
|
|
||||||
impl<F: RichField> PlonkyPermutation<F> for PoseidonPermutation {
|
|
||||||
fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] {
|
|
||||||
F::poseidon(input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct GMiMCPermutation;
|
|
||||||
impl<F: RichField> PlonkyPermutation<F> for GMiMCPermutation {
|
|
||||||
fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] {
|
|
||||||
F::gmimc_permute(input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If `pad` is enabled, the message is padded using the pad10*1 rule. In general this is required
|
/// If `pad` is enabled, the message is padded using the pad10*1 rule. In general this is required
|
||||||
/// for the hash to be secure, but it can safely be disabled in certain cases, like if the input
|
/// for the hash to be secure, but it can safely be disabled in certain cases, like if the input
|
||||||
/// length is fixed.
|
/// length is fixed.
|
||||||
|
|||||||
81
plonky2/src/hash/keccak.rs
Normal file
81
plonky2/src/hash/keccak.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
use std::mem::size_of;
|
||||||
|
|
||||||
|
use keccak_hash::keccak;
|
||||||
|
|
||||||
|
use crate::hash::hash_types::{BytesHash, RichField};
|
||||||
|
use crate::hash::hashing::{PlonkyPermutation, SPONGE_WIDTH};
|
||||||
|
use crate::plonk::config::Hasher;
|
||||||
|
use crate::util::serialization::Buffer;
|
||||||
|
|
||||||
|
/// Keccak-256 pseudo-permutation (not necessarily one-to-one) used in the challenger.
|
||||||
|
/// A state `input: [F; 12]` is sent to the field representation of `H(input) || H(H(input)) || H(H(H(input)))`
|
||||||
|
/// where `H` is the Keccak-256 hash.
|
||||||
|
pub struct KeccakPermutation;
|
||||||
|
impl<F: RichField> PlonkyPermutation<F> for KeccakPermutation {
|
||||||
|
fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] {
|
||||||
|
// Use rejection sampling so that if one of the `u64` values in the output is larger than
|
||||||
|
// the field order, we increment the nonce and start again.
|
||||||
|
'rejection_sampling: for nonce in 0u64.. {
|
||||||
|
// Fill a byte array with the little-endian representation of the field array.
|
||||||
|
let mut buffer = [0u8; (SPONGE_WIDTH + 1) * size_of::<u64>()];
|
||||||
|
for i in 0..SPONGE_WIDTH {
|
||||||
|
buffer[i * size_of::<u64>()..(i + 1) * size_of::<u64>()]
|
||||||
|
.copy_from_slice(&input[i].to_canonical_u64().to_le_bytes());
|
||||||
|
}
|
||||||
|
// Add the nonce at the end of the buffer.
|
||||||
|
buffer[SPONGE_WIDTH * size_of::<u64>()..].copy_from_slice(&nonce.to_le_bytes());
|
||||||
|
// Concatenate `H(input), H(H(input)), H(H(H(input)))`.
|
||||||
|
let permutated_input_bytes = {
|
||||||
|
let mut ans = [0u8; 96];
|
||||||
|
ans[0..32].copy_from_slice(&keccak(buffer).0);
|
||||||
|
ans[32..64].copy_from_slice(&keccak(keccak(buffer).0).0);
|
||||||
|
ans[64..96].copy_from_slice(&keccak(keccak(keccak(buffer).0).0).0);
|
||||||
|
ans
|
||||||
|
};
|
||||||
|
// Write the hashed byte array to a field array.
|
||||||
|
let mut permutated_input = [F::ZERO; SPONGE_WIDTH];
|
||||||
|
for i in 0..SPONGE_WIDTH {
|
||||||
|
let perm_u64 = u64::from_le_bytes(
|
||||||
|
permutated_input_bytes[i * size_of::<u64>()..(i + 1) * size_of::<u64>()]
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
if perm_u64 >= F::ORDER {
|
||||||
|
// If a value is larger than the field order, we break and start again with a new nonce.
|
||||||
|
continue 'rejection_sampling;
|
||||||
|
} else {
|
||||||
|
permutated_input[i] = F::from_canonical_u64(perm_u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return permutated_input;
|
||||||
|
}
|
||||||
|
panic!("Improbable.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Keccak-256 hash function.
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct KeccakHash<const N: usize>;
|
||||||
|
impl<F: RichField, const N: usize> Hasher<F> for KeccakHash<N> {
|
||||||
|
const HASH_SIZE: usize = N;
|
||||||
|
type Hash = BytesHash<N>;
|
||||||
|
type Permutation = KeccakPermutation;
|
||||||
|
|
||||||
|
fn hash(input: Vec<F>, _pad: bool) -> Self::Hash {
|
||||||
|
let mut buffer = Buffer::new(Vec::new());
|
||||||
|
buffer.write_field_vec(&input).unwrap();
|
||||||
|
let mut arr = [0; N];
|
||||||
|
let hash_bytes = keccak(buffer.bytes()).0;
|
||||||
|
arr.copy_from_slice(&hash_bytes[..N]);
|
||||||
|
BytesHash(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash {
|
||||||
|
let mut v = vec![0; N * 2];
|
||||||
|
v[0..N].copy_from_slice(&left.0);
|
||||||
|
v[N..].copy_from_slice(&right.0);
|
||||||
|
let mut arr = [0; N];
|
||||||
|
arr.copy_from_slice(&keccak(v).0[..N]);
|
||||||
|
BytesHash(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ mod arch;
|
|||||||
pub mod gmimc;
|
pub mod gmimc;
|
||||||
pub mod hash_types;
|
pub mod hash_types;
|
||||||
pub mod hashing;
|
pub mod hashing;
|
||||||
|
pub mod keccak;
|
||||||
pub mod merkle_proofs;
|
pub mod merkle_proofs;
|
||||||
pub mod merkle_tree;
|
pub mod merkle_tree;
|
||||||
pub mod path_compression;
|
pub mod path_compression;
|
||||||
|
|||||||
@ -6,11 +6,14 @@ use plonky2_field::field_types::{Field, PrimeField};
|
|||||||
use unroll::unroll_for_loops;
|
use unroll::unroll_for_loops;
|
||||||
|
|
||||||
use crate::gates::gate::Gate;
|
use crate::gates::gate::Gate;
|
||||||
|
use crate::gates::poseidon::PoseidonGate;
|
||||||
use crate::gates::poseidon_mds::PoseidonMdsGate;
|
use crate::gates::poseidon_mds::PoseidonMdsGate;
|
||||||
use crate::hash::hash_types::RichField;
|
use crate::hash::hash_types::{HashOut, RichField};
|
||||||
use crate::hash::hashing::SPONGE_WIDTH;
|
use crate::hash::hashing::{compress, hash_n_to_hash, PlonkyPermutation, SPONGE_WIDTH};
|
||||||
use crate::iop::ext_target::ExtensionTarget;
|
use crate::iop::ext_target::ExtensionTarget;
|
||||||
|
use crate::iop::target::{BoolTarget, Target};
|
||||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::plonk::config::{AlgebraicHasher, Hasher};
|
||||||
|
|
||||||
// The number of full rounds and partial rounds is given by the
|
// The number of full rounds and partial rounds is given by the
|
||||||
// calc_round_numbers.py script. They happen to be the same for both
|
// calc_round_numbers.py script. They happen to be the same for both
|
||||||
@ -615,6 +618,62 @@ pub trait Poseidon: PrimeField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PoseidonPermutation;
|
||||||
|
impl<F: RichField> PlonkyPermutation<F> for PoseidonPermutation {
|
||||||
|
fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] {
|
||||||
|
F::poseidon(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Poseidon hash function.
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct PoseidonHash;
|
||||||
|
impl<F: RichField> Hasher<F> for PoseidonHash {
|
||||||
|
const HASH_SIZE: usize = 4 * 8;
|
||||||
|
type Hash = HashOut<F>;
|
||||||
|
type Permutation = PoseidonPermutation;
|
||||||
|
|
||||||
|
fn hash(input: Vec<F>, pad: bool) -> Self::Hash {
|
||||||
|
hash_n_to_hash::<F, Self::Permutation>(input, pad)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash {
|
||||||
|
compress::<F, Self::Permutation>(left, right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: RichField> AlgebraicHasher<F> for PoseidonHash {
|
||||||
|
fn permute_swapped<const D: usize>(
|
||||||
|
inputs: [Target; SPONGE_WIDTH],
|
||||||
|
swap: BoolTarget,
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
) -> [Target; SPONGE_WIDTH]
|
||||||
|
where
|
||||||
|
F: RichField + Extendable<D>,
|
||||||
|
{
|
||||||
|
let gate_type = PoseidonGate::<F, D>::new();
|
||||||
|
let gate = builder.add_gate(gate_type, vec![]);
|
||||||
|
|
||||||
|
let swap_wire = PoseidonGate::<F, D>::WIRE_SWAP;
|
||||||
|
let swap_wire = Target::wire(gate, swap_wire);
|
||||||
|
builder.connect(swap.target, swap_wire);
|
||||||
|
|
||||||
|
// Route input wires.
|
||||||
|
for i in 0..SPONGE_WIDTH {
|
||||||
|
let in_wire = PoseidonGate::<F, D>::wire_input(i);
|
||||||
|
let in_wire = Target::wire(gate, in_wire);
|
||||||
|
builder.connect(inputs[i], in_wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect output wires.
|
||||||
|
(0..SPONGE_WIDTH)
|
||||||
|
.map(|i| Target::wire(gate, PoseidonGate::<F, D>::wire_output(i)))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod test_helpers {
|
pub(crate) mod test_helpers {
|
||||||
use plonky2_field::field_types::Field;
|
use plonky2_field::field_types::Field;
|
||||||
|
|||||||
@ -15,7 +15,7 @@ use crate::plonk::proof::{OpeningSet, OpeningSetTarget};
|
|||||||
|
|
||||||
/// Observes prover messages, and generates challenges by hashing the transcript, a la Fiat-Shamir.
|
/// Observes prover messages, and generates challenges by hashing the transcript, a la Fiat-Shamir.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Challenger<F: RichField, H: AlgebraicHasher<F>> {
|
pub struct Challenger<F: RichField, H: Hasher<F>> {
|
||||||
sponge_state: [F; SPONGE_WIDTH],
|
sponge_state: [F; SPONGE_WIDTH],
|
||||||
input_buffer: Vec<F>,
|
input_buffer: Vec<F>,
|
||||||
output_buffer: Vec<F>,
|
output_buffer: Vec<F>,
|
||||||
@ -30,7 +30,7 @@ pub struct Challenger<F: RichField, H: AlgebraicHasher<F>> {
|
|||||||
/// design, but it can be viewed as a duplex sponge whose inputs are sometimes zero (when we perform
|
/// design, but it can be viewed as a duplex sponge whose inputs are sometimes zero (when we perform
|
||||||
/// multiple squeezes) and whose outputs are sometimes ignored (when we perform multiple
|
/// multiple squeezes) and whose outputs are sometimes ignored (when we perform multiple
|
||||||
/// absorptions). Thus the security properties of a duplex sponge still apply to our design.
|
/// absorptions). Thus the security properties of a duplex sponge still apply to our design.
|
||||||
impl<F: RichField, H: AlgebraicHasher<F>> Challenger<F, H> {
|
impl<F: RichField, H: Hasher<F>> Challenger<F, H> {
|
||||||
pub fn new() -> Challenger<F, H> {
|
pub fn new() -> Challenger<F, H> {
|
||||||
Challenger {
|
Challenger {
|
||||||
sponge_state: [F::ZERO; SPONGE_WIDTH],
|
sponge_state: [F::ZERO; SPONGE_WIDTH],
|
||||||
|
|||||||
@ -1,23 +1,18 @@
|
|||||||
use std::convert::TryInto;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use keccak_hash::keccak;
|
|
||||||
use plonky2_field::extension_field::quadratic::QuadraticExtension;
|
use plonky2_field::extension_field::quadratic::QuadraticExtension;
|
||||||
use plonky2_field::extension_field::{Extendable, FieldExtension};
|
use plonky2_field::extension_field::{Extendable, FieldExtension};
|
||||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
|
||||||
use crate::gates::gmimc::GMiMCGate;
|
use crate::hash::gmimc::GMiMCHash;
|
||||||
use crate::gates::poseidon::PoseidonGate;
|
use crate::hash::hash_types::HashOut;
|
||||||
use crate::hash::hash_types::RichField;
|
use crate::hash::hash_types::RichField;
|
||||||
use crate::hash::hash_types::{BytesHash, HashOut};
|
use crate::hash::hashing::{PlonkyPermutation, SPONGE_WIDTH};
|
||||||
use crate::hash::hashing::{
|
use crate::hash::keccak::KeccakHash;
|
||||||
compress, hash_n_to_hash, GMiMCPermutation, PlonkyPermutation, PoseidonPermutation,
|
use crate::hash::poseidon::PoseidonHash;
|
||||||
SPONGE_WIDTH,
|
|
||||||
};
|
|
||||||
use crate::iop::target::{BoolTarget, Target};
|
use crate::iop::target::{BoolTarget, Target};
|
||||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||||
use crate::util::serialization::Buffer;
|
|
||||||
|
|
||||||
pub trait GenericHashOut<F: RichField>:
|
pub trait GenericHashOut<F: RichField>:
|
||||||
Copy + Clone + Debug + Eq + PartialEq + Send + Sync + Serialize + DeserializeOwned
|
Copy + Clone + Debug + Eq + PartialEq + Send + Sync + Serialize + DeserializeOwned
|
||||||
@ -34,6 +29,9 @@ pub trait Hasher<F: RichField>: Sized + Clone + Debug + Eq + PartialEq {
|
|||||||
const HASH_SIZE: usize;
|
const HASH_SIZE: usize;
|
||||||
type Hash: GenericHashOut<F>;
|
type Hash: GenericHashOut<F>;
|
||||||
|
|
||||||
|
/// Permutation used in the sponge construction.
|
||||||
|
type Permutation: PlonkyPermutation<F>;
|
||||||
|
|
||||||
fn hash(input: Vec<F>, pad: bool) -> Self::Hash;
|
fn hash(input: Vec<F>, pad: bool) -> Self::Hash;
|
||||||
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash;
|
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash;
|
||||||
}
|
}
|
||||||
@ -43,8 +41,6 @@ pub trait AlgebraicHasher<F: RichField>: Hasher<F, Hash = HashOut<F>> {
|
|||||||
// TODO: Adding a `const WIDTH: usize` here yields a compiler error down the line.
|
// TODO: Adding a `const WIDTH: usize` here yields a compiler error down the line.
|
||||||
// Maybe try again in a while.
|
// Maybe try again in a while.
|
||||||
|
|
||||||
/// Permutation used in the sponge construction.
|
|
||||||
type Permutation: PlonkyPermutation<F>;
|
|
||||||
/// Circuit to conditionally swap two chunks of the inputs (useful in verifying Merkle proofs),
|
/// Circuit to conditionally swap two chunks of the inputs (useful in verifying Merkle proofs),
|
||||||
/// then apply the permutation.
|
/// then apply the permutation.
|
||||||
fn permute_swapped<const D: usize>(
|
fn permute_swapped<const D: usize>(
|
||||||
@ -56,131 +52,6 @@ pub trait AlgebraicHasher<F: RichField>: Hasher<F, Hash = HashOut<F>> {
|
|||||||
F: RichField + Extendable<D>;
|
F: RichField + Extendable<D>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Poseidon hash function.
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct PoseidonHash;
|
|
||||||
impl<F: RichField> Hasher<F> for PoseidonHash {
|
|
||||||
const HASH_SIZE: usize = 4 * 8;
|
|
||||||
type Hash = HashOut<F>;
|
|
||||||
|
|
||||||
fn hash(input: Vec<F>, pad: bool) -> Self::Hash {
|
|
||||||
hash_n_to_hash::<F, <Self as AlgebraicHasher<F>>::Permutation>(input, pad)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash {
|
|
||||||
compress::<F, <Self as AlgebraicHasher<F>>::Permutation>(left, right)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: RichField> AlgebraicHasher<F> for PoseidonHash {
|
|
||||||
type Permutation = PoseidonPermutation;
|
|
||||||
|
|
||||||
fn permute_swapped<const D: usize>(
|
|
||||||
inputs: [Target; SPONGE_WIDTH],
|
|
||||||
swap: BoolTarget,
|
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
|
||||||
) -> [Target; SPONGE_WIDTH]
|
|
||||||
where
|
|
||||||
F: RichField + Extendable<D>,
|
|
||||||
{
|
|
||||||
let gate_type = PoseidonGate::<F, D>::new();
|
|
||||||
let gate = builder.add_gate(gate_type, vec![]);
|
|
||||||
|
|
||||||
let swap_wire = PoseidonGate::<F, D>::WIRE_SWAP;
|
|
||||||
let swap_wire = Target::wire(gate, swap_wire);
|
|
||||||
builder.connect(swap.target, swap_wire);
|
|
||||||
|
|
||||||
// Route input wires.
|
|
||||||
for i in 0..SPONGE_WIDTH {
|
|
||||||
let in_wire = PoseidonGate::<F, D>::wire_input(i);
|
|
||||||
let in_wire = Target::wire(gate, in_wire);
|
|
||||||
builder.connect(inputs[i], in_wire);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect output wires.
|
|
||||||
(0..SPONGE_WIDTH)
|
|
||||||
.map(|i| Target::wire(gate, PoseidonGate::<F, D>::wire_output(i)))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.try_into()
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct GMiMCHash;
|
|
||||||
impl<F: RichField> Hasher<F> for GMiMCHash {
|
|
||||||
const HASH_SIZE: usize = 4 * 8;
|
|
||||||
type Hash = HashOut<F>;
|
|
||||||
|
|
||||||
fn hash(input: Vec<F>, pad: bool) -> Self::Hash {
|
|
||||||
hash_n_to_hash::<F, <Self as AlgebraicHasher<F>>::Permutation>(input, pad)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash {
|
|
||||||
compress::<F, <Self as AlgebraicHasher<F>>::Permutation>(left, right)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: RichField> AlgebraicHasher<F> for GMiMCHash {
|
|
||||||
type Permutation = GMiMCPermutation;
|
|
||||||
|
|
||||||
fn permute_swapped<const D: usize>(
|
|
||||||
inputs: [Target; SPONGE_WIDTH],
|
|
||||||
swap: BoolTarget,
|
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
|
||||||
) -> [Target; SPONGE_WIDTH]
|
|
||||||
where
|
|
||||||
F: RichField + Extendable<D>,
|
|
||||||
{
|
|
||||||
let gate_type = GMiMCGate::<F, D, SPONGE_WIDTH>::new();
|
|
||||||
let gate = builder.add_gate(gate_type, vec![]);
|
|
||||||
|
|
||||||
let swap_wire = GMiMCGate::<F, D, SPONGE_WIDTH>::WIRE_SWAP;
|
|
||||||
let swap_wire = Target::wire(gate, swap_wire);
|
|
||||||
builder.connect(swap.target, swap_wire);
|
|
||||||
|
|
||||||
// Route input wires.
|
|
||||||
for i in 0..SPONGE_WIDTH {
|
|
||||||
let in_wire = GMiMCGate::<F, D, SPONGE_WIDTH>::wire_input(i);
|
|
||||||
let in_wire = Target::wire(gate, in_wire);
|
|
||||||
builder.connect(inputs[i], in_wire);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect output wires.
|
|
||||||
(0..SPONGE_WIDTH)
|
|
||||||
.map(|i| Target::wire(gate, GMiMCGate::<F, D, SPONGE_WIDTH>::wire_output(i)))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.try_into()
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Keccak-256 hash function.
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct KeccakHash<const N: usize>;
|
|
||||||
impl<F: RichField, const N: usize> Hasher<F> for KeccakHash<N> {
|
|
||||||
const HASH_SIZE: usize = N;
|
|
||||||
type Hash = BytesHash<N>;
|
|
||||||
|
|
||||||
fn hash(input: Vec<F>, _pad: bool) -> Self::Hash {
|
|
||||||
let mut buffer = Buffer::new(Vec::new());
|
|
||||||
buffer.write_field_vec(&input).unwrap();
|
|
||||||
let mut arr = [0; N];
|
|
||||||
let hash_bytes = keccak(buffer.bytes()).0;
|
|
||||||
arr.copy_from_slice(&hash_bytes[..N]);
|
|
||||||
BytesHash(arr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash {
|
|
||||||
let mut v = vec![0; N * 2];
|
|
||||||
v[0..N].copy_from_slice(&left.0);
|
|
||||||
v[N..].copy_from_slice(&right.0);
|
|
||||||
let mut arr = [0; N];
|
|
||||||
arr.copy_from_slice(&keccak(v).0[..N]);
|
|
||||||
BytesHash(arr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generic configuration trait.
|
/// Generic configuration trait.
|
||||||
pub trait GenericConfig<const D: usize>:
|
pub trait GenericConfig<const D: usize>:
|
||||||
Debug + Clone + Sync + Sized + Send + Eq + PartialEq
|
Debug + Clone + Sync + Sized + Send + Eq + PartialEq
|
||||||
|
|||||||
@ -32,7 +32,7 @@ fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, cons
|
|||||||
let num_fri_queries = config.fri_config.num_query_rounds;
|
let num_fri_queries = config.fri_config.num_query_rounds;
|
||||||
let lde_size = common_data.lde_size();
|
let lde_size = common_data.lde_size();
|
||||||
|
|
||||||
let mut challenger = Challenger::<F, C::InnerHasher>::new();
|
let mut challenger = Challenger::<F, C::Hasher>::new();
|
||||||
|
|
||||||
// Observe the instance.
|
// Observe the instance.
|
||||||
challenger.observe_hash::<C::Hasher>(common_data.circuit_digest);
|
challenger.observe_hash::<C::Hasher>(common_data.circuit_digest);
|
||||||
|
|||||||
@ -79,7 +79,7 @@ pub(crate) fn prove<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, co
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut challenger = Challenger::new();
|
let mut challenger = Challenger::<F, C::Hasher>::new();
|
||||||
|
|
||||||
// Observe the instance.
|
// Observe the instance.
|
||||||
challenger.observe_hash::<C::Hasher>(common_data.circuit_digest);
|
challenger.observe_hash::<C::Hasher>(common_data.circuit_digest);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user