halo2_proofs/dev/
util.rs

1use std::collections::BTreeMap;
2
3use group::ff::Field;
4use pasta_curves::arithmetic::FieldExt;
5
6use super::{metadata, CellValue, Value};
7use crate::{
8    plonk::{Any, Column, ColumnType, Expression, Gate, VirtualCell},
9    poly::Rotation,
10};
11
12pub(super) fn format_value<F: Field>(v: F) -> String {
13    if v.is_zero_vartime() {
14        "0".into()
15    } else if v == F::one() {
16        "1".into()
17    } else if v == -F::one() {
18        "-1".into()
19    } else {
20        // Format value as hex.
21        let s = format!("{:?}", v);
22        // Remove leading zeroes.
23        let s = s.strip_prefix("0x").unwrap();
24        let s = s.trim_start_matches('0');
25        format!("0x{}", s)
26    }
27}
28
29pub(super) fn load<'a, F: FieldExt, T: ColumnType>(
30    n: i32,
31    row: i32,
32    queries: &'a [(Column<T>, Rotation)],
33    cells: &'a [Vec<CellValue<F>>],
34) -> impl Fn(usize, usize, Rotation) -> Value<F> + 'a {
35    move |index, _, _| {
36        let (column, at) = &queries[index];
37        let resolved_row = (row + at.0) % n;
38        cells[column.index()][resolved_row as usize].into()
39    }
40}
41
42pub(super) fn load_instance<'a, F: FieldExt, T: ColumnType>(
43    n: i32,
44    row: i32,
45    queries: &'a [(Column<T>, Rotation)],
46    cells: &'a [Vec<F>],
47) -> impl Fn(usize, usize, Rotation) -> Value<F> + 'a {
48    move |index, _, _| {
49        let (column, at) = &queries[index];
50        let resolved_row = (row + at.0) % n;
51        Value::Real(cells[column.index()][resolved_row as usize])
52    }
53}
54
55fn cell_value<'a, F: FieldExt>(
56    virtual_cells: &'a [VirtualCell],
57    column_type: Any,
58    load: impl Fn(usize, usize, Rotation) -> Value<F> + 'a,
59) -> impl Fn(usize, usize, Rotation) -> BTreeMap<metadata::VirtualCell, String> + 'a {
60    move |query_index, column_index, rotation| {
61        virtual_cells
62            .iter()
63            .find(|c| {
64                c.column.column_type() == &column_type
65                    && c.column.index() == column_index
66                    && c.rotation == rotation
67            })
68            // None indicates a selector, which we don't bother showing.
69            .map(|cell| {
70                (
71                    cell.clone().into(),
72                    match load(query_index, column_index, rotation) {
73                        Value::Real(v) => format_value(v),
74                        Value::Poison => unreachable!(),
75                    },
76                )
77            })
78            .into_iter()
79            .collect()
80    }
81}
82
83pub(super) fn cell_values<'a, F: FieldExt>(
84    gate: &Gate<F>,
85    poly: &Expression<F>,
86    load_fixed: impl Fn(usize, usize, Rotation) -> Value<F> + 'a,
87    load_advice: impl Fn(usize, usize, Rotation) -> Value<F> + 'a,
88    load_instance: impl Fn(usize, usize, Rotation) -> Value<F> + 'a,
89) -> Vec<(metadata::VirtualCell, String)> {
90    let virtual_cells = gate.queried_cells();
91    let cell_values = poly.evaluate(
92        &|_| BTreeMap::default(),
93        &|_| panic!("virtual selectors are removed during optimization"),
94        &cell_value(virtual_cells, Any::Fixed, load_fixed),
95        &cell_value(virtual_cells, Any::Advice, load_advice),
96        &cell_value(virtual_cells, Any::Instance, load_instance),
97        &|a| a,
98        &|mut a, mut b| {
99            a.append(&mut b);
100            a
101        },
102        &|mut a, mut b| {
103            a.append(&mut b);
104            a
105        },
106        &|a, _| a,
107    );
108    cell_values.into_iter().collect()
109}