use ark_ff under the hood

This commit is contained in:
schaeff
2023-04-17 18:40:47 +02:00
parent 86ec31f474
commit 2f3520c7dc
29 changed files with 556 additions and 405 deletions

View File

@@ -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"

View File

@@ -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)]

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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() {

View File

@@ -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();
}
}
}

View File

@@ -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()
}

View File

@@ -1,6 +1,3 @@
#[macro_use]
extern crate lazy_static;
pub mod analyzer;
pub mod asm_compiler;
pub mod compiler;

View File

@@ -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}")
}
}
}

View File

@@ -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();

View File

@@ -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(),
}

View File

@@ -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,
) {

View File

@@ -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))
)]
);

View File

@@ -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)
);
}
}

View File

@@ -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())

View File

@@ -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()

View File

@@ -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)

View File

@@ -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,
}

View File

@@ -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![]),
});

View File

@@ -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),

View File

@@ -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>>;
}

View File

@@ -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!(

View File

@@ -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 {

View File

@@ -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> {

View File

@@ -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())
}
}

View File

@@ -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)
}

View File

@@ -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();

View File

@@ -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();

View File

@@ -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"
));