use core::fmt::Debug;
use core::mem::size_of;
use std::borrow::Borrow;
use std::borrow::BorrowMut;
use itertools::Itertools;
use p3_field::{AbstractField, PrimeField32};
use serde::{Deserialize, Serialize};
use super::Word;
use crate::stark::PROOF_MAX_NUM_PVS;
pub const SP1_PROOF_NUM_PV_ELTS: usize = size_of::<PublicValues<Word<u8>, u8>>();
pub const PV_DIGEST_NUM_WORDS: usize = 8;
pub const POSEIDON_NUM_WORDS: usize = 8;
#[derive(Serialize, Deserialize, Clone, Copy, Default, Debug)]
#[repr(C)]
pub struct PublicValues<W, T> {
pub committed_value_digest: [W; PV_DIGEST_NUM_WORDS],
pub deferred_proofs_digest: [T; POSEIDON_NUM_WORDS],
pub start_pc: T,
pub next_pc: T,
pub exit_code: T,
pub shard: T,
pub execution_shard: T,
pub previous_init_addr_bits: [T; 32],
pub last_init_addr_bits: [T; 32],
pub previous_finalize_addr_bits: [T; 32],
pub last_finalize_addr_bits: [T; 32],
}
impl PublicValues<u32, u32> {
pub fn to_vec<F: AbstractField>(&self) -> Vec<F> {
let mut ret = vec![F::zero(); PROOF_MAX_NUM_PVS];
let field_values = PublicValues::<Word<F>, F>::from(*self);
let ret_ref_mut: &mut PublicValues<Word<F>, F> = ret.as_mut_slice().borrow_mut();
*ret_ref_mut = field_values;
ret
}
pub fn reset(&self) -> Self {
let mut copy = *self;
copy.shard = 0;
copy.execution_shard = 0;
copy.start_pc = 0;
copy.next_pc = 0;
copy.previous_init_addr_bits = [0; 32];
copy.last_init_addr_bits = [0; 32];
copy.previous_finalize_addr_bits = [0; 32];
copy.last_finalize_addr_bits = [0; 32];
copy
}
}
impl<F: PrimeField32> PublicValues<Word<F>, F> {
pub fn commit_digest_bytes(&self) -> Vec<u8> {
self.committed_value_digest
.iter()
.flat_map(|w| w.into_iter().map(|f| f.as_canonical_u32() as u8))
.collect_vec()
}
}
impl<T: Clone> Borrow<PublicValues<Word<T>, T>> for [T] {
fn borrow(&self) -> &PublicValues<Word<T>, T> {
let size = std::mem::size_of::<PublicValues<Word<u8>, u8>>();
debug_assert!(self.len() >= size);
let slice = &self[0..size];
let (prefix, shorts, _suffix) = unsafe { slice.align_to::<PublicValues<Word<T>, T>>() };
debug_assert!(prefix.is_empty(), "Alignment should match");
debug_assert_eq!(shorts.len(), 1);
&shorts[0]
}
}
impl<T: Clone> BorrowMut<PublicValues<Word<T>, T>> for [T] {
fn borrow_mut(&mut self) -> &mut PublicValues<Word<T>, T> {
let size = std::mem::size_of::<PublicValues<Word<u8>, u8>>();
debug_assert!(self.len() >= size);
let slice = &mut self[0..size];
let (prefix, shorts, _suffix) = unsafe { slice.align_to_mut::<PublicValues<Word<T>, T>>() };
debug_assert!(prefix.is_empty(), "Alignment should match");
debug_assert_eq!(shorts.len(), 1);
&mut shorts[0]
}
}
impl<F: AbstractField> From<PublicValues<u32, u32>> for PublicValues<Word<F>, F> {
fn from(value: PublicValues<u32, u32>) -> Self {
let PublicValues {
committed_value_digest,
deferred_proofs_digest,
start_pc,
next_pc,
exit_code,
shard,
execution_shard,
previous_init_addr_bits,
last_init_addr_bits,
previous_finalize_addr_bits,
last_finalize_addr_bits,
} = value;
let committed_value_digest: [_; PV_DIGEST_NUM_WORDS] =
core::array::from_fn(|i| Word::from(committed_value_digest[i]));
let deferred_proofs_digest: [_; POSEIDON_NUM_WORDS] =
core::array::from_fn(|i| F::from_canonical_u32(deferred_proofs_digest[i]));
let start_pc = F::from_canonical_u32(start_pc);
let next_pc = F::from_canonical_u32(next_pc);
let exit_code = F::from_canonical_u32(exit_code);
let shard = F::from_canonical_u32(shard);
let execution_shard = F::from_canonical_u32(execution_shard);
let previous_init_addr_bits = previous_init_addr_bits.map(F::from_canonical_u32);
let last_init_addr_bits = last_init_addr_bits.map(F::from_canonical_u32);
let previous_finalize_addr_bits = previous_finalize_addr_bits.map(F::from_canonical_u32);
let last_finalize_addr_bits = last_finalize_addr_bits.map(F::from_canonical_u32);
Self {
committed_value_digest,
deferred_proofs_digest,
start_pc,
next_pc,
exit_code,
shard,
execution_shard,
previous_init_addr_bits,
last_init_addr_bits,
previous_finalize_addr_bits,
last_finalize_addr_bits,
}
}
}
#[cfg(test)]
mod tests {
use crate::air::public_values;
#[test]
fn test_public_values_digest_num_words_consistency_zkvm() {
assert_eq!(
public_values::PV_DIGEST_NUM_WORDS,
sp1_zkvm::PV_DIGEST_NUM_WORDS
);
}
}