From 2f3520c7dc15232f027a71da65ba015ed305647a Mon Sep 17 00:00:00 2001 From: schaeff Date: Mon, 17 Apr 2023 18:40:47 +0200 Subject: [PATCH] use ark_ff under the hood --- Cargo.toml | 2 +- src/analyzer/mod.rs | 11 +- src/analyzer/pil_analyzer.rs | 52 ++-- src/asm_compiler/mod.rs | 52 ++-- src/bin/compiler.rs | 8 +- src/compiler.rs | 29 +- src/constant_evaluator/mod.rs | 48 ++- src/lib.rs | 3 - src/number.rs | 289 +++++++++++++++--- src/parser/ast.rs | 13 +- src/parser/powdr.lalrpop | 21 +- src/riscv/mod.rs | 6 +- src/witness_generator/affine_expression.rs | 139 +++------ src/witness_generator/bit_constraints.rs | 64 ++-- src/witness_generator/expression_evaluator.rs | 30 +- src/witness_generator/fixed_evaluator.rs | 4 +- src/witness_generator/generator.rs | 27 +- .../machines/block_machine.rs | 19 +- .../machines/double_sorted_witness_machine.rs | 51 ++-- .../machines/fixed_lookup_machine.rs | 23 +- src/witness_generator/machines/mod.rs | 7 +- .../machines/sorted_witness_machine.rs | 19 +- src/witness_generator/mod.rs | 20 +- src/witness_generator/symbolic_evaluator.rs | 2 +- .../symbolic_witness_evaluator.rs | 4 +- tests/asm.rs | 4 +- tests/common/mod.rs | 4 +- tests/pil.rs | 4 +- tests/riscv.rs | 6 +- 29 files changed, 556 insertions(+), 405 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d4c9d6f18..024b936cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/analyzer/mod.rs b/src/analyzer/mod.rs index 279032c5e..4d4f77aac 100644 --- a/src/analyzer/mod.rs +++ b/src/analyzer/mod.rs @@ -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, + pub constants: HashMap, pub definitions: HashMap)>, pub public_declarations: HashMap, pub identities: Vec, @@ -152,17 +152,14 @@ pub enum Expression { PolynomialReference(PolynomialReference), LocalVariableReference(u64), PublicReference(String), - Number(AbstractNumberType), + Number(FieldElement), String(String), Tuple(Vec), BinaryOperation(Box, BinaryOperator, Box), UnaryOperation(UnaryOperator, Box), /// Call to a non-macro function (like a constant polynomial) FunctionCall(String, Vec), - MatchExpression( - Box, - Vec<(Option, Expression)>, - ), + MatchExpression(Box, Vec<(Option, Expression)>), } #[derive(Debug, PartialEq, Eq, Default, Clone)] diff --git a/src/analyzer/pil_analyzer.rs b/src/analyzer/pil_analyzer.rs index 8435859ff..06938dce6 100644 --- a/src/analyzer/pil_analyzer.rs +++ b/src/analyzer/pil_analyzer.rs @@ -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, + constants: HashMap, definitions: HashMap)>, public_declarations: HashMap, macros: HashMap, @@ -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 { + fn evaluate_expression(&self, expr: &ast::Expression) -> Option { 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 { + ) -> Option { 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 { + ) -> Option { self.evaluate_expression(value).map(|v| match op { UnaryOperator::Plus => v, UnaryOperator::Minus => -v, diff --git a/src/asm_compiler/mod.rs b/src/asm_compiler/mod.rs index 7aadf6086..5f3e4e498 100644 --- a/src/asm_compiler/mod.rs +++ b/src/asm_compiler/mod.rs @@ -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::>(); // 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::>(); 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>, /// The value on the right-hand-side, per assignment register - value: BTreeMap>, + value: BTreeMap>, label: Option, instruction: Option, // 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>(value: V) -> Expression { + Expression::Number(value.into()) } fn extract_update(expr: Expression) -> (Option, Expression) { diff --git a/src/bin/compiler.rs b/src/bin/compiler.rs index 74f3cf10a..7ee7d0f3b 100644 --- a/src/bin/compiler.rs +++ b/src/bin/compiler.rs @@ -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 { +fn split_inputs(inputs: &str) -> Vec { inputs .split(',') .map(|x| x.trim()) .filter(|x| !x.is_empty()) - .map(|x| x.parse().unwrap()) - .collect::>() + .map(|x| x.parse::().unwrap().into()) + .collect::>() } fn main() { diff --git a/src/compiler.rs b/src/compiler.rs index 3c3fc979e..4e7e30a48 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -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 Option> { +pub fn no_callback() -> Option Option> { None } @@ -20,7 +19,7 @@ pub fn no_callback() -> Option Option> { pub fn compile_pil( pil_file: &Path, output_dir: &Path, - query_callback: Option Option>, + query_callback: Option Option>, ) -> 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 Option>, + query_callback: Option Option>, ) -> 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, + inputs: Vec, 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, + inputs: Vec, 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 { + let query_callback = |query: &str| -> Option { let items = query.split(',').map(|s| s.trim()).collect::>(); 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 Option>, + query_callback: Option Option>, ) -> 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)>, + polys: &Vec<(&str, Vec)>, ) { 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(); } } } diff --git a/src/constant_evaluator/mod.rs b/src/constant_evaluator/mod.rs index 93acba581..9b0b603f5 100644 --- a/src/constant_evaluator/mod.rs +++ b/src/constant_evaluator/mod.rs @@ -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)>, DegreeType) { +pub fn generate(analyzed: &Analyzed) -> (Vec<(&str, Vec)>, 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>, -) -> Vec { + other_constants: &HashMap<&str, Vec>, +) -> Vec { 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>, - variables: &'a [AbstractNumberType], + other_constants: &'a HashMap<&'a str, Vec>, + 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::>(); 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) -> Vec { + fn convert(input: Vec) -> Vec { input.into_iter().map(|x| x.into()).collect() } diff --git a/src/lib.rs b/src/lib.rs index 0165040d3..37a6e7c80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,3 @@ -#[macro_use] -extern crate lazy_static; - pub mod analyzer; pub mod asm_compiler; pub mod compiler; diff --git a/src/number.rs b/src/number.rs index 615714d31..89c2bca88 100644 --- a/src/number.rs +++ b/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>; /// 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 { + 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 = 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> From 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 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 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 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 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}") + } } } diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 59d1edae1..d44889e6e 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -1,4 +1,4 @@ -use crate::number::{AbstractNumberType, DegreeType}; +use crate::number::{DegreeType, FieldElement}; #[derive(Debug, PartialEq, Eq)] pub struct PILFile(pub Vec); @@ -41,17 +41,14 @@ pub enum Expression { Constant(String), PolynomialReference(PolynomialReference), PublicReference(String), - Number(AbstractNumberType), + Number(FieldElement), String(String), Tuple(Vec), BinaryOperation(Box, BinaryOperator, Box), UnaryOperation(UnaryOperator, Box), FunctionCall(String, Vec), FreeInput(Box), - MatchExpression( - Box, - Vec<(Option, Expression)>, - ), + MatchExpression(Box, Vec<(Option, 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(); diff --git a/src/parser/powdr.lalrpop b/src/parser/powdr.lalrpop index 7c0012b30..4a5f84223 100644 --- a/src/parser/powdr.lalrpop +++ b/src/parser/powdr.lalrpop @@ -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" ";" => ASMStatement::Degree(<>) + <@L> "degree" ";" => ASMStatement::Degree(<>) } RegisterDeclaration: ASMStatement = { @@ -333,7 +333,7 @@ Term: Box = { 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, "(" "," ")" => { let mut list = vec![head]; list.extend(tail); Box::new(Expression::Tuple(list)) }, @@ -360,8 +360,8 @@ MatchExpression: Box = { "match" "{" <( ",")*> "}" => Box::new(Expression::MatchExpression(<>)) } -MatchArm: (Option, Expression) = { - "=>" => (Some(n), e), +MatchArm: (Option, Expression) = { + "=>" => (Some(n), e), "=>" => (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(), } \ No newline at end of file diff --git a/src/riscv/mod.rs b/src/riscv/mod.rs index 6ba3a274c..d14c131d2 100644 --- a/src/riscv/mod.rs +++ b/src/riscv/mod.rs @@ -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, + inputs: Vec, 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, + inputs: Vec, output_dir: &Path, force_overwrite: bool, ) { diff --git a/src/witness_generator/affine_expression.rs b/src/witness_generator/affine_expression.rs index 99c09b8ce..81468f762 100644 --- a/src/witness_generator/affine_expression.rs +++ b/src/witness_generator/affine_expression.rs @@ -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, - pub offset: AbstractNumberType, + pub coefficients: Vec, + pub offset: FieldElement, } -impl From for AffineExpression { - fn from(value: AbstractNumberType) -> Self { +impl From for AffineExpression { + fn from(value: FieldElement) -> Self { AffineExpression { coefficients: Vec::new(), - offset: wrap(value), + offset: value, } } } @@ -30,7 +29,7 @@ impl From 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 { + pub fn constant_value(&self) -> Option { 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 { + pub fn nonzero_coefficients(&self) -> impl Iterator { 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::>(); @@ -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) -> Vec { + fn convert(input: Vec) -> Vec { 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); impl BitConstraintSet for TestBitConstraints { fn bit_constraint(&self, id: usize) -> Option { @@ -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)) )] ); diff --git a/src/witness_generator/bit_constraints.rs b/src/witness_generator/bit_constraints.rs index 3c63c9b8f..cd3310534 100644 --- a/src/witness_generator/bit_constraints.rs +++ b/src/witness_generator/bit_constraints.rs @@ -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 { - 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 { - if factor.clone() * self.mask.clone() >= get_field_mod() { + pub fn multiple(&self, factor: FieldElement) -> Option { + 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 { +fn smallest_period_candidate(fixed: &[FieldElement]) -> Option { 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::>(); 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::>(); 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::>(); 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::>(); 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) ); } } diff --git a/src/witness_generator/expression_evaluator.rs b/src/witness_generator/expression_evaluator.rs index 2c3382ac5..5feccf6d9 100644 --- a/src/witness_generator/expression_evaluator.rs +++ b/src/witness_generator/expression_evaluator.rs @@ -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 ExpressionEvaluator { 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 ExpressionEvaluator { } 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 ExpressionEvaluator { 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()) diff --git a/src/witness_generator/fixed_evaluator.rs b/src/witness_generator/fixed_evaluator.rs index 453a34ea5..da4e9bbec 100644 --- a/src/witness_generator/fixed_evaluator.rs +++ b/src/witness_generator/fixed_evaluator.rs @@ -17,7 +17,7 @@ impl<'a> FixedEvaluator<'a> { impl<'a> SymbolicVariables for FixedEvaluator<'a> { fn constant(&self, name: &str) -> Result { - Ok(self.fixed_data.constants[name].clone().into()) + Ok(self.fixed_data.constants[name].into()) } fn value(&self, name: &str, next: bool) -> Result { @@ -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() diff --git a/src/witness_generator/generator.rs b/src/witness_generator/generator.rs index b7b3ff4e6..2f54f907c 100644 --- a/src/witness_generator/generator.rs +++ b/src/witness_generator/generator.rs @@ -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, + QueryCallback: FnMut(&'a str) -> Option, { fixed_data: &'a FixedData<'a>, fixed_lookup: &'a mut FixedLookup, @@ -25,9 +24,9 @@ where query_callback: Option, global_bit_constraints: BTreeMap<&'a str, BitConstraint>, /// Values of the witness polynomials - current: Vec>, + current: Vec>, /// Values of the witness polynomials in the next row - next: Vec>, + next: Vec>, /// Bit constraints on the witness polynomials in the next row. next_bit_constraints: Vec>, next_row: DegreeType, @@ -46,7 +45,7 @@ enum EvaluationRow { impl<'a, QueryCallback> Generator<'a, QueryCallback> where - QueryCallback: FnMut(&str) -> Option, + QueryCallback: FnMut(&str) -> Option, { pub fn new( fixed_data: &'a FixedData<'a>, @@ -75,7 +74,7 @@ where } } - pub fn compute_next_row(&mut self, next_row: DegreeType) -> Vec { + pub fn compute_next_row(&mut self, next_row: DegreeType) -> Vec { 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> { + pub fn machine_witness_col_values(&mut self) -> HashMap> { 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("".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>, + pub current_witnesses: &'a Vec>, /// Values of the witness polynomials in the next row - pub next_witnesses: &'a Vec>, + pub next_witnesses: &'a Vec>, 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) diff --git a/src/witness_generator/machines/block_machine.rs b/src/witness_generator/machines/block_machine.rs index 6f0bb8a08..03b402a4a 100644 --- a/src/witness_generator/machines/block_machine.rs +++ b/src/witness_generator/machines/block_machine.rs @@ -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, /// One column of values for each witness. - data: HashMap>>, + data: HashMap>>, /// 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> { + fn witness_col_values(&mut self, fixed_data: &FixedData) -> HashMap> { 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 { 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>>, + pub data: &'a HashMap>>, pub row: DegreeType, } diff --git a/src/witness_generator/machines/double_sorted_witness_machine.rs b/src/witness_generator/machines/double_sorted_witness_machine.rs index d69de2c39..7f1106c49 100644 --- a/src/witness_generator/machines/double_sorted_witness_machine.rs +++ b/src/witness_generator/machines/double_sorted_witness_machine.rs @@ -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, /// (addr, step) -> value - trace: BTreeMap<(AbstractNumberType, AbstractNumberType), Operation>, - data: BTreeMap, + trace: BTreeMap<(FieldElement, FieldElement), Operation>, + data: BTreeMap, } 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> { + fn witness_col_values(&mut self, fixed_data: &FixedData) -> HashMap> { 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![]), }); diff --git a/src/witness_generator/machines/fixed_lookup_machine.rs b/src/witness_generator/machines/fixed_lookup_machine.rs index b8485e308..4911cace3 100644 --- a/src/witness_generator/machines/fixed_lookup_machine.rs +++ b/src/witness_generator/machines/fixed_lookup_machine.rs @@ -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, Vec); -type Index = BTreeMap, Option>; +type Index = BTreeMap, Option>; /// 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, ) -> Option<&Option> { // 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::>(); - let index: BTreeMap, Option> = (0..fixed_data.degree as usize) + let index: BTreeMap, Option> = (0..fixed_data.degree + as usize) .fold( ( - BTreeMap::, Option>::default(), - HashSet::<(Vec, Vec)>::default(), + BTreeMap::, Option>::default(), + HashSet::<(Vec, Vec)>::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), diff --git a/src/witness_generator/machines/mod.rs b/src/witness_generator/machines/mod.rs index 5a74f26c3..5fdd9c6ab 100644 --- a/src/witness_generator/machines/mod.rs +++ b/src/witness_generator/machines/mod.rs @@ -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; /// Returns the final values of the witness columns. - fn witness_col_values( - &mut self, - fixed_data: &FixedData, - ) -> HashMap>; + fn witness_col_values(&mut self, fixed_data: &FixedData) -> HashMap>; } diff --git a/src/witness_generator/machines/sorted_witness_machine.rs b/src/witness_generator/machines/sorted_witness_machine.rs index dc32aecb4..5e934e583 100644 --- a/src/witness_generator/machines/sorted_witness_machine.rs +++ b/src/witness_generator/machines/sorted_witness_machine.rs @@ -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, - data: BTreeMap>>, + data: BTreeMap>>, } 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> { + fn witness_col_values(&mut self, fixed_data: &FixedData) -> HashMap> { 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!( diff --git a/src/witness_generator/mod.rs b/src/witness_generator/mod.rs index ac1dd7d4a..d374b74eb 100644 --- a/src/witness_generator/mod.rs +++ b/src/witness_generator/mod.rs @@ -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)], - query_callback: Option Option>, -) -> Vec<(&'a str, Vec)> { + fixed_cols: &[(&str, Vec)], + query_callback: Option Option>, +) -> Vec<(&'a str, Vec)> { let witness_cols: Vec = analyzed .committed_polys_in_source_order() .iter() @@ -62,7 +62,7 @@ pub fn generate<'a>( query_callback, ); - let mut values: Vec<(&str, Vec)> = + let mut values: Vec<(&str, Vec)> = 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, 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, - fixed_cols: HashMap<&'a str, &'a Vec>, + constants: &'a HashMap, + fixed_cols: HashMap<&'a str, &'a Vec>, witness_cols: &'a Vec>, 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, - fixed_cols: HashMap<&'a str, &'a Vec>, + constants: &'a HashMap, + fixed_cols: HashMap<&'a str, &'a Vec>, witness_cols: &'a Vec>, witness_ids: HashMap<&'a str, usize>, ) -> Self { diff --git a/src/witness_generator/symbolic_evaluator.rs b/src/witness_generator/symbolic_evaluator.rs index c67a72f9f..f55edf795 100644 --- a/src/witness_generator/symbolic_evaluator.rs +++ b/src/witness_generator/symbolic_evaluator.rs @@ -72,7 +72,7 @@ impl<'a> SymbolicEvaluator<'a> { impl<'a> SymbolicVariables for SymbolicEvaluator<'a> { fn constant(&self, name: &str) -> Result { - Ok(self.fixed_data.constants[name].clone().into()) + Ok(self.fixed_data.constants[name].into()) } fn value(&self, name: &str, next: bool) -> Result { diff --git a/src/witness_generator/symbolic_witness_evaluator.rs b/src/witness_generator/symbolic_witness_evaluator.rs index 7055d0a2d..8bc34efe7 100644 --- a/src/witness_generator/symbolic_witness_evaluator.rs +++ b/src/witness_generator/symbolic_witness_evaluator.rs @@ -42,7 +42,7 @@ where WA: WitnessColumnEvaluator + WitnessColumnNamer, { fn constant(&self, name: &str) -> Result { - Ok(self.fixed_data.constants[name].clone().into()) + Ok(self.fixed_data.constants[name].into()) } fn value(&self, name: &str, next: bool) -> Result { @@ -62,7 +62,7 @@ where } else { self.row }; - Ok(values[row as usize].clone().into()) + Ok(values[row as usize].into()) } } diff --git a/tests/asm.rs b/tests/asm.rs index adc141154..dae81c9fb 100644 --- a/tests/asm.rs +++ b/tests/asm.rs @@ -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) { +fn verify_asm(file_name: &str, inputs: Vec) { let contents = fs::read_to_string(format!("./tests/asm_data/{file_name}")).unwrap(); verify_asm_string(file_name, &contents, inputs) } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 02f822da8..c9f1c5e01 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -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) { +pub fn verify_asm_string(file_name: &str, contents: &str, inputs: Vec) { 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(); diff --git a/tests/pil.rs b/tests/pil.rs index 15e056633..fdd38d7fc 100644 --- a/tests/pil.rs +++ b/tests/pil.rs @@ -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 Option>) { +pub fn verify_pil(file_name: &str, query_callback: Option Option>) { let input_file = Path::new(&format!("./tests/pil_data/{file_name}")) .canonicalize() .unwrap(); diff --git a/tests/riscv.rs b/tests/riscv.rs index 7a5a285eb..b1c646f5d 100644 --- a/tests/riscv.rs +++ b/tests/riscv.rs @@ -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) { +fn verify_file(case: &str, inputs: Vec) { 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) { +fn verify_crate(case: &str, inputs: Vec) { let riscv_asm = powdr::riscv::compile_rust_crate_to_riscv_asm(&format!( "tests/riscv_data/{case}/Cargo.toml" ));