halo2_axiom/dev/
util.rs

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    /// Query index
15    pub index: Option<usize>,
16    /// Column type
17    pub column_type: Any,
18    /// Column index
19    pub column_index: usize,
20    /// Rotation of this query
21    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        // Format value as hex.
66        let s = format!("{:?}", v);
67        // Remove leading zeroes.
68        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            // None indicates a selector, which we don't bother showing.
120            .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}