add serialization to circuit targets.

This commit is contained in:
M Alghazwi 2025-04-09 16:32:40 +02:00
parent b2bb9ebf52
commit 6a119c3d4c
No known key found for this signature in database
GPG Key ID: 646E567CAD7DB607
4 changed files with 59 additions and 22 deletions

View File

@ -12,8 +12,10 @@ use plonky2::{
}; };
use std::marker::PhantomData; use std::marker::PhantomData;
use plonky2::plonk::config::AlgebraicHasher; use plonky2::plonk::config::AlgebraicHasher;
use serde::{Deserialize, Serialize};
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
use crate::circuits::keyed_compress::key_compress_circuit; use crate::circuits::keyed_compress::key_compress_circuit;
use crate::circuits::serialization::SerializableHashOutTarget;
use crate::circuits::utils::{add_assign_hash_out_target, mul_hash_out_target}; use crate::circuits::utils::{add_assign_hash_out_target, mul_hash_out_target};
use crate::Result; use crate::Result;
use crate::error::CircuitError; use crate::error::CircuitError;
@ -34,10 +36,10 @@ pub struct MerkleTreeTargets{
pub merkle_path: MerkleProofTarget, pub merkle_path: MerkleProofTarget,
} }
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct MerkleProofTarget { pub struct MerkleProofTarget {
/// The Merkle digest of each sibling subtree, staying from the bottommost layer. /// The Merkle digest of each sibling subtree, staying from the bottommost layer.
pub path: Vec<HashOutTarget>, pub path: Vec<SerializableHashOutTarget>,
} }
/// Merkle tree circuit contains the functions for /// Merkle tree circuit contains the functions for
@ -139,8 +141,8 @@ impl<
let mut left = vec![]; let mut left = vec![];
let mut right = vec![]; let mut right = vec![];
for j in 0..NUM_HASH_OUT_ELTS { for j in 0..NUM_HASH_OUT_ELTS {
left.push( builder.select(bit, sibling.elements[j], state[i].elements[j])); left.push( builder.select(bit, sibling.0.elements[j], state[i].elements[j]));
right.push( builder.select(bit, state[i].elements[j], sibling.elements[j])); right.push( builder.select(bit, state[i].elements[j], sibling.0.elements[j]));
} }
// Compress them with a keyed-hash function // Compress them with a keyed-hash function

View File

@ -4,3 +4,4 @@ pub mod utils;
pub mod params; pub mod params;
pub mod keyed_compress; pub mod keyed_compress;
pub mod sponge; pub mod sponge;
pub mod serialization;

View File

