mirror of
https://github.com/Dhole/polyexen.git
synced 2026-04-17 03:00:54 -04:00
WIP
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use crate::expr::{Expr, Var};
|
||||
use crate::expr::{modinv, mul, neg, Expr, Var};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use num_bigint::{BigInt, BigUint, Sign};
|
||||
use num_traits::{cast::ToPrimitive, One, Zero};
|
||||
@@ -10,6 +11,15 @@ pub enum Bound {
|
||||
Set(Vec<BigUint>), // non contiguous set, always sorted
|
||||
}
|
||||
|
||||
impl Display for Bound {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Bound::Range(start, end) => write!(f, "[{},{}]", start, end),
|
||||
Bound::Set(xs) => write!(f, "{:?}", xs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Bound {
|
||||
pub fn new<I: IntoIterator<Item = BigUint>>(iter: I) -> Self {
|
||||
let one = BigUint::from(1u64);
|
||||
@@ -100,6 +110,18 @@ impl Bound {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub fn unique(&self) -> Option<&BigUint> {
|
||||
match self {
|
||||
Bound::Set(xs) => {
|
||||
if xs.len() == 1 {
|
||||
Some(&xs[0])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -134,7 +156,7 @@ pub fn bound_base(p: &BigUint) -> Bound {
|
||||
}
|
||||
|
||||
pub fn find_bounds_poly<V: Var>(e: &Expr<V>, p: &BigUint, analysis: &mut Analysis<V>) {
|
||||
let (exhaustive, solutions_list) = find_solutions(e);
|
||||
let (exhaustive, solutions_list) = find_solutions(e, p);
|
||||
let mut solutions = HashMap::new();
|
||||
if exhaustive {
|
||||
for (var, value) in &solutions_list {
|
||||
@@ -170,6 +192,10 @@ fn find_solutions_base<V: Var>(e: &Expr<V>) -> (bool, Vec<(V, BigInt)>) {
|
||||
Var(v) => (true, vec![(v.clone(), BigInt::zero())]),
|
||||
Neg(e) => find_solutions_base(e),
|
||||
Sum(es) => {
|
||||
// println!("DBG1");
|
||||
// for e in es {
|
||||
// println!(" {}", e);
|
||||
// }
|
||||
let mut var: Option<V> = None;
|
||||
let mut con: Option<BigInt> = None;
|
||||
let mut neg = false;
|
||||
@@ -204,10 +230,51 @@ fn find_solutions_base<V: Var>(e: &Expr<V>) -> (bool, Vec<(V, BigInt)>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn solve_1(a: &BigUint, b: &BigUint, p: &BigUint) -> BigUint {
|
||||
// a + b*x = 0
|
||||
// x = -a * inv(b)
|
||||
mul(neg(a.clone(), p), &modinv(b.clone(), p), p)
|
||||
}
|
||||
|
||||
pub fn find_solution_1<V: Var>(e: &Expr<V>, p: &BigUint) -> Option<(V, BigInt)> {
|
||||
use Expr::*;
|
||||
match e {
|
||||
Mul(xs) => {
|
||||
if xs.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
if let (Const(b), Var(v)) = (&xs[0], &xs[1]) {
|
||||
let res = solve_1(&BigUint::zero(), &b, p);
|
||||
return Some((v.clone(), BigInt::from(res)));
|
||||
}
|
||||
return None;
|
||||
}
|
||||
Sum(xs) => {
|
||||
if xs.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
if let (Const(a), Mul(ys)) = (&xs[0], &xs[1]) {
|
||||
if ys.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
if let (Const(b), Var(v)) = (&ys[0], &ys[1]) {
|
||||
let res = solve_1(&a, &b, p);
|
||||
return Some((v.clone(), BigInt::from(res)));
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to find solutions to `e(X) == 0` by matching on the pattern `(x - A)(y - B)...`.
|
||||
// Returns true when the solutions returned are exhaustive.
|
||||
pub fn find_solutions<V: Var>(e: &Expr<V>) -> (bool, Vec<(V, BigInt)>) {
|
||||
pub fn find_solutions<V: Var>(e: &Expr<V>, p: &BigUint) -> (bool, Vec<(V, BigInt)>) {
|
||||
use Expr::*;
|
||||
if let Some(solution) = find_solution_1(e, p) {
|
||||
return (true, vec![solution]);
|
||||
}
|
||||
match e {
|
||||
Mul(es) => {
|
||||
let mut exhaustive = true;
|
||||
@@ -235,7 +302,8 @@ mod tests_with_parser {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_solutions() {
|
||||
fn test_find_solutions00() {
|
||||
let p = prime();
|
||||
for (e_str, sol_str, expected_exhaustive) in [
|
||||
("(a - 5) * (b + 8)", vec![("a", "5"), ("b", "-8")], true),
|
||||
("(a - 5) * (a - 7)", vec![("a", "5"), ("a", "7")], true),
|
||||
@@ -257,7 +325,7 @@ mod tests_with_parser {
|
||||
}
|
||||
expected_solutions.sort();
|
||||
|
||||
let (exhaustive, mut solutions) = find_solutions(&e);
|
||||
let (exhaustive, mut solutions) = find_solutions(&e, &p);
|
||||
solutions.sort();
|
||||
assert_eq!(exhaustive, expected_exhaustive, "{}", e_str);
|
||||
assert_eq!(solutions, expected_solutions, "{}", e_str);
|
||||
@@ -265,7 +333,7 @@ mod tests_with_parser {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_bounds_poly() {
|
||||
fn test_find_bounds_poly00() {
|
||||
let p = prime();
|
||||
|
||||
let poly1 = parse_expr("(a - 0) * (a - 1)").unwrap();
|
||||
@@ -293,4 +361,13 @@ mod tests_with_parser {
|
||||
find_bounds_poly(&poly1, &p, &mut analysis);
|
||||
println!("{:?}", &analysis);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_bounds_poly01() {
|
||||
let p = prime();
|
||||
let poly1 = parse_expr("5*(1 - tag[1])").unwrap();
|
||||
let mut analysis = Analysis::new();
|
||||
find_bounds_poly(&poly1, &p, &mut analysis);
|
||||
println!("{:?}", &analysis);
|
||||
}
|
||||
}
|
||||
|
||||
226
src/expr.rs
226
src/expr.rs
@@ -308,15 +308,44 @@ fn add(lhs: BigUint, rhs: BigUint, p: &BigUint) -> BigUint {
|
||||
}
|
||||
}
|
||||
|
||||
fn neg(n: BigUint, p: &BigUint) -> BigUint {
|
||||
pub(crate) fn neg(n: BigUint, p: &BigUint) -> BigUint {
|
||||
p - n
|
||||
}
|
||||
|
||||
fn mul(lhs: BigUint, rhs: &BigUint, p: &BigUint) -> BigUint {
|
||||
pub(crate) fn mul(lhs: BigUint, rhs: &BigUint, p: &BigUint) -> BigUint {
|
||||
(lhs * rhs).mod_floor(p)
|
||||
}
|
||||
|
||||
pub(crate) fn modinv(n: BigUint, p: &BigUint) -> BigUint {
|
||||
if p.is_one() {
|
||||
return BigUint::one();
|
||||
}
|
||||
|
||||
let n = BigInt::from(n);
|
||||
let p = BigInt::from(p.clone());
|
||||
|
||||
let (mut a, mut m, mut x, mut inv) = (n.clone(), p.clone(), BigInt::zero(), BigInt::one());
|
||||
|
||||
let one = BigInt::one();
|
||||
while a > one {
|
||||
let (div, rem) = a.div_rem(&m);
|
||||
inv -= div * &x;
|
||||
a = rem;
|
||||
std::mem::swap(&mut a, &mut m);
|
||||
std::mem::swap(&mut x, &mut inv);
|
||||
}
|
||||
|
||||
if inv < BigInt::zero() {
|
||||
inv += p
|
||||
}
|
||||
|
||||
let (sign, res) = inv.into_parts();
|
||||
assert_eq!(sign, Sign::Plus);
|
||||
res
|
||||
}
|
||||
|
||||
impl<V: Var> Expr<V> {
|
||||
// p is the base field
|
||||
pub fn eval(&self, p: &BigUint, vars: &HashMap<V, BigUint>) -> BigUint {
|
||||
use Expr::*;
|
||||
match self {
|
||||
@@ -446,6 +475,8 @@ impl<V: Var> Expr<V> {
|
||||
r.extend(tail.into_iter());
|
||||
let m = if r.len() == 1 {
|
||||
r.swap_remove(0)
|
||||
} else if r.len() == 0 {
|
||||
Const(BigUint::one())
|
||||
} else {
|
||||
Mul(r)
|
||||
};
|
||||
@@ -599,6 +630,8 @@ impl<V: Var> Expr<V> {
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Simplify the expression in places where it can be partially evaluated
|
||||
pub fn simplify_move(self, p: &BigUint) -> Self {
|
||||
let ip = BigInt::from(p.clone());
|
||||
let e = self._simplify(p, &ip);
|
||||
@@ -607,6 +640,7 @@ impl<V: Var> Expr<V> {
|
||||
e
|
||||
}
|
||||
|
||||
/// Simplify the expression in places where it can be partially evaluated
|
||||
pub fn simplify(&mut self, p: &BigUint) -> &mut Self {
|
||||
let e = mem::replace(self, Expr::Const(BigUint::zero()));
|
||||
let e = e.simplify_move(p);
|
||||
@@ -614,48 +648,168 @@ impl<V: Var> Expr<V> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Take a list of multiplicands and return a Mul expression whith the multiplication of
|
||||
/// coefficients evaluated
|
||||
fn _mul_const(xs: Vec<Expr<V>>, p: &BigUint) -> Expr<V> {
|
||||
use Expr::*;
|
||||
let mut mul_const = BigUint::one();
|
||||
let mut mul_exprs = Vec::new();
|
||||
for x in xs {
|
||||
match x {
|
||||
Const(f) => mul_const = mul(mul_const, &f, p),
|
||||
e => mul_exprs.push(e),
|
||||
}
|
||||
}
|
||||
if mul_exprs.len() == 0 {
|
||||
return Const(mul_const);
|
||||
}
|
||||
let mut xs = Vec::new();
|
||||
if !mul_const.is_one() {
|
||||
xs.push(Const(mul_const))
|
||||
}
|
||||
xs.extend_from_slice(&mul_exprs[..]);
|
||||
Mul(xs)
|
||||
}
|
||||
|
||||
/// Apply "a * b % p" where a and b are expressions. Evaluate coefficient multiplication in
|
||||
/// the resulting expression.
|
||||
fn _normalize_mul(a: Expr<V>, b: Expr<V>, p: &BigUint) -> Expr<V> {
|
||||
use Expr::*;
|
||||
match (a, b) {
|
||||
(Const(a), Const(b)) => Const(mul(a, &b, p)),
|
||||
(Mul(mut xs), Mul(ys)) => {
|
||||
xs.extend_from_slice(&ys[..]);
|
||||
Self::_mul_const(xs, p)
|
||||
}
|
||||
(e, Mul(xs)) => {
|
||||
let mut ys = vec![e];
|
||||
ys.extend_from_slice(&xs[..]);
|
||||
Self::_mul_const(ys, p)
|
||||
}
|
||||
(Mul(mut xs), e) => {
|
||||
xs.push(e.clone());
|
||||
Self::_mul_const(xs, p)
|
||||
}
|
||||
(a, b) => Mul(vec![a, b]),
|
||||
}
|
||||
}
|
||||
|
||||
fn _normalize(self, p: &BigUint) -> Self {
|
||||
use Expr::*;
|
||||
// p-1 == -1
|
||||
let p_1 = p.clone() - BigUint::one();
|
||||
match self {
|
||||
Neg(e) => Mul(vec![Const(p_1), *e]),
|
||||
Neg(e) => Mul(vec![Const(p_1), *e])._normalize(p),
|
||||
Sum(xs) => {
|
||||
let xs: Vec<Expr<V>> = xs.into_iter().map(|x| x.normalize_move(p)).collect();
|
||||
let xs = xs.into_iter().map(|x: Expr<V>| x._normalize(p));
|
||||
let mut sum_const = BigUint::zero();
|
||||
let mut sum_exprs = Vec::new();
|
||||
for x in xs {
|
||||
match x {
|
||||
Const(f) => sum_const = add(sum_const, f, p),
|
||||
Sum(xs) => {
|
||||
for x in xs {
|
||||
match x {
|
||||
Const(f) => sum_const = add(sum_const, f, p),
|
||||
e => sum_exprs.push(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
e => sum_exprs.push(e),
|
||||
}
|
||||
}
|
||||
let mut xs = Vec::new();
|
||||
if !sum_const.is_zero() {
|
||||
xs.push(Const(sum_const))
|
||||
}
|
||||
xs.extend_from_slice(&sum_exprs[..]);
|
||||
Sum(xs)
|
||||
}
|
||||
Mul(xs) => {
|
||||
let mut xs: Vec<Expr<V>> = xs.into_iter().map(|x| x.normalize_move(p)).collect();
|
||||
xs.sort();
|
||||
let mut iter = xs.into_iter();
|
||||
let mul_acc = iter.next().unwrap();
|
||||
let mut mul_acc = match mul_acc {
|
||||
Sum(xs) => xs,
|
||||
e => vec![e],
|
||||
};
|
||||
for next in iter {
|
||||
let e = match next {
|
||||
Sum(xs) => xs,
|
||||
e => vec![e],
|
||||
};
|
||||
let mut acc = Vec::new();
|
||||
for a in mul_acc.into_iter() {
|
||||
for b in &e {
|
||||
acc.push(Mul(vec![a.clone(), b.clone()]));
|
||||
// println!("DBG1 {}", Mul(xs.clone()));
|
||||
let xs = xs.into_iter().map(|x| x._normalize(p));
|
||||
// flat muls
|
||||
let mut ys = Vec::new();
|
||||
for x in xs {
|
||||
match x {
|
||||
Mul(xs) => {
|
||||
ys.extend_from_slice(&xs[..]);
|
||||
}
|
||||
_ => ys.push(x),
|
||||
}
|
||||
}
|
||||
let xs = ys;
|
||||
let mut mul_const = BigUint::one();
|
||||
let mut mul_vars: Vec<Expr<V>> = Vec::new();
|
||||
let mut mul_sums: Vec<Vec<Expr<V>>> = Vec::new();
|
||||
|
||||
for x in xs {
|
||||
match x {
|
||||
Const(f) => mul_const = mul(mul_const, &f, p),
|
||||
Var(v) => mul_vars.push(Var(v)),
|
||||
Sum(xs) => mul_sums.push(xs),
|
||||
_ => {
|
||||
dbg!(x);
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
mul_acc = acc;
|
||||
}
|
||||
Sum(mul_acc)
|
||||
// println!("DBG4 {:?}", mul_sums);
|
||||
|
||||
let mut first = Vec::new();
|
||||
if !mul_const.is_one() {
|
||||
first.push(Const(mul_const))
|
||||
}
|
||||
first.extend_from_slice(&mul_vars[..]);
|
||||
while mul_sums.len() >= 2 {
|
||||
let mut result = Vec::new();
|
||||
let lhs = &mul_sums[mul_sums.len() - 1];
|
||||
let rhs = &mul_sums[mul_sums.len() - 2];
|
||||
for a in lhs {
|
||||
for b in rhs {
|
||||
result.push(Self::_normalize_mul(a.clone(), b.clone(), p));
|
||||
}
|
||||
}
|
||||
mul_sums.pop();
|
||||
let last_index = mul_sums.len() - 1;
|
||||
mul_sums[last_index] = result;
|
||||
}
|
||||
if mul_sums.len() > 0 {
|
||||
for e in mul_sums[0].iter_mut() {
|
||||
*e = Self::_normalize_mul(Mul(first.clone()), e.clone(), p);
|
||||
}
|
||||
// println!("DBG2 {}", Sum(mul_sums[0].clone()));
|
||||
Sum(mul_sums.pop().unwrap())
|
||||
} else {
|
||||
// println!("DBG3 {}", Mul(first.clone()));
|
||||
Self::_mul_const(first, p)
|
||||
}
|
||||
}
|
||||
Pow(e, f) => {
|
||||
let e = e._normalize(p);
|
||||
match e {
|
||||
Const(b) => {
|
||||
let mut res = BigUint::one();
|
||||
let exp: u32 = f.to_u32().expect("exponent too big");
|
||||
// TODO: Implement efficient expmod
|
||||
for _ in 0..exp {
|
||||
res = mul(res, &b, p);
|
||||
}
|
||||
Const(res)
|
||||
}
|
||||
e => Pow(Box::new(e), f),
|
||||
}
|
||||
}
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the expression in coefficient form
|
||||
pub fn normalize_move(self, p: &BigUint) -> Self {
|
||||
self.simplify_move(p)._normalize(p).simplify_move(p)
|
||||
self.simplify_move(p)._normalize(p)
|
||||
}
|
||||
|
||||
/// Return the expression in coefficient form
|
||||
pub fn normalize(&mut self, p: &BigUint) -> &mut Self {
|
||||
let e = mem::replace(self, Expr::Const(BigUint::zero()));
|
||||
let e = e.normalize_move(p);
|
||||
@@ -684,6 +838,7 @@ impl<V: Var> Expr<V> {
|
||||
}
|
||||
|
||||
// TODO: Document the probability of success
|
||||
// Using Schwartz–Zippel lemma
|
||||
pub fn test_eq<R: Rng>(&self, rng: &mut R, other: &Self) -> bool {
|
||||
let p = BigUint::parse_bytes(b"100000000000000000000000000000000", 16).unwrap()
|
||||
- BigUint::from(159u64);
|
||||
@@ -899,7 +1054,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normalize() {
|
||||
fn test_normalize00() {
|
||||
let p = BigUint::from(0x10000u64 - 15);
|
||||
let vars: HashMap<&'static str, BigUint> = {
|
||||
let mut rng = ChaCha20Rng::seed_from_u64(0);
|
||||
@@ -996,4 +1151,25 @@ mod tests_with_parser {
|
||||
let s2 = format!("{}", e2);
|
||||
assert_eq!(s2, e2_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normalize01() {
|
||||
let p = prime();
|
||||
let e1_str = "1*5*(1 - (1 - (1 - 0)*(1 - tag[1]))*(1 - 0))";
|
||||
// let e1_str = "1 - (1 - tag[1])";
|
||||
let e1 = parse_expr(e1_str).unwrap();
|
||||
let e2 = e1.normalize_move(&p);
|
||||
// let e2 = e2.normalize_move(&p);
|
||||
println!("{}", e2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simplify01() {
|
||||
let p = prime();
|
||||
let e1_str = "(1 - 0)*1";
|
||||
let e1 = parse_expr(e1_str).unwrap();
|
||||
let e2 = e1.simplify_move(&p);
|
||||
println!("{:?}", e2);
|
||||
println!("{}", e2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,26 +27,22 @@ lazy_static! {
|
||||
pub fn parse_expr_pairs(expression: Pairs<Rule>) -> Ex {
|
||||
use Expr::*;
|
||||
PRATT_PARSER
|
||||
.map_primary(|primary| {
|
||||
dbg!(&primary);
|
||||
match primary.as_rule() {
|
||||
Rule::dec => (
|
||||
Const(BigUint::parse_bytes(primary.as_str().as_bytes(), 10).unwrap()),
|
||||
true,
|
||||
),
|
||||
Rule::hex => (
|
||||
Const(BigUint::parse_bytes(primary.as_str().as_bytes(), 16).unwrap()),
|
||||
true,
|
||||
),
|
||||
Rule::var => (Var(primary.as_str().to_string()), true),
|
||||
Rule::neg => (Neg(Box::new(parse_expr_pairs(primary.into_inner()))), true),
|
||||
Rule::expr => (parse_expr_pairs(primary.into_inner()), false),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.map_primary(|primary| match primary.as_rule() {
|
||||
Rule::dec => (
|
||||
Const(BigUint::parse_bytes(primary.as_str().as_bytes(), 10).unwrap()),
|
||||
true,
|
||||
),
|
||||
Rule::hex => (
|
||||
Const(BigUint::parse_bytes(primary.as_str().as_bytes(), 16).unwrap()),
|
||||
true,
|
||||
),
|
||||
Rule::var => (Var(primary.as_str().to_string()), true),
|
||||
Rule::neg => (Neg(Box::new(parse_expr_pairs(primary.into_inner()))), true),
|
||||
Rule::expr => (parse_expr_pairs(primary.into_inner()), false),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
// lcont and rcont tell wether the lhs and rhs terms belong to the same expr or not
|
||||
.map_infix(|(lhs, lcont), op, (rhs, rcont)| {
|
||||
dbg!(&lhs, &op, &rhs);
|
||||
(
|
||||
match op.as_rule() {
|
||||
Rule::add => match (lhs, rhs, lcont & rcont) {
|
||||
|
||||
197
src/plaf.rs
197
src/plaf.rs
@@ -1,6 +1,7 @@
|
||||
use crate::expr::{self, Column, ColumnKind, Expr, PlonkVar as Var};
|
||||
use num_bigint::BigUint;
|
||||
use num_traits::Zero;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{self, Debug, Display, Write};
|
||||
|
||||
pub mod backends;
|
||||
@@ -22,7 +23,7 @@ pub struct Witness {
|
||||
num_rows: usize,
|
||||
columns: Vec<ColumnWitness>,
|
||||
// The advice cells in the circuit, arranged as [column][row].
|
||||
witness: Vec<Vec<Option<BigUint>>>,
|
||||
pub witness: Vec<Vec<Option<BigUint>>>,
|
||||
}
|
||||
|
||||
/// Adaptor struct to format the witness columns assignments as CSV
|
||||
@@ -68,7 +69,7 @@ impl ColumnWitness {
|
||||
phase,
|
||||
}
|
||||
}
|
||||
fn name(&self) -> &String {
|
||||
pub fn name(&self) -> &String {
|
||||
self.aliases.get(0).unwrap_or(&self.name)
|
||||
}
|
||||
}
|
||||
@@ -86,7 +87,7 @@ impl ColumnFixed {
|
||||
aliases: Vec::new(),
|
||||
}
|
||||
}
|
||||
fn name(&self) -> &String {
|
||||
pub fn name(&self) -> &String {
|
||||
self.aliases.get(0).unwrap_or(&self.name)
|
||||
}
|
||||
}
|
||||
@@ -104,7 +105,7 @@ impl ColumnPublic {
|
||||
aliases: Vec::new(),
|
||||
}
|
||||
}
|
||||
fn name(&self) -> &String {
|
||||
pub fn name(&self) -> &String {
|
||||
self.aliases.get(0).unwrap_or(&self.name)
|
||||
}
|
||||
}
|
||||
@@ -139,7 +140,7 @@ pub struct Columns {
|
||||
pub public: Vec<ColumnPublic>,
|
||||
}
|
||||
|
||||
/// Polynomial constraint
|
||||
/// Polynomial identity constraint
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Poly {
|
||||
pub name: String,
|
||||
@@ -163,7 +164,7 @@ pub struct CopyC {
|
||||
/// Circuit general information
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Info {
|
||||
/// Field modulus
|
||||
/// Field modulus / Size of the field
|
||||
pub p: BigUint,
|
||||
/// Number of rows. This is always a power of 2 in halo2.
|
||||
pub num_rows: usize,
|
||||
@@ -276,38 +277,6 @@ impl Plaf {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(&self, e: &Expr<Var>, offset: usize) -> Expr<Cell> {
|
||||
use Expr::*;
|
||||
match e {
|
||||
Neg(e) => Neg(Box::new(self.resolve(e, offset))),
|
||||
Const(f) => Const(f.clone()),
|
||||
Var(v) => match v {
|
||||
expr::PlonkVar::ColumnQuery { column, rotation } => {
|
||||
let offset =
|
||||
(offset as i32 + rotation).rem_euclid(self.info.num_rows as i32) as usize;
|
||||
match column.kind {
|
||||
ColumnKind::Fixed => Const(
|
||||
self.fixed[column.index][offset]
|
||||
.clone()
|
||||
.unwrap_or_else(BigUint::zero),
|
||||
),
|
||||
_ => Var(Cell {
|
||||
column: *column,
|
||||
offset,
|
||||
}),
|
||||
}
|
||||
}
|
||||
expr::PlonkVar::Challenge { index: _, phase: _ } => {
|
||||
// TODO: Figure out something better :P
|
||||
Const(BigUint::from(1234u64))
|
||||
}
|
||||
},
|
||||
Sum(es) => Sum(es.iter().map(|e| self.resolve(e, offset)).collect()),
|
||||
Mul(es) => Mul(es.iter().map(|e| self.resolve(e, offset)).collect()),
|
||||
Pow(e, f) => Pow(Box::new(self.resolve(e, offset)), *f),
|
||||
}
|
||||
}
|
||||
|
||||
/// Simplify expressions in polynomial constraints and lookups.
|
||||
pub fn simplify(&mut self) {
|
||||
let p = &self.info.p;
|
||||
@@ -323,8 +292,159 @@ impl Plaf {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alias_map(&self) -> AliasMap {
|
||||
let mut map = HashMap::new();
|
||||
for (index, challenge) in self.info.challenges.iter().enumerate() {
|
||||
let var = Var::Challenge {
|
||||
index,
|
||||
phase: challenge.phase,
|
||||
};
|
||||
map.insert(challenge.name.clone(), var.clone());
|
||||
if let Some(alias) = &challenge.alias {
|
||||
map.insert(alias.clone(), var.clone());
|
||||
}
|
||||
}
|
||||
for (index, column) in self.columns.witness.iter().enumerate() {
|
||||
let var = Var::ColumnQuery {
|
||||
column: Column {
|
||||
kind: ColumnKind::Witness,
|
||||
index,
|
||||
},
|
||||
rotation: 0,
|
||||
};
|
||||
map.insert(column.name.clone(), var.clone());
|
||||
for alias in &column.aliases {
|
||||
map.insert(alias.clone(), var.clone());
|
||||
}
|
||||
}
|
||||
for (index, column) in self.columns.fixed.iter().enumerate() {
|
||||
let var = Var::ColumnQuery {
|
||||
column: Column {
|
||||
kind: ColumnKind::Fixed,
|
||||
index,
|
||||
},
|
||||
rotation: 0,
|
||||
};
|
||||
map.insert(column.name.clone(), var.clone());
|
||||
for alias in &column.aliases {
|
||||
map.insert(alias.clone(), var.clone());
|
||||
}
|
||||
}
|
||||
for (index, column) in self.columns.public.iter().enumerate() {
|
||||
let var = Var::ColumnQuery {
|
||||
column: Column {
|
||||
kind: ColumnKind::Public,
|
||||
index,
|
||||
},
|
||||
rotation: 0,
|
||||
};
|
||||
map.insert(column.name.clone(), var.clone());
|
||||
for alias in &column.aliases {
|
||||
map.insert(alias.clone(), var.clone());
|
||||
}
|
||||
}
|
||||
AliasMap(map)
|
||||
}
|
||||
|
||||
pub fn gen_empty_witness(&self) -> Witness {
|
||||
let mut witness = Vec::with_capacity(self.columns.witness.len());
|
||||
for i in 0..self.columns.witness.len() {
|
||||
witness.push(vec![None; self.info.num_rows]);
|
||||
}
|
||||
Witness {
|
||||
num_rows: self.info.num_rows,
|
||||
columns: self.columns.witness.clone(),
|
||||
witness,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_partial<F, V>(&self, e: &Expr<V>, eval_var: &F, offset: usize) -> Expr<Cell>
|
||||
where
|
||||
V: expr::Var,
|
||||
F: Fn(&V, usize) -> Expr<Cell>,
|
||||
{
|
||||
use Expr::*;
|
||||
match e {
|
||||
Neg(e) => Neg(Box::new(self.eval_partial(e, eval_var, offset))),
|
||||
Const(f) => Const(f.clone()),
|
||||
Var(v) => eval_var(v, offset),
|
||||
Sum(es) => Sum(es
|
||||
.iter()
|
||||
.map(|e| self.eval_partial(e, eval_var, offset))
|
||||
.collect()),
|
||||
Mul(es) => Mul(es
|
||||
.iter()
|
||||
.map(|e| self.eval_partial(e, eval_var, offset))
|
||||
.collect()),
|
||||
Pow(e, f) => Pow(Box::new(self.eval_partial(e, eval_var, offset)), *f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(&self, e: &Expr<Var>, offset: usize) -> Expr<Cell> {
|
||||
self.eval_partial(
|
||||
e,
|
||||
&|v: &Var, offset: usize| -> Expr<Cell> {
|
||||
match v {
|
||||
expr::PlonkVar::ColumnQuery { column, rotation } => {
|
||||
let offset = (offset as i32 + rotation)
|
||||
.rem_euclid(self.info.num_rows as i32)
|
||||
as usize;
|
||||
match column.kind {
|
||||
ColumnKind::Fixed => Expr::Const(
|
||||
self.fixed[column.index][offset]
|
||||
.clone()
|
||||
.unwrap_or_else(BigUint::zero),
|
||||
),
|
||||
_ => Expr::Var(Cell {
|
||||
column: *column,
|
||||
offset,
|
||||
}),
|
||||
}
|
||||
}
|
||||
expr::PlonkVar::Challenge { index: _, phase: _ } => {
|
||||
// TODO: Figure out something better :P
|
||||
Expr::Const(BigUint::from(1234u64))
|
||||
}
|
||||
}
|
||||
},
|
||||
offset,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _eval_partial(&self, e: &Expr<Cell>, witness: &Witness, offset: usize) -> Expr<Cell> {
|
||||
use Expr::*;
|
||||
match e {
|
||||
Neg(e) => Neg(Box::new(self._eval_partial(e, witness, offset))),
|
||||
Const(f) => Const(f.clone()),
|
||||
Var(v) => {
|
||||
let Cell { column, offset } = v;
|
||||
match column.kind {
|
||||
ColumnKind::Witness => {
|
||||
if let Some(f) = &witness.witness[column.index][*offset] {
|
||||
Const(f.clone())
|
||||
} else {
|
||||
e.clone()
|
||||
}
|
||||
}
|
||||
_ => e.clone(),
|
||||
}
|
||||
}
|
||||
Sum(es) => Sum(es
|
||||
.iter()
|
||||
.map(|e| self._eval_partial(e, witness, offset))
|
||||
.collect()),
|
||||
Mul(es) => Mul(es
|
||||
.iter()
|
||||
.map(|e| self._eval_partial(e, witness, offset))
|
||||
.collect()),
|
||||
Pow(e, f) => Pow(Box::new(self._eval_partial(e, witness, offset)), *f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AliasMap(pub HashMap<String, Var>);
|
||||
|
||||
/// Adaptor struct to format the fixed columns assignments as CSV
|
||||
pub struct PlafDisplayFixedCSV<'a>(pub &'a Plaf);
|
||||
|
||||
@@ -361,6 +481,7 @@ impl Display for PlafDisplayBaseTOML<'_> {
|
||||
let this = self.0;
|
||||
writeln!(f, "[info]")?;
|
||||
writeln!(f, "num_rows = {}", this.info.num_rows)?;
|
||||
writeln!(f, "p = {}", this.info.p)?;
|
||||
writeln!(f)?;
|
||||
|
||||
writeln!(f, "[info.challenges]")?;
|
||||
|
||||
@@ -379,20 +379,15 @@ pub fn gen_witness<F: Field + PrimeField<Repr = [u8; 32]>, ConcreteCircuit: Circ
|
||||
cs.constants().clone(),
|
||||
)?;
|
||||
|
||||
let mut witness = Witness {
|
||||
num_rows: n,
|
||||
columns: plaf.columns.witness.clone(),
|
||||
witness: vec![vec![]; plaf.columns.witness.len()],
|
||||
};
|
||||
let mut witness = plaf.gen_empty_witness();
|
||||
|
||||
for i in 0..plaf.columns.witness.len() {
|
||||
let mut column = vec![None; n];
|
||||
let column = &mut witness.witness[i];
|
||||
for (j, cell) in assembly.advice[i].iter().enumerate() {
|
||||
if let CellValue::Assigned(v) = cell {
|
||||
column[j] = Some(BigUint::from_bytes_le(&v.to_repr()[..]));
|
||||
}
|
||||
}
|
||||
witness.witness[i] = column;
|
||||
}
|
||||
|
||||
Ok(witness)
|
||||
|
||||
Reference in New Issue
Block a user