mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-05 23:33:07 +00:00
fix bn conversion and some minor improvements.
This commit is contained in:
parent
db9c63095f
commit
b33ed53ed7
@ -39,6 +39,7 @@ rust-bn254-hash = {git = "https://github.com/codex-storage/rust-bn254-hash.git"}
|
||||
ark-serialize = {version = "0.5.0"}
|
||||
ark-bn254 = "0.5.0"
|
||||
ark-ff = "0.5.0"
|
||||
num-bigint = { version = "0.4", default-features = false }
|
||||
|
||||
# Local dependencies
|
||||
plonky2_field = { version = "1.0.0", path = "../field", default-features = false }
|
||||
@ -79,6 +80,10 @@ harness = false
|
||||
name = "hashing"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "bn254_hash"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "merkle"
|
||||
harness = false
|
||||
|
||||
@ -1,16 +1,14 @@
|
||||
use std::fs;
|
||||
// use std::fs;
|
||||
use anyhow::Result;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use plonky2::gates::noop::NoopGate;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, Poseidon2BN254Config};
|
||||
use plonky2::plonk::prover::ProverOptions;
|
||||
use plonky2::plonk::verifier::{VerifierOptions, HashStatisticsPrintLevel};
|
||||
use plonky2::plonk::prover::DEFAULT_PROVER_OPTIONS;
|
||||
use plonky2::plonk::verifier::{HashStatisticsPrintLevel, VerifierOptions};
|
||||
|
||||
/// An example of using Plonky2 to prove a statement of the form
|
||||
/// "I know the 100th element of the Fibonacci sequence, starting with constants a and b."
|
||||
/// When a == 0 and b == 1, this is proving knowledge of the 100th (standard) Fibonacci number.
|
||||
/// An example of using Plonky2 over BN254 to a dummy circuit of size S.
|
||||
fn main() -> Result<()> {
|
||||
const D: usize = 2;
|
||||
type C = Poseidon2BN254Config;
|
||||
@ -18,34 +16,20 @@ fn main() -> Result<()> {
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
// The arithmetic circuit.
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
let mut prev_target = initial_a;
|
||||
let mut cur_target = initial_b;
|
||||
for _ in 0..99 {
|
||||
let temp = builder.add(prev_target, cur_target);
|
||||
prev_target = cur_target;
|
||||
cur_target = temp;
|
||||
const S: usize = 5;
|
||||
let num_dummy_gates = (1 << (S - 1)) + 1;
|
||||
for _ in 0..num_dummy_gates {
|
||||
builder.add_gate(NoopGate, vec![]);
|
||||
}
|
||||
|
||||
// Public inputs are the two initial values (provided below) and the result (which is generated).
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(cur_target);
|
||||
|
||||
// Provide initial values.
|
||||
let mut pw = PartialWitness::new();
|
||||
pw.set_target(initial_a, F::ZERO)?;
|
||||
pw.set_target(initial_b, F::ONE)?;
|
||||
let pw = PartialWitness::new();
|
||||
|
||||
let data = builder.build::<C>();
|
||||
println!("circ size = {}", data.common.degree_bits());
|
||||
|
||||
let prover_opts = ProverOptions {
|
||||
export_witness: Some(String::from("fibonacci_witness.json")),
|
||||
print_hash_statistics: HashStatisticsPrintLevel::Info,
|
||||
};
|
||||
let prover_opts = DEFAULT_PROVER_OPTIONS;
|
||||
|
||||
println!("proving ...");
|
||||
|
||||
let proof = data.prove_with_options(pw, &prover_opts)?;
|
||||
|
||||
@ -53,20 +37,15 @@ fn main() -> Result<()> {
|
||||
// let common_circuit_data_serialized = serde_json::to_string(&data.common ).unwrap();
|
||||
// let verifier_only_circuit_data_serialized = serde_json::to_string(&data.verifier_only).unwrap();
|
||||
// let proof_serialized = serde_json::to_string(&proof ).unwrap();
|
||||
// fs::write("fibonacci_common_k.json" , common_circuit_data_serialized) .expect("Unable to write file");
|
||||
// fs::write("fibonacci_vkey_k.json" , verifier_only_circuit_data_serialized).expect("Unable to write file");
|
||||
// fs::write("fibonacci_proof_k.json" , proof_serialized) .expect("Unable to write file");
|
||||
// println!("const sigma: {:?}", data.verifier_only.constants_sigmas_cap);
|
||||
// println!("circ digest: {:?}", data.verifier_only.circuit_digest);
|
||||
// println!("proof part: {:?}", proof.proof.wires_cap.0);
|
||||
|
||||
println!(
|
||||
"100th Fibonacci number mod |F| (starting with {}, {}) is: {}",
|
||||
proof.public_inputs[0], proof.public_inputs[1], proof.public_inputs[2]
|
||||
);
|
||||
// fs::write("bn_common.json" , common_circuit_data_serialized) .expect("Unable to write file");
|
||||
// fs::write("bn_vkey.json" , verifier_only_circuit_data_serialized).expect("Unable to write file");
|
||||
// fs::write("bn_proof.json" , proof_serialized) .expect("Unable to write file");
|
||||
|
||||
let verifier_opts = VerifierOptions {
|
||||
print_hash_statistics: HashStatisticsPrintLevel::Summary,
|
||||
};
|
||||
data.verify_with_options(proof, &verifier_opts)
|
||||
|
||||
assert!(data.verify_with_options(proof, &verifier_opts).is_ok());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ use crate::hash::merkle_tree::MerkleCap;
|
||||
use crate::iop::challenger::{Challenger, RecursiveChallenger};
|
||||
use crate::iop::target::Target;
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericConfig, GenericField, Hasher};
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericConfig, GenericField, Hasher, IntoGenericFieldVec};
|
||||
|
||||
impl<F: RichField, H: Hasher<F>> Challenger<F, H> {
|
||||
pub fn observe_openings<const D: usize>(&mut self, openings: &FriOpenings<F, D>)
|
||||
@ -57,7 +57,7 @@ impl<F: RichField, H: Hasher<F>> Challenger<F, H> {
|
||||
if let Some(step_count) = max_num_query_steps {
|
||||
let cap_len = (1 << config.cap_height) * NUM_HASH_OUT_ELTS;
|
||||
let zero_cap = vec![F::ZERO; cap_len];
|
||||
let zero_cap_felts: Vec<GenericField<F>> = zero_cap.into_iter().map(GenericField::Goldilocks).collect();
|
||||
let zero_cap_felts: Vec<GenericField<F>> = zero_cap.into_generic_field_vec();
|
||||
for _ in commit_phase_merkle_caps.len()..step_count {
|
||||
// self.observe_elements(&zero_cap);
|
||||
self.observe_elements(&zero_cap_felts);
|
||||
@ -75,7 +75,7 @@ impl<F: RichField, H: Hasher<F>> Challenger<F, H> {
|
||||
}
|
||||
}
|
||||
|
||||
self.observe_element(GenericField::Goldilocks(pow_witness));
|
||||
self.observe_element(pow_witness.into());
|
||||
let fri_pow_response = self.get_challenge();
|
||||
|
||||
let fri_query_indices = (0..num_fri_queries)
|
||||
|
||||
@ -14,7 +14,7 @@ use crate::hash::hash_types::{RichField, NUM_HASH_OUT_ELTS};
|
||||
use crate::hash::hashing::*;
|
||||
use crate::hash::merkle_tree::MerkleTree;
|
||||
use crate::iop::challenger::Challenger;
|
||||
use crate::plonk::config::{GenericConfig, GenericField};
|
||||
use crate::plonk::config::{GenericConfig, GenericField, IntoGenericFieldVec};
|
||||
use crate::plonk::plonk_common::reduce_with_powers;
|
||||
use crate::plonk::prover::ProverOptions;
|
||||
use crate::plonk::verifier::HashStatisticsPrintLevel;
|
||||
@ -136,7 +136,7 @@ fn fri_committed_trees<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>,
|
||||
if let Some(step_count) = max_num_query_steps {
|
||||
let cap_len = (1 << fri_params.config.cap_height) * NUM_HASH_OUT_ELTS;
|
||||
let zero_cap = vec![F::ZERO; cap_len];
|
||||
let zero_cap_felts: Vec<GenericField<F>> = zero_cap.into_iter().map(GenericField::Goldilocks).collect();
|
||||
let zero_cap_felts: Vec<GenericField<F>> = zero_cap.into_generic_field_vec();
|
||||
for _ in fri_params.reduction_arity_bits.len()..step_count {
|
||||
challenger.observe_elements(&zero_cap_felts);
|
||||
challenger.get_extension_challenge::<D>();
|
||||
@ -177,7 +177,7 @@ pub(crate) fn fri_proof_of_work<
|
||||
// println!("pow_witness = {:?}",pow_witness);
|
||||
|
||||
// Recompute pow_response using our normal Challenger code, and make sure it matches.
|
||||
challenger.observe_element(GenericField::Goldilocks(pow_witness));
|
||||
challenger.observe_element(pow_witness.into());
|
||||
let pow_response = challenger.get_challenge();
|
||||
let leading_zeros = pow_response.to_canonical_u64().leading_zeros();
|
||||
assert!(leading_zeros >= min_leading_zeros);
|
||||
|
||||
@ -10,7 +10,7 @@ use crate::hash::merkle_proofs::MerkleProof;
|
||||
use crate::hash::merkle_tree::{
|
||||
capacity_up_to_mut, fill_digests_buf, merkle_tree_prove, MerkleCap,
|
||||
};
|
||||
use crate::plonk::config::{GenericField, GenericHashOut, Hasher};
|
||||
use crate::plonk::config::{GenericField, GenericHashOut, Hasher, IntoGenericFieldVec};
|
||||
use crate::util::log2_strict;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
@ -56,14 +56,12 @@ impl<F: RichField, H: Hasher<F>> BatchMerkleTree<F, H> {
|
||||
let mut digests_buf_pos = 0;
|
||||
|
||||
let mut cap = vec![];
|
||||
let dummy_leaves_felts = vec![vec![GenericField::Goldilocks(F::ZERO)]; 1 << cap_height];
|
||||
let dummy_leaves_felts = vec![vec![F::ZERO.into()]; 1 << cap_height];
|
||||
let mut leaves_felts: Vec<Vec<Vec<GenericField<F>>>> = leaves.clone().into_iter()
|
||||
.map(|matrix| {
|
||||
matrix.into_iter()
|
||||
.map(|vec| {
|
||||
vec.into_iter()
|
||||
.map(|f| GenericField::Goldilocks(f))
|
||||
.collect()
|
||||
vec.into_generic_field_vec()
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
@ -184,7 +182,7 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::hash::merkle_proofs::verify_batch_merkle_proof_to_cap;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use crate::plonk::config::{GenericConfig, IntoGenericFieldVec, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
@ -208,10 +206,10 @@ mod tests {
|
||||
let fmt: BatchMerkleTree<GoldilocksField, H> = BatchMerkleTree::new(vec![mat_1], 0);
|
||||
|
||||
let mat_1_leaf_hashes = [
|
||||
H::hash_or_noop(&[F::ZERO, F::ONE]),
|
||||
H::hash_or_noop(&[F::TWO, F::ONE]),
|
||||
H::hash_or_noop(&[F::TWO, F::TWO]),
|
||||
H::hash_or_noop(&[F::ZERO, F::ZERO]),
|
||||
H::hash_or_noop(&[F::ZERO.into(), F::ONE.into()]),
|
||||
H::hash_or_noop(&[F::TWO.into(), F::ONE.into()]),
|
||||
H::hash_or_noop(&[F::TWO.into(), F::TWO.into()]),
|
||||
H::hash_or_noop(&[F::ZERO.into(), F::ZERO.into()]),
|
||||
];
|
||||
assert_eq!(mat_1_leaf_hashes[0..2], fmt.digests[0..2]);
|
||||
assert_eq!(mat_1_leaf_hashes[2..4], fmt.digests[4..6]);
|
||||
@ -260,10 +258,10 @@ mod tests {
|
||||
BatchMerkleTree::new(vec![mat_1, mat_2.clone()], 0);
|
||||
|
||||
let mat_1_leaf_hashes = [
|
||||
H::hash_or_noop(&[F::ZERO, F::ONE]),
|
||||
H::hash_or_noop(&[F::TWO, F::ONE]),
|
||||
H::hash_or_noop(&[F::TWO, F::TWO]),
|
||||
H::hash_or_noop(&[F::ZERO, F::ZERO]),
|
||||
H::hash_or_noop(&[F::ZERO.into(), F::ONE.into()]),
|
||||
H::hash_or_noop(&[F::TWO.into(), F::ONE.into()]),
|
||||
H::hash_or_noop(&[F::TWO.into(), F::TWO.into()]),
|
||||
H::hash_or_noop(&[F::ZERO.into(), F::ZERO.into()]),
|
||||
];
|
||||
assert_eq!(mat_1_leaf_hashes, fmt.digests[0..4]);
|
||||
|
||||
@ -276,10 +274,10 @@ mod tests {
|
||||
.zip(mat_2.iter())
|
||||
.map(|(row1, row2)| {
|
||||
let mut new_row = row1.clone();
|
||||
new_row.extend_from_slice(row2);
|
||||
new_row.extend_from_slice(&row2.clone().into_generic_field_vec());
|
||||
new_row
|
||||
})
|
||||
.collect::<Vec<Vec<F>>>();
|
||||
.collect::<Vec<Vec<GenericField<F>>>>();
|
||||
let layer_1 = [
|
||||
H::hash_or_noop(&new_leaves[0]),
|
||||
H::hash_or_noop(&new_leaves[1]),
|
||||
|
||||
@ -107,7 +107,7 @@ impl<F: RichField, H: Hasher<F>> DuplexState<F,H> {
|
||||
.find_any(|&candidate| {
|
||||
let mut duplex_state = state.clone();
|
||||
let mut sponge_input = input.clone();
|
||||
sponge_input.push(GenericField::Goldilocks(F::from_canonical_u64(candidate)));
|
||||
sponge_input.push(F::from_canonical_u64(candidate).into());
|
||||
H::sponge(&mut duplex_state, sponge_input);
|
||||
let temp_buf = Self::squeeze_f(&mut duplex_state);
|
||||
let pow_response = temp_buf.iter().last().unwrap();
|
||||
|
||||
@ -12,7 +12,7 @@ use crate::hash::poseidon::Poseidon;
|
||||
use crate::iop::target::Target;
|
||||
use crate::plonk::config::{GenericField, GenericHashOut};
|
||||
use ark_bn254::Fr as BN254Fr;
|
||||
use crate::hash::poseidon2_bn254::{bytes_to_felts, felts_to_bytes};
|
||||
use crate::hash::poseidon2_bn254::{bytes_le_to_felts, felts_to_bytes_le};
|
||||
|
||||
/// A prime order field with the features we need to use it as a base field in our argument system.
|
||||
pub trait RichField: PrimeField64 + Poseidon {}
|
||||
@ -30,7 +30,7 @@ impl Serialize for BN254HashOut {
|
||||
fn serialize < S > ( & self, serializer: S) -> Result < S::Ok, S::Error >
|
||||
where S: Serializer {
|
||||
|
||||
let element_to_bytes = felts_to_bytes(&self.element);
|
||||
let element_to_bytes = felts_to_bytes_le(&self.element);
|
||||
serializer.serialize_bytes( & element_to_bytes)
|
||||
}
|
||||
}
|
||||
@ -44,7 +44,7 @@ impl<'de> Deserialize<'de> for BN254HashOut {
|
||||
let mut element_array = < [u8; 32] >::default();
|
||||
element_array.copy_from_slice( & element_as_bytes[0..32]);
|
||||
|
||||
let deserialized_element = bytes_to_felts(&element_array);
|
||||
let deserialized_element = bytes_le_to_felts(&element_array);
|
||||
|
||||
Ok( Self {
|
||||
element: deserialized_element,
|
||||
@ -56,18 +56,18 @@ impl<'de> Deserialize<'de> for BN254HashOut {
|
||||
/// `F` here is the goldilocks not the BN254 field
|
||||
impl<F: RichField> GenericHashOut<F> for BN254HashOut {
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
felts_to_bytes(&self.element)
|
||||
felts_to_bytes_le(&self.element)
|
||||
}
|
||||
|
||||
fn from_bytes(bytes: &[u8]) -> Self {
|
||||
assert_eq!(bytes.len(), 32);
|
||||
BN254HashOut{
|
||||
element: bytes_to_felts(bytes)
|
||||
element: bytes_le_to_felts(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
fn to_vec(&self) -> Vec<GenericField<F>> {
|
||||
vec![GenericField::BN254(self.element.clone())]
|
||||
vec![self.element.clone().into()]
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,6 +163,7 @@ impl<F: RichField> GenericHashOut<F> for HashOut<F> {
|
||||
.copied()
|
||||
.map(GenericField::<F>::Goldilocks)
|
||||
.collect()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +248,7 @@ impl<F: RichField, const N: usize> GenericHashOut<F> for BytesHash<N> {
|
||||
let mut arr = [0u8; 8];
|
||||
arr[..bytes.len()].copy_from_slice(bytes);
|
||||
let raw = F::from_canonical_u64(u64::from_le_bytes(arr));
|
||||
GenericField::<F>::Goldilocks(raw)
|
||||
raw.into()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -109,11 +109,11 @@ impl<F: RichField, const N: usize> Hasher<F> for KeccakHash<N> {
|
||||
|
||||
fn hash_pad(input: &[GenericField<F>]) -> Self::Hash {
|
||||
let mut padded_input = input.to_vec();
|
||||
padded_input.push(GenericField::Goldilocks(F::ONE));
|
||||
padded_input.push(F::ONE.into());
|
||||
while (padded_input.len() + 1) % Self::Permutation::RATE != 0 {
|
||||
padded_input.push(GenericField::Goldilocks(F::ZERO));
|
||||
padded_input.push(F::ZERO.into());
|
||||
}
|
||||
padded_input.push(GenericField::Goldilocks(F::ONE));
|
||||
padded_input.push(F::ONE.into());
|
||||
Self::hash_no_pad(&padded_input)
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ use crate::hash::merkle_tree::MerkleCap;
|
||||
use crate::iop::target::{BoolTarget, Target};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::VerifierCircuitTarget;
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericField, GenericHashOut, Hasher};
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericField, GenericHashOut, Hasher, IntoGenericFieldVec};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||
#[serde(bound = "")]
|
||||
@ -79,7 +79,7 @@ pub fn verify_batch_merkle_proof_to_cap<F: RichField, H: Hasher<F>>(
|
||||
assert_eq!(leaf_data.len(), leaf_heights.len());
|
||||
let leaf_data_felts: Vec<Vec<GenericField<F>>> = leaf_data.into_iter()
|
||||
.map(|inner| {
|
||||
inner.into_iter().map(|f| GenericField::Goldilocks(f.clone())).collect()
|
||||
inner.clone().into_generic_field_vec()
|
||||
})
|
||||
.collect();
|
||||
let mut current_digest = H::hash_or_noop(&leaf_data_felts[0]);
|
||||
@ -102,7 +102,7 @@ pub fn verify_batch_merkle_proof_to_cap<F: RichField, H: Hasher<F>>(
|
||||
leaf_data_index += 1;
|
||||
}
|
||||
}
|
||||
assert_eq!(leaf_data_index, leaf_data.len());
|
||||
assert_eq!(leaf_data_index, leaf_data_felts.len());
|
||||
ensure!(
|
||||
current_digest == merkle_cap.0[leaf_index],
|
||||
"Invalid Merkle proof."
|
||||
|
||||
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::hash::merkle_proofs::MerkleProof;
|
||||
use crate::plonk::config::{GenericField, GenericHashOut, Hasher};
|
||||
use crate::plonk::config::{GenericField, GenericHashOut, Hasher, IntoGenericFieldVec};
|
||||
use crate::util::log2_strict;
|
||||
|
||||
/// The Merkle cap of height `h` of a Merkle tree is the `h`-th layer (from the root) of the tree.
|
||||
@ -209,7 +209,7 @@ impl<F: RichField, H: Hasher<F>> MerkleTree<F, H> {
|
||||
let cap_buf = capacity_up_to_mut(&mut cap, len_cap);
|
||||
let leaves_felts: Vec<Vec<GenericField<F>>> = leaves.clone().into_iter()
|
||||
.map(|inner| {
|
||||
inner.into_iter().map(|f| GenericField::Goldilocks(f)).collect()
|
||||
inner.into_generic_field_vec()
|
||||
})
|
||||
.collect();
|
||||
fill_digests_buf::<F, H>(digests_buf, cap_buf, &leaves_felts[..], cap_height);
|
||||
|
||||
@ -6,7 +6,7 @@ use num::Integer;
|
||||
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::hash::merkle_proofs::MerkleProof;
|
||||
use crate::plonk::config::{GenericField, Hasher};
|
||||
use crate::plonk::config::{GenericField, Hasher, IntoGenericFieldVec};
|
||||
|
||||
/// Compress multiple Merkle proofs on the same tree by removing redundancy in the Merkle paths.
|
||||
pub(crate) fn compress_merkle_proofs<F: RichField, H: Hasher<F>>(
|
||||
@ -68,7 +68,7 @@ pub(crate) fn decompress_merkle_proofs<F: RichField, H: Hasher<F>>(
|
||||
|
||||
for (&i, v) in leaves_indices.iter().zip(leaves_data) {
|
||||
// Observe the leaves.
|
||||
let v_felts: Vec<GenericField<F>> = v.clone().into_iter().map(GenericField::Goldilocks).collect();
|
||||
let v_felts: Vec<GenericField<F>> = v.clone().into_generic_field_vec();
|
||||
seen.insert(i + num_leaves, H::hash_or_noop(&v_felts));
|
||||
}
|
||||
|
||||
|
||||
@ -894,11 +894,11 @@ impl<F: RichField> Hasher<F> for PoseidonHash {
|
||||
|
||||
fn hash_pad(input: &[GenericField<F>]) -> Self::Hash {
|
||||
let mut padded_input = input.to_vec();
|
||||
padded_input.push(GenericField::Goldilocks(F::ONE));
|
||||
padded_input.push(F::ONE.into());
|
||||
while (padded_input.len() + 1) % Self::Permutation::RATE != 0 {
|
||||
padded_input.push(GenericField::Goldilocks(F::ZERO));
|
||||
padded_input.push(F::ZERO.into());
|
||||
}
|
||||
padded_input.push(GenericField::Goldilocks(F::ONE));
|
||||
padded_input.push(F::ONE.into());
|
||||
Self::hash_no_pad(&padded_input)
|
||||
}
|
||||
|
||||
|
||||
@ -10,9 +10,14 @@ use rust_bn254_hash::state::State;
|
||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||
use ark_bn254::{Fr as BN254Fr};
|
||||
use rust_bn254_hash::poseidon2::permutation::permute_inplace as permute_bn254_inplace;
|
||||
use ark_ff::{BigInt, PrimeField, Zero};
|
||||
use ark_ff::{ PrimeField, Zero,};
|
||||
use num::Integer;
|
||||
use num_bigint::BigUint;
|
||||
use ark_ff::BigInt as arkBigInt;
|
||||
use rust_bn254_hash::hash::Hash;
|
||||
use rust_bn254_hash::sponge::{sponge_felts_no_pad, sponge_felts_pad};
|
||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||
use plonky2_field::types::Field64;
|
||||
|
||||
pub const SPONGE_RATE: usize = 2;
|
||||
pub const SPONGE_CAPACITY: usize = 1;
|
||||
@ -84,8 +89,6 @@ impl PlonkyPermutation<BN254Fr> for Poseidon2BN254Perm {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Poseidon2BN254;
|
||||
impl<F: RichField> Hasher<F> for Poseidon2BN254 {
|
||||
@ -152,16 +155,46 @@ impl<F: RichField> Hasher<F> for Poseidon2BN254 {
|
||||
}
|
||||
|
||||
fn squeeze_goldilocks(state: &mut Self::Permutation) -> Vec<F> {
|
||||
// Squeeze out BN254 elements from the sponge state.
|
||||
let bn_out = state.squeeze();
|
||||
let bn_bytes: Vec<u8> = bn_out.iter().flat_map(|e| felts_to_bytes(e)).collect();
|
||||
let goldilocks_felts: Vec<F> = bytes_to_u64(&bn_bytes).iter().map(|e| F::from_canonical_u64(*e)).collect();
|
||||
assert!(goldilocks_felts.len()>0);
|
||||
goldilocks_felts
|
||||
|
||||
// convert bn to goldilocks
|
||||
bn_to_goldilocks(bn_out)
|
||||
}
|
||||
}
|
||||
|
||||
// --------- Conversion helper functions ---------------------
|
||||
|
||||
/// Converts a slice of BN254 field elements to a vector of Goldilocks (F)
|
||||
fn bn_to_goldilocks<F: RichField>(input: &[BN254Fr]) -> Vec<F> {
|
||||
// Goldilocks order
|
||||
let r: BigUint = BigUint::from(GoldilocksField::ORDER);
|
||||
|
||||
let mut goldilocks_felts = Vec::new();
|
||||
// For each BN254 field element, extract 3 Goldilocks elements.
|
||||
for fe in input.into_iter().cloned() {
|
||||
// Convert BN254Fr -> 256-bit big integer.
|
||||
let mut big: BigUint = fe.into_bigint().into();
|
||||
|
||||
// We want three remainders in [0, p_Goldilocks), each fits into a 64-bit integer.
|
||||
for _ in 0..3 {
|
||||
|
||||
let (quotient, remainder) = big.div_rem(&r);
|
||||
let rem_u64 = remainder.to_u64_digits();
|
||||
|
||||
// check just for safety:
|
||||
assert_eq!(rem_u64.len(), 1, "Remainder unexpectedly larger than 64 bits.");
|
||||
|
||||
let r64 = rem_u64[0];
|
||||
goldilocks_felts.push(F::from_canonical_u64(r64));
|
||||
|
||||
// Update big to the quotient for the next remainder.
|
||||
big = quotient;
|
||||
}
|
||||
}
|
||||
goldilocks_felts
|
||||
}
|
||||
|
||||
/// converts a vec of goldilocks to bn254
|
||||
/// takes 7 goldilocks and converts to 2 bn254
|
||||
fn goldilocks_to_bn<F: RichField>(input: &Vec<F>) -> Vec<BN254Fr>{
|
||||
@ -184,20 +217,15 @@ fn goldilocks_to_bn<F: RichField>(input: &Vec<F>) -> Vec<BN254Fr>{
|
||||
ws[i] = u64s[7 * m + i];
|
||||
}
|
||||
let (a, b) = u64s_to_felts(ws);
|
||||
// check that we don't push zero field elements
|
||||
if a != BN254Fr::zero() {
|
||||
result.push(a);
|
||||
}
|
||||
if b != BN254Fr::zero() {
|
||||
result.push(b);
|
||||
}
|
||||
result.push(a);
|
||||
result.push(b);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
const BIGINT_TWO_TO_64: BigInt<4> = BigInt( [0,1,0,0] );
|
||||
const BIGINT_TWO_TO_128: BigInt<4> = BigInt( [0,0,1,0] );
|
||||
const BIGINT_TWO_TO_192: BigInt<4> = BigInt( [0,0,0,1] );
|
||||
const BIGINT_TWO_TO_64: arkBigInt<4> = arkBigInt( [0,1,0,0] );
|
||||
const BIGINT_TWO_TO_128: arkBigInt<4> = arkBigInt( [0,0,1,0] );
|
||||
const BIGINT_TWO_TO_192: arkBigInt<4> = arkBigInt( [0,0,0,1] );
|
||||
|
||||
/// converts u64 to BN254 - taken directly from: rust-bn254-hash
|
||||
pub fn u64s_to_felts(ws: [u64; 7]) -> (BN254Fr, BN254Fr) {
|
||||
@ -224,38 +252,6 @@ pub fn u64s_to_felts(ws: [u64; 7]) -> (BN254Fr, BN254Fr) {
|
||||
(x, y)
|
||||
}
|
||||
|
||||
/// converts a slice of bytes to 64 by taking 63 bits at a time
|
||||
/// this makes it safe for conversion from bytes to Goldilocks field elems
|
||||
/// this fn ignores any remaining bit that are less than 63 bits at the end
|
||||
pub fn bytes_to_u64(x: &[u8]) -> Vec<u64> {
|
||||
let total_bits = x.len() * 8;
|
||||
let num_chunks = total_bits / 63; // ignore any leftover bits
|
||||
let mut result = Vec::with_capacity(num_chunks);
|
||||
|
||||
for i in 0..num_chunks {
|
||||
let bit_offset = i * 63;
|
||||
let first_byte = bit_offset / 8;
|
||||
let shift = bit_offset % 8;
|
||||
// how many bits do we need? We need (shift + 63) bits in total.
|
||||
// convert that to bytes by rounding up.
|
||||
let needed_bytes = ((shift + 63) + 7) / 8;
|
||||
|
||||
if first_byte + needed_bytes > x.len() {
|
||||
break; // break out if incomplete chunk
|
||||
}
|
||||
|
||||
let mut chunk: u128 = 0;
|
||||
for j in 0..needed_bytes {
|
||||
chunk |= (x[first_byte + j] as u128) << (8 * j);
|
||||
}
|
||||
// shift right with `shift` bits, then mask 63 bits.
|
||||
let value = (chunk >> shift) & ((1u128 << 63) - 1);
|
||||
result.push(value as u64);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// helper function: converts a slice of GenericField<F> into a Vec<BN254Fr>
|
||||
/// the fn groups consecutive Goldilocks elements and converting them in one shot.
|
||||
fn generic_field_to_bn<F: RichField>(input: &[GenericField<F>]) -> Vec<BN254Fr> {
|
||||
@ -302,7 +298,7 @@ fn check_len_in_bytes<F: RichField>(input: &[GenericField<F>]) -> usize{
|
||||
|
||||
//------------------ serialization for BN254 ---------------------
|
||||
|
||||
pub fn felts_to_bytes<E>(f: &E) -> Vec<u8> where
|
||||
pub fn felts_to_bytes_le<E>(f: &E) -> Vec<u8> where
|
||||
E: CanonicalSerialize
|
||||
{
|
||||
let mut bytes = Vec::new();
|
||||
@ -310,7 +306,7 @@ pub fn felts_to_bytes<E>(f: &E) -> Vec<u8> where
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn bytes_to_felts<E>(bytes: &[u8]) -> E where
|
||||
pub fn bytes_le_to_felts<E>(bytes: &[u8]) -> E where
|
||||
E: CanonicalDeserialize
|
||||
{
|
||||
let fr_res = E::deserialize_uncompressed(bytes).unwrap();
|
||||
@ -329,3 +325,41 @@ pub fn felts_to_u64<E>(f: E) -> Vec<u64>
|
||||
.map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ark_bn254::Fr as BN254Fr;
|
||||
use ark_ff::{One, Zero};
|
||||
|
||||
/// Test that converting a bn254 element to bytes and back.
|
||||
#[test]
|
||||
fn test_felts_bytes_roundtrip() {
|
||||
let element = <BN254Fr as PrimeField>::from_bigint(arkBigInt::from(987654321u64)).unwrap();
|
||||
let bytes = felts_to_bytes_le(&element);
|
||||
assert_eq!(bytes.len(), 32, "Expected 32 bytes for BN254Fr serialization");
|
||||
let recovered: BN254Fr = bytes_le_to_felts(&bytes);
|
||||
assert_eq!(element, recovered, "Roundtrip conversion did not recover the original element");
|
||||
}
|
||||
|
||||
/// Test roundtrip with edge cases: zero and one.
|
||||
#[test]
|
||||
fn test_zero_and_one_byte_conversion() {
|
||||
let zero = BN254Fr::zero();
|
||||
let one = BN254Fr::one();
|
||||
|
||||
let zero_bytes = felts_to_bytes_le(&zero);
|
||||
let one_bytes = felts_to_bytes_le(&one);
|
||||
|
||||
// Check that both serializations are 32 bytes.
|
||||
assert_eq!(zero_bytes.len(), 32, "Zero should serialize to 32 bytes");
|
||||
assert_eq!(one_bytes.len(), 32, "One should serialize to 32 bytes");
|
||||
|
||||
let zero_back: BN254Fr = bytes_le_to_felts(&zero_bytes);
|
||||
let one_back: BN254Fr = bytes_le_to_felts(&one_bytes);
|
||||
|
||||
assert_eq!(zero, zero_back, "Zero did not roundtrip correctly");
|
||||
assert_eq!(one, one_back, "One did not roundtrip correctly");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ impl<F: RichField, H: Hasher<F>> Challenger<F, H>
|
||||
where
|
||||
F: RichField + Extendable<D>,
|
||||
{
|
||||
let elements = element.to_basefield_array().map(|e: F|GenericField::<F>::Goldilocks(e));
|
||||
let elements = element.to_basefield_array().map(|e: F|e.into());
|
||||
|
||||
self.observe_elements(&elements);
|
||||
}
|
||||
@ -268,7 +268,7 @@ mod tests {
|
||||
use crate::iop::witness::{PartialWitness, Witness};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use crate::plonk::config::{GenericConfig, GenericField, IntoGenericFieldVec, PoseidonGoldilocksConfig};
|
||||
|
||||
#[test]
|
||||
fn no_duplicate_challenges() {
|
||||
@ -280,7 +280,7 @@ mod tests {
|
||||
|
||||
for i in 1..10 {
|
||||
challenges.extend(challenger.get_n_challenges(i));
|
||||
challenger.observe_element(F::rand());
|
||||
challenger.observe_element(F::rand().into());
|
||||
}
|
||||
|
||||
let dedup_challenges = {
|
||||
@ -304,10 +304,14 @@ mod tests {
|
||||
let num_outputs_per_round = [1, 2, 4];
|
||||
|
||||
// Generate random input messages.
|
||||
let inputs_per_round: Vec<Vec<F>> = num_inputs_per_round
|
||||
let inputs_per_round_f: Vec<Vec<F>> = num_inputs_per_round
|
||||
.iter()
|
||||
.map(|&n| F::rand_vec(n))
|
||||
.collect();
|
||||
let inputs_per_round: Vec<Vec<GenericField<F>>> = inputs_per_round_f
|
||||
.iter()
|
||||
.map(|n| n.clone().into_generic_field_vec())
|
||||
.collect();
|
||||
|
||||
let mut challenger = Challenger::<F, <C as GenericConfig<D>>::InnerHasher>::new();
|
||||
let mut outputs_per_round: Vec<Vec<F>> = Vec::new();
|
||||
@ -321,7 +325,7 @@ mod tests {
|
||||
let mut recursive_challenger =
|
||||
RecursiveChallenger::<F, <C as GenericConfig<D>>::InnerHasher, D>::new(&mut builder);
|
||||
let mut recursive_outputs_per_round: Vec<Vec<Target>> = Vec::new();
|
||||
for (r, inputs) in inputs_per_round.iter().enumerate() {
|
||||
for (r, inputs) in inputs_per_round_f.iter().enumerate() {
|
||||
recursive_challenger.observe_elements(&builder.constants(inputs));
|
||||
recursive_outputs_per_round.push(
|
||||
recursive_challenger.get_n_challenges(&mut builder, num_outputs_per_round[r]),
|
||||
|
||||
@ -44,7 +44,7 @@ use crate::plonk::circuit_data::{
|
||||
CircuitConfig, CircuitData, CommonCircuitData, MockCircuitData, ProverCircuitData,
|
||||
ProverOnlyCircuitData, VerifierCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData,
|
||||
};
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericConfig, GenericField, GenericHashOut, Hasher};
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericConfig, GenericField, GenericHashOut, Hasher, IntoGenericFieldVec};
|
||||
use crate::plonk::copy_constraint::CopyConstraint;
|
||||
use crate::plonk::permutation_argument::Forest;
|
||||
use crate::plonk::plonk_common::PlonkOracle;
|
||||
@ -1256,14 +1256,14 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
};
|
||||
let constants_sigmas_cap = constants_sigmas_commitment.merkle_tree.cap.clone();
|
||||
let domain_separator = self.domain_separator.unwrap_or_default();
|
||||
let ds_felts: Vec<GenericField<F>> = domain_separator.clone().into_iter().map(GenericField::Goldilocks).collect();
|
||||
let ds_felts: Vec<GenericField<F>> = domain_separator.clone().into_generic_field_vec();
|
||||
let domain_separator_digest = C::Hasher::hash_pad(&ds_felts);
|
||||
// TODO: This should also include an encoding of gate constraints.
|
||||
let circuit_digest_parts = [
|
||||
constants_sigmas_cap.flatten(),
|
||||
domain_separator_digest.to_vec(),
|
||||
vec![
|
||||
GenericField::Goldilocks(F::from_canonical_usize(degree_bits)),
|
||||
F::from_canonical_usize(degree_bits).into(),
|
||||
/* Add other circuit data here */
|
||||
],
|
||||
];
|
||||
|
||||
@ -24,7 +24,7 @@ use crate::iop::target::{BoolTarget, Target};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use ark_bn254::Fr as BN254Fr;
|
||||
use ark_ff::{One, Zero};
|
||||
use crate::hash::poseidon2_bn254::{bytes_to_felts, felts_to_bytes, Poseidon2BN254};
|
||||
use crate::hash::poseidon2_bn254::{bytes_le_to_felts, felts_to_bytes_le, Poseidon2BN254};
|
||||
|
||||
pub trait GenericHashOut<F: RichField>:
|
||||
Copy + Clone + Debug + Eq + PartialEq + Send + Sync + Serialize + DeserializeOwned
|
||||
@ -43,13 +43,44 @@ pub enum GenericField<F: RichField> {
|
||||
BN254(BN254Fr),
|
||||
}
|
||||
|
||||
// Convert a Goldilocks field element into a GenericField.
|
||||
impl<F: RichField> From<F> for GenericField<F> {
|
||||
fn from(x: F) -> Self {
|
||||
GenericField::Goldilocks(x)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert a BN254Fr element into a GenericField.
|
||||
impl<F: RichField> From<BN254Fr> for GenericField<F> {
|
||||
fn from(x: BN254Fr) -> Self {
|
||||
GenericField::BN254(x)
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension trait to convert vectors of F or BN254Fr to Vec<GenericField<F>>.
|
||||
pub trait IntoGenericFieldVec<F: RichField> {
|
||||
fn into_generic_field_vec(self) -> Vec<GenericField<F>>;
|
||||
}
|
||||
|
||||
impl<F: RichField> IntoGenericFieldVec<F> for Vec<F> {
|
||||
fn into_generic_field_vec(self) -> Vec<GenericField<F>> {
|
||||
self.into_iter().map(GenericField::from).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: RichField> IntoGenericFieldVec<F> for Vec<BN254Fr> {
|
||||
fn into_generic_field_vec(self) -> Vec<GenericField<F>> {
|
||||
self.into_iter().map(GenericField::from).collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// hasher field trait to cover fields in `GenericField` enum
|
||||
pub trait HasherField: Default + Sized + Copy + Debug + Eq + PartialEq + Sync + Send {
|
||||
fn get_one() -> Self;
|
||||
fn get_zero() -> Self;
|
||||
fn to_bytes(&self) -> Vec<u8>;
|
||||
fn to_bytes_le(&self) -> Vec<u8>;
|
||||
|
||||
fn from_bytes(b: &[u8]) -> Self;
|
||||
fn from_bytes_le(b: &[u8]) -> Self;
|
||||
|
||||
}
|
||||
|
||||
@ -63,12 +94,12 @@ impl HasherField for BN254Fr {
|
||||
BN254Fr::zero()
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
felts_to_bytes::<BN254Fr>(&self)
|
||||
fn to_bytes_le(&self) -> Vec<u8> {
|
||||
felts_to_bytes_le::<BN254Fr>(&self)
|
||||
}
|
||||
|
||||
fn from_bytes(b: &[u8]) -> Self {
|
||||
bytes_to_felts::<BN254Fr>(b)
|
||||
fn from_bytes_le(b: &[u8]) -> Self {
|
||||
bytes_le_to_felts::<BN254Fr>(b)
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,11 +113,11 @@ impl <T: RichField> HasherField for T {
|
||||
T::ZERO
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
fn to_bytes_le(&self) -> Vec<u8> {
|
||||
self.to_canonical_u64().to_le_bytes().to_vec()
|
||||
}
|
||||
|
||||
fn from_bytes(b: &[u8]) -> Self {
|
||||
fn from_bytes_le(b: &[u8]) -> Self {
|
||||
assert_eq!(b.len(), 8, "Input vector must have exactly 8 bytes");
|
||||
let arr: [u8; 8] = b.try_into().expect("Conversion to array failed");
|
||||
let element = u64::from_le_bytes(arr);
|
||||
@ -180,7 +211,7 @@ impl GenericConfig<2> for KeccakGoldilocksConfig {
|
||||
}
|
||||
|
||||
/// Configuration using Poseidon2BN254 as hasher over the Goldilocks field.
|
||||
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Serialize)]
|
||||
pub struct Poseidon2BN254Config;
|
||||
impl GenericConfig<2> for Poseidon2BN254Config {
|
||||
type F = GoldilocksField;
|
||||
|
||||
@ -25,7 +25,7 @@ use crate::hash::merkle_tree::MerkleCap;
|
||||
use crate::iop::ext_target::ExtensionTarget;
|
||||
use crate::iop::target::Target;
|
||||
use crate::plonk::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData};
|
||||
use crate::plonk::config::{GenericConfig, GenericField, Hasher};
|
||||
use crate::plonk::config::{GenericConfig, GenericField, Hasher, IntoGenericFieldVec};
|
||||
use crate::plonk::verifier::{verify_with_challenges, DEFAULT_VERIFIER_OPTIONS};
|
||||
use crate::util::serialization::{Buffer, Read, Write};
|
||||
|
||||
@ -104,7 +104,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
pub fn get_public_inputs_hash(
|
||||
&self,
|
||||
) -> <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash {
|
||||
let pi_felts: Vec<GenericField<F>> = self.public_inputs.clone().into_iter().map(GenericField::Goldilocks).collect();
|
||||
let pi_felts: Vec<GenericField<F>> = self.public_inputs.clone().into_generic_field_vec();
|
||||
C::InnerHasher::hash_no_pad(&pi_felts)
|
||||
}
|
||||
|
||||
@ -235,7 +235,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
pub(crate) fn get_public_inputs_hash(
|
||||
&self,
|
||||
) -> <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash {
|
||||
let pi_felts: Vec<GenericField<F>> = self.public_inputs.clone().into_iter().map(GenericField::Goldilocks).collect();
|
||||
let pi_felts: Vec<GenericField<F>> = self.public_inputs.clone().into_generic_field_vec();
|
||||
C::InnerHasher::hash_no_pad(&pi_felts)
|
||||
}
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ use crate::iop::target::Target;
|
||||
use crate::iop::witness::{MatrixWitness, PartialWitness, PartitionWitness, Witness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::NUM_COINS_LOOKUP;
|
||||
use crate::plonk::circuit_data::{CommonCircuitData, ProverOnlyCircuitData};
|
||||
use crate::plonk::config::{GenericConfig, GenericField, Hasher};
|
||||
use crate::plonk::config::{GenericConfig, GenericField, Hasher, IntoGenericFieldVec};
|
||||
use crate::plonk::plonk_common::PlonkOracle;
|
||||
use crate::plonk::proof::{OpeningSet, Proof, ProofWithPublicInputs};
|
||||
use crate::plonk::vanishing_poly::{eval_vanishing_poly_base_batch, get_lut_poly};
|
||||
@ -269,7 +269,7 @@ where
|
||||
set_lookup_wires(prover_data, common_data, &mut partition_witness)?;
|
||||
|
||||
let public_inputs = partition_witness.get_targets(&prover_data.public_inputs);
|
||||
let pi_felts: Vec<GenericField<F>> = public_inputs.clone().into_iter().map(GenericField::Goldilocks).collect();
|
||||
let pi_felts: Vec<GenericField<F>> = public_inputs.clone().into_generic_field_vec();
|
||||
let public_inputs_hash = C::InnerHasher::hash_no_pad(&pi_felts);
|
||||
|
||||
let witness = timed!(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user