diff --git a/Cargo.lock b/Cargo.lock index 86dec8e..c4632f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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]] diff --git a/Cargo.toml b/Cargo.toml index 17dc949..3fd0971 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/src/expr.rs b/src/expr.rs index 90b46d1..369ed4a 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -313,7 +313,7 @@ fn mul(lhs: BigUint, rhs: &BigUint, p: &BigUint) -> BigUint { (lhs * rhs).mod_floor(p) } -impl Expr { +impl Expr { pub fn eval(&self, p: &BigUint, vars: &HashMap) -> BigUint { use Expr::*; match self { @@ -353,11 +353,11 @@ impl Expr { // 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 Expr { Var(v) => Var(v), Sum(es) => { let mut xs: Vec> = 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 Expr { // TODO: get Pow's out of Mul elements let mut xs: Vec> = 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 Expr { } } + fn is_linear_comb(e: &Self, base: &mut Option, elems: &mut Vec) -> 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)> { + 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); + } } diff --git a/src/ir.rs b/src/ir.rs index 2c58a23..1590a60 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -31,28 +31,29 @@ pub struct Witness { witness: Vec>>, } -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 { // A range of available rows for assignment and copies. usable_rows: Range, challenges: Vec, + // region: Option<(String, HashMap, String>)>, + // regions: HashMap, String>>, } impl Assignment for WitnessAssembly { @@ -76,11 +79,12 @@ impl Assignment for WitnessAssembly { NR: Into, 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( @@ -98,7 +102,11 @@ impl Assignment for WitnessAssembly { fn query_instance(&self, column: Column, row: usize) -> Result, 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 Assignment for WitnessAssembly { AR: Into, { 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 Assignment for WitnessAssembly { fn pop_namespace(&mut self, _: Option) { // TODO: Do something with namespaces :) } + + fn annotate_column(&mut self, annotation: A, column: Column) + where + A: FnOnce() -> AR, + AR: Into, + { + } } /// Assembly to be used in circuit synthesis. @@ -198,19 +217,22 @@ struct Assembly { // A range of available rows for assignment and copies. usable_rows: Range, _marker: std::marker::PhantomData, + region: Option<(String, HashMap, String>)>, + regions: HashMap, String>>, } impl Assignment for Assembly { - fn enter_region(&mut self, _: N) + fn enter_region(&mut self, name: N) where NR: Into, 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(&mut self, _: A, selector: &Selector, row: usize) -> Result<(), Error> @@ -219,7 +241,11 @@ impl Assignment for Assembly { AR: Into, { 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 Assignment for Assembly { fn query_instance(&self, _: Column, row: usize) -> Result, 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 Assignment for Assembly { AR: Into, { 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 Assignment for Assembly { 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 Assignment for Assembly { to: Value>, ) -> 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 Assignment for Assembly { fn pop_namespace(&mut self, _: Option) { // Do nothing; we don't care about namespaces in this context. } + + fn annotate_column(&mut self, annotation: A, column: Column) + where + A: FnOnce() -> AR, + AR: Into, + { + 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, 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, +} + +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, +} + +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, 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, - pub fixed: Vec, - pub public: Vec, + pub fixed: Vec, + pub public: Vec, } #[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, 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, ConcreteCircuit: Circ Ok(witness) } -pub fn get_ir, ConcreteCircuit: Circuit>( +pub fn gen_plaf, ConcreteCircuit: Circuit>( k: u32, circuit: &ConcreteCircuit, ) -> Result { @@ -588,7 +728,6 @@ pub fn get_ir, ConcreteCircuit: Circuit, ConcreteCircuit: Circuit, ConcreteCircuit: Circuit 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;