mirror of
https://github.com/powdr-labs/powdr.git
synced 2026-04-20 03:03:25 -04:00
use ark_ff under the hood
This commit is contained in:
@@ -5,6 +5,7 @@ edition = "2021"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
ark-ff = "0.4.2"
|
||||
clap = { version = "^4.1", features = ["derive"] }
|
||||
codespan-reporting = "^0.11"
|
||||
env_logger = "0.10.0"
|
||||
@@ -14,7 +15,6 @@ lalrpop-util = {version = "^0.19", features = ["lexer"]}
|
||||
lazy_static = "^1.4.0"
|
||||
log = "0.4.17"
|
||||
mktemp = "0.5.0"
|
||||
num-bigint = "^0.4"
|
||||
regex = "^1.7.0"
|
||||
walkdir = "2.3.3"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ pub mod pil_analyzer;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::number::{AbstractNumberType, DegreeType};
|
||||
use crate::number::{DegreeType, FieldElement};
|
||||
pub use crate::parser::ast::{BinaryOperator, UnaryOperator};
|
||||
|
||||
pub fn analyze(path: &Path) -> Analyzed {
|
||||
@@ -23,7 +23,7 @@ pub enum StatementIdentifier {
|
||||
|
||||
pub struct Analyzed {
|
||||
/// Constants are not namespaced!
|
||||
pub constants: HashMap<String, AbstractNumberType>,
|
||||
pub constants: HashMap<String, FieldElement>,
|
||||
pub definitions: HashMap<String, (Polynomial, Option<FunctionValueDefinition>)>,
|
||||
pub public_declarations: HashMap<String, PublicDeclaration>,
|
||||
pub identities: Vec<Identity>,
|
||||
@@ -152,17 +152,14 @@ pub enum Expression {
|
||||
PolynomialReference(PolynomialReference),
|
||||
LocalVariableReference(u64),
|
||||
PublicReference(String),
|
||||
Number(AbstractNumberType),
|
||||
Number(FieldElement),
|
||||
String(String),
|
||||
Tuple(Vec<Expression>),
|
||||
BinaryOperation(Box<Expression>, BinaryOperator, Box<Expression>),
|
||||
UnaryOperation(UnaryOperator, Box<Expression>),
|
||||
/// Call to a non-macro function (like a constant polynomial)
|
||||
FunctionCall(String, Vec<Expression>),
|
||||
MatchExpression(
|
||||
Box<Expression>,
|
||||
Vec<(Option<AbstractNumberType>, Expression)>,
|
||||
),
|
||||
MatchExpression(Box<Expression>, Vec<(Option<FieldElement>, Expression)>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Default, Clone)]
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::number::{abstract_to_degree, DegreeType};
|
||||
use crate::number::DegreeType;
|
||||
use crate::parser::ast::{self, ArrayExpression};
|
||||
pub use crate::parser::ast::{BinaryOperator, UnaryOperator};
|
||||
use crate::{parser, utils};
|
||||
@@ -26,7 +26,7 @@ struct PILContext {
|
||||
namespace: String,
|
||||
polynomial_degree: DegreeType,
|
||||
/// Constants are not namespaced!
|
||||
constants: HashMap<String, AbstractNumberType>,
|
||||
constants: HashMap<String, FieldElement>,
|
||||
definitions: HashMap<String, (Polynomial, Option<FunctionValueDefinition>)>,
|
||||
public_declarations: HashMap<String, PublicDeclaration>,
|
||||
macros: HashMap<String, MacroDefinition>,
|
||||
@@ -260,7 +260,8 @@ impl PILContext {
|
||||
}
|
||||
|
||||
fn handle_namespace(&mut self, name: &str, degree: &ast::Expression) {
|
||||
self.polynomial_degree = abstract_to_degree(&self.evaluate_expression(degree).unwrap());
|
||||
// TODO: the polynomial degree should be handled without going through a field element. This requires having types in Expression
|
||||
self.polynomial_degree = self.evaluate_expression(degree).unwrap().to_degree();
|
||||
self.namespace = name.to_owned();
|
||||
}
|
||||
|
||||
@@ -292,7 +293,7 @@ impl PILContext {
|
||||
let length = array_size
|
||||
.as_ref()
|
||||
.map(|l| self.evaluate_expression(l).unwrap())
|
||||
.map(|l| abstract_to_degree(&l));
|
||||
.map(|l| l.to_degree());
|
||||
if length.is_some() {
|
||||
assert!(value.is_none());
|
||||
}
|
||||
@@ -344,7 +345,7 @@ impl PILContext {
|
||||
ast::FunctionDefinition::Array(value) => {
|
||||
let star_value = value.solve(self.polynomial_degree);
|
||||
let expressions = self.process_array_expression(value, star_value);
|
||||
assert_eq!(expressions.len() as u64, self.polynomial_degree);
|
||||
assert_eq!(expressions.len() as DegreeType, self.polynomial_degree);
|
||||
FunctionValueDefinition::Array(expressions)
|
||||
}
|
||||
});
|
||||
@@ -373,7 +374,7 @@ impl PILContext {
|
||||
source,
|
||||
name: name.to_string(),
|
||||
polynomial: self.process_polynomial_reference(poly),
|
||||
index: abstract_to_degree(&self.evaluate_expression(index).unwrap()),
|
||||
index: self.evaluate_expression(index).unwrap().to_degree(),
|
||||
},
|
||||
);
|
||||
self.source_order
|
||||
@@ -480,7 +481,7 @@ impl PILContext {
|
||||
}
|
||||
}
|
||||
ast::Expression::PublicReference(name) => Expression::PublicReference(name.clone()),
|
||||
ast::Expression::Number(n) => Expression::Number(n.clone()),
|
||||
ast::Expression::Number(n) => Expression::Number(*n),
|
||||
ast::Expression::String(value) => Expression::String(value.clone()),
|
||||
ast::Expression::Tuple(items) => Expression::Tuple(self.process_expressions(items)),
|
||||
ast::Expression::BinaryOperation(left, op, right) => {
|
||||
@@ -511,7 +512,7 @@ impl PILContext {
|
||||
ast::Expression::MatchExpression(scrutinee, arms) => Expression::MatchExpression(
|
||||
Box::new(self.process_expression(scrutinee)),
|
||||
arms.iter()
|
||||
.map(|(n, e)| (n.clone(), self.process_expression(e)))
|
||||
.map(|(n, e)| (*n, self.process_expression(e)))
|
||||
.collect(),
|
||||
),
|
||||
ast::Expression::FreeInput(_) => panic!(),
|
||||
@@ -555,7 +556,7 @@ impl PILContext {
|
||||
.index
|
||||
.as_ref()
|
||||
.map(|i| self.evaluate_expression(i).unwrap())
|
||||
.map(|i| abstract_to_degree(&i));
|
||||
.map(|i| i.to_degree());
|
||||
PolynomialReference {
|
||||
name: self.namespaced_ref(&poly.namespace, &poly.name),
|
||||
index,
|
||||
@@ -563,17 +564,17 @@ impl PILContext {
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_expression(&self, expr: &ast::Expression) -> Option<AbstractNumberType> {
|
||||
fn evaluate_expression(&self, expr: &ast::Expression) -> Option<FieldElement> {
|
||||
match expr {
|
||||
ast::Expression::Constant(name) => Some(
|
||||
self.constants
|
||||
*self
|
||||
.constants
|
||||
.get(name)
|
||||
.unwrap_or_else(|| panic!("Constant {name} not found."))
|
||||
.clone(),
|
||||
.unwrap_or_else(|| panic!("Constant {name} not found.")),
|
||||
),
|
||||
ast::Expression::PolynomialReference(_) => None,
|
||||
ast::Expression::PublicReference(_) => None,
|
||||
ast::Expression::Number(n) => Some(n.clone()),
|
||||
ast::Expression::Number(n) => Some(*n),
|
||||
ast::Expression::String(_) => None,
|
||||
ast::Expression::Tuple(_) => None,
|
||||
ast::Expression::BinaryOperation(left, op, right) => {
|
||||
@@ -591,7 +592,7 @@ impl PILContext {
|
||||
left: &ast::Expression,
|
||||
op: &BinaryOperator,
|
||||
right: &ast::Expression,
|
||||
) -> Option<AbstractNumberType> {
|
||||
) -> Option<FieldElement> {
|
||||
if let (Some(left), Some(right)) = (
|
||||
self.evaluate_expression(left),
|
||||
self.evaluate_expression(right),
|
||||
@@ -600,17 +601,18 @@ impl PILContext {
|
||||
BinaryOperator::Add => left + right,
|
||||
BinaryOperator::Sub => left - right,
|
||||
BinaryOperator::Mul => left * right,
|
||||
BinaryOperator::Div => left / right,
|
||||
BinaryOperator::Div => left.integer_div(right),
|
||||
BinaryOperator::Pow => {
|
||||
assert!(AbstractNumberType::from(0) <= right && right <= u32::MAX.into());
|
||||
left.pow(abstract_to_degree(&right) as u32)
|
||||
let right_int = right.to_integer();
|
||||
assert!(right_int <= u32::MAX.into());
|
||||
left.pow(right_int)
|
||||
}
|
||||
BinaryOperator::Mod => left % right,
|
||||
BinaryOperator::BinaryAnd => left & right,
|
||||
BinaryOperator::BinaryXor => left ^ right,
|
||||
BinaryOperator::BinaryOr => left | right,
|
||||
BinaryOperator::ShiftLeft => left << abstract_to_degree(&right),
|
||||
BinaryOperator::ShiftRight => left >> abstract_to_degree(&right),
|
||||
BinaryOperator::Mod => (left.to_integer() % right.to_integer()).into(),
|
||||
BinaryOperator::BinaryAnd => (left.to_integer() & right.to_integer()).into(),
|
||||
BinaryOperator::BinaryXor => (left.to_integer() ^ right.to_integer()).into(),
|
||||
BinaryOperator::BinaryOr => (left.to_integer() | right.to_integer()).into(),
|
||||
BinaryOperator::ShiftLeft => (left.to_integer() << right.to_integer()).into(),
|
||||
BinaryOperator::ShiftRight => (left.to_integer() >> right.to_integer()).into(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -621,7 +623,7 @@ impl PILContext {
|
||||
&self,
|
||||
op: &UnaryOperator,
|
||||
value: &ast::Expression,
|
||||
) -> Option<AbstractNumberType> {
|
||||
) -> Option<FieldElement> {
|
||||
self.evaluate_expression(value).map(|v| match op {
|
||||
UnaryOperator::Plus => v,
|
||||
UnaryOperator::Minus => -v,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use crate::number::abstract_to_degree;
|
||||
use crate::number::AbstractNumberType;
|
||||
use crate::number::DegreeType;
|
||||
use crate::number::FieldElement;
|
||||
use crate::parser;
|
||||
use crate::parser::asm_ast::*;
|
||||
use crate::parser::ast::*;
|
||||
@@ -50,20 +49,20 @@ impl ASMPILConverter {
|
||||
let mut statements = input.0.into_iter().peekable();
|
||||
|
||||
if let Some(ASMStatement::Degree(_, degree)) = statements.peek() {
|
||||
self.set_degree(crate::number::abstract_to_degree(degree));
|
||||
self.set_degree(*degree as DegreeType);
|
||||
statements.next();
|
||||
}
|
||||
|
||||
self.pil.push(Statement::Namespace(
|
||||
0,
|
||||
"Assembly".to_string(),
|
||||
Expression::Number(AbstractNumberType::from(self.degree())),
|
||||
Expression::Number(self.degree().into()),
|
||||
));
|
||||
self.pil.push(Statement::PolynomialConstantDefinition(
|
||||
0,
|
||||
"first_step".to_string(),
|
||||
FunctionDefinition::Array(
|
||||
ArrayExpression::value(vec![build_number(1.into())]).pad_with_zeroes(),
|
||||
ArrayExpression::value(vec![build_number(1u64)]).pad_with_zeroes(),
|
||||
),
|
||||
));
|
||||
|
||||
@@ -114,7 +113,7 @@ impl ASMPILConverter {
|
||||
if Some(name) == self.pc_name.as_ref() {
|
||||
// Force pc to zero on first row.
|
||||
update = build_mul(
|
||||
build_sub(build_number(1.into()), next_reference("first_step")),
|
||||
build_sub(build_number(1u64), next_reference("first_step")),
|
||||
update,
|
||||
)
|
||||
}
|
||||
@@ -166,7 +165,7 @@ impl ASMPILConverter {
|
||||
self.pc_name = Some(name.to_string());
|
||||
self.line_lookup
|
||||
.push((name.to_string(), "line".to_string()));
|
||||
default_update = Some(build_add(direct_reference(name), build_number(1.into())));
|
||||
default_update = Some(build_add(direct_reference(name), build_number(1u64)));
|
||||
}
|
||||
Some(RegisterFlag::IsAssignment) => {
|
||||
// no updates
|
||||
@@ -181,7 +180,7 @@ impl ASMPILConverter {
|
||||
conditioned_updates = vec![
|
||||
// The value here is actually irrelevant, it is only important
|
||||
// that "first_step'" is included to compute the "default condition"
|
||||
(next_reference("first_step"), build_number(0.into())),
|
||||
(next_reference("first_step"), build_number(0u64)),
|
||||
];
|
||||
let assignment_regs = self.assignment_registers().cloned().collect::<Vec<_>>();
|
||||
// TODO do this at the same place where we set up the read flags.
|
||||
@@ -395,7 +394,7 @@ impl ASMPILConverter {
|
||||
fn process_assignment_value(
|
||||
&self,
|
||||
value: Expression,
|
||||
) -> Vec<(AbstractNumberType, AffineExpressionComponent)> {
|
||||
) -> Vec<(FieldElement, AffineExpressionComponent)> {
|
||||
match value {
|
||||
Expression::Constant(_) => panic!(),
|
||||
Expression::PublicReference(_) => panic!(),
|
||||
@@ -453,13 +452,10 @@ impl ASMPILConverter {
|
||||
) = (&left[..], &right[..])
|
||||
{
|
||||
// TODO overflow?
|
||||
if *r > (u32::MAX).into() {
|
||||
if r.to_integer() > (u32::MAX).into() {
|
||||
panic!("Exponent too large");
|
||||
}
|
||||
vec![(
|
||||
l.pow(abstract_to_degree(r) as u32),
|
||||
AffineExpressionComponent::Constant,
|
||||
)]
|
||||
vec![(l.pow(r.to_integer()), AffineExpressionComponent::Constant)]
|
||||
} else {
|
||||
panic!("Exponentiation of non-constants.");
|
||||
}
|
||||
@@ -483,9 +479,9 @@ impl ASMPILConverter {
|
||||
|
||||
fn add_assignment_value(
|
||||
&self,
|
||||
mut left: Vec<(AbstractNumberType, AffineExpressionComponent)>,
|
||||
right: Vec<(AbstractNumberType, AffineExpressionComponent)>,
|
||||
) -> Vec<(AbstractNumberType, AffineExpressionComponent)> {
|
||||
mut left: Vec<(FieldElement, AffineExpressionComponent)>,
|
||||
right: Vec<(FieldElement, AffineExpressionComponent)>,
|
||||
) -> Vec<(FieldElement, AffineExpressionComponent)> {
|
||||
// TODO combine (or at leats check for) same components.
|
||||
left.extend(right);
|
||||
left
|
||||
@@ -493,8 +489,8 @@ impl ASMPILConverter {
|
||||
|
||||
fn negate_assignment_value(
|
||||
&self,
|
||||
expr: Vec<(AbstractNumberType, AffineExpressionComponent)>,
|
||||
) -> Vec<(AbstractNumberType, AffineExpressionComponent)> {
|
||||
expr: Vec<(FieldElement, AffineExpressionComponent)>,
|
||||
) -> Vec<(FieldElement, AffineExpressionComponent)> {
|
||||
expr.into_iter().map(|(v, c)| (-v, c)).collect()
|
||||
}
|
||||
|
||||
@@ -539,7 +535,7 @@ impl ASMPILConverter {
|
||||
let mut program_constants = self
|
||||
.program_constant_names
|
||||
.iter()
|
||||
.map(|n| (n, vec![AbstractNumberType::from(0); self.code_lines.len()]))
|
||||
.map(|n| (n, vec![FieldElement::from(0); self.code_lines.len()]))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let mut free_value_queries = self
|
||||
.assignment_registers()
|
||||
@@ -573,21 +569,21 @@ impl ASMPILConverter {
|
||||
.get_mut(&format!("p_read_{assign_reg}_{reg}"))
|
||||
.unwrap_or_else(|| {
|
||||
panic!("Register combination <={assign_reg}= {reg} not found.")
|
||||
})[i] = coeff.clone();
|
||||
})[i] = *coeff;
|
||||
}
|
||||
AffineExpressionComponent::Constant => {
|
||||
program_constants
|
||||
.get_mut(&format!("p_{assign_reg}_const"))
|
||||
.unwrap()[i] = coeff.clone()
|
||||
.unwrap()[i] = *coeff
|
||||
}
|
||||
AffineExpressionComponent::FreeInput(expr) => {
|
||||
// The program just stores that we read a free input, the actual value
|
||||
// is part of the execution trace that generates the witness.
|
||||
program_constants
|
||||
.get_mut(&format!("p_{assign_reg}_read_free"))
|
||||
.unwrap()[i] = coeff.clone();
|
||||
.unwrap()[i] = *coeff;
|
||||
free_value_queries.get_mut(assign_reg).unwrap().push(
|
||||
Expression::Tuple(vec![build_number(i.into()), expr.clone()]),
|
||||
Expression::Tuple(vec![build_number(i as u64), expr.clone()]),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -706,7 +702,7 @@ impl Register {
|
||||
(_, None) => Some(updates.unwrap()),
|
||||
(_, Some(def)) => {
|
||||
let default_condition = build_sub(
|
||||
build_number(1.into()),
|
||||
build_number(1u64),
|
||||
self.conditioned_updates
|
||||
.iter()
|
||||
.map(|(cond, _value)| cond.clone())
|
||||
@@ -749,7 +745,7 @@ struct CodeLine {
|
||||
/// Maps assignment register to a vector of regular registers.
|
||||
write_regs: BTreeMap<String, Vec<String>>,
|
||||
/// The value on the right-hand-side, per assignment register
|
||||
value: BTreeMap<String, Vec<(AbstractNumberType, AffineExpressionComponent)>>,
|
||||
value: BTreeMap<String, Vec<(FieldElement, AffineExpressionComponent)>>,
|
||||
label: Option<String>,
|
||||
instruction: Option<String>,
|
||||
// TODO we only support labels for now.
|
||||
@@ -815,8 +811,8 @@ fn build_unary_expr(op: UnaryOperator, exp: Expression) -> Expression {
|
||||
Expression::UnaryOperation(op, Box::new(exp))
|
||||
}
|
||||
|
||||
fn build_number(value: AbstractNumberType) -> Expression {
|
||||
Expression::Number(value)
|
||||
fn build_number<V: Into<FieldElement>>(value: V) -> Expression {
|
||||
Expression::Number(value.into())
|
||||
}
|
||||
|
||||
fn extract_update(expr: Expression) -> (Option<String>, Expression) {
|
||||
|
||||
@@ -2,7 +2,7 @@ use clap::{Parser, Subcommand};
|
||||
use env_logger::{Builder, Target};
|
||||
use log::LevelFilter;
|
||||
use powdr::compiler::no_callback;
|
||||
use powdr::number::AbstractNumberType;
|
||||
use powdr::number::FieldElement;
|
||||
use std::{fs, io::Write, path::Path};
|
||||
|
||||
#[derive(Parser)]
|
||||
@@ -102,13 +102,13 @@ enum Commands {
|
||||
},
|
||||
}
|
||||
|
||||
fn split_inputs(inputs: &str) -> Vec<AbstractNumberType> {
|
||||
fn split_inputs(inputs: &str) -> Vec<FieldElement> {
|
||||
inputs
|
||||
.split(',')
|
||||
.map(|x| x.trim())
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(|x| x.parse().unwrap())
|
||||
.collect::<Vec<AbstractNumberType>>()
|
||||
.map(|x| x.parse::<u64>().unwrap().into())
|
||||
.collect::<Vec<FieldElement>>()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -3,13 +3,12 @@ use std::io::{BufWriter, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use itertools::Itertools;
|
||||
use num_bigint::Sign;
|
||||
|
||||
use crate::number::{abstract_to_degree, AbstractNumberType, DegreeType};
|
||||
use crate::number::{DegreeType, FieldElement};
|
||||
use crate::parser::ast::PILFile;
|
||||
use crate::{analyzer, asm_compiler, constant_evaluator, json_exporter, witness_generator};
|
||||
|
||||
pub fn no_callback() -> Option<fn(&str) -> Option<AbstractNumberType>> {
|
||||
pub fn no_callback() -> Option<fn(&str) -> Option<FieldElement>> {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -20,7 +19,7 @@ pub fn no_callback() -> Option<fn(&str) -> Option<AbstractNumberType>> {
|
||||
pub fn compile_pil(
|
||||
pil_file: &Path,
|
||||
output_dir: &Path,
|
||||
query_callback: Option<impl FnMut(&str) -> Option<AbstractNumberType>>,
|
||||
query_callback: Option<impl FnMut(&str) -> Option<FieldElement>>,
|
||||
) -> bool {
|
||||
compile(
|
||||
&analyzer::analyze(pil_file),
|
||||
@@ -34,7 +33,7 @@ pub fn compile_pil_ast(
|
||||
pil: &PILFile,
|
||||
file_name: &str,
|
||||
output_dir: &Path,
|
||||
query_callback: Option<impl FnMut(&str) -> Option<AbstractNumberType>>,
|
||||
query_callback: Option<impl FnMut(&str) -> Option<FieldElement>>,
|
||||
) -> bool {
|
||||
// TODO exporting this to string as a hack because the parser
|
||||
// is tied into the analyzer due to imports.
|
||||
@@ -50,7 +49,7 @@ pub fn compile_pil_ast(
|
||||
/// fixed and witness columns.
|
||||
pub fn compile_asm(
|
||||
file_name: &str,
|
||||
inputs: Vec<AbstractNumberType>,
|
||||
inputs: Vec<FieldElement>,
|
||||
output_dir: &Path,
|
||||
force_overwrite: bool,
|
||||
) {
|
||||
@@ -63,7 +62,7 @@ pub fn compile_asm(
|
||||
pub fn compile_asm_string(
|
||||
file_name: &str,
|
||||
contents: &str,
|
||||
inputs: Vec<AbstractNumberType>,
|
||||
inputs: Vec<FieldElement>,
|
||||
output_dir: &Path,
|
||||
force_overwrite: bool,
|
||||
) {
|
||||
@@ -85,7 +84,7 @@ pub fn compile_asm_string(
|
||||
}
|
||||
fs::write(pil_file_name.clone(), format!("{pil}")).unwrap();
|
||||
|
||||
let query_callback = |query: &str| -> Option<AbstractNumberType> {
|
||||
let query_callback = |query: &str| -> Option<FieldElement> {
|
||||
let items = query.split(',').map(|s| s.trim()).collect::<Vec<_>>();
|
||||
let mut it = items.iter();
|
||||
let _current_step = it.next().unwrap();
|
||||
@@ -112,7 +111,7 @@ fn compile(
|
||||
analyzed: &analyzer::Analyzed,
|
||||
file_name: &str,
|
||||
output_dir: &Path,
|
||||
query_callback: Option<impl FnMut(&str) -> Option<AbstractNumberType>>,
|
||||
query_callback: Option<impl FnMut(&str) -> Option<FieldElement>>,
|
||||
) -> bool {
|
||||
let mut success = true;
|
||||
log::info!("Evaluating fixed columns...");
|
||||
@@ -148,17 +147,13 @@ fn compile(
|
||||
fn write_polys_file(
|
||||
file: &mut impl Write,
|
||||
degree: DegreeType,
|
||||
polys: &Vec<(&str, Vec<AbstractNumberType>)>,
|
||||
polys: &Vec<(&str, Vec<FieldElement>)>,
|
||||
) {
|
||||
for i in 0..degree as usize {
|
||||
for (_name, constant) in polys {
|
||||
let mut v = constant[i].clone();
|
||||
if v.sign() == Sign::Minus {
|
||||
// This hardcodes the goldilocks field
|
||||
v += 0xffffffff00000001u64;
|
||||
}
|
||||
file.write_all(&abstract_to_degree(&v).to_le_bytes())
|
||||
.unwrap();
|
||||
let bytes = constant[i].to_bytes_le();
|
||||
assert_eq!(bytes.len(), 8);
|
||||
file.write_all(&bytes).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ use std::collections::HashMap;
|
||||
use crate::analyzer::{
|
||||
Analyzed, BinaryOperator, Expression, FunctionValueDefinition, UnaryOperator,
|
||||
};
|
||||
use crate::number::{abstract_to_degree, AbstractNumberType, DegreeType};
|
||||
use crate::number::{DegreeType, FieldElement};
|
||||
|
||||
/// Generates the constant polynomial values for all constant polynomials
|
||||
/// that are defined (and not just declared).
|
||||
/// @returns the values (in source order) and the degree of the polynomials.
|
||||
pub fn generate(analyzed: &Analyzed) -> (Vec<(&str, Vec<AbstractNumberType>)>, DegreeType) {
|
||||
pub fn generate(analyzed: &Analyzed) -> (Vec<(&str, Vec<FieldElement>)>, DegreeType) {
|
||||
let mut degree = None;
|
||||
let mut other_constants = HashMap::new();
|
||||
for (poly, value) in analyzed.constant_polys_in_source_order() {
|
||||
@@ -35,8 +35,8 @@ fn generate_values(
|
||||
analyzed: &Analyzed,
|
||||
degree: DegreeType,
|
||||
body: &FunctionValueDefinition,
|
||||
other_constants: &HashMap<&str, Vec<AbstractNumberType>>,
|
||||
) -> Vec<AbstractNumberType> {
|
||||
other_constants: &HashMap<&str, Vec<FieldElement>>,
|
||||
) -> Vec<FieldElement> {
|
||||
match body {
|
||||
FunctionValueDefinition::Mapping(body) => (0..degree)
|
||||
.map(|i| {
|
||||
@@ -67,18 +67,18 @@ fn generate_values(
|
||||
|
||||
struct Evaluator<'a> {
|
||||
analyzed: &'a Analyzed,
|
||||
other_constants: &'a HashMap<&'a str, Vec<AbstractNumberType>>,
|
||||
variables: &'a [AbstractNumberType],
|
||||
other_constants: &'a HashMap<&'a str, Vec<FieldElement>>,
|
||||
variables: &'a [FieldElement],
|
||||
}
|
||||
|
||||
impl<'a> Evaluator<'a> {
|
||||
fn evaluate(&self, expr: &Expression) -> AbstractNumberType {
|
||||
fn evaluate(&self, expr: &Expression) -> FieldElement {
|
||||
match expr {
|
||||
Expression::Constant(name) => self.analyzed.constants[name].clone(),
|
||||
Expression::Constant(name) => self.analyzed.constants[name],
|
||||
Expression::PolynomialReference(_) => todo!(),
|
||||
Expression::LocalVariableReference(i) => self.variables[*i as usize].clone(),
|
||||
Expression::LocalVariableReference(i) => self.variables[*i as usize],
|
||||
Expression::PublicReference(_) => todo!(),
|
||||
Expression::Number(n) => n.clone(),
|
||||
Expression::Number(n) => *n,
|
||||
Expression::String(_) => panic!(),
|
||||
Expression::Tuple(_) => panic!(),
|
||||
Expression::BinaryOperation(left, op, right) => {
|
||||
@@ -89,7 +89,7 @@ impl<'a> Evaluator<'a> {
|
||||
let arg_values = args.iter().map(|a| self.evaluate(a)).collect::<Vec<_>>();
|
||||
assert!(arg_values.len() == 1);
|
||||
let values = &self.other_constants[name.as_str()];
|
||||
values[abstract_to_degree(&arg_values[0]) as usize % values.len()].clone()
|
||||
values[arg_values[0].to_degree() as usize % values.len()]
|
||||
}
|
||||
Expression::MatchExpression(scrutinee, arms) => {
|
||||
let v = self.evaluate(scrutinee);
|
||||
@@ -106,7 +106,7 @@ impl<'a> Evaluator<'a> {
|
||||
left: &Expression,
|
||||
op: &BinaryOperator,
|
||||
right: &Expression,
|
||||
) -> AbstractNumberType {
|
||||
) -> FieldElement {
|
||||
let left = self.evaluate(left);
|
||||
let right = self.evaluate(right);
|
||||
match op {
|
||||
@@ -117,24 +117,20 @@ impl<'a> Evaluator<'a> {
|
||||
if left == 0.into() {
|
||||
0.into()
|
||||
} else {
|
||||
left / right
|
||||
left.integer_div(right)
|
||||
}
|
||||
}
|
||||
BinaryOperator::Pow => left.pow(abstract_to_degree(&right) as u32),
|
||||
BinaryOperator::Mod => left % right,
|
||||
BinaryOperator::BinaryAnd => left & right,
|
||||
BinaryOperator::BinaryXor => left ^ right,
|
||||
BinaryOperator::BinaryOr => left | right,
|
||||
BinaryOperator::ShiftLeft => left << abstract_to_degree(&right),
|
||||
BinaryOperator::ShiftRight => left >> abstract_to_degree(&right),
|
||||
BinaryOperator::Pow => left.pow(right.to_integer()),
|
||||
BinaryOperator::Mod => (left.to_integer() % right.to_integer()).into(),
|
||||
BinaryOperator::BinaryAnd => (left.to_integer() & right.to_integer()).into(),
|
||||
BinaryOperator::BinaryXor => (left.to_integer() ^ right.to_integer()).into(),
|
||||
BinaryOperator::BinaryOr => (left.to_integer() | right.to_integer()).into(),
|
||||
BinaryOperator::ShiftLeft => (left.to_integer() << right.to_integer()).into(),
|
||||
BinaryOperator::ShiftRight => (left.to_integer() >> right.to_integer()).into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_unary_operation(
|
||||
&self,
|
||||
op: &UnaryOperator,
|
||||
expr: &Expression,
|
||||
) -> AbstractNumberType {
|
||||
fn evaluate_unary_operation(&self, op: &UnaryOperator, expr: &Expression) -> FieldElement {
|
||||
let v = self.evaluate(expr);
|
||||
match op {
|
||||
UnaryOperator::Plus => v,
|
||||
@@ -149,7 +145,7 @@ mod test {
|
||||
|
||||
use super::*;
|
||||
|
||||
fn convert(input: Vec<i32>) -> Vec<AbstractNumberType> {
|
||||
fn convert(input: Vec<i32>) -> Vec<FieldElement> {
|
||||
input.into_iter().map(|x| x.into()).collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
pub mod analyzer;
|
||||
pub mod asm_compiler;
|
||||
pub mod compiler;
|
||||
|
||||
289
src/number.rs
289
src/number.rs
@@ -1,47 +1,262 @@
|
||||
use num_bigint::{BigInt, Sign};
|
||||
use std::sync::Mutex;
|
||||
use std::{fmt, ops::AddAssign};
|
||||
|
||||
use ark_ff::{
|
||||
fields::{Field, Fp64, MontBackend, MontConfig},
|
||||
BigInteger, PrimeField, Zero,
|
||||
};
|
||||
|
||||
#[derive(MontConfig)]
|
||||
#[modulus = "18446744069414584321"]
|
||||
#[generator = "7"]
|
||||
pub struct GoldilocksBaseFieldConfig;
|
||||
pub type GoldilocksBaseField = Fp64<MontBackend<GoldilocksBaseFieldConfig, 1>>;
|
||||
|
||||
/// The abstract type of numbers to be computed with.
|
||||
/// They have arbitrary precision, but need to be converted
|
||||
/// to a finite field element once we generate the column values.
|
||||
pub type AbstractNumberType = num_bigint::BigInt;
|
||||
/// TODO: use arbitrary precision
|
||||
pub type AbstractNumberType = u128;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, PartialOrd, Ord, Hash)]
|
||||
pub struct FieldElement {
|
||||
value: GoldilocksBaseField,
|
||||
}
|
||||
/// The type of polynomial degrees and indices into columns.
|
||||
pub type DegreeType = u64;
|
||||
|
||||
pub fn abstract_to_degree(input: &AbstractNumberType) -> DegreeType {
|
||||
match input.to_biguint().unwrap().to_u64_digits()[..] {
|
||||
[] => 0,
|
||||
[d] => d,
|
||||
_ => panic!(),
|
||||
impl FieldElement {
|
||||
pub fn to_degree(&self) -> DegreeType {
|
||||
self.to_integer() as DegreeType
|
||||
}
|
||||
|
||||
pub fn to_integer(&self) -> AbstractNumberType {
|
||||
let value_big = self.value.into_bigint();
|
||||
assert_eq!(value_big.0.len(), 1);
|
||||
value_big.0[0] as AbstractNumberType
|
||||
}
|
||||
|
||||
pub fn modulus() -> AbstractNumberType {
|
||||
GoldilocksBaseField::MODULUS.0[0] as AbstractNumberType
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Self::from(0)
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.value.is_zero()
|
||||
}
|
||||
|
||||
pub fn pow(self, exponent: AbstractNumberType) -> Self {
|
||||
Self {
|
||||
value: self.value.pow([exponent as u64]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn integer_div(self, other: Self) -> Self {
|
||||
(self.to_integer() / other.to_integer()).into()
|
||||
}
|
||||
|
||||
pub fn to_bytes_le(&self) -> Vec<u8> {
|
||||
self.value.into_bigint().to_bytes_le()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_zero(x: &AbstractNumberType) -> bool {
|
||||
x.sign() == Sign::NoSign
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
// default field modulus is goldilocks
|
||||
static ref GOLDILOCKS_MOD : BigInt = BigInt::parse_bytes(b"FFFFFFFF00000001", 16).unwrap();
|
||||
static ref FIELD_MOD : Mutex<BigInt> = Mutex::new(BigInt::parse_bytes(b"FFFFFFFF00000001", 16).unwrap());
|
||||
}
|
||||
|
||||
pub fn get_goldilocks_mod() -> BigInt {
|
||||
GOLDILOCKS_MOD.clone()
|
||||
}
|
||||
|
||||
pub fn get_field_mod() -> BigInt {
|
||||
FIELD_MOD.lock().unwrap().clone()
|
||||
}
|
||||
|
||||
pub fn set_field_mod(n: BigInt) {
|
||||
*FIELD_MOD.lock().unwrap() = n;
|
||||
}
|
||||
|
||||
pub fn format_number(x: &AbstractNumberType) -> String {
|
||||
if *x > (get_field_mod() / BigInt::from(2)) {
|
||||
format!("-{}", get_field_mod() - x)
|
||||
} else {
|
||||
format!("{x}")
|
||||
impl<V: Into<GoldilocksBaseField>> From<V> for FieldElement {
|
||||
fn from(value: V) -> Self {
|
||||
Self {
|
||||
value: value.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add
|
||||
|
||||
impl std::ops::Add for FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value + rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Add<&'a FieldElement> for FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn add(self, rhs: &'a FieldElement) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value + rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Add for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value + rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Add<FieldElement> for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn add(self, rhs: FieldElement) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value + rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for FieldElement {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.value.add_assign(rhs.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Sub
|
||||
|
||||
impl std::ops::Sub for FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value - rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Sub<&'a FieldElement> for FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn sub(self, rhs: &'a FieldElement) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value - rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Sub for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value - rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Sub<FieldElement> for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn sub(self, rhs: FieldElement) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value - rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mul
|
||||
|
||||
impl std::ops::Mul for FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value * rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Mul<&'a FieldElement> for FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn mul(self, rhs: &'a FieldElement) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value * rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Mul for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value * rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Mul<FieldElement> for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn mul(self, rhs: FieldElement) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value * rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Div
|
||||
|
||||
impl std::ops::Div for FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value / rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Div<&'a FieldElement> for FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn div(self, rhs: &'a FieldElement) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value / rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Div for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value / rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Div<FieldElement> for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn div(self, rhs: FieldElement) -> Self::Output {
|
||||
FieldElement {
|
||||
value: self.value / rhs.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Neg for FieldElement {
|
||||
type Output = FieldElement;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self { value: -self.value }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FieldElement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let value = self.to_integer();
|
||||
if value > (Self::modulus() - 1) / 2 {
|
||||
write!(f, "-{}", Self::modulus() - value)
|
||||
} else {
|
||||
write!(f, "{value}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::number::{AbstractNumberType, DegreeType};
|
||||
use crate::number::{DegreeType, FieldElement};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct PILFile(pub Vec<Statement>);
|
||||
@@ -41,17 +41,14 @@ pub enum Expression {
|
||||
Constant(String),
|
||||
PolynomialReference(PolynomialReference),
|
||||
PublicReference(String),
|
||||
Number(AbstractNumberType),
|
||||
Number(FieldElement),
|
||||
String(String),
|
||||
Tuple(Vec<Expression>),
|
||||
BinaryOperation(Box<Expression>, BinaryOperator, Box<Expression>),
|
||||
UnaryOperation(UnaryOperator, Box<Expression>),
|
||||
FunctionCall(String, Vec<Expression>),
|
||||
FreeInput(Box<Expression>),
|
||||
MatchExpression(
|
||||
Box<Expression>,
|
||||
Vec<(Option<AbstractNumberType>, Expression)>,
|
||||
),
|
||||
MatchExpression(Box<Expression>, Vec<(Option<FieldElement>, Expression)>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Default, Clone)]
|
||||
@@ -151,8 +148,8 @@ impl ArrayExpression {
|
||||
/// find the total length of an array expression as an affine expression: `a + b*x`
|
||||
fn len(&self) -> (DegreeType, DegreeType) {
|
||||
match self {
|
||||
ArrayExpression::RepeatedValue(e) => (0, e.len() as u64),
|
||||
ArrayExpression::Value(e) => (e.len() as u64, 0),
|
||||
ArrayExpression::RepeatedValue(e) => (0, e.len() as DegreeType),
|
||||
ArrayExpression::Value(e) => (e.len() as DegreeType, 0),
|
||||
ArrayExpression::Concat(left, right) => {
|
||||
let (a0, b0) = left.len();
|
||||
let (a1, b1) = right.len();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::str::FromStr;
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::asm_ast::*;
|
||||
use crate::number::AbstractNumberType;
|
||||
use crate::number::{AbstractNumberType, FieldElement};
|
||||
|
||||
grammar;
|
||||
|
||||
@@ -158,7 +158,7 @@ ASMStatement: ASMStatement = {
|
||||
}
|
||||
|
||||
Degree: ASMStatement = {
|
||||
<@L> "degree" <Number> ";" => ASMStatement::Degree(<>)
|
||||
<@L> "degree" <Integer> ";" => ASMStatement::Degree(<>)
|
||||
}
|
||||
|
||||
RegisterDeclaration: ASMStatement = {
|
||||
@@ -333,7 +333,7 @@ Term: Box<Expression> = {
|
||||
ConstantIdentifier => Box::new(Expression::Constant(<>)),
|
||||
PolynomialReference => Box::new(Expression::PolynomialReference(<>)),
|
||||
PublicReference => Box::new(Expression::PublicReference(<>)),
|
||||
Number => Box::new(Expression::Number(<>)),
|
||||
FieldElement => Box::new(Expression::Number(<>)),
|
||||
StringLiteral => Box::new(Expression::String(<>)),
|
||||
MatchExpression,
|
||||
"(" <head:Expression> "," <tail:ExpressionList> ")" => { let mut list = vec![head]; list.extend(tail); Box::new(Expression::Tuple(list)) },
|
||||
@@ -360,8 +360,8 @@ MatchExpression: Box<Expression> = {
|
||||
"match" <BoxedExpression> "{" <(<MatchArm> ",")*> "}" => Box::new(Expression::MatchExpression(<>))
|
||||
}
|
||||
|
||||
MatchArm: (Option<AbstractNumberType>, Expression) = {
|
||||
<n:Number> "=>" <e:Expression> => (Some(n), e),
|
||||
MatchArm: (Option<FieldElement>, Expression) = {
|
||||
<n:FieldElement> "=>" <e:Expression> => (Some(n), e),
|
||||
<n:"_"> "=>" <e:Expression> => (None, e),
|
||||
}
|
||||
|
||||
@@ -382,7 +382,12 @@ ConstantIdentifier: String = {
|
||||
r"%[a-zA-Z_][a-zA-Z$_0-9@]*" => <>.to_string(),
|
||||
}
|
||||
|
||||
Number: AbstractNumberType = {
|
||||
r"[0-9][0-9_]*" => i128::from_str(&<>.replace('_', "")).unwrap().into(),
|
||||
r"0x[0-9A-Fa-f][0-9A-Fa-f_]*" => i128::from_str_radix(&<>[2..].replace('_', ""), 16).unwrap().into(),
|
||||
FieldElement: FieldElement = {
|
||||
r"[0-9][0-9_]*" => i128::from_str(&<>.replace('_', "")).unwrap().try_into().unwrap(),
|
||||
r"0x[0-9A-Fa-f][0-9A-Fa-f_]*" => i128::from_str_radix(&<>[2..].replace('_', ""), 16).unwrap().try_into().unwrap(),
|
||||
}
|
||||
|
||||
Integer: AbstractNumberType = {
|
||||
r"[0-9][0-9_]*" => i128::from_str(&<>.replace('_', "")).unwrap().try_into().unwrap(),
|
||||
r"0x[0-9A-Fa-f][0-9A-Fa-f_]*" => i128::from_str_radix(&<>[2..].replace('_', ""), 16).unwrap().try_into().unwrap(),
|
||||
}
|
||||
@@ -4,7 +4,7 @@ use mktemp::Temp;
|
||||
use std::fs;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::number::AbstractNumberType;
|
||||
use crate::number::FieldElement;
|
||||
|
||||
pub mod compiler;
|
||||
pub mod parser;
|
||||
@@ -14,7 +14,7 @@ pub mod parser;
|
||||
pub fn compile_rust(
|
||||
file_name: &str,
|
||||
full_crate: bool,
|
||||
inputs: Vec<AbstractNumberType>,
|
||||
inputs: Vec<FieldElement>,
|
||||
output_dir: &Path,
|
||||
force_overwrite: bool,
|
||||
) {
|
||||
@@ -57,7 +57,7 @@ pub fn compile_rust(
|
||||
pub fn compile_riscv_asm(
|
||||
original_file_name: &str,
|
||||
file_name: &str,
|
||||
inputs: Vec<AbstractNumberType>,
|
||||
inputs: Vec<FieldElement>,
|
||||
output_dir: &Path,
|
||||
force_overwrite: bool,
|
||||
) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::ops::Not;
|
||||
|
||||
use crate::number::AbstractNumberType;
|
||||
// TODO this should probably rather be a finite field element.
|
||||
use crate::number::{format_number, get_field_mod, is_zero, AbstractNumberType};
|
||||
use crate::number::FieldElement;
|
||||
|
||||
use super::bit_constraints::BitConstraintSet;
|
||||
use super::eval_error::EvalError::ConflictingBitConstraints;
|
||||
@@ -13,15 +12,15 @@ use super::EvalResult;
|
||||
/// An expression affine in the committed polynomials.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AffineExpression {
|
||||
pub coefficients: Vec<AbstractNumberType>,
|
||||
pub offset: AbstractNumberType,
|
||||
pub coefficients: Vec<FieldElement>,
|
||||
pub offset: FieldElement,
|
||||
}
|
||||
|
||||
impl From<AbstractNumberType> for AffineExpression {
|
||||
fn from(value: AbstractNumberType) -> Self {
|
||||
impl From<FieldElement> for AffineExpression {
|
||||
fn from(value: FieldElement) -> Self {
|
||||
AffineExpression {
|
||||
coefficients: Vec::new(),
|
||||
offset: wrap(value),
|
||||
offset: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +29,7 @@ impl From<u32> for AffineExpression {
|
||||
fn from(value: u32) -> Self {
|
||||
AffineExpression {
|
||||
coefficients: Vec::new(),
|
||||
offset: wrap(value.into()),
|
||||
offset: value.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,9 +46,9 @@ impl AffineExpression {
|
||||
self.nonzero_coefficients().next().is_none()
|
||||
}
|
||||
|
||||
pub fn constant_value(&self) -> Option<AbstractNumberType> {
|
||||
pub fn constant_value(&self) -> Option<FieldElement> {
|
||||
if self.is_constant() {
|
||||
Some(self.offset.clone())
|
||||
Some(self.offset)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -60,19 +59,18 @@ impl AffineExpression {
|
||||
}
|
||||
|
||||
/// @returns an iterator of the nonzero coefficients and their variable IDs (but not the offset).
|
||||
pub fn nonzero_coefficients(&self) -> impl Iterator<Item = (usize, &AbstractNumberType)> {
|
||||
pub fn nonzero_coefficients(&self) -> impl Iterator<Item = (usize, &FieldElement)> {
|
||||
self.coefficients
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, c)| !is_zero(c))
|
||||
.filter(|(_, c)| !c.is_zero())
|
||||
}
|
||||
|
||||
pub fn mul(mut self, factor: AbstractNumberType) -> AffineExpression {
|
||||
let fac = wrap(factor);
|
||||
pub fn mul(mut self, factor: FieldElement) -> AffineExpression {
|
||||
for f in &mut self.coefficients {
|
||||
*f = wrap(f.clone() * fac.clone());
|
||||
*f = *f * factor;
|
||||
}
|
||||
self.offset = wrap(self.offset.clone() * fac);
|
||||
self.offset = self.offset * factor;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -89,11 +87,11 @@ impl AffineExpression {
|
||||
Ok(vec![(
|
||||
i,
|
||||
Constraint::Assignment(if *c == 1.into() {
|
||||
wrap(-self.offset.clone())
|
||||
} else if *c == (-1).into() || *c == (get_field_mod() - 1u64) {
|
||||
self.offset.clone()
|
||||
-self.offset
|
||||
} else if *c == (-1).into() {
|
||||
self.offset
|
||||
} else {
|
||||
wrap(-wrap(self.offset.clone() * inv(c.clone(), get_field_mod())))
|
||||
-self.offset / *c
|
||||
}),
|
||||
)])
|
||||
}
|
||||
@@ -177,7 +175,7 @@ impl AffineExpression {
|
||||
}
|
||||
if *solve_for.1 == 1.into() {
|
||||
return (-self.clone()).try_transfer_constraints(known_constraints);
|
||||
} else if *solve_for.1 != wrap((-1).into()) {
|
||||
} else if *solve_for.1 != (-1).into() {
|
||||
// We could try to divide by this in the future.
|
||||
return None;
|
||||
}
|
||||
@@ -190,7 +188,7 @@ impl AffineExpression {
|
||||
.map(|(i, coeff)| {
|
||||
known_constraints
|
||||
.bit_constraint(i)
|
||||
.and_then(|con| con.multiple(coeff.clone()))
|
||||
.and_then(|con| con.multiple(*coeff))
|
||||
});
|
||||
|
||||
parts
|
||||
@@ -219,7 +217,7 @@ impl AffineExpression {
|
||||
known_constraints
|
||||
.bit_constraint(i)
|
||||
.unwrap()
|
||||
.multiple(coeff.clone()),
|
||||
.multiple(*coeff),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -227,25 +225,25 @@ impl AffineExpression {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
// Check if they are mutually exclusive and compute assignments.
|
||||
let mut covered_bits: AbstractNumberType = 0.into();
|
||||
let mut covered_bits: AbstractNumberType = 0;
|
||||
let mut assignments = vec![];
|
||||
let mut offset = wrap(-self.offset.clone());
|
||||
let mut offset = (-self.offset).to_integer();
|
||||
for (i, coeff, constraint) in parts {
|
||||
let constraint = constraint.clone().unwrap();
|
||||
let mask = constraint.mask();
|
||||
if mask.clone() & covered_bits.clone() != 0.into() {
|
||||
if mask & covered_bits != 0 {
|
||||
return Ok(vec![]);
|
||||
} else {
|
||||
covered_bits |= mask.clone();
|
||||
covered_bits |= mask;
|
||||
}
|
||||
assignments.push((
|
||||
i,
|
||||
Constraint::Assignment((offset.clone() & mask.clone()) / coeff.clone()),
|
||||
Constraint::Assignment(((offset & mask) / coeff.to_integer()).into()),
|
||||
));
|
||||
offset &= mask.not();
|
||||
offset &= !mask;
|
||||
}
|
||||
|
||||
if offset != 0.into() {
|
||||
if offset != 0 {
|
||||
// We were not able to cover all of the offset, so this equation cannot be solved.
|
||||
Err(ConflictingBitConstraints)
|
||||
} else {
|
||||
@@ -259,10 +257,10 @@ impl AffineExpression {
|
||||
let name = namer.name(i);
|
||||
if *c == 1.into() {
|
||||
name
|
||||
} else if *c == wrap((-1).into()) {
|
||||
} else if *c == (-1).into() {
|
||||
format!("-{name}")
|
||||
} else {
|
||||
format!("{} * {name}", format_number(c))
|
||||
format!("{} * {name}", c)
|
||||
}
|
||||
})
|
||||
.chain(self.constant_value().map(|v| format!("{v}")))
|
||||
@@ -271,37 +269,6 @@ impl AffineExpression {
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap(mut x: AbstractNumberType) -> AbstractNumberType {
|
||||
while x < 0.into() {
|
||||
x += get_field_mod()
|
||||
}
|
||||
x % get_field_mod()
|
||||
}
|
||||
|
||||
fn pow(
|
||||
mut x: AbstractNumberType,
|
||||
mut y: AbstractNumberType,
|
||||
m: AbstractNumberType,
|
||||
) -> AbstractNumberType {
|
||||
assert!(y >= 0.into());
|
||||
if y == 0.into() {
|
||||
return 1.into();
|
||||
}
|
||||
let mut r: AbstractNumberType = 1.into();
|
||||
while y >= 2.into() {
|
||||
if y.bit(0) {
|
||||
r = (r * x.clone()) % m.clone();
|
||||
}
|
||||
x = (x.clone() * x) % m.clone();
|
||||
y = y.clone() >> 1;
|
||||
}
|
||||
(r * x) % m
|
||||
}
|
||||
|
||||
fn inv(x: AbstractNumberType, m: AbstractNumberType) -> AbstractNumberType {
|
||||
pow(x, m.clone() - 2, m)
|
||||
}
|
||||
|
||||
impl PartialEq for AffineExpression {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.offset == other.offset && self.nonzero_coefficients().eq(other.nonzero_coefficients())
|
||||
@@ -317,11 +284,11 @@ impl std::ops::Add for AffineExpression {
|
||||
coefficients.resize(self.coefficients.len(), 0.into());
|
||||
}
|
||||
for (i, v) in self.coefficients.iter().enumerate() {
|
||||
coefficients[i] = wrap(coefficients[i].clone() + v);
|
||||
coefficients[i] = coefficients[i] + v;
|
||||
}
|
||||
AffineExpression {
|
||||
coefficients,
|
||||
offset: wrap(self.offset + rhs.offset),
|
||||
offset: self.offset + rhs.offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -330,10 +297,8 @@ impl std::ops::Neg for AffineExpression {
|
||||
type Output = AffineExpression;
|
||||
|
||||
fn neg(mut self) -> Self::Output {
|
||||
self.coefficients
|
||||
.iter_mut()
|
||||
.for_each(|v| *v = wrap(-v.clone()));
|
||||
self.offset = wrap(-self.offset);
|
||||
self.coefficients.iter_mut().for_each(|v| *v = -*v);
|
||||
self.offset = -self.offset;
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -352,11 +317,11 @@ mod test {
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
number::{get_goldilocks_mod, AbstractNumberType},
|
||||
number::FieldElement,
|
||||
witness_generator::{bit_constraints::BitConstraint, eval_error::EvalError},
|
||||
};
|
||||
|
||||
fn convert(input: Vec<i32>) -> Vec<AbstractNumberType> {
|
||||
fn convert(input: Vec<i32>) -> Vec<FieldElement> {
|
||||
input.into_iter().map(|x| x.into()).collect()
|
||||
}
|
||||
|
||||
@@ -369,8 +334,12 @@ mod test {
|
||||
assert_eq!(
|
||||
-a,
|
||||
AffineExpression {
|
||||
coefficients: vec![get_field_mod() - 1u64, 0.into(), get_field_mod() - 2u64,],
|
||||
offset: get_field_mod() - 9u64,
|
||||
coefficients: vec![
|
||||
FieldElement::from(0) - FieldElement::from(1u64),
|
||||
0.into(),
|
||||
FieldElement::from(0) - FieldElement::from(2u64),
|
||||
],
|
||||
offset: FieldElement::from(0) - FieldElement::from(9u64),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -395,26 +364,6 @@ mod test {
|
||||
assert_eq!(b.clone() + a.clone(), a + b,);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn mod_arith() {
|
||||
assert_eq!(pow(7.into(), 0.into(), get_goldilocks_mod()), 1.into());
|
||||
assert_eq!(pow(7.into(), 1.into(), get_goldilocks_mod()), 7.into());
|
||||
assert_eq!(pow(7.into(), 0.into(), get_field_mod()), 1.into());
|
||||
assert_eq!(pow(7.into(), 1.into(), get_field_mod()), 7.into());
|
||||
assert_eq!(pow(7.into(), 2.into(), get_field_mod()), (7 * 7).into());
|
||||
assert_eq!(inv(1.into(), get_field_mod()), 1.into());
|
||||
|
||||
if get_field_mod() == get_goldilocks_mod() {
|
||||
let inverse_of_four = 13835058052060938241u64;
|
||||
assert_eq!(inv(4.into(), get_field_mod()), inverse_of_four.into());
|
||||
assert_eq!(
|
||||
(4u128 * inverse_of_four as u128)
|
||||
% (get_field_mod().iter_u64_digits().next().unwrap() as u128),
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct TestBitConstraints(BTreeMap<usize, BitConstraint>);
|
||||
impl BitConstraintSet for TestBitConstraints {
|
||||
fn bit_constraint(&self, id: usize) -> Option<BitConstraint> {
|
||||
@@ -460,7 +409,7 @@ mod test {
|
||||
expr.solve_with_bit_constraints(&known_constraints).unwrap(),
|
||||
vec![(
|
||||
1,
|
||||
Constraint::BitConstraint(BitConstraint::from_mask(0x1fef.into()))
|
||||
Constraint::BitConstraint(BitConstraint::from_mask(0x1fef))
|
||||
)]
|
||||
);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use crate::analyzer::{BinaryOperator, Expression, Identity, IdentityKind};
|
||||
use crate::number::{get_field_mod, AbstractNumberType};
|
||||
use crate::number::{AbstractNumberType, FieldElement};
|
||||
use crate::witness_generator::util::{contains_next_ref, WitnessColumnNamer};
|
||||
|
||||
use super::expression_evaluator::ExpressionEvaluator;
|
||||
@@ -23,7 +23,7 @@ impl BitConstraint {
|
||||
pub fn from_max_bit(max_bit: u64) -> Self {
|
||||
assert!(max_bit < 1024);
|
||||
BitConstraint {
|
||||
mask: (AbstractNumberType::from(1) << (max_bit + 1)) - AbstractNumberType::from(1),
|
||||
mask: (1 << (max_bit + 1)) - 1,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,9 @@ impl BitConstraint {
|
||||
|
||||
/// The bit constraint of the sum of two expressions.
|
||||
pub fn try_combine_sum(&self, other: &BitConstraint) -> Option<BitConstraint> {
|
||||
if self.mask.clone() & other.mask.clone() == 0.into() {
|
||||
if self.mask & other.mask == 0 {
|
||||
Some(BitConstraint {
|
||||
mask: self.mask.clone() | other.mask.clone(),
|
||||
mask: self.mask | other.mask,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -45,21 +45,21 @@ impl BitConstraint {
|
||||
/// Returns the conjunction of this constraint and the other.
|
||||
pub fn conjunction(self, other: &BitConstraint) -> BitConstraint {
|
||||
BitConstraint {
|
||||
mask: self.mask & other.mask.clone(),
|
||||
mask: self.mask & other.mask,
|
||||
}
|
||||
}
|
||||
|
||||
/// The bit constraint of an integer multiple of an expression.
|
||||
/// TODO this assumes goldilocks
|
||||
pub fn multiple(&self, factor: AbstractNumberType) -> Option<BitConstraint> {
|
||||
if factor.clone() * self.mask.clone() >= get_field_mod() {
|
||||
pub fn multiple(&self, factor: FieldElement) -> Option<BitConstraint> {
|
||||
if factor.to_integer() * self.mask >= FieldElement::modulus() {
|
||||
None
|
||||
} else {
|
||||
// TODO use binary logarithm
|
||||
(0..64).find_map(|i| {
|
||||
if factor.clone() == (1u64 << i).into() {
|
||||
if factor == (1u64 << i).into() {
|
||||
Some(BitConstraint {
|
||||
mask: self.mask.clone() << i,
|
||||
mask: self.mask << i,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -69,7 +69,7 @@ impl BitConstraint {
|
||||
}
|
||||
|
||||
pub fn mask(&self) -> AbstractNumberType {
|
||||
self.mask.clone()
|
||||
self.mask
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,24 +156,20 @@ pub fn determine_global_constraints<'a>(
|
||||
/// Analyzes a fixed column and checks if its values correspond exactly
|
||||
/// to a certain bit pattern.
|
||||
/// TODO do this on the symbolic definition instead of the values.
|
||||
fn process_fixed_column(fixed: &[AbstractNumberType]) -> Option<(BitConstraint, bool)> {
|
||||
fn process_fixed_column(fixed: &[FieldElement]) -> Option<(BitConstraint, bool)> {
|
||||
if let Some(bit) = smallest_period_candidate(fixed) {
|
||||
let mask: AbstractNumberType =
|
||||
(AbstractNumberType::from(1) << bit) - AbstractNumberType::from(1);
|
||||
let mask: AbstractNumberType = (1 << bit) - 1;
|
||||
if fixed
|
||||
.iter()
|
||||
.enumerate()
|
||||
.all(|(i, v)| *v == AbstractNumberType::from(i) & mask.clone())
|
||||
.all(|(i, v)| v.to_integer() == i as AbstractNumberType & mask)
|
||||
{
|
||||
return Some((BitConstraint::from_mask(mask), true));
|
||||
}
|
||||
}
|
||||
let mut mask = 0.into();
|
||||
let mut mask = 0;
|
||||
for v in fixed.iter() {
|
||||
if *v < 0.into() {
|
||||
return None;
|
||||
}
|
||||
mask |= v.clone();
|
||||
mask |= v.to_integer();
|
||||
}
|
||||
|
||||
Some((BitConstraint::from_mask(mask), false))
|
||||
@@ -316,7 +312,7 @@ fn try_transfer_constraints<'a>(
|
||||
})
|
||||
}
|
||||
|
||||
fn smallest_period_candidate(fixed: &[AbstractNumberType]) -> Option<u64> {
|
||||
fn smallest_period_candidate(fixed: &[FieldElement]) -> Option<u64> {
|
||||
if fixed.first() != Some(&0.into()) {
|
||||
return None;
|
||||
}
|
||||
@@ -337,7 +333,7 @@ mod test {
|
||||
let fixed = [0, 0, 0, 0].iter().map(|v| (*v).into()).collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
process_fixed_column(&fixed),
|
||||
Some((BitConstraint::from_mask(0.into()), false))
|
||||
Some((BitConstraint::from_mask(0), false))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -349,7 +345,7 @@ mod test {
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
process_fixed_column(&fixed),
|
||||
Some((BitConstraint::from_mask(1.into()), true))
|
||||
Some((BitConstraint::from_mask(1), true))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -361,7 +357,7 @@ mod test {
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
process_fixed_column(&fixed),
|
||||
Some((BitConstraint::from_mask(3.into()), true))
|
||||
Some((BitConstraint::from_mask(3), true))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -373,7 +369,7 @@ mod test {
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
process_fixed_column(&fixed),
|
||||
Some((BitConstraint::from_mask(0x1106.into()), false))
|
||||
Some((BitConstraint::from_mask(0x1106), false))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -408,7 +404,7 @@ namespace Global(2**20);
|
||||
vec![
|
||||
("Global.BYTE", BitConstraint::from_max_bit(7)),
|
||||
("Global.BYTE2", BitConstraint::from_max_bit(15)),
|
||||
("Global.SHIFTED", BitConstraint::from_mask(0xff0.into())),
|
||||
("Global.SHIFTED", BitConstraint::from_mask(0xff0)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
@@ -445,11 +441,11 @@ namespace Global(2**20);
|
||||
vec![
|
||||
("Global.A", BitConstraint::from_max_bit(0)),
|
||||
("Global.B", BitConstraint::from_max_bit(7)),
|
||||
("Global.C", BitConstraint::from_mask(0x2ff.into())),
|
||||
("Global.D", BitConstraint::from_mask(0xf0.into())),
|
||||
("Global.C", BitConstraint::from_mask(0x2ff)),
|
||||
("Global.D", BitConstraint::from_mask(0xf0)),
|
||||
("Global.BYTE", BitConstraint::from_max_bit(7)),
|
||||
("Global.BYTE2", BitConstraint::from_max_bit(15)),
|
||||
("Global.SHIFTED", BitConstraint::from_mask(0xff0.into())),
|
||||
("Global.SHIFTED", BitConstraint::from_mask(0xff0)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
@@ -459,23 +455,23 @@ namespace Global(2**20);
|
||||
#[test]
|
||||
fn combinations() {
|
||||
let a = BitConstraint::from_max_bit(7);
|
||||
assert_eq!(a, BitConstraint::from_mask(0xff.into()));
|
||||
assert_eq!(a, BitConstraint::from_mask(0xff));
|
||||
let b = a.multiple(256.into()).unwrap();
|
||||
assert_eq!(b, BitConstraint::from_mask(0xff00.into()));
|
||||
assert_eq!(b, BitConstraint::from_mask(0xff00));
|
||||
assert_eq!(
|
||||
b.try_combine_sum(&a).unwrap(),
|
||||
BitConstraint::from_mask(0xffff.into())
|
||||
BitConstraint::from_mask(0xffff)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weird_combinations() {
|
||||
let a = BitConstraint::from_mask(0xf00f.into());
|
||||
let a = BitConstraint::from_mask(0xf00f);
|
||||
let b = a.multiple(256.into()).unwrap();
|
||||
assert_eq!(b, BitConstraint::from_mask(0xf00f00.into()));
|
||||
assert_eq!(b, BitConstraint::from_mask(0xf00f00));
|
||||
assert_eq!(
|
||||
b.try_combine_sum(&a).unwrap(),
|
||||
BitConstraint::from_mask(0xf0ff0f.into())
|
||||
BitConstraint::from_mask(0xf0ff0f)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::analyzer::{BinaryOperator, Expression, UnaryOperator};
|
||||
use crate::number::abstract_to_degree;
|
||||
use crate::number::FieldElement;
|
||||
|
||||
use super::affine_expression::AffineExpression;
|
||||
use super::eval_error::{self, EvalError};
|
||||
@@ -29,7 +29,7 @@ impl<SV: SymbolicVariables> ExpressionEvaluator<SV> {
|
||||
match expr {
|
||||
Expression::Constant(name) => self.variables.constant(name),
|
||||
Expression::PolynomialReference(poly) => self.variables.value(&poly.name, poly.next),
|
||||
Expression::Number(n) => Ok(n.clone().into()),
|
||||
Expression::Number(n) => Ok((*n).into()),
|
||||
Expression::BinaryOperation(left, op, right) => {
|
||||
self.evaluate_binary_operation(left, op, right)
|
||||
}
|
||||
@@ -103,7 +103,7 @@ impl<SV: SymbolicVariables> ExpressionEvaluator<SV> {
|
||||
}
|
||||
BinaryOperator::Pow => {
|
||||
if let (Some(l), Some(r)) = (left.constant_value(), right.constant_value()) {
|
||||
Ok(l.pow(abstract_to_degree(&r) as u32).into())
|
||||
Ok(l.pow(r.to_integer()).into())
|
||||
} else {
|
||||
Err(format!(
|
||||
"Pow of two non-constants: ({}) ** ({})",
|
||||
@@ -122,13 +122,23 @@ impl<SV: SymbolicVariables> ExpressionEvaluator<SV> {
|
||||
if let (Some(left), Some(right)) =
|
||||
(left.constant_value(), right.constant_value())
|
||||
{
|
||||
let result = match op {
|
||||
BinaryOperator::Mod => left % right,
|
||||
BinaryOperator::BinaryAnd => left & right,
|
||||
BinaryOperator::BinaryXor => left ^ right,
|
||||
BinaryOperator::BinaryOr => left | right,
|
||||
BinaryOperator::ShiftLeft => left << abstract_to_degree(&right),
|
||||
BinaryOperator::ShiftRight => left >> abstract_to_degree(&right),
|
||||
let result: FieldElement = match op {
|
||||
BinaryOperator::Mod => (left.to_integer() % right.to_integer()).into(),
|
||||
BinaryOperator::BinaryAnd => {
|
||||
(left.to_integer() & right.to_integer()).into()
|
||||
}
|
||||
BinaryOperator::BinaryXor => {
|
||||
(left.to_integer() ^ right.to_integer()).into()
|
||||
}
|
||||
BinaryOperator::BinaryOr => {
|
||||
(left.to_integer() | right.to_integer()).into()
|
||||
}
|
||||
BinaryOperator::ShiftLeft => {
|
||||
(left.to_integer() << right.to_integer()).into()
|
||||
}
|
||||
BinaryOperator::ShiftRight => {
|
||||
(left.to_integer() >> right.to_integer()).into()
|
||||
}
|
||||
_ => panic!(),
|
||||
};
|
||||
Ok(result.into())
|
||||
|
||||
@@ -17,7 +17,7 @@ impl<'a> FixedEvaluator<'a> {
|
||||
|
||||
impl<'a> SymbolicVariables for FixedEvaluator<'a> {
|
||||
fn constant(&self, name: &str) -> Result<AffineExpression, EvalError> {
|
||||
Ok(self.fixed_data.constants[name].clone().into())
|
||||
Ok(self.fixed_data.constants[name].into())
|
||||
}
|
||||
|
||||
fn value(&self, name: &str, next: bool) -> Result<AffineExpression, EvalError> {
|
||||
@@ -29,7 +29,7 @@ impl<'a> SymbolicVariables for FixedEvaluator<'a> {
|
||||
} else {
|
||||
self.row
|
||||
};
|
||||
Ok(col_data[row].clone().into())
|
||||
Ok(col_data[row].into())
|
||||
} else {
|
||||
Err("Can only access fixed columns in the fixed evaluator."
|
||||
.to_string()
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use crate::analyzer::{Expression, Identity, IdentityKind};
|
||||
use crate::number::format_number;
|
||||
use crate::utils::indent;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
// TODO should use finite field instead of abstract number
|
||||
use crate::number::{AbstractNumberType, DegreeType};
|
||||
use crate::number::{DegreeType, FieldElement};
|
||||
|
||||
use super::affine_expression::AffineExpression;
|
||||
use super::bit_constraints::{BitConstraint, BitConstraintSet};
|
||||
@@ -16,7 +15,7 @@ use super::{Constraint, EvalResult, FixedData, WitnessColumn};
|
||||
|
||||
pub struct Generator<'a, QueryCallback>
|
||||
where
|
||||
QueryCallback: FnMut(&'a str) -> Option<AbstractNumberType>,
|
||||
QueryCallback: FnMut(&'a str) -> Option<FieldElement>,
|
||||
{
|
||||
fixed_data: &'a FixedData<'a>,
|
||||
fixed_lookup: &'a mut FixedLookup,
|
||||
@@ -25,9 +24,9 @@ where
|
||||
query_callback: Option<QueryCallback>,
|
||||
global_bit_constraints: BTreeMap<&'a str, BitConstraint>,
|
||||
/// Values of the witness polynomials
|
||||
current: Vec<Option<AbstractNumberType>>,
|
||||
current: Vec<Option<FieldElement>>,
|
||||
/// Values of the witness polynomials in the next row
|
||||
next: Vec<Option<AbstractNumberType>>,
|
||||
next: Vec<Option<FieldElement>>,
|
||||
/// Bit constraints on the witness polynomials in the next row.
|
||||
next_bit_constraints: Vec<Option<BitConstraint>>,
|
||||
next_row: DegreeType,
|
||||
@@ -46,7 +45,7 @@ enum EvaluationRow {
|
||||
|
||||
impl<'a, QueryCallback> Generator<'a, QueryCallback>
|
||||
where
|
||||
QueryCallback: FnMut(&str) -> Option<AbstractNumberType>,
|
||||
QueryCallback: FnMut(&str) -> Option<FieldElement>,
|
||||
{
|
||||
pub fn new(
|
||||
fixed_data: &'a FixedData<'a>,
|
||||
@@ -75,7 +74,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_next_row(&mut self, next_row: DegreeType) -> Vec<AbstractNumberType> {
|
||||
pub fn compute_next_row(&mut self, next_row: DegreeType) -> Vec<FieldElement> {
|
||||
if next_row >= self.last_report + 1000 {
|
||||
log::info!(
|
||||
"{next_row} of {} rows ({} %)",
|
||||
@@ -180,12 +179,12 @@ where
|
||||
// violate constraints.
|
||||
self.current
|
||||
.iter()
|
||||
.map(|v| v.clone().unwrap_or_default())
|
||||
.map(|v| (*v).unwrap_or_default())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn machine_witness_col_values(&mut self) -> HashMap<String, Vec<AbstractNumberType>> {
|
||||
pub fn machine_witness_col_values(&mut self) -> HashMap<String, Vec<FieldElement>> {
|
||||
let mut result: HashMap<_, _> = Default::default();
|
||||
for m in &mut self.machines {
|
||||
result.extend(m.witness_col_values(self.fixed_data));
|
||||
@@ -212,7 +211,7 @@ where
|
||||
"{} = {}",
|
||||
AffineExpression::from_witness_poly_value(i).format(self.fixed_data),
|
||||
v.as_ref()
|
||||
.map(format_number)
|
||||
.map(ToString::to_string)
|
||||
.unwrap_or("<unknown>".to_string())
|
||||
)
|
||||
})
|
||||
@@ -424,9 +423,9 @@ impl<'a> BitConstraintSet for WitnessBitConstraintSet<'a> {
|
||||
struct EvaluationData<'a> {
|
||||
pub fixed_data: &'a FixedData<'a>,
|
||||
/// Values of the witness polynomials in the current / last row
|
||||
pub current_witnesses: &'a Vec<Option<AbstractNumberType>>,
|
||||
pub current_witnesses: &'a Vec<Option<FieldElement>>,
|
||||
/// Values of the witness polynomials in the next row
|
||||
pub next_witnesses: &'a Vec<Option<AbstractNumberType>>,
|
||||
pub next_witnesses: &'a Vec<Option<FieldElement>>,
|
||||
pub evaluate_row: EvaluationRow,
|
||||
}
|
||||
|
||||
@@ -439,13 +438,13 @@ impl<'a> WitnessColumnEvaluator for EvaluationData<'a> {
|
||||
// The exception is when we start the analysis on the first row.
|
||||
self.current_witnesses[id]
|
||||
.as_ref()
|
||||
.map(|value| value.clone().into())
|
||||
.map(|value| (*value).into())
|
||||
.ok_or_else(|| EvalError::PreviousValueUnknown(name.to_string()))
|
||||
}
|
||||
(false, EvaluationRow::Next) | (true, EvaluationRow::Current) => {
|
||||
Ok(if let Some(value) = &self.next_witnesses[id] {
|
||||
// We already computed the concrete value
|
||||
value.clone().into()
|
||||
(*value).into()
|
||||
} else {
|
||||
// We continue with a symbolic value
|
||||
AffineExpression::from_witness_poly_value(id)
|
||||
|
||||
@@ -4,7 +4,7 @@ use itertools::Itertools;
|
||||
|
||||
use super::{EvalResult, FixedData, FixedLookup};
|
||||
use crate::analyzer::{Expression, Identity, IdentityKind, SelectedExpressions};
|
||||
use crate::number::{AbstractNumberType, DegreeType};
|
||||
use crate::number::{DegreeType, FieldElement};
|
||||
use crate::witness_generator::eval_error;
|
||||
use crate::witness_generator::{
|
||||
affine_expression::AffineExpression,
|
||||
@@ -26,7 +26,7 @@ pub struct BlockMachine {
|
||||
selector: String,
|
||||
identities: Vec<Identity>,
|
||||
/// One column of values for each witness.
|
||||
data: HashMap<usize, Vec<Option<AbstractNumberType>>>,
|
||||
data: HashMap<usize, Vec<Option<FieldElement>>>,
|
||||
/// Current row in the machine
|
||||
row: DegreeType,
|
||||
/// Bit constraints, are deleted outside the current block.
|
||||
@@ -149,10 +149,7 @@ impl Machine for BlockMachine {
|
||||
})
|
||||
}
|
||||
|
||||
fn witness_col_values(
|
||||
&mut self,
|
||||
fixed_data: &FixedData,
|
||||
) -> HashMap<String, Vec<AbstractNumberType>> {
|
||||
fn witness_col_values(&mut self, fixed_data: &FixedData) -> HashMap<String, Vec<FieldElement>> {
|
||||
std::mem::take(&mut self.data)
|
||||
.into_iter()
|
||||
.map(|(id, values)| {
|
||||
@@ -220,8 +217,8 @@ impl BlockMachine {
|
||||
row_delta,
|
||||
identity,
|
||||
} = step;
|
||||
self.row =
|
||||
(old_len as i64 + row_delta + fixed_data.degree as i64) as u64 % fixed_data.degree;
|
||||
self.row = (old_len as i64 + row_delta + fixed_data.degree as i64) as DegreeType
|
||||
% fixed_data.degree;
|
||||
match self.process_identity(fixed_data, fixed_lookup, left, right, identity) {
|
||||
Ok(result) => {
|
||||
if !result.is_empty() {
|
||||
@@ -266,7 +263,7 @@ impl BlockMachine {
|
||||
.into_iter()
|
||||
.filter_map(|(poly, constraint)| {
|
||||
let (poly, next) = self.extract_next(poly);
|
||||
let r = (self.row + next as u64) % self.degree;
|
||||
let r = (self.row + next as DegreeType) % self.degree;
|
||||
let is_outside_poly = !self.data.contains_key(&poly);
|
||||
if is_outside_poly {
|
||||
assert!(!next);
|
||||
@@ -431,7 +428,7 @@ impl BitConstraintSet for BlockMachine {
|
||||
fn bit_constraint(&self, id: usize) -> Option<BitConstraint> {
|
||||
let (poly, next) = self.extract_next(id);
|
||||
self.global_bit_constraints.get(&poly).cloned().or_else(|| {
|
||||
let row = (self.row + next as u64) % self.degree;
|
||||
let row = (self.row + next as DegreeType) % self.degree;
|
||||
self.bit_constraints.get(&poly)?.get(&row).cloned()
|
||||
})
|
||||
}
|
||||
@@ -440,7 +437,7 @@ impl BitConstraintSet for BlockMachine {
|
||||
#[derive(Clone)]
|
||||
struct WitnessData<'a> {
|
||||
pub fixed_data: &'a FixedData<'a>,
|
||||
pub data: &'a HashMap<usize, Vec<Option<AbstractNumberType>>>,
|
||||
pub data: &'a HashMap<usize, Vec<Option<FieldElement>>>,
|
||||
pub row: DegreeType,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use itertools::{Either, Itertools};
|
||||
use super::{FixedLookup, Machine};
|
||||
use crate::analyzer::PolynomialReference;
|
||||
use crate::analyzer::{Expression, Identity, IdentityKind, SelectedExpressions};
|
||||
use crate::number::AbstractNumberType;
|
||||
use crate::number::FieldElement;
|
||||
use crate::witness_generator::{
|
||||
affine_expression::AffineExpression,
|
||||
eval_error::{self, EvalError},
|
||||
@@ -22,13 +22,13 @@ pub struct DoubleSortedWitnesses {
|
||||
/// The key column has a position of usize::max
|
||||
//witness_positions: HashMap<String, usize>,
|
||||
/// (addr, step) -> value
|
||||
trace: BTreeMap<(AbstractNumberType, AbstractNumberType), Operation>,
|
||||
data: BTreeMap<AbstractNumberType, AbstractNumberType>,
|
||||
trace: BTreeMap<(FieldElement, FieldElement), Operation>,
|
||||
data: BTreeMap<FieldElement, FieldElement>,
|
||||
}
|
||||
|
||||
struct Operation {
|
||||
pub is_write: bool,
|
||||
pub value: AbstractNumberType,
|
||||
pub value: FieldElement,
|
||||
}
|
||||
|
||||
impl DoubleSortedWitnesses {
|
||||
@@ -90,10 +90,7 @@ impl Machine for DoubleSortedWitnesses {
|
||||
Some(self.process_plookup_internal(fixed_data, left, right))
|
||||
}
|
||||
|
||||
fn witness_col_values(
|
||||
&mut self,
|
||||
fixed_data: &FixedData,
|
||||
) -> HashMap<String, Vec<AbstractNumberType>> {
|
||||
fn witness_col_values(&mut self, fixed_data: &FixedData) -> HashMap<String, Vec<FieldElement>> {
|
||||
let mut addr = vec![];
|
||||
let mut step = vec![];
|
||||
let mut value = vec![];
|
||||
@@ -102,8 +99,8 @@ impl Machine for DoubleSortedWitnesses {
|
||||
let mut is_read = vec![];
|
||||
|
||||
for ((a, s), o) in std::mem::take(&mut self.trace) {
|
||||
addr.push(a.clone());
|
||||
step.push(s.clone());
|
||||
addr.push(a);
|
||||
step.push(s);
|
||||
value.push(o.value);
|
||||
op.push(1.into());
|
||||
|
||||
@@ -120,9 +117,9 @@ impl Machine for DoubleSortedWitnesses {
|
||||
is_read.push(0.into());
|
||||
}
|
||||
while addr.len() < fixed_data.degree as usize {
|
||||
addr.push(addr.last().unwrap().clone());
|
||||
step.push(step.last().unwrap().clone() + 1);
|
||||
value.push(value.last().unwrap().clone());
|
||||
addr.push(*addr.last().unwrap());
|
||||
step.push(*step.last().unwrap() + FieldElement::from(1));
|
||||
value.push(*value.last().unwrap());
|
||||
op.push(0.into());
|
||||
is_write.push(0.into());
|
||||
is_read.push(0.into());
|
||||
@@ -196,10 +193,11 @@ impl DoubleSortedWitnesses {
|
||||
})?;
|
||||
|
||||
log::trace!(
|
||||
"Query addr={addr:x}, step={step}, write: {is_write}, left: {}",
|
||||
"Query addr={:x}, step={step}, write: {is_write}, left: {}",
|
||||
addr.to_integer(),
|
||||
left[2].format(fixed_data)
|
||||
);
|
||||
if addr.clone() % 4 != 0.into() {
|
||||
if addr.clone().to_integer() % 4 != 0 {
|
||||
panic!("UNALIGNED");
|
||||
}
|
||||
|
||||
@@ -210,21 +208,30 @@ impl DoubleSortedWitnesses {
|
||||
Some(v) => v,
|
||||
None => return Ok(vec![]),
|
||||
};
|
||||
log::debug!("Memory write: addr={addr:x}, step={step}, value={value:x}");
|
||||
self.data.insert(addr.clone(), value.clone());
|
||||
|
||||
log::debug!(
|
||||
"Memory write: addr={:x}, step={step}, value={:x}",
|
||||
addr.to_integer(),
|
||||
value.to_integer()
|
||||
);
|
||||
self.data.insert(addr, value);
|
||||
self.trace
|
||||
.insert((addr, step), Operation { is_write, value });
|
||||
} else {
|
||||
let value = self.data.entry(addr.clone()).or_default();
|
||||
let value = self.data.entry(addr).or_default();
|
||||
self.trace.insert(
|
||||
(addr.clone(), step.clone()),
|
||||
(addr, step),
|
||||
Operation {
|
||||
is_write,
|
||||
value: value.clone(),
|
||||
value: *value,
|
||||
},
|
||||
);
|
||||
log::debug!("Memory read: addr={addr:x}, step={step}, value={value:x}");
|
||||
assignments.extend(match (left[2].clone() - value.clone().into()).solve() {
|
||||
log::debug!(
|
||||
"Memory read: addr={:x}, step={step}, value={:x}",
|
||||
addr.to_integer(),
|
||||
value.to_integer()
|
||||
);
|
||||
assignments.extend(match (left[2].clone() - (*value).into()).solve() {
|
||||
Ok(ass) => ass,
|
||||
Err(_) => return Ok(vec![]),
|
||||
});
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
|
||||
use crate::analyzer::{Identity, IdentityKind, SelectedExpressions};
|
||||
use crate::number::{AbstractNumberType, DegreeType};
|
||||
use crate::number::{DegreeType, FieldElement};
|
||||
|
||||
use crate::witness_generator::util::is_simple_poly;
|
||||
use crate::witness_generator::{
|
||||
@@ -14,7 +12,7 @@ use crate::witness_generator::{
|
||||
};
|
||||
|
||||
type Application = (Vec<String>, Vec<String>);
|
||||
type Index = BTreeMap<Vec<AbstractNumberType>, Option<DegreeType>>;
|
||||
type Index = BTreeMap<Vec<FieldElement>, Option<DegreeType>>;
|
||||
|
||||
/// Indices for applications of fixed columns. For each application `(INPUT_COLS, OUTPUT_COLS)`, stores
|
||||
/// - `(V, None)` if there exists two different rows where `INPUT_COLS == V` match but `OUTPUT_COLS` differ. TODO: store bitmasks of all possible outputs instead.
|
||||
@@ -29,7 +27,7 @@ impl IndexedColumns {
|
||||
fn get_match(
|
||||
&mut self,
|
||||
fixed_data: &FixedData,
|
||||
mut assignment: Vec<(String, AbstractNumberType)>,
|
||||
mut assignment: Vec<(String, FieldElement)>,
|
||||
mut output_fixed_columns: Vec<String>,
|
||||
) -> Option<&Option<DegreeType>> {
|
||||
// sort in order to have a single index for [X, Y] and for [Y, X]
|
||||
@@ -82,21 +80,22 @@ impl IndexedColumns {
|
||||
.map(|name| fixed_data.fixed_cols.get(name.as_str()).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let index: BTreeMap<Vec<BigInt>, Option<u64>> = (0..fixed_data.degree as usize)
|
||||
let index: BTreeMap<Vec<FieldElement>, Option<DegreeType>> = (0..fixed_data.degree
|
||||
as usize)
|
||||
.fold(
|
||||
(
|
||||
BTreeMap::<Vec<AbstractNumberType>, Option<DegreeType>>::default(),
|
||||
HashSet::<(Vec<AbstractNumberType>, Vec<AbstractNumberType>)>::default(),
|
||||
BTreeMap::<Vec<FieldElement>, Option<DegreeType>>::default(),
|
||||
HashSet::<(Vec<FieldElement>, Vec<FieldElement>)>::default(),
|
||||
),
|
||||
|(mut acc, mut set), row| {
|
||||
let input: Vec<_> = input_column_values
|
||||
.iter()
|
||||
.map(|column| column[row].clone())
|
||||
.map(|column| column[row])
|
||||
.collect();
|
||||
|
||||
let output: Vec<_> = output_column_values
|
||||
.iter()
|
||||
.map(|column| column[row].clone())
|
||||
.map(|column| column[row])
|
||||
.collect();
|
||||
|
||||
let input_output = (input, output);
|
||||
@@ -113,7 +112,7 @@ impl IndexedColumns {
|
||||
.and_modify(|value| {
|
||||
*value = None;
|
||||
})
|
||||
.or_insert(Some(row as u64));
|
||||
.or_insert(Some(row as DegreeType));
|
||||
|
||||
(acc, set)
|
||||
}
|
||||
@@ -243,7 +242,7 @@ impl FixedLookup {
|
||||
for (l, r) in output_expressions.iter().zip(output) {
|
||||
match l {
|
||||
Ok(l) => {
|
||||
let evaluated = l.clone() - r.clone().into();
|
||||
let evaluated = l.clone() - (*r).into();
|
||||
// TODO we could use bit constraints here
|
||||
match evaluated.solve() {
|
||||
Ok(constraints) => result.extend(constraints),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::analyzer::{IdentityKind, SelectedExpressions};
|
||||
use crate::number::AbstractNumberType;
|
||||
use crate::number::FieldElement;
|
||||
|
||||
pub use self::fixed_lookup_machine::FixedLookup;
|
||||
|
||||
@@ -41,8 +41,5 @@ pub trait Machine {
|
||||
) -> Option<EvalResult>;
|
||||
|
||||
/// Returns the final values of the witness columns.
|
||||
fn witness_col_values(
|
||||
&mut self,
|
||||
fixed_data: &FixedData,
|
||||
) -> HashMap<String, Vec<AbstractNumberType>>;
|
||||
fn witness_col_values(&mut self, fixed_data: &FixedData) -> HashMap<String, Vec<FieldElement>>;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::fixed_lookup_machine::FixedLookup;
|
||||
use super::Machine;
|
||||
use super::{EvalResult, FixedData};
|
||||
use crate::analyzer::{Expression, Identity, IdentityKind, SelectedExpressions};
|
||||
use crate::number::AbstractNumberType;
|
||||
use crate::number::FieldElement;
|
||||
use crate::witness_generator::{
|
||||
eval_error::{self, EvalError},
|
||||
expression_evaluator::ExpressionEvaluator,
|
||||
@@ -27,7 +27,7 @@ pub struct SortedWitnesses {
|
||||
/// Position of the witness columns in the data.
|
||||
/// The key column has a position of usize::max
|
||||
witness_positions: HashMap<String, usize>,
|
||||
data: BTreeMap<AbstractNumberType, Vec<Option<AbstractNumberType>>>,
|
||||
data: BTreeMap<FieldElement, Vec<Option<FieldElement>>>,
|
||||
}
|
||||
|
||||
impl SortedWitnesses {
|
||||
@@ -87,7 +87,7 @@ fn check_identity<'a>(fixed_data: &'a FixedData, id: &Identity) -> Option<&'a st
|
||||
return None;
|
||||
}
|
||||
let pos = ev.evaluate(positive).ok()?.constant_value()?;
|
||||
if pos != (row + 1).into() {
|
||||
if pos != (row as u64 + 1).into() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@@ -157,10 +157,7 @@ impl Machine for SortedWitnesses {
|
||||
|
||||
Some(self.process_plookup_internal(fixed_data, left, right, rhs))
|
||||
}
|
||||
fn witness_col_values(
|
||||
&mut self,
|
||||
fixed_data: &FixedData,
|
||||
) -> HashMap<String, Vec<AbstractNumberType>> {
|
||||
fn witness_col_values(&mut self, fixed_data: &FixedData) -> HashMap<String, Vec<FieldElement>> {
|
||||
let mut result = HashMap::new();
|
||||
|
||||
let (mut keys, mut values): (Vec<_>, Vec<_>) =
|
||||
@@ -168,8 +165,8 @@ impl Machine for SortedWitnesses {
|
||||
|
||||
let mut last_key = keys.last().cloned().unwrap_or_default();
|
||||
while keys.len() < fixed_data.degree as usize {
|
||||
last_key += 1;
|
||||
keys.push(last_key.clone());
|
||||
last_key += 1u64.into();
|
||||
keys.push(last_key);
|
||||
}
|
||||
result.insert(self.key_col.clone(), keys);
|
||||
|
||||
@@ -220,14 +217,14 @@ impl SortedWitnesses {
|
||||
let mut assignments = vec![];
|
||||
let stored_values = self
|
||||
.data
|
||||
.entry(key_value.clone())
|
||||
.entry(key_value)
|
||||
.or_insert_with(|| vec![None; self.witness_positions.len()]);
|
||||
for (&l, &r) in left.iter().zip(rhs.iter()).skip(1) {
|
||||
let stored_value = &mut stored_values[self.witness_positions[r]];
|
||||
match stored_value {
|
||||
// There is a stored value
|
||||
Some(v) => {
|
||||
match (l.clone() - (*v).clone().into()).solve() {
|
||||
match (l.clone() - (*v).into()).solve() {
|
||||
Err(EvalError::ConstraintUnsatisfiable(_)) => {
|
||||
// The LHS value is known and it is differetn from the stored one.
|
||||
return Err(format!(
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::analyzer::{Analyzed, Expression, FunctionValueDefinition};
|
||||
use crate::number::{AbstractNumberType, DegreeType};
|
||||
use crate::number::{DegreeType, FieldElement};
|
||||
|
||||
use self::bit_constraints::BitConstraint;
|
||||
use self::eval_error::EvalError;
|
||||
@@ -24,9 +24,9 @@ mod util;
|
||||
pub fn generate<'a>(
|
||||
analyzed: &'a Analyzed,
|
||||
degree: DegreeType,
|
||||
fixed_cols: &[(&str, Vec<AbstractNumberType>)],
|
||||
query_callback: Option<impl FnMut(&str) -> Option<AbstractNumberType>>,
|
||||
) -> Vec<(&'a str, Vec<AbstractNumberType>)> {
|
||||
fixed_cols: &[(&str, Vec<FieldElement>)],
|
||||
query_callback: Option<impl FnMut(&str) -> Option<FieldElement>>,
|
||||
) -> Vec<(&'a str, Vec<FieldElement>)> {
|
||||
let witness_cols: Vec<WitnessColumn> = analyzed
|
||||
.committed_polys_in_source_order()
|
||||
.iter()
|
||||
@@ -62,7 +62,7 @@ pub fn generate<'a>(
|
||||
query_callback,
|
||||
);
|
||||
|
||||
let mut values: Vec<(&str, Vec<AbstractNumberType>)> =
|
||||
let mut values: Vec<(&str, Vec<FieldElement>)> =
|
||||
witness_cols.iter().map(|p| (p.name, Vec::new())).collect();
|
||||
for row in 0..degree as DegreeType {
|
||||
let row_values = generator.compute_next_row(row);
|
||||
@@ -89,7 +89,7 @@ type EvalResult = Result<Vec<(usize, Constraint)>, EvalError>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Constraint {
|
||||
Assignment(AbstractNumberType),
|
||||
Assignment(FieldElement),
|
||||
BitConstraint(BitConstraint),
|
||||
}
|
||||
|
||||
@@ -105,8 +105,8 @@ impl Display for Constraint {
|
||||
/// Data that is fixed for witness generation.
|
||||
pub struct FixedData<'a> {
|
||||
degree: DegreeType,
|
||||
constants: &'a HashMap<String, AbstractNumberType>,
|
||||
fixed_cols: HashMap<&'a str, &'a Vec<AbstractNumberType>>,
|
||||
constants: &'a HashMap<String, FieldElement>,
|
||||
fixed_cols: HashMap<&'a str, &'a Vec<FieldElement>>,
|
||||
witness_cols: &'a Vec<WitnessColumn<'a>>,
|
||||
witness_ids: HashMap<&'a str, usize>,
|
||||
}
|
||||
@@ -114,8 +114,8 @@ pub struct FixedData<'a> {
|
||||
impl<'a> FixedData<'a> {
|
||||
pub fn new(
|
||||
degree: DegreeType,
|
||||
constants: &'a HashMap<String, AbstractNumberType>,
|
||||
fixed_cols: HashMap<&'a str, &'a Vec<AbstractNumberType>>,
|
||||
constants: &'a HashMap<String, FieldElement>,
|
||||
fixed_cols: HashMap<&'a str, &'a Vec<FieldElement>>,
|
||||
witness_cols: &'a Vec<WitnessColumn<'a>>,
|
||||
witness_ids: HashMap<&'a str, usize>,
|
||||
) -> Self {
|
||||
|
||||
@@ -72,7 +72,7 @@ impl<'a> SymbolicEvaluator<'a> {
|
||||
|
||||
impl<'a> SymbolicVariables for SymbolicEvaluator<'a> {
|
||||
fn constant(&self, name: &str) -> Result<AffineExpression, EvalError> {
|
||||
Ok(self.fixed_data.constants[name].clone().into())
|
||||
Ok(self.fixed_data.constants[name].into())
|
||||
}
|
||||
|
||||
fn value(&self, name: &str, next: bool) -> Result<AffineExpression, EvalError> {
|
||||
|
||||
@@ -42,7 +42,7 @@ where
|
||||
WA: WitnessColumnEvaluator + WitnessColumnNamer,
|
||||
{
|
||||
fn constant(&self, name: &str) -> Result<AffineExpression, EvalError> {
|
||||
Ok(self.fixed_data.constants[name].clone().into())
|
||||
Ok(self.fixed_data.constants[name].into())
|
||||
}
|
||||
|
||||
fn value(&self, name: &str, next: bool) -> Result<AffineExpression, EvalError> {
|
||||
@@ -62,7 +62,7 @@ where
|
||||
} else {
|
||||
self.row
|
||||
};
|
||||
Ok(values[row as usize].clone().into())
|
||||
Ok(values[row as usize].into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use common::verify_asm_string;
|
||||
use powdr::number::AbstractNumberType;
|
||||
use powdr::number::FieldElement;
|
||||
use std::fs;
|
||||
|
||||
mod common;
|
||||
|
||||
fn verify_asm(file_name: &str, inputs: Vec<AbstractNumberType>) {
|
||||
fn verify_asm(file_name: &str, inputs: Vec<FieldElement>) {
|
||||
let contents = fs::read_to_string(format!("./tests/asm_data/{file_name}")).unwrap();
|
||||
verify_asm_string(file_name, &contents, inputs)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ use std::{fs, path::Path, process::Command};
|
||||
|
||||
use itertools::Itertools;
|
||||
use powdr::compiler;
|
||||
use powdr::number::AbstractNumberType;
|
||||
use powdr::number::FieldElement;
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn verify_asm_string(file_name: &str, contents: &str, inputs: Vec<AbstractNumberType>) {
|
||||
pub fn verify_asm_string(file_name: &str, contents: &str, inputs: Vec<FieldElement>) {
|
||||
let pil = powdr::asm_compiler::compile(Some(file_name), contents).unwrap();
|
||||
let pil_file_name = "asm.pil";
|
||||
let temp_dir = mktemp::Temp::new_dir().unwrap();
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::path::Path;
|
||||
|
||||
use powdr::compiler;
|
||||
use powdr::number::AbstractNumberType;
|
||||
use powdr::number::FieldElement;
|
||||
|
||||
use crate::common::verify;
|
||||
|
||||
mod common;
|
||||
|
||||
pub fn verify_pil(file_name: &str, query_callback: Option<fn(&str) -> Option<AbstractNumberType>>) {
|
||||
pub fn verify_pil(file_name: &str, query_callback: Option<fn(&str) -> Option<FieldElement>>) {
|
||||
let input_file = Path::new(&format!("./tests/pil_data/{file_name}"))
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use common::verify_asm_string;
|
||||
use powdr::number::AbstractNumberType;
|
||||
use powdr::number::FieldElement;
|
||||
|
||||
mod common;
|
||||
|
||||
@@ -52,14 +52,14 @@ fn test_keccak() {
|
||||
verify_crate(case, vec![]);
|
||||
}
|
||||
|
||||
fn verify_file(case: &str, inputs: Vec<AbstractNumberType>) {
|
||||
fn verify_file(case: &str, inputs: Vec<FieldElement>) {
|
||||
let riscv_asm = powdr::riscv::compile_rust_to_riscv_asm(&format!("tests/riscv_data/{case}"));
|
||||
let powdr_asm = powdr::riscv::compiler::compile_riscv_asm(&riscv_asm);
|
||||
|
||||
verify_asm_string(&format!("{case}.asm"), &powdr_asm, inputs);
|
||||
}
|
||||
|
||||
fn verify_crate(case: &str, inputs: Vec<AbstractNumberType>) {
|
||||
fn verify_crate(case: &str, inputs: Vec<FieldElement>) {
|
||||
let riscv_asm = powdr::riscv::compile_rust_crate_to_riscv_asm(&format!(
|
||||
"tests/riscv_data/{case}/Cargo.toml"
|
||||
));
|
||||
|
||||
Reference in New Issue
Block a user