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