1use group::ff::Field;
2use std::collections::BTreeMap;
3
4use super::{metadata, CellValue, InstanceValue, Value};
5use crate::{
6 plonk::{
7 Advice, AdviceQuery, Any, Column, ColumnType, Expression, FixedQuery, Gate, InstanceQuery,
8 VirtualCell,
9 },
10 poly::Rotation,
11};
12
13pub(crate) struct AnyQuery {
14 pub index: Option<usize>,
16 pub column_type: Any,
18 pub column_index: usize,
20 pub rotation: Rotation,
22}
23
24impl From<FixedQuery> for AnyQuery {
25 fn from(query: FixedQuery) -> Self {
26 Self {
27 index: query.index,
28 column_type: Any::Fixed,
29 column_index: query.column_index,
30 rotation: query.rotation,
31 }
32 }
33}
34
35impl From<AdviceQuery> for AnyQuery {
36 fn from(query: AdviceQuery) -> Self {
37 Self {
38 index: query.index,
39 column_type: Any::Advice(Advice { phase: query.phase }),
40 column_index: query.column_index,
41 rotation: query.rotation,
42 }
43 }
44}
45
46impl From<InstanceQuery> for AnyQuery {
47 fn from(query: InstanceQuery) -> Self {
48 Self {
49 index: query.index,
50 column_type: Any::Instance,
51 column_index: query.column_index,
52 rotation: query.rotation,
53 }
54 }
55}
56
57pub(super) fn format_value<F: Field>(v: F) -> String {
58 if v.is_zero_vartime() {
59 "0".into()
60 } else if v == F::ONE {
61 "1".into()
62 } else if v == -F::ONE {
63 "-1".into()
64 } else {
65 let s = format!("{:?}", v);
67 let s = s.strip_prefix("0x").unwrap();
69 let s = s.trim_start_matches('0');
70 format!("0x{}", s)
71 }
72}
73
74pub(super) fn load<'a, F: Field, T: ColumnType, Q: Into<AnyQuery> + Copy>(
75 n: i32,
76 row: i32,
77 queries: &'a [(Column<T>, Rotation)],
78 cells: &'a [Vec<CellValue<F>>],
79) -> impl Fn(Q) -> Value<F> + 'a {
80 move |query| {
81 let (column, at) = &queries[query.into().index.unwrap()];
82 let resolved_row = (row + at.0) % n;
83 cells[column.index()][resolved_row as usize].into()
84 }
85}
86
87pub(super) fn load_instance<'a, F: Field, T: ColumnType, Q: Into<AnyQuery> + Copy>(
88 n: i32,
89 row: i32,
90 queries: &'a [(Column<T>, Rotation)],
91 cells: &'a [Vec<InstanceValue<F>>],
92) -> impl Fn(Q) -> Value<F> + 'a {
93 move |query| {
94 let (column, at) = &queries[query.into().index.unwrap()];
95 let resolved_row = (row + at.0) % n;
96 let cell = &cells[column.index()][resolved_row as usize];
97 Value::Real(cell.value())
98 }
99}
100
101fn cell_value<'a, F: Field, Q: Into<AnyQuery> + Copy>(
102 virtual_cells: &'a [VirtualCell],
103 load: impl Fn(Q) -> Value<F> + 'a,
104) -> impl Fn(Q) -> BTreeMap<metadata::VirtualCell, String> + 'a {
105 move |query| {
106 let AnyQuery {
107 column_type,
108 column_index,
109 rotation,
110 ..
111 } = query.into();
112 virtual_cells
113 .iter()
114 .find(|c| {
115 c.column.column_type() == &column_type
116 && c.column.index() == column_index
117 && c.rotation == rotation
118 })
119 .map(|cell| {
121 (
122 cell.clone().into(),
123 match load(query) {
124 Value::Real(v) => format_value(v),
125 Value::Poison => unreachable!(),
126 },
127 )
128 })
129 .into_iter()
130 .collect()
131 }
132}
133
134pub(super) fn cell_values<'a, F: Field>(
135 gate: &Gate<F>,
136 poly: &Expression<F>,
137 load_fixed: impl Fn(FixedQuery) -> Value<F> + 'a,
138 load_advice: impl Fn(AdviceQuery) -> Value<F> + 'a,
139 load_instance: impl Fn(InstanceQuery) -> Value<F> + 'a,
140) -> Vec<(metadata::VirtualCell, String)> {
141 let virtual_cells = gate.queried_cells();
142 let cell_values = poly.evaluate(
143 &|_| BTreeMap::default(),
144 &|_| panic!("virtual selectors are removed during optimization"),
145 &cell_value(virtual_cells, load_fixed),
146 &cell_value(virtual_cells, load_advice),
147 &cell_value(virtual_cells, load_instance),
148 &|_| BTreeMap::default(),
149 &|a| a,
150 &|mut a, mut b| {
151 a.append(&mut b);
152 a
153 },
154 &|mut a, mut b| {
155 a.append(&mut b);
156 a
157 },
158 &|a, _| a,
159 );
160 cell_values.into_iter().collect()
161}