halo2_proofs/dev/
util.rs

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