openvm_circuit_primitives/
utils.rs1use itertools::zip_eq;
2use openvm_stark_backend::{
3 p3_air::{AirBuilder, VirtualPairCol},
4 p3_field::{Field, PrimeCharacteristicRing},
5};
6
7pub const fn next_power_of_two_or_zero(n: usize) -> usize {
10 if n == 0 {
11 0
12 } else {
13 n.next_power_of_two()
14 }
15}
16
17pub fn not<F: PrimeCharacteristicRing>(a: impl Into<F>) -> F {
18 F::ONE - a.into()
19}
20
21pub fn and<F: PrimeCharacteristicRing>(a: impl Into<F>, b: impl Into<F>) -> F {
22 a.into() * b.into()
23}
24
25pub fn or<F: PrimeCharacteristicRing>(a: impl Into<F>, b: impl Into<F>) -> F {
27 let a = a.into();
28 let b = b.into();
29 a.clone() + b.clone() - and(a, b)
30}
31
32pub fn implies<F: PrimeCharacteristicRing>(a: impl Into<F>, b: impl Into<F>) -> F {
34 or(F::ONE - a.into(), b.into())
35}
36
37pub fn select<F: PrimeCharacteristicRing>(
39 cond: impl Into<F>,
40 a: impl Into<F>,
41 b: impl Into<F>,
42) -> F {
43 let cond = cond.into();
44 cond.clone() * a.into() + (F::ONE - cond) * b.into()
45}
46
47pub fn to_vcols<F: Field>(cols: &[usize]) -> Vec<VirtualPairCol<F>> {
48 cols.iter()
49 .copied()
50 .map(VirtualPairCol::single_main)
51 .collect()
52}
53
54pub fn fill_slc_to_f<F: Field>(dest: &mut [F], src: &[u32]) {
55 dest.iter_mut()
56 .zip(src.iter())
57 .for_each(|(d, s)| *d = F::from_u32(*s));
58}
59
60pub fn to_field_vec<F: Field>(src: &[u32]) -> Vec<F> {
61 src.iter().map(|s| F::from_u32(*s)).collect()
62}
63
64pub fn assert_array_eq<AB: AirBuilder, I1: Into<AB::Expr>, I2: Into<AB::Expr>, const N: usize>(
65 builder: &mut AB,
66 x: [I1; N],
67 y: [I2; N],
68) {
69 for (x, y) in zip_eq(x, y) {
70 builder.assert_eq(x, y);
71 }
72}
73
74#[inline]
76pub fn compose<F: PrimeCharacteristicRing>(a: &[impl Into<F> + Clone], limb_size: usize) -> F {
77 a.iter().enumerate().fold(F::ZERO, |acc, (i, x)| {
78 acc + x.clone().into() * F::from_usize(1 << (i * limb_size))
79 })
80}
81
82#[cfg(test)]
83pub use test_utils::*;
84#[cfg(test)]
85mod test_utils {
86 #[cfg(feature = "cuda")]
87 use openvm_cuda_backend::BabyBearPoseidon2GpuEngine;
88 #[cfg(feature = "cuda")]
89 use openvm_cuda_common::{
90 common::get_device,
91 stream::{CudaStream, GpuDeviceCtx, StreamGuard},
92 };
93 use openvm_stark_backend::{test_utils::test_system_params_small, StarkEngine};
94 use openvm_stark_sdk::{config::baby_bear_poseidon2::*, utils::setup_tracing};
95
96 pub fn test_engine_small() -> BabyBearPoseidon2CpuEngine<DuplexSponge> {
97 setup_tracing();
98 BabyBearPoseidon2CpuEngine::new(test_system_params_small(3, 9, 3))
100 }
101
102 #[cfg(feature = "cuda")]
103 pub fn test_gpu_engine_small() -> BabyBearPoseidon2GpuEngine {
104 setup_tracing();
105 BabyBearPoseidon2GpuEngine::new(test_system_params_small(4, 12, 4))
106 }
107
108 #[cfg(feature = "cuda")]
109 pub fn test_device_ctx() -> GpuDeviceCtx {
110 GpuDeviceCtx {
111 device_id: get_device().unwrap() as u32,
112 stream: StreamGuard::new(CudaStream::new_non_blocking().unwrap()),
113 }
114 }
115}
116
117#[cfg(all(feature = "touchemall", feature = "cuda"))]
118pub use touchemall::*;
119#[cfg(all(feature = "touchemall", feature = "cuda"))]
120mod touchemall {
121 use openvm_cuda_backend::{prelude::F, GpuBackend};
122 use openvm_cuda_common::{
123 common::get_device,
124 stream::{CudaStream, GpuDeviceCtx, StreamGuard},
125 };
126 use openvm_stark_backend::prover::AirProvingContext;
127
128 fn touchemall_device_ctx() -> GpuDeviceCtx {
129 GpuDeviceCtx {
130 device_id: get_device().unwrap() as u32,
131 stream: StreamGuard::new(CudaStream::new_non_blocking().unwrap()),
132 }
133 }
134
135 pub fn check_trace_validity(proving_ctx: &AirProvingContext<GpuBackend>, name: &str) {
136 use openvm_cuda_common::{copy::MemCopyD2H, stream::device_synchronize};
137 use openvm_stark_backend::prover::MatrixDimensions;
138
139 device_synchronize().unwrap();
141 let trace = &proving_ctx.common_main;
142 let height = trace.height();
143 let width = trace.width();
144 let trace = trace.to_host_on(&touchemall_device_ctx()).unwrap();
145 for r in 0..height {
146 for c in 0..width {
147 let value = trace[c * height + r];
148 let value_u32 = unsafe { *(&value as *const F as *const u32) };
149 assert!(
150 value_u32 != 0xffffffff,
151 "potentially untouched value at ({r}, {c}) of a trace of size {height}x{width} for air {name}"
152 );
153 }
154 }
155 }
156}