mirror of
https://github.com/Dhole/polyexen.git
synced 2026-05-09 03:00:02 -04:00
Feat: various improvements
- Add simplify pow - Add simplify linear combination - Add column aliases - Split display functions
This commit is contained in:
72
Cargo.lock
generated
72
Cargo.lock
generated
@@ -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]]
|
||||
|
||||
@@ -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" }
|
||||
|
||||
184
src/expr.rs
184
src/expr.rs
@@ -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
350
src/ir.rs
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user