1use alloc::{format, string::String, sync::Arc, vec::Vec};
13
14use spin::RwLock;
15use spongefish::{Permutation, Unit};
16
17use crate::{
18 allocator::{FieldVar, VarAllocator},
19 error::InvalidRelation,
20 expr::{Ring, Sum},
21};
22
23#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct QueryAnswerPair<U, const WIDTH: usize> {
27 pub input: [U; WIDTH],
28 pub output: [U; WIDTH],
29}
30
31impl<U, const WIDTH: usize> QueryAnswerPair<U, WIDTH> {
32 pub const fn new(input: [U; WIDTH], output: [U; WIDTH]) -> Self {
33 Self { input, output }
34 }
35}
36
37#[derive(Clone, Debug, PartialEq, Eq)]
39pub struct LinearEquation<T> {
40 pub terms: Sum<T>,
42 pub image: T,
44}
45
46impl<T> LinearEquation<T> {
47 pub fn new(terms: impl Into<Sum<T>>, image: T) -> Self {
48 Self {
49 terms: terms.into(),
50 image,
51 }
52 }
53}
54
55pub struct PermutationRelation<T, const WIDTH: usize> {
78 label: String,
79 allocator: VarAllocator<T>,
80 queries: Arc<RwLock<Vec<QueryAnswerPair<FieldVar, WIDTH>>>>,
81 equations: Arc<RwLock<Vec<LinearEquation<T>>>>,
82}
83
84impl<T, const WIDTH: usize> Clone for PermutationRelation<T, WIDTH> {
85 fn clone(&self) -> Self {
86 Self {
87 label: self.label.clone(),
88 allocator: self.allocator.clone(),
89 queries: Arc::clone(&self.queries),
90 equations: Arc::clone(&self.equations),
91 }
92 }
93}
94
95impl<T: Unit, const WIDTH: usize> Default for PermutationRelation<T, WIDTH> {
96 fn default() -> Self {
97 Self::new()
98 }
99}
100
101impl<T: Unit, const WIDTH: usize> PermutationRelation<T, WIDTH> {
102 pub fn new() -> Self {
104 Self::with_allocator(VarAllocator::new())
105 }
106
107 pub fn labeled(label: impl Into<String>) -> Self {
113 let mut relation = Self::new();
114 relation.label = label.into();
115 relation
116 }
117
118 pub fn with_allocator(allocator: VarAllocator<T>) -> Self {
120 Self {
121 label: String::new(),
122 allocator,
123 queries: Arc::default(),
124 equations: Arc::default(),
125 }
126 }
127
128 pub fn label(&self) -> &str {
130 &self.label
131 }
132
133 pub const fn allocator(&self) -> &VarAllocator<T> {
135 &self.allocator
136 }
137
138 pub fn allocate_var(&self) -> FieldVar {
140 self.allocator.allocate_var()
141 }
142
143 pub fn allocate_vars<const N: usize>(&self) -> [FieldVar; N] {
145 self.allocator.allocate_vars()
146 }
147
148 pub fn allocate_vars_vec(&self, count: usize) -> Vec<FieldVar> {
150 self.allocator.allocate_vars_vec(count)
151 }
152
153 pub fn allocate_var_with(&self, value: T) -> FieldVar
155 where
156 T: PartialEq,
157 {
158 self.allocator.allocate_var_with(value)
159 }
160
161 pub fn allocate_vars_with<const N: usize>(&self, values: &[T; N]) -> [FieldVar; N]
163 where
164 T: PartialEq,
165 {
166 self.allocator.allocate_vars_with(values)
167 }
168
169 pub fn allocate_vars_vec_with(&self, values: &[T]) -> Vec<FieldVar>
171 where
172 T: PartialEq,
173 {
174 self.allocator.allocate_vars_vec_with(values)
175 }
176
177 pub fn set_var(&self, var: FieldVar, value: T)
179 where
180 T: PartialEq,
181 {
182 self.allocator.set_var(var, value);
183 }
184
185 pub fn set_vars<Var, Val>(
187 &self,
188 vars: impl IntoIterator<Item = Var>,
189 values: impl IntoIterator<Item = Val>,
190 ) where
191 Var: core::borrow::Borrow<FieldVar>,
192 Val: core::borrow::Borrow<T>,
193 T: PartialEq,
194 {
195 self.allocator.set_vars(vars, values);
196 }
197
198 pub fn allocate_permutation(&self, input: &[FieldVar; WIDTH]) -> [FieldVar; WIDTH] {
201 let output = self.allocate_vars();
202 self.add_permutation(*input, output);
203 output
204 }
205
206 pub fn add_permutation(&self, input: [FieldVar; WIDTH], output: [FieldVar; WIDTH]) {
208 self.queries
209 .write()
210 .push(QueryAnswerPair::new(input, output));
211 }
212
213 pub fn add_equation(&self, terms: impl Into<Sum<T>>, image: T) {
221 self.equations
222 .write()
223 .push(LinearEquation::new(terms, image));
224 }
225
226 pub fn queries(&self) -> Vec<QueryAnswerPair<FieldVar, WIDTH>> {
228 self.queries.read().clone()
229 }
230
231 pub fn equations(&self) -> Vec<LinearEquation<T>> {
233 self.equations.read().clone()
234 }
235
236 pub fn public_vars(&self) -> Vec<(FieldVar, T)> {
238 self.allocator.public_vars()
239 }
240
241 pub fn compile(&self) -> Result<PermutationInstance<T, WIDTH>, InvalidRelation>
249 where
250 T: PartialEq,
251 {
252 let values = self.allocator.values();
253 let vars_count = values.len();
254 let public_values = values
255 .into_iter()
256 .enumerate()
257 .filter_map(|(index, value)| Some((FieldVar::try_from_index(index)?, value?)))
258 .collect();
259 PermutationInstance::validated(
260 self.label.clone(),
261 vars_count,
262 public_values,
263 self.queries(),
264 self.equations(),
265 )
266 }
267}
268
269impl<T: Unit, const WIDTH: usize> PermutationInstance<T, WIDTH> {
270 pub(crate) fn validated(
273 label: String,
274 vars_count: usize,
275 public_values: Vec<(FieldVar, T)>,
276 queries: Vec<QueryAnswerPair<FieldVar, WIDTH>>,
277 equations: Vec<LinearEquation<T>>,
278 ) -> Result<Self, InvalidRelation>
279 where
280 T: PartialEq,
281 {
282 let mut bound = alloc::vec![false; vars_count];
283 for (var, _) in &public_values {
284 match bound.get_mut(var.index()) {
285 Some(slot) => *slot = true,
286 None => {
287 return Err(InvalidRelation::new(format!(
288 "public variable {} is unallocated",
289 var.index()
290 )))
291 }
292 }
293 }
294 for (index, query) in queries.iter().enumerate() {
295 for var in query.input.iter().chain(&query.output) {
296 let Some(slot) = bound.get_mut(var.index()) else {
297 return Err(InvalidRelation::new(format!(
298 "query {index} references unallocated variable {}",
299 var.index()
300 )));
301 };
302 *slot = true;
303 }
304 }
305
306 for (index, equation) in equations.iter().enumerate() {
307 for term in equation.terms.terms() {
308 match bound.get(term.var.index()) {
309 None => {
310 return Err(InvalidRelation::new(format!(
311 "equation {index} references unallocated variable {}",
312 term.var.index()
313 )))
314 }
315 Some(false) if term.weight != T::ZERO => {
316 return Err(InvalidRelation::new(format!(
317 "equation {index} weights variable {}, which no query or \
318 assignment binds",
319 term.var.index()
320 )))
321 }
322 Some(_) => {}
323 }
324 }
325 }
326
327 Ok(Self {
328 label,
329 vars_count,
330 public_values,
331 queries,
332 equations,
333 })
334 }
335}
336
337impl<T: Unit, const WIDTH: usize> Permutation<WIDTH> for PermutationRelation<T, WIDTH> {
338 type U = FieldVar;
339
340 fn permute_mut(&self, state: &mut [Self::U; WIDTH]) {
343 *state = self.allocate_permutation(state);
344 }
345
346 fn permute(&self, state: &[Self::U; WIDTH]) -> [Self::U; WIDTH] {
347 self.allocate_permutation(state)
348 }
349}
350
351#[derive(Clone, Debug, PartialEq, Eq)]
356pub struct PermutationInstance<T, const WIDTH: usize> {
357 pub(crate) label: String,
358 pub(crate) vars_count: usize,
359 pub(crate) public_values: Vec<(FieldVar, T)>,
360 pub(crate) queries: Vec<QueryAnswerPair<FieldVar, WIDTH>>,
361 pub(crate) equations: Vec<LinearEquation<T>>,
362}
363
364impl<T, const WIDTH: usize> PermutationInstance<T, WIDTH> {
365 pub fn label(&self) -> &str {
367 &self.label
368 }
369
370 pub const fn vars_count(&self) -> usize {
372 self.vars_count
373 }
374
375 pub fn public_vars(&self) -> &[(FieldVar, T)] {
377 &self.public_values
378 }
379
380 pub fn queries(&self) -> &[QueryAnswerPair<FieldVar, WIDTH>] {
382 &self.queries
383 }
384
385 pub fn equations(&self) -> &[LinearEquation<T>] {
387 &self.equations
388 }
389
390 pub fn value(&self, var: FieldVar) -> Option<&T> {
392 let index = self
393 .public_values
394 .binary_search_by_key(&var.index(), |(var, _)| var.index())
395 .ok()?;
396 self.public_values.get(index).map(|(_, value)| value)
397 }
398
399 pub fn is_witness_valid<P>(
409 &self,
410 permutation: &P,
411 witness: &PermutationWitness<T, WIDTH>,
412 ) -> bool
413 where
414 T: Ring,
415 P: Permutation<WIDTH, U = T>,
416 {
417 if witness.trace.len() != self.queries.len() {
418 return false;
419 }
420
421 let mut values: Vec<Option<T>> = alloc::vec![None; self.vars_count];
422 for (var, value) in &self.public_values {
423 match values.get_mut(var.index()) {
424 Some(slot) => *slot = Some(value.clone()),
425 None => return false,
426 }
427 }
428
429 for (query, step) in self.queries.iter().zip(&witness.trace) {
430 if permutation.permute(&step.input) != step.output {
431 return false;
432 }
433 let wires = query.input.iter().chain(&query.output);
434 let seen = step.input.iter().chain(&step.output);
435 for (var, value) in wires.zip(seen) {
436 match values.get_mut(var.index()) {
437 Some(Some(known)) if known == value => {}
438 Some(slot @ None) => *slot = Some(value.clone()),
439 _ => return false,
440 }
441 }
442 }
443
444 self.equations.iter().all(|equation| {
445 let mut sum = T::ZERO;
446 for term in equation.terms.terms() {
447 let Some(Some(value)) = values.get(term.var.index()) else {
448 return false;
449 };
450 sum = Ring::add(sum, Ring::mul(term.weight.clone(), value.clone()));
451 }
452 sum == equation.image
453 })
454 }
455}
456
457pub struct PermutationWitnessBuilder<P: Permutation<WIDTH>, const WIDTH: usize> {
463 permutation: P,
464 trace: Arc<RwLock<Vec<QueryAnswerPair<P::U, WIDTH>>>>,
465}
466
467impl<P: Permutation<WIDTH>, const WIDTH: usize> Clone for PermutationWitnessBuilder<P, WIDTH> {
468 fn clone(&self) -> Self {
469 Self {
470 permutation: self.permutation.clone(),
471 trace: Arc::clone(&self.trace),
472 }
473 }
474}
475
476impl<P: Permutation<WIDTH>, const WIDTH: usize> From<P> for PermutationWitnessBuilder<P, WIDTH> {
477 fn from(permutation: P) -> Self {
478 Self::new(permutation)
479 }
480}
481
482impl<P: Permutation<WIDTH>, const WIDTH: usize> PermutationWitnessBuilder<P, WIDTH> {
483 pub fn new(permutation: P) -> Self {
484 Self {
485 permutation,
486 trace: Arc::default(),
487 }
488 }
489
490 pub const fn permutation(&self) -> &P {
492 &self.permutation
493 }
494
495 pub fn allocate_permutation(&self, input: &[P::U; WIDTH]) -> [P::U; WIDTH] {
497 let output = self.permutation.permute(input);
498 self.add_permutation(input, &output);
499 output
500 }
501
502 pub fn add_permutation(&self, input: &[P::U; WIDTH], output: &[P::U; WIDTH]) {
504 self.trace
505 .write()
506 .push(QueryAnswerPair::new(input.clone(), output.clone()));
507 }
508
509 pub fn trace(&self) -> Vec<QueryAnswerPair<P::U, WIDTH>> {
511 self.trace.read().clone()
512 }
513
514 pub fn snapshot(&self) -> PermutationWitness<P::U, WIDTH> {
516 PermutationWitness {
517 trace: self.trace(),
518 }
519 }
520}
521
522impl<P: Permutation<WIDTH>, const WIDTH: usize> Permutation<WIDTH>
523 for PermutationWitnessBuilder<P, WIDTH>
524{
525 type U = P::U;
526
527 fn permute_mut(&self, state: &mut [Self::U; WIDTH]) {
529 *state = self.allocate_permutation(state);
530 }
531
532 fn permute(&self, state: &[Self::U; WIDTH]) -> [Self::U; WIDTH] {
533 self.allocate_permutation(state)
534 }
535}
536
537#[derive(Clone, Debug, PartialEq, Eq)]
539pub struct PermutationWitness<T, const WIDTH: usize> {
540 pub(crate) trace: Vec<QueryAnswerPair<T, WIDTH>>,
541}
542
543impl<T, const WIDTH: usize> PermutationWitness<T, WIDTH> {
544 pub fn trace(&self) -> &[QueryAnswerPair<T, WIDTH>] {
546 &self.trace
547 }
548}