1#![cfg_attr(not(feature = "std"), no_std)]
16
17#![allow(clippy::needless_lifetimes)]
31
32extern crate alloc;
33
34pub mod control_id;
35#[cfg(feature = "prove")]
36mod cpp;
37#[cfg(feature = "prove")]
38pub mod cpu;
39#[cfg(feature = "cuda")]
40pub mod cuda;
41mod info;
42pub mod layout;
43#[cfg(all(
44 feature = "prove",
45 any(all(target_os = "macos", target_arch = "aarch64"), target_os = "ios")
46))]
47pub mod metal;
48mod poly_ext;
49#[cfg(feature = "prove")]
50pub mod prove;
51mod taps;
52#[cfg(feature = "prove")]
53pub mod zkr;
54
55use risc0_core::field::baby_bear::{BabyBearElem, BabyBearExtElem};
56use risc0_zkp::{
57 adapter::{CircuitCoreDef, TapsProvider},
58 field::baby_bear::BabyBear,
59 taps::TapSet,
60};
61
62pub const REGISTER_GROUP_ACCUM: usize = 0;
63pub const REGISTER_GROUP_CODE: usize = 1;
64pub const REGISTER_GROUP_CTRL: usize = 1;
65pub const REGISTER_GROUP_DATA: usize = 2;
66
67pub const GLOBAL_MIX: usize = 0;
68pub const GLOBAL_OUT: usize = 1;
69
70pub const CHECKED_COEFFS_PER_POLY: usize = 16;
71
72pub struct CircuitImpl;
75
76#[allow(clippy::new_without_default)]
77impl CircuitImpl {
78 pub const fn new() -> Self {
79 CircuitImpl
80 }
81}
82
83pub const CIRCUIT: CircuitImpl = CircuitImpl::new();
84
85impl TapsProvider for CircuitImpl {
86 fn get_taps(&self) -> &'static TapSet<'static> {
87 self::taps::TAPSET
88 }
89}
90
91impl CircuitCoreDef<BabyBear> for CircuitImpl {}
92
93pub mod micro_op {
95 pub const CONST: u32 = 0;
96 pub const ADD: u32 = 1;
97 pub const SUB: u32 = 2;
98 pub const MUL: u32 = 3;
99 pub const INV: u32 = 4;
100 pub const EQ: u32 = 5;
101 pub const READ_IOP_HEADER: u32 = 6;
102 pub const READ_IOP_BODY: u32 = 7;
103 pub const MIX_RNG: u32 = 8;
104 pub const SELECT: u32 = 9;
105 pub const EXTRACT: u32 = 10;
106}
107
108pub trait Externs {
110 fn wom_write(&mut self, _addr: BabyBearElem, _val: BabyBearExtElem) {
111 unimplemented!()
112 }
113
114 fn wom_read(&self, _addr: BabyBearElem) -> BabyBearExtElem {
115 unimplemented!()
116 }
117
118 fn read_iop_header(&mut self, _count: BabyBearElem, _k_and_flip_flag: BabyBearElem) {
119 unimplemented!()
120 }
121
122 fn read_iop_body(&mut self, _do_mont: BabyBearElem) -> BabyBearExtElem {
123 unimplemented!()
124 }
125
126 fn read_input_word(&mut self) -> u32 {
127 unimplemented!()
128 }
129}
130
131#[cfg(feature = "test")]
132pub mod testutil {
133 use rand::{thread_rng, Rng};
134 use risc0_zkp::{
135 adapter::{CircuitInfo, TapsProvider},
136 field::{
137 baby_bear::{BabyBearElem, BabyBearExtElem},
138 Elem, ExtElem,
139 },
140 hal::{Buffer, CircuitHal, Hal},
141 INV_RATE,
142 };
143
144 use crate::{CircuitImpl, REGISTER_GROUP_ACCUM, REGISTER_GROUP_CODE, REGISTER_GROUP_DATA};
145
146 pub struct EvalCheckParams {
147 pub po2: usize,
148 pub steps: usize,
149 pub domain: usize,
150 pub code: Vec<BabyBearElem>,
151 pub data: Vec<BabyBearElem>,
152 pub accum: Vec<BabyBearElem>,
153 pub mix: Vec<BabyBearElem>,
154 pub out: Vec<BabyBearElem>,
155 pub poly_mix: BabyBearExtElem,
156 }
157
158 impl EvalCheckParams {
159 pub fn new(po2: usize) -> Self {
160 let mut rng = thread_rng();
161 let steps = 1 << po2;
162 let domain = steps * INV_RATE;
163 let circuit = CircuitImpl::new();
164 let taps = circuit.get_taps();
165 let code_size = taps.group_size(REGISTER_GROUP_CODE);
166 let data_size = taps.group_size(REGISTER_GROUP_DATA);
167 let accum_size = taps.group_size(REGISTER_GROUP_ACCUM);
168 let code = random_fps(&mut rng, code_size * domain);
169 let data = random_fps(&mut rng, data_size * domain);
170 let accum = random_fps(&mut rng, accum_size * domain);
171 let mix = random_fps(&mut rng, CircuitImpl::MIX_SIZE);
172 let out = random_fps(&mut rng, CircuitImpl::OUTPUT_SIZE);
173 let poly_mix = BabyBearExtElem::random(&mut rng);
174 tracing::debug!("code: {} bytes", code.len() * 4);
175 tracing::debug!("data: {} bytes", data.len() * 4);
176 tracing::debug!("accum: {} bytes", accum.len() * 4);
177 tracing::debug!("mix: {} bytes", mix.len() * 4);
178 tracing::debug!("out: {} bytes", out.len() * 4);
179 Self {
180 po2,
181 steps,
182 domain,
183 code,
184 data,
185 accum,
186 mix,
187 out,
188 poly_mix,
189 }
190 }
191 }
192
193 fn random_fps<E: Elem>(rng: &mut impl Rng, size: usize) -> Vec<E> {
194 let mut ret = Vec::new();
195 for _ in 0..size {
196 ret.push(E::random(rng));
197 }
198 ret
199 }
200
201 #[allow(unused)]
202 pub(crate) fn eval_check<H1, H2, C1, C2>(hal1: &H1, eval1: C1, hal2: &H2, eval2: C2, po2: usize)
203 where
204 H1: Hal<Elem = BabyBearElem, ExtElem = BabyBearExtElem>,
205 H2: Hal<Elem = BabyBearElem, ExtElem = BabyBearExtElem>,
206 C1: CircuitHal<H1>,
207 C2: CircuitHal<H2>,
208 {
209 let params = EvalCheckParams::new(po2);
210 let check1 = eval_check_impl(¶ms, hal1, &eval1);
211 let check2 = eval_check_impl(¶ms, hal2, &eval2);
212 assert_eq!(check1, check2);
213 }
214
215 pub fn eval_check_impl<H, C>(params: &EvalCheckParams, hal: &H, eval: &C) -> Vec<H::Elem>
216 where
217 H: Hal<Elem = BabyBearElem, ExtElem = BabyBearExtElem>,
218 C: CircuitHal<H>,
219 {
220 let check = hal.alloc_elem("check", BabyBearExtElem::EXT_SIZE * params.domain);
221 let code = hal.copy_from_elem("code", ¶ms.code);
222 let data = hal.copy_from_elem("data", ¶ms.data);
223 let accum = hal.copy_from_elem("accum", ¶ms.accum);
224 let mix = hal.copy_from_elem("mix", ¶ms.mix);
225 let out = hal.copy_from_elem("out", ¶ms.out);
226 eval.eval_check(
227 &check,
228 &[&accum, &code, &data],
229 &[&mix, &out],
230 params.poly_mix,
231 params.po2,
232 params.steps,
233 );
234 let mut ret = vec![H::Elem::ZERO; check.size()];
235 check.view(|view| {
236 ret.clone_from_slice(view);
237 });
238 ret
239 }
240}