sp1_recursion_circuit/machine/
public_values.rs1use 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
16pub(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
30pub(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
43pub(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
57pub(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}