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