1use alloc::{str::from_utf8, vec::Vec};
18use core::fmt;
19
20use anyhow::Result;
21use risc0_core::field::{Elem, ExtElem, Field};
22use serde::{Deserialize, Serialize};
23
24use crate::{hal::cpu::SyncSlice, taps::TapSet};
25
26pub const REGISTER_GROUP_ACCUM: usize = 0;
29pub const REGISTER_GROUP_CODE: usize = 1;
30pub const REGISTER_GROUP_DATA: usize = 2;
31
32const ADAPTER_TRACE_ENABLED: bool = false;
34
35macro_rules! trace_if_enabled {
36 ($($args:tt)*) => {
37 if ADAPTER_TRACE_ENABLED {
38 tracing::trace!($($args)*)
39 }
40 }
41}
42
43#[derive(Clone, Copy, Debug)]
44pub struct MixState<EE: ExtElem> {
45 pub tot: EE,
46 pub mul: EE,
47}
48
49pub trait CircuitStepHandler<E: Elem> {
50 fn call(
51 &mut self,
52 cycle: usize,
53 name: &str,
54 extra: &str,
55 args: &[E],
56 outs: &mut [E],
57 ) -> Result<()>;
58
59 fn sort(&mut self, name: &str);
60}
61
62pub struct CircuitStepContext {
63 pub size: usize,
64 pub cycle: usize,
65}
66
67pub trait CircuitStep<E: Elem> {
68 fn step_exec<S: CircuitStepHandler<E>>(
69 &self,
70 ctx: &CircuitStepContext,
71 custom: &mut S,
72 args: &[SyncSlice<E>],
73 ) -> Result<E>;
74
75 fn step_verify_bytes<S: CircuitStepHandler<E>>(
76 &self,
77 ctx: &CircuitStepContext,
78 custom: &mut S,
79 args: &[SyncSlice<E>],
80 ) -> Result<E>;
81
82 fn step_verify_mem<S: CircuitStepHandler<E>>(
83 &self,
84 ctx: &CircuitStepContext,
85 custom: &mut S,
86 args: &[SyncSlice<E>],
87 ) -> Result<E>;
88
89 fn step_compute_accum<S: CircuitStepHandler<E>>(
90 &self,
91 ctx: &CircuitStepContext,
92 custom: &mut S,
93 args: &[SyncSlice<E>],
94 ) -> Result<E>;
95
96 fn step_verify_accum<S: CircuitStepHandler<E>>(
97 &self,
98 ctx: &CircuitStepContext,
99 custom: &mut S,
100 args: &[SyncSlice<E>],
101 ) -> Result<E>;
102}
103
104pub trait PolyFp<F: Field> {
105 fn poly_fp(
106 &self,
107 cycle: usize,
108 steps: usize,
109 mix: &[F::ExtElem],
110 args: &[&[F::Elem]],
111 ) -> F::ExtElem;
112}
113
114pub trait PolyExt<F: Field> {
115 fn poly_ext(
116 &self,
117 mix: &F::ExtElem,
118 u: &[F::ExtElem],
119 args: &[&[F::Elem]],
120 ) -> MixState<F::ExtElem>;
121}
122
123pub trait TapsProvider {
124 fn get_taps(&self) -> &'static TapSet<'static>;
125
126 fn accum_size(&self) -> usize {
127 self.get_taps().group_size(REGISTER_GROUP_ACCUM)
128 }
129
130 fn code_size(&self) -> usize {
131 self.get_taps().group_size(REGISTER_GROUP_CODE)
132 }
133
134 fn ctrl_size(&self) -> usize {
135 self.get_taps().group_size(REGISTER_GROUP_CODE)
136 }
137
138 fn data_size(&self) -> usize {
139 self.get_taps().group_size(REGISTER_GROUP_DATA)
140 }
141}
142
143#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
147pub struct ProtocolInfo(pub [u8; 16]);
148
149impl ProtocolInfo {
150 pub fn encode<E: Elem>(&self) -> [E; 16] {
154 let mut elems = [E::ZERO; 16];
155 for (i, elem) in elems.iter_mut().enumerate().take(self.0.len()) {
156 *elem = E::from_u64(self.0[i] as u64);
157 }
158 elems
159 }
160}
161
162impl fmt::Display for ProtocolInfo {
163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164 match from_utf8(&self.0) {
165 Ok(s) => write!(f, "{}", s),
166 Err(_) => write!(f, "0x{}", hex::encode(self.0)),
167 }
168 }
169}
170
171pub const PROOF_SYSTEM_INFO: ProtocolInfo = ProtocolInfo(*b"RISC0_STARK:v1__");
176
177pub trait CircuitInfo {
178 const CIRCUIT_INFO: ProtocolInfo;
179 const OUTPUT_SIZE: usize;
180 const MIX_SIZE: usize;
181}
182
183pub trait CircuitCoreDef<F: Field>: CircuitInfo + PolyExt<F> + TapsProvider {}
185
186pub trait CircuitProveDef<F: Field>:
188 CircuitStep<F::Elem> + PolyFp<F> + CircuitCoreDef<F> + Sync
189{
190}
191
192pub type Arg = usize;
193pub type Var = usize;
194
195pub struct PolyExtStepDef {
196 pub block: &'static [PolyExtStep],
197 pub ret: Var,
198}
199
200#[derive(Debug)]
201pub enum PolyExtStep {
202 Const(u32),
203 ConstExt(u32, u32, u32, u32),
204 Get(usize),
205 GetGlobal(Arg, usize),
206 Add(Var, Var),
207 Sub(Var, Var),
208 Mul(Var, Var),
209 True,
210 AndEqz(Var, Var),
211 AndCond(Var, Var, Var),
212 Shift,
213}
214
215impl PolyExtStep {
216 pub fn step<F: Field>(
217 &self,
218 fp_vars: &mut Vec<F::ExtElem>,
219 mix_vars: &mut Vec<MixState<F::ExtElem>>,
220 mix: &F::ExtElem,
221 u: &[F::ExtElem],
222 args: &[&[F::Elem]],
223 ) {
224 match self {
225 PolyExtStep::Const(value) => {
226 let elem = F::Elem::from_u64(*value as u64);
227 trace_if_enabled!("[{}] {self:?} -> {elem:?}", fp_vars.len());
228 fp_vars.push(F::ExtElem::from_subfield(&elem));
229 }
230 PolyExtStep::ConstExt(x0, x1, x2, x3) => {
231 let elem = F::ExtElem::from_subelems([
232 F::Elem::from_u64(*x0 as u64),
233 F::Elem::from_u64(*x1 as u64),
234 F::Elem::from_u64(*x2 as u64),
235 F::Elem::from_u64(*x3 as u64),
236 ]);
237 trace_if_enabled!("[{}] {self:?} -> {elem:?}", fp_vars.len());
238 fp_vars.push(elem);
239 }
240 PolyExtStep::Get(tap) => {
241 let val = u[*tap];
242 trace_if_enabled!("[{}] {self:?} -> {val:?}", fp_vars.len());
243 fp_vars.push(val);
244 }
245 PolyExtStep::GetGlobal(base, offset) => {
246 let val = F::ExtElem::from_subfield(&args[*base][*offset]);
247 trace_if_enabled!("[{}] {self:?} -> {val:?}", fp_vars.len());
248 fp_vars.push(val);
249 }
250 PolyExtStep::Add(x1, x2) => {
251 let val = fp_vars[*x1] + fp_vars[*x2];
252 trace_if_enabled!("[{}] {self:?} -> {val:?}", fp_vars.len());
253 fp_vars.push(val);
254 }
255 PolyExtStep::Sub(x1, x2) => {
256 let val = fp_vars[*x1] - fp_vars[*x2];
257 trace_if_enabled!("[{}] {self:?} -> {val:?}", fp_vars.len());
258 fp_vars.push(val);
259 }
260 PolyExtStep::Mul(x1, x2) => {
261 let val = fp_vars[*x1] * fp_vars[*x2];
262 trace_if_enabled!("[{}] {self:?} -> {val:?}", fp_vars.len());
263 fp_vars.push(val);
264 }
265 PolyExtStep::Shift => {
266 let val = F::ExtElem::from_subelems(
269 [F::Elem::ZERO, F::Elem::ONE]
270 .into_iter()
271 .chain(core::iter::repeat(F::Elem::ZERO))
272 .take(F::ExtElem::EXT_SIZE),
273 );
274 trace_if_enabled!("[{}] {self:?} -> {val:?}", mix_vars.len());
275 fp_vars.push(val);
276 }
277 PolyExtStep::True => {
278 let mix_val = MixState {
279 tot: F::ExtElem::ZERO,
280 mul: F::ExtElem::ONE,
281 };
282 trace_if_enabled!("[{}] {self:?} -> {mix_val:?}", mix_vars.len());
283 mix_vars.push(mix_val);
284 }
285 PolyExtStep::AndEqz(x, val) => {
286 let x = mix_vars[*x];
287 let val = fp_vars[*val];
288 let mix_val = MixState {
289 tot: x.tot + x.mul * val,
290 mul: x.mul * *mix,
291 };
292 trace_if_enabled!("[{}] {self:?} -> {mix_val:?}", mix_vars.len());
293 mix_vars.push(mix_val);
294 }
295 PolyExtStep::AndCond(x, cond, inner) => {
296 let x = mix_vars[*x];
297 let cond = fp_vars[*cond];
298 let inner = mix_vars[*inner];
299 let mix_val = MixState {
300 tot: x.tot + cond * inner.tot * x.mul,
301 mul: x.mul * inner.mul,
302 };
303 trace_if_enabled!("[{}] {self:?} -> {mix_val:?}", mix_vars.len());
304 mix_vars.push(mix_val);
305 }
306 }
307 }
308}
309
310impl PolyExtStepDef {
311 pub fn step<F: Field>(
312 &self,
313 mix: &F::ExtElem,
314 u: &[F::ExtElem],
315 args: &[&[F::Elem]],
316 ) -> MixState<F::ExtElem> {
317 let mut fp_vars = Vec::with_capacity(self.block.len() - (self.ret + 1));
318 let mut mix_vars = Vec::with_capacity(self.ret + 1);
319 for op in self.block.iter() {
320 op.step::<F>(&mut fp_vars, &mut mix_vars, mix, u, args);
321 }
322 assert_eq!(
323 fp_vars.len(),
324 self.block.len() - (self.ret + 1),
325 "Miscalculated capacity for fp_vars"
326 );
327 assert_eq!(
328 mix_vars.len(),
329 self.ret + 1,
330 "Miscalculated capacity for mix_vars"
331 );
332 mix_vars[self.ret]
333 }
334}