Skip to main content

sp1_recursion_circuit/machine/
public_values.rs

1use itertools::Itertools;
2use sp1_derive::AlignedBorrow;
3use sp1_hypercube::air::{PROOF_NONCE_NUM_WORDS, PV_DIGEST_NUM_WORDS};
4use sp1_primitives::SP1Field;
5use sp1_recursion_compiler::ir::{Builder, Felt};
6use sp1_recursion_executor::{RecursionPublicValues, DIGEST_SIZE, NUM_PV_ELMS_TO_HASH};
7
8use crate::{hash::Poseidon2SP1FieldHasherVariable, CircuitConfig};
9
10#[derive(Debug, Clone, Copy, Default, AlignedBorrow)]
11#[repr(C)]
12pub struct RootPublicValues<T> {
13    pub(crate) inner: RecursionPublicValues<T>,
14}
15
16/// Verifies the digest of a recursive public values struct.
17pub(crate) fn assert_recursion_public_values_valid<C, H>(
18    builder: &mut Builder<C>,
19    public_values: &RecursionPublicValues<Felt<SP1Field>>,
20) where
21    C: CircuitConfig,
22    H: Poseidon2SP1FieldHasherVariable<C>,
23{
24    let digest = recursion_public_values_digest::<C, H>(builder, public_values);
25    for (value, expected) in public_values.digest.iter().copied().zip_eq(digest) {
26        builder.assert_felt_eq(value, expected);
27    }
28}
29
30/// Verifies the digest of a recursive public values struct.
31pub(crate) fn recursion_public_values_digest<C, H>(
32    builder: &mut Builder<C>,
33    public_values: &RecursionPublicValues<Felt<SP1Field>>,
34) -> [Felt<SP1Field>; DIGEST_SIZE]
35where
36    C: CircuitConfig,
37    H: Poseidon2SP1FieldHasherVariable<C>,
38{
39    let pv_slice = public_values.as_array();
40    H::poseidon2_hash(builder, &pv_slice[..NUM_PV_ELMS_TO_HASH])
41}
42
43/// Assert that the digest of the root public values is correct.
44pub(crate) fn assert_root_public_values_valid<C, H>(
45    builder: &mut Builder<C>,
46    public_values: &RootPublicValues<Felt<SP1Field>>,
47) where
48    C: CircuitConfig,
49    H: Poseidon2SP1FieldHasherVariable<C>,
50{
51    let expected_digest = root_public_values_digest::<C, H>(builder, &public_values.inner);
52    for (value, expected) in public_values.inner.digest.iter().copied().zip_eq(expected_digest) {
53        builder.assert_felt_eq(value, expected);
54    }
55}
56
57/// Compute the digest of the root public values.
58pub(crate) fn root_public_values_digest<C, H>(
59    builder: &mut Builder<C>,
60    public_values: &RecursionPublicValues<Felt<SP1Field>>,
61) -> [Felt<SP1Field>; DIGEST_SIZE]
62where
63    C: CircuitConfig,
64    H: Poseidon2SP1FieldHasherVariable<C>,
65{
66    let input = public_values
67        .sp1_vk_digest
68        .into_iter()
69        .chain(public_values.committed_value_digest.into_iter().flat_map(|word| word.into_iter()))
70        .chain(std::iter::once(public_values.exit_code))
71        .chain(public_values.vk_root)
72        .chain(public_values.proof_nonce)
73        .collect::<Vec<_>>();
74    H::poseidon2_hash(builder, &input)
75}
76
77impl<T> RootPublicValues<T> {
78    pub const fn new(inner: RecursionPublicValues<T>) -> Self {
79        Self { inner }
80    }
81
82    #[inline]
83    pub const fn sp1_vk_digest(&self) -> &[T; DIGEST_SIZE] {
84        &self.inner.sp1_vk_digest
85    }
86
87    #[inline]
88    pub const fn committed_value_digest(&self) -> &[[T; 4]; PV_DIGEST_NUM_WORDS] {
89        &self.inner.committed_value_digest
90    }
91
92    #[inline]
93    pub const fn digest(&self) -> &[T; DIGEST_SIZE] {
94        &self.inner.digest
95    }
96
97    #[inline]
98    pub const fn exit_code(&self) -> &T {
99        &self.inner.exit_code
100    }
101
102    #[inline]
103    pub const fn vk_root(&self) -> &[T; DIGEST_SIZE] {
104        &self.inner.vk_root
105    }
106
107    #[inline]
108    pub const fn proof_nonce(&self) -> &[T; PROOF_NONCE_NUM_WORDS] {
109        &self.inner.proof_nonce
110    }
111}