Feat: various improvements

- Add simplify pow
- Add simplify linear combination
- Add column aliases
- Split display functions
This commit is contained in:
Dhole
2023-02-08 17:04:48 +01:00
parent 1cda65d657
commit 5cb817bdfe
4 changed files with 500 additions and 109 deletions

72
Cargo.lock generated
View File

@@ -43,6 +43,16 @@ dependencies = [
"constant_time_eq",
]
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"block-padding",
"generic-array",
]
[[package]]
name = "block-buffer"
version = "0.10.3"
@@ -52,6 +62,12 @@ dependencies = [
"generic-array",
]
[[package]]
name = "block-padding"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -126,13 +142,22 @@ dependencies = [
"typenum",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]]
name = "digest"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
dependencies = [
"block-buffer",
"block-buffer 0.10.3",
"crypto-common",
]
@@ -199,15 +224,17 @@ dependencies = [
"ff",
"group",
"halo2curves",
"log",
"rand_core",
"rayon",
"sha3",
"tracing",
]
[[package]]
name = "halo2curves"
version = "0.2.1"
source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.0#83c72d49762343ffc9576ca11a2aa615efe1029b"
version = "0.3.1"
source = "git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1#9b67e19bca30a35208b0c1b41c1723771e2c9f49"
dependencies = [
"ff",
"group",
@@ -230,6 +257,15 @@ dependencies = [
"libc",
]
[[package]]
name = "keccak"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768"
dependencies = [
"cpufeatures",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -242,6 +278,15 @@ version = "0.2.135"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
@@ -320,6 +365,12 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "pasta_curves"
version = "0.4.1"
@@ -391,6 +442,7 @@ version = "0.1.0"
dependencies = [
"halo2_proofs",
"lazy_static",
"log",
"nom",
"num-bigint",
"num-integer",
@@ -497,7 +549,19 @@ checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
"digest 0.10.5",
]
[[package]]
name = "sha3"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809"
dependencies = [
"block-buffer 0.9.0",
"digest 0.9.0",
"keccak",
"opaque-debug",
]
[[package]]

View File

@@ -17,6 +17,7 @@ pest = "2.4"
pest_derive = "2.4"
lazy_static = "1.4"
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_09_10" }
log = "0.4.14"
[patch."https://github.com/privacy-scaling-explorations/halo2.git"]
halo2_proofs = { path = "../zkevm/halo2/halo2_proofs" }
halo2_proofs = { path = "../halo2/halo2_proofs" }

View File

@@ -313,7 +313,7 @@ fn mul(lhs: BigUint, rhs: &BigUint, p: &BigUint) -> BigUint {
(lhs * rhs).mod_floor(p)
}
impl<V: Var + Eq + Hash + Ord> Expr<V> {
impl<V: Var + Eq + Hash + Ord + Display> Expr<V> {
pub fn eval(&self, p: &BigUint, vars: &HashMap<V, BigUint>) -> BigUint {
use Expr::*;
match self {
@@ -353,11 +353,11 @@ impl<V: Var + Eq + Hash + Ord> Expr<V> {
// let p_1 = p.clone() - BigUint::one();
match self {
Pow(e, f) => {
let e = e.simplify(p);
let e = e._simplify(p, ip);
Pow(Box::new(e), f)
}
Neg(e) => {
let e = e.simplify(p);
let e = e._simplify(p, ip);
match e {
Neg(ne) => *ne, // double negate concels itself
e => Neg(Box::new(e)),
@@ -373,7 +373,7 @@ impl<V: Var + Eq + Hash + Ord> Expr<V> {
Var(v) => Var(v),
Sum(es) => {
let mut xs: Vec<Expr<V>> = Vec::new();
for x in es.into_iter().map(|x| x.simplify(p)) {
for x in es.into_iter().map(|x| x._simplify(p, ip)) {
match x {
Sum(es) => xs.extend(es.into_iter()),
e => xs.push(e),
@@ -413,7 +413,7 @@ impl<V: Var + Eq + Hash + Ord> Expr<V> {
// TODO: get Pow's out of Mul elements
let mut xs: Vec<Expr<V>> = Vec::new();
let mut neg = false;
for x in es.into_iter().map(|x| x.simplify(p)) {
for x in es.into_iter().map(|x| x._simplify(p, ip)) {
match x {
Neg(e) => {
neg ^= true;
@@ -457,9 +457,152 @@ impl<V: Var + Eq + Hash + Ord> Expr<V> {
}
}
fn is_linear_comb(e: &Self, base: &mut Option<Self>, elems: &mut Vec<Self>) -> bool {
use Expr::*;
// match pattern "sum_lhs + sum_rhs"
// where "sum_rhs = mul_lhs * mul_rhs"
// in summary "sum_lhs + mul_lhs * mul_rhs"
match e {
Sum(xs) => {
if xs.len() != 2 {
return false;
}
let sum_lhs = &xs[0];
let sum_rhs = &xs[1];
match sum_rhs {
Mul(ys) => {
if ys.len() < 2 {
return false;
}
let mul_lhs = &ys[0];
if base.is_none() {
*base = Some(mul_lhs.clone());
}
// When elem is 0, this "r * (0 + r * (10 ..))" becomes this
// "r * r * (10 ..)"
for v in &ys[1..ys.len() - 1] {
if Some(v) == base.as_ref() {
elems.push(Const(BigUint::zero()));
continue;
}
return false;
}
let mul_rhs = &ys[ys.len() - 1];
// sort (mul_lhs, mul_rhs) so that base into mul_lhs (if it exists)
let (mul_lhs, mul_rhs) = if Some(mul_lhs) == base.as_ref() {
(mul_lhs, mul_rhs)
} else if Some(mul_rhs) == base.as_ref() {
(mul_rhs, mul_lhs)
} else {
(mul_lhs, mul_rhs)
};
if Some(mul_lhs) == base.as_ref() {
elems.push(sum_lhs.clone());
if mul_rhs.is_terminal() {
elems.push(mul_rhs.clone());
return true;
}
return Self::is_linear_comb(&mul_rhs, base, elems);
}
return false;
}
_ => return false,
}
}
_ => return false,
}
}
fn get_linear_comb(&self) -> Option<(Self, Vec<Self>)> {
let mut base = None;
let mut elems = Vec::new();
let result = Self::is_linear_comb(self, &mut base, &mut elems);
if result {
Some((base.expect("base found"), elems))
} else {
None
}
}
// Find linear combinations expressed in recursive form "a + r * (b + r * (c + r * (...)))"
// and replace them by "a + b*r + c*r^2 + ..."
fn normalize_linear_comb(self) -> Self {
use Expr::*;
match self {
Neg(e) => Neg(Box::new(e.normalize_linear_comb())),
Sum(xs) => {
let e = Sum(xs);
if let Some((base, elems)) = e.get_linear_comb() {
if elems.len() >= 3 {
let mut xs = Vec::with_capacity(elems.len());
for (i, elem) in elems.into_iter().enumerate() {
// let e = if i == 0 {
// elem
// } else {
// Mul(vec![elem, Pow(Box::new(base.clone()), BigUint::from(i))])
// };
let e = Mul(vec![elem, Pow(Box::new(base.clone()), BigUint::from(i))]);
xs.push(e);
}
return Sum(xs);
}
}
if let Sum(xs) = e {
Sum(xs.into_iter().map(|e| e.normalize_linear_comb()).collect())
} else {
unreachable!();
}
}
Mul(xs) => Mul(xs.into_iter().map(|e| e.normalize_linear_comb()).collect()),
_ => self,
}
}
// Find multiplications with repeated elements and turn them into pows
fn normalize_pow(self) -> Self {
use Expr::*;
match self {
Neg(e) => Neg(Box::new(e.normalize_pow())),
Sum(xs) => Sum(xs.into_iter().map(|e| e.normalize_pow()).collect()),
Mul(xs) => {
let mut elems = Vec::new();
let mut pow: Option<(Self, usize)> = None;
for x in xs {
let x = x.normalize_pow();
if let Some((base, exp)) = pow {
if x == base {
pow = Some((base, exp + 1));
} else {
if exp == 1 {
elems.push(base);
} else {
elems.push(Pow(Box::new(base), BigUint::from(exp)));
}
pow = Some((x, 1));
}
} else {
pow = Some((x, 1));
}
}
if let Some((base, exp)) = pow {
if exp == 1 {
elems.push(base);
} else {
elems.push(Pow(Box::new(base), BigUint::from(exp)));
}
}
Mul(elems)
}
_ => self,
}
}
pub fn simplify(self, p: &BigUint) -> Self {
let ip = BigInt::from(p.clone());
self._simplify(p, &ip)
let e = self._simplify(p, &ip);
let e = e.normalize_linear_comb();
let e = e.normalize_pow();
e
}
fn _normalize(self, p: &BigUint) -> Self {
@@ -745,7 +888,7 @@ mod tests {
#[cfg(test)]
mod tests_with_parser {
// use super::*;
use super::*;
use crate::parser::parse_expr;
use rand::SeedableRng;
@@ -760,4 +903,31 @@ mod tests_with_parser {
assert!(e1.test_eq(&mut rng, &e2))
}
}
#[test]
fn test_simplify_linear_comb() {
let p = BigUint::from(0x10000u64 - 15);
let e1_str = "112 + r_word*(164 + r_word*(133 + r_word*(93 + r_word*(4 + r_word*(216 + r_word*(250 + r_word*(123 + r_word*(59 + r_word*(39 + r_word*(130 + r_word*(202 + r_word*(83 + r_word*(182 + r_word*r_word*(229 + r_word*(192 + r_word*(3 + r_word*(199 + r_word*(220 + r_word*(178 + r_word*(125 + r_word*(126 + r_word*(146 + r_word*(60 + r_word*(35 + r_word*(247 + r_word*(134 + r_word*(1 + r_word*(70 + r_word*(210 + 197*r_word)))))))))))))))))))))))))))))";
let e2_str = "112*r_word^0 + 164*r_word^1 + 133*r_word^2 + 93*r_word^3 + 4*r_word^4 + 216*r_word^5 + 250*r_word^6 + 123*r_word^7 + 59*r_word^8 + 39*r_word^9 + 130*r_word^10 + 202*r_word^11 + 83*r_word^12 + 0*r_word^13 + 182*r_word^14 + 229*r_word^15 + 192*r_word^16 + 3*r_word^17 + 199*r_word^18 + 220*r_word^19 + 178*r_word^20 + 125*r_word^21 + 126*r_word^22 + 146*r_word^23 + 60*r_word^24 + 35*r_word^25 + 247*r_word^26 + 134*r_word^27 + 1*r_word^28 + 70*r_word^29 + 210*r_word^30 + 197*r_word^31";
let e1 = parse_expr(e1_str).unwrap();
let e2 = e1.simplify(&p);
// println!("{:?}", e1.normalize_linear_comb());
let s2 = format!("{}", e2);
assert_eq!(s2, e2_str);
}
#[test]
fn test_simplify_pow() {
let p = BigUint::from(0x10000u64 - 15);
let e1_str =
"4*(r_word + r_word*r_word + r_word*r_word*r_word + r_word*r_word*r_word*r_word)";
let e2_str = "4*(r_word + r_word^2 + r_word^3 + r_word^4)";
// TODO: Debug parser with this
// let e1_str ="f05*w77*w78*w79*w80*(1 - w76)*(w26 - (w26[-1]*2^0 + w25[-1]*2^1 + w24[-1]*2^2 + w23[-1]*2^3) + 2*(w25*2^0 + w24*2^1 + w23*2^2) + r_word*(w28 - w28[-1]) + r_word*r_word*(w27 - w27[-1]) + r_word*r_word*r_word*(w38 - w38[-1]) + r_word*r_word*r_word*r_word*(w37 - w37[-1]) + r_word*r_word*r_word*r_word*r_word*(w36 - w36[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*(w35 - w35[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w34 - w34[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w33 - w33[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w32 - w32[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w31 - w31[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w30 - w30[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w29 - w29[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w05 - w05[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w69 - (w69[-1] + 2^8*w70[-1]) + 2^8*w70))";
let e1 = parse_expr(e1_str).unwrap();
let e2 = e1.simplify(&p);
// println!("{:?}", e1.normalize_linear_comb());
let s2 = format!("{}", e2);
assert_eq!(s2, e2_str);
}
}

350
src/ir.rs
View File

@@ -31,28 +31,29 @@ pub struct Witness {
witness: Vec<Vec<Option<BigUint>>>,
}
impl Display for Witness {
/// Adaptor struct to format the witness columns assignments as CSV
pub struct WitnessDisplayCSV<'a>(pub &'a Witness);
impl Display for WitnessDisplayCSV<'_> {
/// Format witness assignment as CSV
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "--- witness ---\n")?;
for (i, col) in self.columns.iter().enumerate() {
if i != 0 {
write!(f, ",")?;
}
write!(f, "{}", col.name)?;
let this = self.0;
write!(f, "offset")?;
for col in this.columns.iter() {
write!(f, ",")?;
write!(f, "{}", col.name())?;
}
writeln!(f)?;
for row_idx in 0..self.num_rows {
for col_idx in 0..self.columns.len() {
if col_idx != 0 {
write!(f, ",")?;
}
if let Some(ref v) = self.witness[col_idx][row_idx] {
for row_idx in 0..this.num_rows {
write!(f, "{}", row_idx)?;
for col_idx in 0..this.columns.len() {
write!(f, ",")?;
if let Some(ref v) = this.witness[col_idx][row_idx] {
write!(f, "{}", v)?;
}
}
writeln!(f)?;
}
writeln!(f)?;
Ok(())
}
@@ -68,6 +69,8 @@ struct WitnessAssembly<F: Field> {
// A range of available rows for assignment and copies.
usable_rows: Range<usize>,
challenges: Vec<F>,
// region: Option<(String, HashMap<Column<Any>, String>)>,
// regions: HashMap<String, HashMap<Column<Any>, String>>,
}
impl<F: Field> Assignment<F> for WitnessAssembly<F> {
@@ -76,11 +79,12 @@ impl<F: Field> Assignment<F> for WitnessAssembly<F> {
NR: Into<String>,
N: FnOnce() -> NR,
{
// Do nothing; we don't care about regions in this context.
// self.region = Some((name().into(), HashMap::new()));
}
fn exit_region(&mut self) {
// Do nothing; we don't care about regions in this context.
// let (name, annotations) = self.region.take().unwrap();
// self.regions.insert(name, annotations);
}
fn enable_selector<A, AR>(
@@ -98,7 +102,11 @@ impl<F: Field> Assignment<F> for WitnessAssembly<F> {
fn query_instance(&self, column: Column<Instance>, row: usize) -> Result<Value<F>, Error> {
if !self.usable_rows.contains(&row) {
return Err(Error::not_enough_rows_available(self.k));
panic!(
"query_instance: row={} not in usable_rows={:?}",
row, self.usable_rows
);
// return Err(Error::not_enough_rows_available(self.k));
}
self.instance
@@ -122,7 +130,11 @@ impl<F: Field> Assignment<F> for WitnessAssembly<F> {
AR: Into<String>,
{
if !self.usable_rows.contains(&row) {
return Err(Error::not_enough_rows_available(self.k));
panic!(
"assign_advice: row={} not in usable_rows={:?}",
row, self.usable_rows
);
// return Err(Error::not_enough_rows_available(self.k));
}
*self
@@ -185,6 +197,13 @@ impl<F: Field> Assignment<F> for WitnessAssembly<F> {
fn pop_namespace(&mut self, _: Option<String>) {
// TODO: Do something with namespaces :)
}
fn annotate_column<A, AR>(&mut self, annotation: A, column: Column<Any>)
where
A: FnOnce() -> AR,
AR: Into<String>,
{
}
}
/// Assembly to be used in circuit synthesis.
@@ -198,19 +217,22 @@ struct Assembly<F: Field> {
// A range of available rows for assignment and copies.
usable_rows: Range<usize>,
_marker: std::marker::PhantomData<F>,
region: Option<(String, HashMap<Column<Any>, String>)>,
regions: HashMap<String, HashMap<Column<Any>, String>>,
}
impl<F: Field> Assignment<F> for Assembly<F> {
fn enter_region<NR, N>(&mut self, _: N)
fn enter_region<NR, N>(&mut self, name: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
// Do nothing; we don't care about regions in this context.
self.region = Some((name().into(), HashMap::new()));
}
fn exit_region(&mut self) {
// Do nothing; we don't care about regions in this context.
let (name, annotations) = self.region.take().expect("exit from a region");
self.regions.insert(name, annotations);
}
fn enable_selector<A, AR>(&mut self, _: A, selector: &Selector, row: usize) -> Result<(), Error>
@@ -219,7 +241,11 @@ impl<F: Field> Assignment<F> for Assembly<F> {
AR: Into<String>,
{
if !self.usable_rows.contains(&row) {
return Err(Error::not_enough_rows_available(self.k));
panic!(
"enable_selector: row={} not in usable_rows={:?}",
row, self.usable_rows
);
// return Err(Error::not_enough_rows_available(self.k));
}
self.selectors[selector.index()][row] = true;
@@ -229,7 +255,11 @@ impl<F: Field> Assignment<F> for Assembly<F> {
fn query_instance(&self, _: Column<Instance>, row: usize) -> Result<Value<F>, Error> {
if !self.usable_rows.contains(&row) {
return Err(Error::not_enough_rows_available(self.k));
panic!(
"query_instance: row={} not in usable_rows={:?}",
row, self.usable_rows
);
// return Err(Error::not_enough_rows_available(self.k));
}
// There is no instance in this context.
@@ -267,7 +297,11 @@ impl<F: Field> Assignment<F> for Assembly<F> {
AR: Into<String>,
{
if !self.usable_rows.contains(&row) {
return Err(Error::not_enough_rows_available(self.k));
panic!(
"assign_fixed: row={} not in usable_rows={:?}",
row, self.usable_rows
);
// return Err(Error::not_enough_rows_available(self.k));
}
*self
@@ -288,7 +322,12 @@ impl<F: Field> Assignment<F> for Assembly<F> {
right_row: usize,
) -> Result<(), Error> {
if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) {
return Err(Error::not_enough_rows_available(self.k));
panic!(
"copy: rows={:?} not in usable_rows={:?}",
(left_row, right_row),
self.usable_rows
);
// return Err(Error::not_enough_rows_available(self.k));
}
// TODO: Sort columns
@@ -307,7 +346,11 @@ impl<F: Field> Assignment<F> for Assembly<F> {
to: Value<Assigned<F>>,
) -> Result<(), Error> {
if !self.usable_rows.contains(&from_row) {
return Err(Error::not_enough_rows_available(self.k));
panic!(
"fill_from_row: from_row={} not in usable_rows={:?}",
from_row, self.usable_rows
);
// return Err(Error::not_enough_rows_available(self.k));
}
for row in self.usable_rows.clone().skip(from_row) {
@@ -332,25 +375,98 @@ impl<F: Field> Assignment<F> for Assembly<F> {
fn pop_namespace(&mut self, _: Option<String>) {
// Do nothing; we don't care about namespaces in this context.
}
fn annotate_column<A, AR>(&mut self, annotation: A, column: Column<Any>)
where
A: FnOnce() -> AR,
AR: Into<String>,
{
let (_, ref mut annotations) = self.region.as_mut().expect("annotate in a region");
annotations.insert(column, annotation().into());
}
}
#[derive(Debug, Clone)]
pub struct ColumnWitness {
pub name: String,
pub aliases: Vec<String>,
pub phase: usize,
}
impl ColumnWitness {
fn new(name: String, phase: usize) -> Self {
Self {
name,
aliases: Vec::new(),
phase,
}
}
fn name(&self) -> &String {
self.aliases.get(0).unwrap_or(&self.name)
}
}
#[derive(Debug, Clone)]
pub struct ColumnFixed {
pub name: String,
pub aliases: Vec<String>,
}
impl ColumnFixed {
fn new(name: String) -> Self {
Self {
name,
aliases: Vec::new(),
}
}
fn name(&self) -> &String {
self.aliases.get(0).unwrap_or(&self.name)
}
}
#[derive(Debug, Clone)]
pub struct ColumnPublic {
pub name: String,
pub aliases: Vec<String>,
}
impl ColumnPublic {
fn new(name: String) -> Self {
Self {
name,
aliases: Vec::new(),
}
}
fn name(&self) -> &String {
self.aliases.get(0).unwrap_or(&self.name)
}
}
#[derive(Debug)]
pub struct Challenge {
pub name: String,
pub alias: Option<String>,
pub phase: usize,
}
impl Challenge {
fn new(name: String, phase: usize) -> Self {
Self {
name,
alias: None,
phase,
}
}
fn name(&self) -> &String {
self.alias.as_ref().unwrap_or(&self.name)
}
}
#[derive(Debug, Default)]
pub struct Columns {
pub witness: Vec<ColumnWitness>,
pub fixed: Vec<String>,
pub public: Vec<String>,
pub fixed: Vec<ColumnFixed>,
pub public: Vec<ColumnPublic>,
}
#[derive(Debug)]
@@ -395,9 +511,9 @@ impl Plaf {
f,
"{}",
match c.kind {
Witness => &self.columns.witness[c.index].name,
Public => &self.columns.public[c.index],
Fixed => &self.columns.fixed[c.index],
Witness => self.columns.witness[c.index].name(),
Public => self.columns.public[c.index].name(),
Fixed => self.columns.fixed[c.index].name(),
}
)
}
@@ -411,79 +527,122 @@ impl Plaf {
Ok(())
}
Var::Challenge { index, phase: _ } => {
write!(f, "{}", self.info.challenges[*index].name)
write!(f, "{}", self.info.challenges[*index].name())
}
}
}
pub fn set_challange_alias(&mut self, index: usize, name: String) {
self.info.challenges[index].alias = Some(name)
}
}
impl Display for Plaf {
/// Adaptor struct to format the fixed columns assignments as CSV
pub struct PlafDisplayFixedCSV<'a>(pub &'a Plaf);
impl Display for PlafDisplayFixedCSV<'_> {
/// Format fixed columns assignments as CSV
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let this = self.0;
write!(f, "offset")?;
for col in this.columns.fixed.iter() {
write!(f, ",")?;
write!(f, "{}", col.name())?;
}
writeln!(f)?;
for row_idx in 0..this.info.num_rows {
write!(f, "{}", row_idx)?;
for col_idx in 0..this.columns.fixed.len() {
write!(f, ",")?;
if let Some(ref v) = this.fixed[col_idx][row_idx] {
write!(f, "{}", v)?;
}
}
writeln!(f)?;
}
Ok(())
}
}
/// Adaptor struct to format the entire Plaf as toml except for the Fixed Column assignments
pub struct PlafDisplayBaseTOML<'a>(pub &'a Plaf);
impl Display for PlafDisplayBaseTOML<'_> {
/// Format entire Plaf as toml except for Fixed Columns assignments
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let this = self.0;
writeln!(f, "[info]")?;
writeln!(f, "num_rows = {}", self.info.num_rows)?;
writeln!(f, "num_rows = {}", this.info.num_rows)?;
writeln!(f)?;
writeln!(f, "[info.challenges]")?;
for ch in &self.info.challenges {
writeln!(f, "{} = {{ phase = {} }}", ch.name, ch.phase)?;
for ch in &this.info.challenges {
write!(f, "{} = {{ phase = {}", ch.name, ch.phase)?;
if let Some(alias) = &ch.alias {
writeln!(f, ", alias = \"{}\" }}", alias)?;
} else {
writeln!(f, "}}")?;
}
}
writeln!(f)?;
writeln!(f, "[columns.public]")?;
for c in &self.columns.public {
writeln!(f, "{} = {{}}", c)?;
for c in &this.columns.public {
writeln!(f, "{} = {{ aliases = {:?} }}", c.name, c.aliases)?;
}
writeln!(f)?;
writeln!(f, "[columns.fixed]")?;
for c in &self.columns.fixed {
writeln!(f, "{} = {{}}", c)?;
for c in &this.columns.fixed {
writeln!(f, "{} = {{ aliases = {:?} }}", c.name, c.aliases)?;
}
writeln!(f)?;
writeln!(f, "[columns.witness]")?;
for c in &self.columns.witness {
writeln!(f, "{} = {{ phase = {} }}", c.name, c.phase)?;
for c in &this.columns.witness {
writeln!(
f,
"{} = {{ phase = {}, aliases = {:?} }}",
c.name, c.phase, c.aliases
)?;
}
writeln!(f)?;
writeln!(f, "[constraints.polys]")?;
for p in &self.polys {
write!(f, "\"{}\" = \"", p.name)?;
for p in &this.polys {
writeln!(f, "[constraints.polys.\"{}\"]", p.name)?;
write!(f, "c = \"")?;
p.exp
.fmt_ascii(f, &mut |f: &mut fmt::Formatter<'_>, v: &Var| {
self.fmt_var(f, v)
this.fmt_var(f, v)
})?;
writeln!(f, "\"")?;
}
writeln!(f)?;
writeln!(f, "[constraints.lookups]")?;
for l in &self.lookups {
write!(f, "\"{}\" = [[", l.name)?;
for (i, lhs) in l.exps.0.iter().enumerate() {
write!(f, "\"{}\"", lhs)?;
if i != l.exps.0.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "], [")?;
for (i, rhs) in l.exps.1.iter().enumerate() {
write!(f, "\"{}\"", rhs)?;
if i != l.exps.1.len() - 1 {
write!(f, ", ")?;
}
for l in &this.lookups {
writeln!(f, "[constraints.lookups.\"{}\"]", l.name)?;
writeln!(f, "l = [")?;
for (lhs, rhs) in l.exps.0.iter().zip(l.exps.1.iter()) {
write!(f, " [\"")?;
lhs.fmt_ascii(f, &mut |f: &mut fmt::Formatter<'_>, v: &Var| {
this.fmt_var(f, v)
})?;
writeln!(f, "\",")?;
write!(f, " \"")?;
rhs.fmt_ascii(f, &mut |f: &mut fmt::Formatter<'_>, v: &Var| {
this.fmt_var(f, v)
})?;
writeln!(f, "\"],")?;
}
writeln!(f, "]")?;
}
writeln!(f)?;
for c in &self.copys {
for c in &this.copys {
writeln!(f, "[[constraints.copys]]")?;
write!(f, "columns = [\"")?;
self.fmt_column(f, &c.columns.0)?;
this.fmt_column(f, &c.columns.0)?;
write!(f, "\", \"")?;
self.fmt_column(f, &c.columns.1)?;
this.fmt_column(f, &c.columns.1)?;
writeln!(f, "\"]")?;
writeln!(f, "offsets = [")?;
for (a, b) in &c.offsets {
@@ -493,27 +652,6 @@ impl Display for Plaf {
}
writeln!(f)?;
writeln!(f, "--- fixed ---\n")?;
for (i, col) in self.columns.fixed.iter().enumerate() {
if i != 0 {
write!(f, ",")?;
}
write!(f, "{}", col)?;
}
writeln!(f)?;
for row_idx in 0..self.info.num_rows {
for col_idx in 0..self.columns.fixed.len() {
if col_idx != 0 {
write!(f, ",")?;
}
if let Some(ref v) = self.fixed[col_idx][row_idx] {
write!(f, "{}", v)?;
}
}
writeln!(f)?;
}
writeln!(f)?;
Ok(())
}
}
@@ -550,6 +688,8 @@ pub fn get_witness<F: Field + PrimeField<Repr = [u8; 32]>, ConcreteCircuit: Circ
advice,
usable_rows: 0..n as usize - (cs.blinding_factors() + 1),
challenges,
// region: None,
// regions: HashMap::new(),
};
ConcreteCircuit::FloorPlanner::synthesize(
@@ -578,7 +718,7 @@ pub fn get_witness<F: Field + PrimeField<Repr = [u8; 32]>, ConcreteCircuit: Circ
Ok(witness)
}
pub fn get_ir<F: Field + PrimeField<Repr = [u8; 32]>, ConcreteCircuit: Circuit<F>>(
pub fn gen_plaf<F: Field + PrimeField<Repr = [u8; 32]>, ConcreteCircuit: Circuit<F>>(
k: u32,
circuit: &ConcreteCircuit,
) -> Result<Plaf, Error> {
@@ -588,7 +728,6 @@ pub fn get_ir<F: Field + PrimeField<Repr = [u8; 32]>, ConcreteCircuit: Circuit<F
let config = ConcreteCircuit::configure(&mut cs);
let degree = cs.degree();
println!("Degree = {}", degree);
if n < cs.minimum_rows() {
panic!("not enough rows available, k = {}", k);
@@ -601,6 +740,8 @@ pub fn get_ir<F: Field + PrimeField<Repr = [u8; 32]>, ConcreteCircuit: Circuit<F
selectors: vec![vec![false; n as usize]; cs.num_selectors()],
usable_rows: 0..n as usize - (cs.blinding_factors() + 1),
_marker: std::marker::PhantomData,
region: None,
regions: HashMap::new(),
};
ConcreteCircuit::FloorPlanner::synthesize(
@@ -627,25 +768,40 @@ pub fn get_ir<F: Field + PrimeField<Repr = [u8; 32]>, ConcreteCircuit: Circuit<F
let challenge_phase = cs.challenge_phase();
for i in 0..cs.num_challenges() {
let phase = challenge_phase[i];
plaf.info.challenges.push(Challenge {
name: format!("ch{}_{}", i, phase),
phase: phase as usize,
});
plaf.info
.challenges
.push(Challenge::new(format!("ch{}_{}", i, phase), phase as usize));
}
for i in 0..cs.num_fixed_columns() {
plaf.columns.fixed.push(format!("f{:02}", i));
plaf.columns
.fixed
.push(ColumnFixed::new(format!("f{:02}", i)));
}
for i in 0..cs.num_instance_columns() {
plaf.columns.public.push(format!("i{:02}", i));
plaf.columns
.public
.push(ColumnPublic::new(format!("i{:02}", i)));
}
let column_phase = cs.advice_column_phase();
for i in 0..cs.num_advice_columns() {
plaf.columns.witness.push(ColumnWitness {
name: format!("w{:02}", i),
phase: column_phase[i] as usize,
});
plaf.columns.witness.push(ColumnWitness::new(
format!("w{:02}", i),
column_phase[i] as usize,
));
}
for (region_name, region) in assembly.regions {
for (column, name) in region.iter() {
let name = name.clone();
match column.column_type() {
Any::Advice(..) => plaf.columns.witness[column.index()].aliases.push(name),
Any::Fixed => plaf.columns.fixed[column.index()].aliases.push(name),
Any::Instance => plaf.columns.public[column.index()].aliases.push(name),
}
}
}
for gate in cs.gates() {
let name = gate.name();
let len_log10 = (gate.polynomials().len() as f64).log10().ceil() as usize;