Use outer hash in Challenger

This commit is contained in:
wborgeaud 2021-12-29 16:41:43 +01:00
parent c126641c5d
commit 314a5845b7
6 changed files with 51 additions and 19 deletions

View File

@ -135,7 +135,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
pub(crate) fn open_plonk(
commitments: &[&Self; 4],
zeta: F::Extension,
challenger: &mut Challenger<F, C::InnerHasher>,
challenger: &mut Challenger<F, C::Hasher>,
common_data: &CommonCircuitData<F, C, D>,
timing: &mut TimingTree,
) -> (FriProof<F, C::Hasher, D>, OpeningSet<F, D>) {

View File

@ -21,7 +21,7 @@ pub fn fri_proof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const
lde_polynomial_coeffs: PolynomialCoeffs<F::Extension>,
// Evaluation of the polynomial on the large domain.
lde_polynomial_values: PolynomialValues<F::Extension>,
challenger: &mut Challenger<F, C::InnerHasher>,
challenger: &mut Challenger<F, C::Hasher>,
common_data: &CommonCircuitData<F, C, D>,
timing: &mut TimingTree,
) -> 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>(
mut coeffs: PolynomialCoeffs<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>,
) -> (
Vec<MerkleTree<F, C::Hasher>>,
@ -140,7 +140,7 @@ fn fri_prover_query_rounds<
>(
initial_merkle_trees: &[&MerkleTree<F, C::Hasher>],
trees: &[MerkleTree<F, C::Hasher>],
challenger: &mut Challenger<F, C::InnerHasher>,
challenger: &mut Challenger<F, C::Hasher>,
n: usize,
common_data: &CommonCircuitData<F, C, D>,
) -> Vec<FriQueryRound<F, C::Hasher, D>> {
@ -156,7 +156,7 @@ fn fri_prover_query_round<
>(
initial_merkle_trees: &[&MerkleTree<F, C::Hasher>],
trees: &[MerkleTree<F, C::Hasher>],
challenger: &mut Challenger<F, C::InnerHasher>,
challenger: &mut Challenger<F, C::Hasher>,
n: usize,
common_data: &CommonCircuitData<F, C, D>,
) -> FriQueryRound<F, C::Hasher, D> {

View File

@ -15,7 +15,7 @@ use crate::plonk::proof::{OpeningSet, OpeningSetTarget};
/// Observes prover messages, and generates challenges by hashing the transcript, a la Fiat-Shamir.
#[derive(Clone)]
pub struct Challenger<F: RichField, H: AlgebraicHasher<F>> {
pub struct Challenger<F: RichField, H: Hasher<F>> {
sponge_state: [F; SPONGE_WIDTH],
input_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
/// 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.
impl<F: RichField, H: AlgebraicHasher<F>> Challenger<F, H> {
impl<F: RichField, H: Hasher<F>> Challenger<F, H> {
pub fn new() -> Challenger<F, H> {
Challenger {
sponge_state: [F::ZERO; SPONGE_WIDTH],

View File

@ -34,6 +34,9 @@ pub trait Hasher<F: RichField>: Sized + Clone + Debug + Eq + PartialEq {
const HASH_SIZE: usize;
type Hash: GenericHashOut<F>;
/// Permutation used in the sponge construction.
type Permutation: PlonkyPermutation<F>;
fn hash(input: Vec<F>, pad: bool) -> Self::Hash;
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash;
}
@ -43,8 +46,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.
// 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),
/// then apply the permutation.
fn permute_swapped<const D: usize>(
@ -62,19 +63,18 @@ 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 as AlgebraicHasher<F>>::Permutation>(input, pad)
hash_n_to_hash::<F, Self::Permutation>(input, pad)
}
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash {
compress::<F, <Self as AlgebraicHasher<F>>::Permutation>(left, right)
compress::<F, Self::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,
@ -111,19 +111,18 @@ 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 as AlgebraicHasher<F>>::Permutation>(input, pad)
hash_n_to_hash::<F, Self::Permutation>(input, pad)
}
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash {
compress::<F, <Self as AlgebraicHasher<F>>::Permutation>(left, right)
compress::<F, Self::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,
@ -155,12 +154,45 @@ impl<F: RichField> AlgebraicHasher<F> for GMiMCHash {
}
}
/// Keccak-256 permutation used in the challenger.
pub struct KeccakPermutation;
impl<F: RichField> PlonkyPermutation<F> for KeccakPermutation {
fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] {
// Fill a byte array with the little-endian representation of the field array.
let mut buffer = [0u8; SPONGE_WIDTH * std::mem::size_of::<u64>()];
for i in 0..SPONGE_WIDTH {
buffer[i * std::mem::size_of::<F>()..(i + 1) * std::mem::size_of::<F>()]
.copy_from_slice(&input[i].to_canonical_u64().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 {
permutated_input[i] = F::from_noncanonical_u64(u64::from_le_bytes(
permutated_input_bytes
[i * std::mem::size_of::<F>()..(i + 1) * std::mem::size_of::<F>()]
.try_into()
.unwrap(),
));
}
permutated_input
}
}
/// 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());

View File

@ -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 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.
challenger.observe_hash::<C::Hasher>(common_data.circuit_digest);

View File

@ -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.
challenger.observe_hash::<C::Hasher>(common_data.circuit_digest);