1use std::{array::from_fn, sync::Arc};
2
3use num_bigint::BigUint;
4use openvm_circuit::arch::{instructions::exe::VmExe, MemoryConfig};
5pub use openvm_circuit::system::program::trace::VmCommittedExe;
6use openvm_native_compiler::ir::DIGEST_SIZE;
7use openvm_stark_backend::{
8 config::{Com, StarkGenericConfig, Val},
9 engine::StarkEngine,
10 p3_field::PrimeField32,
11};
12use openvm_stark_sdk::{
13 config::{baby_bear_poseidon2::BabyBearPoseidon2Engine, FriParameters},
14 engine::StarkFriEngine,
15 openvm_stark_backend::p3_field::FieldAlgebra,
16 p3_baby_bear::BabyBear,
17 p3_bn254_fr::Bn254Fr,
18};
19use serde::{Deserialize, Serialize};
20use serde_with::serde_as;
21use tracing::instrument;
22
23use crate::{types::BN254_BYTES, F, SC};
24
25#[serde_as]
29#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
30pub struct CommitBytes(#[serde_as(as = "serde_with::hex::Hex")] [u8; BN254_BYTES]);
31
32impl CommitBytes {
33 pub fn new(bytes: [u8; BN254_BYTES]) -> Self {
34 Self(bytes)
35 }
36
37 pub fn as_slice(&self) -> &[u8; BN254_BYTES] {
38 &self.0
39 }
40
41 pub fn to_bn254(&self) -> Bn254Fr {
42 bytes_to_bn254(&self.0)
43 }
44
45 pub fn to_u32_digest(&self) -> [u32; DIGEST_SIZE] {
46 bytes_to_u32_digest(&self.0)
47 }
48
49 pub fn from_bn254(bn254: Bn254Fr) -> Self {
50 Self(bn254_to_bytes(bn254))
51 }
52
53 pub fn from_u32_digest(digest: &[u32; DIGEST_SIZE]) -> Self {
54 Self(u32_digest_to_bytes(digest))
55 }
56
57 pub fn reverse(&mut self) {
58 self.0.reverse();
59 }
60}
61
62impl std::fmt::Display for CommitBytes {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 write!(f, "{}", hex::encode(self.0))
65 }
66}
67
68#[serde_as]
70#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
71pub struct AppExecutionCommit {
72 pub app_exe_commit: CommitBytes,
82
83 pub app_vm_commit: CommitBytes,
87}
88
89impl AppExecutionCommit {
90 #[instrument(name = "AppExecutionCommit::compute", skip_all)]
93 pub fn compute<SC: StarkGenericConfig>(
94 app_memory_config: &MemoryConfig,
95 app_exe: &VmExe<Val<SC>>,
96 app_program_commit: Com<SC>,
97 leaf_verifier_program_commit: Com<SC>,
98 ) -> Self
99 where
100 Com<SC>: AsRef<[Val<SC>; DIGEST_SIZE]>
101 + From<[Val<SC>; DIGEST_SIZE]>
102 + Into<[Val<SC>; DIGEST_SIZE]>,
103 Val<SC>: PrimeField32,
104 {
105 let exe_commit: [Val<SC>; DIGEST_SIZE] = VmCommittedExe::<SC>::compute_exe_commit(
106 &app_program_commit,
107 app_exe,
108 app_memory_config,
109 )
110 .into();
111 let vm_commit: [Val<SC>; DIGEST_SIZE] = leaf_verifier_program_commit.into();
112 Self::from_field_commit(exe_commit, vm_commit)
113 }
114
115 pub fn from_field_commit<F: PrimeField32>(
116 exe_commit: [F; DIGEST_SIZE],
117 vm_commit: [F; DIGEST_SIZE],
118 ) -> Self {
119 Self {
120 app_exe_commit: CommitBytes::from_u32_digest(&exe_commit.map(|x| x.as_canonical_u32())),
121 app_vm_commit: CommitBytes::from_u32_digest(&vm_commit.map(|x| x.as_canonical_u32())),
122 }
123 }
124}
125
126pub fn commit_app_exe(
127 app_fri_params: FriParameters,
128 app_exe: impl Into<VmExe<F>>,
129) -> Arc<VmCommittedExe<SC>> {
130 let exe: VmExe<_> = app_exe.into();
131 let app_engine = BabyBearPoseidon2Engine::new(app_fri_params);
132 Arc::new(VmCommittedExe::<SC>::commit(exe, app_engine.config().pcs()))
133}
134
135pub(crate) fn babybear_digest_to_bn254(digest: &[F; DIGEST_SIZE]) -> Bn254Fr {
136 let mut ret = Bn254Fr::ZERO;
137 let order = Bn254Fr::from_canonical_u32(BabyBear::ORDER_U32);
138 let mut base = Bn254Fr::ONE;
139 digest.iter().for_each(|&x| {
140 ret += base * Bn254Fr::from_canonical_u32(x.as_canonical_u32());
141 base *= order;
142 });
143 ret
144}
145
146fn bytes_to_bn254(bytes: &[u8; BN254_BYTES]) -> Bn254Fr {
147 let order = Bn254Fr::from_canonical_u32(1 << 8);
148 let mut ret = Bn254Fr::ZERO;
149 let mut base = Bn254Fr::ONE;
150 for byte in bytes.iter().rev() {
151 ret += base * Bn254Fr::from_canonical_u8(*byte);
152 base *= order;
153 }
154 ret
155}
156
157fn bn254_to_bytes(bn254: Bn254Fr) -> [u8; BN254_BYTES] {
158 let mut ret = bn254.value.to_bytes();
159 ret.reverse();
160 ret
161}
162
163fn bytes_to_u32_digest(bytes: &[u8; BN254_BYTES]) -> [u32; DIGEST_SIZE] {
164 let mut bigint = BigUint::ZERO;
165 for byte in bytes.iter() {
166 bigint <<= 8;
167 bigint += BigUint::from(*byte);
168 }
169 let order = BabyBear::ORDER_U32;
170 from_fn(|_| {
171 let bigint_digit = bigint.clone() % order;
172 let digit = if bigint_digit == BigUint::ZERO {
173 0u32
174 } else {
175 bigint_digit.to_u32_digits()[0]
176 };
177 bigint /= order;
178 digit
179 })
180}
181
182fn u32_digest_to_bytes(digest: &[u32; DIGEST_SIZE]) -> [u8; BN254_BYTES] {
183 bn254_to_bytes(babybear_digest_to_bn254(&digest.map(F::from_canonical_u32)))
184}