@ -19,6 +19,7 @@ use plonky2::{
plonk::circuit_builder::CircuitBuilder, plonk::circuit_builder::CircuitBuilder,
}; };
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
use serde::{Deserialize, Serialize};
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
use crate::{ use crate::{
@ -32,6 +33,7 @@ use crate::{
error::CircuitError, error::CircuitError,
}; };
use crate::circuit_helper::Plonky2Circuit; use crate::circuit_helper::Plonky2Circuit;
use crate::circuits::serialization::SerializableHashOutTarget;
/// circuit for sampling a slot in a dataset merkle tree /// circuit for sampling a slot in a dataset merkle tree
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -60,14 +62,14 @@ impl<
/// struct of input to the circuit as targets /// struct of input to the circuit as targets
/// used to build the circuit and can be assigned after building /// used to build the circuit and can be assigned after building
#[derive(Clone, Debug)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SampleTargets { pub struct SampleTargets {
pub entropy: HashOutTarget, // public input pub entropy: SerializableHashOutTarget, // public input
pub dataset_root: HashOutTarget, // public input pub dataset_root: SerializableHashOutTarget, // public input
pub slot_index: Target, // public input pub slot_index: Target, // public input
pub slot_root: HashOutTarget, pub slot_root: SerializableHashOutTarget,
pub n_cells_per_slot: Target, pub n_cells_per_slot: Target,
pub n_slots_per_dataset: Target, pub n_slots_per_dataset: Target,
@ -108,7 +110,7 @@ pub struct MerklePath<
} }
/// a vec of cell targets /// a vec of cell targets
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct CellTarget { pub struct CellTarget {
pub data: Vec<Target> pub data: Vec<Target>
} }
@ -137,8 +139,8 @@ impl<
let targets = self.sample_slot_circuit(builder)?; let targets = self.sample_slot_circuit(builder)?;
let mut pub_targets = vec![]; let mut pub_targets = vec![];
pub_targets.push(targets.slot_index); pub_targets.push(targets.slot_index);
pub_targets.extend_from_slice(&targets.dataset_root.elements); pub_targets.extend_from_slice(&targets.dataset_root.0.elements);
pub_targets.extend_from_slice(&targets.entropy.elements); pub_targets.extend_from_slice(&targets.entropy.0.elements);
builder.register_public_inputs(&pub_targets); builder.register_public_inputs(&pub_targets);
Ok(targets) Ok(targets)
} }
@ -180,7 +182,7 @@ impl<
// dataset Merkle path (sibling hashes from leaf to root) // dataset Merkle path (sibling hashes from leaf to root)
let d_merkle_path = MerkleProofTarget { let d_merkle_path = MerkleProofTarget {
path: (0..max_log2_n_slots).map(|_| builder.add_virtual_hash()).collect(), path: (0..max_log2_n_slots).map(|_| builder.add_virtual_hash()).map(SerializableHashOutTarget::from).collect(),
}; };
// create MerkleTreeTargets struct // create MerkleTreeTargets struct
@ -255,11 +257,11 @@ impl<
let s_path_bits = b_path_bits.split_off(block_tree_depth); let s_path_bits = b_path_bits.split_off(block_tree_depth);
let b_merkle_path = MerkleProofTarget { let b_merkle_path = MerkleProofTarget {
path: (0..block_tree_depth).map(|_| builder.add_virtual_hash()).collect(), path: (0..block_tree_depth).map(|_| builder.add_virtual_hash()).map(SerializableHashOutTarget::from).collect(),
}; };
let s_merkle_path = MerkleProofTarget { let s_merkle_path = MerkleProofTarget {
path: (0..(max_depth - block_tree_depth)).map(|_| builder.add_virtual_hash()).collect(), path: (0..(max_depth - block_tree_depth)).map(|_| builder.add_virtual_hash()).map(SerializableHashOutTarget::from).collect(),
}; };
let mut block_targets = MerkleTreeTargets { let mut block_targets = MerkleTreeTargets {
@ -304,10 +306,10 @@ impl<
} }
let st = SampleTargets { let st = SampleTargets {
entropy: entropy_target, entropy: entropy_target.into(),
dataset_root: d_expected_root, dataset_root: d_expected_root.into(),
slot_index, slot_index,
slot_root: d_targets.leaf, slot_root: d_targets.leaf.into(),
n_cells_per_slot, n_cells_per_slot,
n_slots_per_dataset, n_slots_per_dataset,
slot_proof: d_targets.merkle_path, slot_proof: d_targets.merkle_path,
@ -367,7 +369,7 @@ impl<
// assign dataset proof // assign dataset proof
for (i, sibling_hash) in witnesses.slot_proof.iter().enumerate() { for (i, sibling_hash) in witnesses.slot_proof.iter().enumerate() {
pw.set_hash_target(targets.slot_proof.path[i], *sibling_hash) pw.set_hash_target(targets.slot_proof.path[i].0, *sibling_hash)
.map_err(|e| { .map_err(|e| {
CircuitError::HashTargetAssignmentError("slot_proof".to_string(), e.to_string()) CircuitError::HashTargetAssignmentError("slot_proof".to_string(), e.to_string())
})?; })?;
@ -379,19 +381,19 @@ impl<
})?; })?;
// assign the expected Merkle root of dataset to the target // assign the expected Merkle root of dataset to the target
pw.set_hash_target(targets.dataset_root, witnesses.dataset_root) pw.set_hash_target(targets.dataset_root.0, witnesses.dataset_root)
.map_err(|e| { .map_err(|e| {
CircuitError::HashTargetAssignmentError("dataset_root".to_string(), e.to_string()) CircuitError::HashTargetAssignmentError("dataset_root".to_string(), e.to_string())
})?; })?;
// assign the sampled slot // assign the sampled slot
pw.set_hash_target(targets.slot_root, witnesses.slot_root) pw.set_hash_target(targets.slot_root.0, witnesses.slot_root)
.map_err(|e| { .map_err(|e| {
CircuitError::HashTargetAssignmentError("slot_root".to_string(), e.to_string()) CircuitError::HashTargetAssignmentError("slot_root".to_string(), e.to_string())
})?; })?;
// assign entropy // assign entropy
assign_hash_out_targets(pw, &targets.entropy, &witnesses.entropy)?; assign_hash_out_targets(pw, &targets.entropy.0, &witnesses.entropy)?;
// do the sample N times // do the sample N times
for i in 0..n_samples { for i in 0..n_samples {
@ -406,7 +408,7 @@ impl<
// assign proof for that cell // assign proof for that cell
let cell_proof = witnesses.merkle_paths[i].path.clone(); let cell_proof = witnesses.merkle_paths[i].path.clone();
for k in 0..max_depth { for k in 0..max_depth {
pw.set_hash_target(targets.merkle_paths[i].path[k], cell_proof[k]) pw.set_hash_target(targets.merkle_paths[i].path[k].0, cell_proof[k])
.map_err(|e| { .map_err(|e| {
CircuitError::HashTargetAssignmentError("merkle_paths".to_string(), e.to_string()) CircuitError::HashTargetAssignmentError("merkle_paths".to_string(), e.to_string())
})?; })?;

View File

@ -0,0 +1,32 @@
use plonky2::hash::hash_types::{HashOutTarget, NUM_HASH_OUT_ELTS};
use plonky2::iop::target::Target;
use serde::{Serialize, Deserialize};
/// Define a wrapper around HashOutTarget just for serialization
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct SerializableHashOutTarget(pub HashOutTarget);
impl From<HashOutTarget> for SerializableHashOutTarget {
fn from(inner: HashOutTarget) -> Self {
SerializableHashOutTarget(inner)
}
}
impl Serialize for SerializableHashOutTarget {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.elements.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for SerializableHashOutTarget {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let elements = <[Target; NUM_HASH_OUT_ELTS]>::deserialize(deserializer)?;
Ok(SerializableHashOutTarget(HashOutTarget { elements }))
}
}