diff --git a/.github/workflows/publish-acvm.yml b/.github/workflows/publish-acvm.yml index 06876f27c8..59a104e3f7 100644 --- a/.github/workflows/publish-acvm.yml +++ b/.github/workflows/publish-acvm.yml @@ -51,12 +51,6 @@ jobs: env: CARGO_REGISTRY_TOKEN: ${{ secrets.ACVM_CRATES_IO_TOKEN }} - - name: Publish acvm_stdlib - run: | - cargo publish --package acvm_stdlib - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.ACVM_CRATES_IO_TOKEN }} - - name: Publish brillig_vm run: | cargo publish --package brillig_vm diff --git a/Cargo.lock b/Cargo.lock index b8478357f9..129840f67f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,7 +41,6 @@ version = "0.37.1" dependencies = [ "acir", "acvm_blackbox_solver", - "acvm_stdlib", "brillig_vm", "indexmap 1.9.3", "log", @@ -87,13 +86,6 @@ dependencies = [ "wasm-logger", ] -[[package]] -name = "acvm_stdlib" -version = "0.37.1" -dependencies = [ - "acir", -] - [[package]] name = "addr2line" version = "0.20.0" diff --git a/Cargo.toml b/Cargo.toml index a49b7c97f1..5a7499f21a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,6 @@ members = [ "acvm-repo/acir", "acvm-repo/acvm", "acvm-repo/acvm_js", - "acvm-repo/stdlib", "acvm-repo/brillig", "acvm-repo/brillig_vm", "acvm-repo/blackbox_solver", diff --git a/acvm-repo/acir/src/circuit/black_box_functions.rs b/acvm-repo/acir/src/circuit/black_box_functions.rs index 9129f44008..d00cd6d28d 100644 --- a/acvm-repo/acir/src/circuit/black_box_functions.rs +++ b/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -1,8 +1,5 @@ //! Black box functions are ACIR opcodes which rely on backends implementing support for specialized constraints. //! This makes certain zk-snark unfriendly computations cheaper than if they were implemented in more basic constraints. -//! -//! It is possible to fallback to less efficient implementations written in ACIR in some cases. -//! These are implemented inside the ACVM stdlib. use serde::{Deserialize, Serialize}; #[cfg(test)] diff --git a/acvm-repo/acir/src/circuit/opcodes.rs b/acvm-repo/acir/src/circuit/opcodes.rs index dc7f73b47e..62566fee7f 100644 --- a/acvm-repo/acir/src/circuit/opcodes.rs +++ b/acvm-repo/acir/src/circuit/opcodes.rs @@ -33,21 +33,6 @@ pub enum Opcode { }, } -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum UnsupportedMemoryOpcode { - MemoryOp, - MemoryInit, -} - -impl std::fmt::Display for UnsupportedMemoryOpcode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - UnsupportedMemoryOpcode::MemoryOp => write!(f, "MemoryOp"), - UnsupportedMemoryOpcode::MemoryInit => write!(f, "MemoryInit"), - } - } -} - impl Opcode { // TODO We can add a domain separator by doing something like: // TODO concat!("directive:", directive.name) @@ -62,17 +47,6 @@ impl Opcode { } } - pub fn unsupported_opcode(&self) -> UnsupportedMemoryOpcode { - match self { - Opcode::MemoryOp { .. } => UnsupportedMemoryOpcode::MemoryOp, - Opcode::MemoryInit { .. } => UnsupportedMemoryOpcode::MemoryInit, - Opcode::BlackBoxFuncCall(_) => { - unreachable!("Unsupported Blackbox function should not be reported here") - } - _ => unreachable!("Opcode is supported"), - } - } - pub fn is_arithmetic(&self) -> bool { matches!(self, Opcode::Arithmetic(_)) } diff --git a/acvm-repo/acvm/Cargo.toml b/acvm-repo/acvm/Cargo.toml index 6a1ac372ed..498d1a80fe 100644 --- a/acvm-repo/acvm/Cargo.toml +++ b/acvm-repo/acvm/Cargo.toml @@ -19,28 +19,23 @@ thiserror.workspace = true log.workspace = true acir.workspace = true -stdlib.workspace = true brillig_vm.workspace = true acvm_blackbox_solver.workspace = true indexmap = "1.7.0" [features] -default = ["bn254", "testing"] +default = ["bn254"] bn254 = [ "acir/bn254", - "stdlib/bn254", "brillig_vm/bn254", "acvm_blackbox_solver/bn254", ] bls12_381 = [ "acir/bls12_381", - "stdlib/bls12_381", "brillig_vm/bls12_381", "acvm_blackbox_solver/bls12_381", ] -testing = ["stdlib/testing", "unstable-fallbacks"] -unstable-fallbacks = [] [dev-dependencies] rand = "0.8.5" diff --git a/acvm-repo/acvm/src/compiler/mod.rs b/acvm-repo/acvm/src/compiler/mod.rs index 0ed5b59167..1a73f841f3 100644 --- a/acvm-repo/acvm/src/compiler/mod.rs +++ b/acvm-repo/acvm/src/compiler/mod.rs @@ -1,10 +1,6 @@ use std::collections::HashMap; -use acir::{ - circuit::{opcodes::UnsupportedMemoryOpcode, Circuit, Opcode, OpcodeLocation}, - BlackBoxFunc, -}; -use thiserror::Error; +use acir::circuit::{Circuit, OpcodeLocation}; use crate::Language; @@ -17,14 +13,6 @@ use optimizers::optimize_internal; pub use transformers::transform; use transformers::transform_internal; -#[derive(PartialEq, Eq, Debug, Error)] -pub enum CompileError { - #[error("The blackbox function {0} is not supported by the backend and acvm does not have a fallback implementation")] - UnsupportedBlackBox(BlackBoxFunc), - #[error("The opcode {0} is not supported by the backend and acvm does not have a fallback implementation")] - UnsupportedMemoryOpcode(UnsupportedMemoryOpcode), -} - /// This module moves and decomposes acir opcodes. The transformation map allows consumers of this module to map /// metadata they had about the opcodes to the new opcode structure generated after the transformation. #[derive(Debug)] @@ -81,19 +69,15 @@ fn transform_assert_messages( } /// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] specific optimizations to a [`Circuit`]. -pub fn compile( - acir: Circuit, - np_language: Language, - is_opcode_supported: impl Fn(&Opcode) -> bool, -) -> Result<(Circuit, AcirTransformationMap), CompileError> { +pub fn compile(acir: Circuit, np_language: Language) -> (Circuit, AcirTransformationMap) { let (acir, acir_opcode_positions) = optimize_internal(acir); let (mut acir, acir_opcode_positions) = - transform_internal(acir, np_language, is_opcode_supported, acir_opcode_positions)?; + transform_internal(acir, np_language, acir_opcode_positions); let transformation_map = AcirTransformationMap::new(acir_opcode_positions); acir.assert_messages = transform_assert_messages(acir.assert_messages, &transformation_map); - Ok((acir, transformation_map)) + (acir, transformation_map) } diff --git a/acvm-repo/acvm/src/compiler/transformers/fallback.rs b/acvm-repo/acvm/src/compiler/transformers/fallback.rs deleted file mode 100644 index 06dfc84a79..0000000000 --- a/acvm-repo/acvm/src/compiler/transformers/fallback.rs +++ /dev/null @@ -1,158 +0,0 @@ -use super::super::CompileError; -use acir::{ - circuit::{opcodes::BlackBoxFuncCall, Circuit, Opcode}, - native_types::Expression, -}; - -/// The initial transformer to act on a [`Circuit`]. This replaces any unsupported opcodes with -/// fallback implementations consisting of well supported opcodes. -pub(crate) struct FallbackTransformer; - -impl FallbackTransformer { - //ACIR pass which replace unsupported opcodes using arithmetic fallback - pub(crate) fn transform( - acir: Circuit, - is_supported: impl Fn(&Opcode) -> bool, - opcode_positions: Vec, - ) -> Result<(Circuit, Vec), CompileError> { - let mut acir_supported_opcodes = Vec::with_capacity(acir.opcodes.len()); - let mut new_opcode_positions = Vec::with_capacity(opcode_positions.len()); - let mut witness_idx = acir.current_witness_index + 1; - - for (idx, opcode) in acir.opcodes.into_iter().enumerate() { - match &opcode { - Opcode::Arithmetic(_) | Opcode::Directive(_) | Opcode::Brillig(_) => { - // directive, arithmetic expression or blocks are handled by acvm - new_opcode_positions.push(opcode_positions[idx]); - acir_supported_opcodes.push(opcode); - continue; - } - Opcode::MemoryInit { .. } | Opcode::MemoryOp { .. } => { - if !is_supported(&opcode) { - return Err(CompileError::UnsupportedMemoryOpcode( - opcode.unsupported_opcode(), - )); - } - new_opcode_positions.push(opcode_positions[idx]); - acir_supported_opcodes.push(opcode); - } - Opcode::BlackBoxFuncCall(bb_func_call) => { - // We know it is an black box function. Now check if it is - // supported by the backend. If it is supported, then we can simply - // collect the opcode - if is_supported(&opcode) { - new_opcode_positions.push(opcode_positions[idx]); - acir_supported_opcodes.push(opcode); - continue; - } else { - // If we get here then we know that this black box function is not supported - // so we need to replace it with a version of the opcode which only uses arithmetic - // expressions - let (updated_witness_index, opcodes_fallback) = - Self::opcode_fallback(bb_func_call, witness_idx)?; - witness_idx = updated_witness_index; - new_opcode_positions - .extend(vec![opcode_positions[idx]; opcodes_fallback.len()]); - acir_supported_opcodes.extend(opcodes_fallback); - } - } - } - } - - Ok(( - Circuit { - current_witness_index: witness_idx - 1, - opcodes: acir_supported_opcodes, - ..acir - }, - new_opcode_positions, - )) - } - - fn opcode_fallback( - gc: &BlackBoxFuncCall, - current_witness_idx: u32, - ) -> Result<(u32, Vec), CompileError> { - let (updated_witness_index, opcodes_fallback) = match gc { - BlackBoxFuncCall::AND { lhs, rhs, output } => { - assert_eq!( - lhs.num_bits, rhs.num_bits, - "number of bits specified for each input must be the same" - ); - stdlib::blackbox_fallbacks::and( - Expression::from(lhs.witness), - Expression::from(rhs.witness), - *output, - lhs.num_bits, - current_witness_idx, - ) - } - BlackBoxFuncCall::XOR { lhs, rhs, output } => { - assert_eq!( - lhs.num_bits, rhs.num_bits, - "number of bits specified for each input must be the same" - ); - stdlib::blackbox_fallbacks::xor( - Expression::from(lhs.witness), - Expression::from(rhs.witness), - *output, - lhs.num_bits, - current_witness_idx, - ) - } - BlackBoxFuncCall::RANGE { input } => { - // Note there are no outputs because range produces no outputs - stdlib::blackbox_fallbacks::range( - Expression::from(input.witness), - input.num_bits, - current_witness_idx, - ) - } - #[cfg(feature = "unstable-fallbacks")] - BlackBoxFuncCall::SHA256 { inputs, outputs } => { - let sha256_inputs = - inputs.iter().map(|input| (input.witness.into(), input.num_bits)).collect(); - stdlib::blackbox_fallbacks::sha256( - sha256_inputs, - outputs.to_vec(), - current_witness_idx, - ) - } - #[cfg(feature = "unstable-fallbacks")] - BlackBoxFuncCall::Blake2s { inputs, outputs } => { - let blake2s_inputs = - inputs.iter().map(|input| (input.witness.into(), input.num_bits)).collect(); - stdlib::blackbox_fallbacks::blake2s( - blake2s_inputs, - outputs.to_vec(), - current_witness_idx, - ) - } - #[cfg(feature = "unstable-fallbacks")] - BlackBoxFuncCall::HashToField128Security { inputs, output } => { - let hash_to_field_inputs = - inputs.iter().map(|input| (input.witness.into(), input.num_bits)).collect(); - stdlib::blackbox_fallbacks::hash_to_field( - hash_to_field_inputs, - *output, - current_witness_idx, - ) - } - #[cfg(feature = "unstable-fallbacks")] - BlackBoxFuncCall::Keccak256 { inputs, outputs } => { - let keccak_inputs = - inputs.iter().map(|input| (input.witness.into(), input.num_bits)).collect(); - stdlib::blackbox_fallbacks::keccak256( - keccak_inputs, - outputs.to_vec(), - current_witness_idx, - ) - } - _ => { - return Err(CompileError::UnsupportedBlackBox(gc.get_black_box_func())); - } - }; - - Ok((updated_witness_index, opcodes_fallback)) - } -} diff --git a/acvm-repo/acvm/src/compiler/transformers/mod.rs b/acvm-repo/acvm/src/compiler/transformers/mod.rs index c4c94e371b..fc406ba2b5 100644 --- a/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -8,33 +8,27 @@ use indexmap::IndexMap; use crate::Language; mod csat; -mod fallback; mod r1cs; pub(crate) use csat::CSatTransformer; -pub(crate) use fallback::FallbackTransformer; pub(crate) use r1cs::R1CSTransformer; -use super::{transform_assert_messages, AcirTransformationMap, CompileError}; +use super::{transform_assert_messages, AcirTransformationMap}; /// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] specific optimizations to a [`Circuit`]. -pub fn transform( - acir: Circuit, - np_language: Language, - is_opcode_supported: impl Fn(&Opcode) -> bool, -) -> Result<(Circuit, AcirTransformationMap), CompileError> { +pub fn transform(acir: Circuit, np_language: Language) -> (Circuit, AcirTransformationMap) { // Track original acir opcode positions throughout the transformation passes of the compilation // by applying the modifications done to the circuit opcodes and also to the opcode_positions (delete and insert) let acir_opcode_positions = acir.opcodes.iter().enumerate().map(|(i, _)| i).collect(); let (mut acir, acir_opcode_positions) = - transform_internal(acir, np_language, is_opcode_supported, acir_opcode_positions)?; + transform_internal(acir, np_language, acir_opcode_positions); let transformation_map = AcirTransformationMap::new(acir_opcode_positions); acir.assert_messages = transform_assert_messages(acir.assert_messages, &transformation_map); - Ok((acir, transformation_map)) + (acir, transformation_map) } /// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] specific optimizations to a [`Circuit`]. @@ -43,19 +37,14 @@ pub fn transform( pub(super) fn transform_internal( acir: Circuit, np_language: Language, - is_opcode_supported: impl Fn(&Opcode) -> bool, acir_opcode_positions: Vec, -) -> Result<(Circuit, Vec), CompileError> { +) -> (Circuit, Vec) { log::trace!("Start circuit transformation"); - // Fallback transformer pass - let (acir, acir_opcode_positions) = - FallbackTransformer::transform(acir, is_opcode_supported, acir_opcode_positions)?; - let mut transformer = match &np_language { crate::Language::R1CS => { let transformer = R1CSTransformer::new(acir); - return Ok((transformer.transform(), acir_opcode_positions)); + return (transformer.transform(), acir_opcode_positions); } crate::Language::PLONKCSat { width } => { let mut csat = CSatTransformer::new(*width); @@ -219,5 +208,5 @@ pub(super) fn transform_internal( log::trace!("Finish circuit transformation"); - Ok((acir, new_acir_opcode_positions)) + (acir, new_acir_opcode_positions) } diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index c1edf60161..859ad010dc 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -11,7 +11,7 @@ use acir::{ use acvm_blackbox_solver::BlackBoxResolutionError; use self::{arithmetic::ArithmeticSolver, directives::solve_directives, memory_op::MemoryOpSolver}; -use crate::{BlackBoxFunctionSolver, Language}; +use crate::BlackBoxFunctionSolver; use thiserror::Error; @@ -104,8 +104,6 @@ impl std::fmt::Display for ErrorLocation { pub enum OpcodeResolutionError { #[error("Cannot solve opcode: {0}")] OpcodeNotSolvable(#[from] OpcodeNotSolvable), - #[error("Backend does not currently support the {0} opcode. ACVM does not currently have a fallback for this opcode.")] - UnsupportedBlackBoxFunc(BlackBoxFunc), #[error("Cannot satisfy constraint")] UnsatisfiedConstrain { opcode_location: ErrorLocation }, #[error("Index out of bounds, array has size {array_size:?}, but index was {index:?}")] @@ -122,9 +120,6 @@ impl From for OpcodeResolutionError { BlackBoxResolutionError::Failed(func, reason) => { OpcodeResolutionError::BlackBoxFunctionFailed(func, reason) } - BlackBoxResolutionError::Unsupported(func) => { - OpcodeResolutionError::UnsupportedBlackBoxFunc(func) - } } } } @@ -450,30 +445,3 @@ fn any_witness_from_expression(expr: &Expression) -> Option { Some(expr.linear_combinations[0].1) } } - -#[deprecated( - note = "For backwards compatibility, this method allows you to derive _sensible_ defaults for opcode support based on the np language. \n Backends should simply specify what they support." -)] -// This is set to match the previous functionality that we had -// Where we could deduce what opcodes were supported -// by knowing the np complete language -pub fn default_is_opcode_supported(language: Language) -> fn(&Opcode) -> bool { - // R1CS does not support any of the opcode except Arithmetic by default. - // The compiler will replace those that it can -- ie range, xor, and - fn r1cs_is_supported(opcode: &Opcode) -> bool { - matches!(opcode, Opcode::Arithmetic(_)) - } - - // PLONK supports most of the opcodes by default - // The ones which are not supported, the acvm compiler will - // attempt to transform into supported opcodes. If these are also not available - // then a compiler error will be emitted. - fn plonk_is_supported(_opcode: &Opcode) -> bool { - true - } - - match language { - Language::R1CS => r1cs_is_supported, - Language::PLONKCSat { .. } => plonk_is_supported, - } -} diff --git a/acvm-repo/acvm/tests/stdlib.rs b/acvm-repo/acvm/tests/stdlib.rs deleted file mode 100644 index c96c55f940..0000000000 --- a/acvm-repo/acvm/tests/stdlib.rs +++ /dev/null @@ -1,354 +0,0 @@ -#![cfg(feature = "testing")] -mod solver; -use crate::solver::StubbedBackend; -use acir::{ - circuit::{ - opcodes::{BlackBoxFuncCall, FunctionInput}, - Circuit, Opcode, - }, - native_types::{Expression, Witness}, - FieldElement, -}; -use acvm::{ - compiler::compile, - pwg::{ACVMStatus, ACVM}, - Language, -}; -use acvm_blackbox_solver::{blake2s, hash_to_field_128_security, keccak256, sha256}; -use paste::paste; -use proptest::prelude::*; -use std::collections::{BTreeMap, BTreeSet}; -use stdlib::blackbox_fallbacks::{UInt32, UInt64, UInt8}; - -test_uint!(test_uint8, UInt8, u8, 8); -test_uint!(test_uint32, UInt32, u32, 32); -test_uint!(test_uint64, UInt64, u64, 64); - -#[macro_export] -macro_rules! test_uint { - ( - $name:tt, - $uint:ident, - $u:ident, - $size:expr - ) => { - paste! { - test_uint_inner!( - [<$name _rol>], - [<$name _ror>], - [<$name _euclidean_division>], - [<$name _add>], - [<$name _sub>], - [<$name _left_shift>], - [<$name _right_shift>], - [<$name _less_than>], - $uint, - $u, - $size - ); - } - }; -} - -#[macro_export] -macro_rules! test_uint_inner { - ( - $rol:tt, - $ror:tt, - $euclidean_division:tt, - $add:tt, - $sub:tt, - $left_shift:tt, - $right_shift:tt, - $less_than:tt, - $uint: ident, - $u: ident, - $size: expr - ) => { - proptest! { - #[test] - fn $rol(x in 0..$u::MAX, y in 0..32_u32) { - let fe = FieldElement::from(x as u128); - let w = Witness(1); - let result = x.rotate_left(y); - let uint = $uint::new(w); - let (w, extra_opcodes, _) = uint.rol(y, 2); - let witness_assignments = BTreeMap::from([(Witness(1), fe)]).into(); - let mut acvm = ACVM::new(&StubbedBackend, &extra_opcodes, witness_assignments); - let solver_status = acvm.solve(); - - prop_assert_eq!(acvm.witness_map().get(&w.get_inner()).unwrap(), &FieldElement::from(result as u128)); - prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); - } - - #[test] - fn $ror(x in 0..$u::MAX, y in 0..32_u32) { - let fe = FieldElement::from(x as u128); - let w = Witness(1); - let result = x.rotate_right(y); - let uint = $uint::new(w); - let (w, extra_opcodes, _) = uint.ror(y, 2); - let witness_assignments = BTreeMap::from([(Witness(1), fe)]).into(); - let mut acvm = ACVM::new(&StubbedBackend, &extra_opcodes, witness_assignments); - let solver_status = acvm.solve(); - - prop_assert_eq!(acvm.witness_map().get(&w.get_inner()).unwrap(), &FieldElement::from(result as u128)); - prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); - } - - #[test] - fn $euclidean_division(x in 0..$u::MAX, y in 1 - ..$u::MAX) { - let lhs = FieldElement::from(x as u128); - let rhs = FieldElement::from(y as u128); - let w1 = Witness(1); - let w2 = Witness(2); - let q = x.div_euclid(y); - let r = x.rem_euclid(y); - let u32_1 = $uint::new(w1); - let u32_2 = $uint::new(w2); - let (q_w, r_w, extra_opcodes, _) = $uint::euclidean_division(&u32_1, &u32_2, 3); - let witness_assignments = BTreeMap::from([(Witness(1), lhs),(Witness(2), rhs)]).into(); - let mut acvm = ACVM::new(&StubbedBackend, &extra_opcodes, witness_assignments); - let solver_status = acvm.solve(); - - prop_assert_eq!(acvm.witness_map().get(&q_w.get_inner()).unwrap(), &FieldElement::from(q as u128)); - prop_assert_eq!(acvm.witness_map().get(&r_w.get_inner()).unwrap(), &FieldElement::from(r as u128)); - prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); - } - - #[test] - fn $add(x in 0..$u::MAX, y in 0..$u::MAX, z in 0..$u::MAX) { - let lhs = FieldElement::from(x as u128); - let rhs = FieldElement::from(y as u128); - let rhs_z = FieldElement::from(z as u128); - let result = FieldElement::from(((x as u128).wrapping_add(y as u128) % (1_u128 << $size)).wrapping_add(z as u128) % (1_u128 << $size)); - let w1 = Witness(1); - let w2 = Witness(2); - let w3 = Witness(3); - let u32_1 = $uint::new(w1); - let u32_2 = $uint::new(w2); - let u32_3 = $uint::new(w3); - let mut opcodes = Vec::new(); - let (w, extra_opcodes, num_witness) = u32_1.add(&u32_2, 4); - opcodes.extend(extra_opcodes); - let (w2, extra_opcodes, _) = w.add(&u32_3, num_witness); - opcodes.extend(extra_opcodes); - let witness_assignments = BTreeMap::from([(Witness(1), lhs), (Witness(2), rhs), (Witness(3), rhs_z)]).into(); - let mut acvm = ACVM::new(&StubbedBackend, &opcodes, witness_assignments); - let solver_status = acvm.solve(); - - prop_assert_eq!(acvm.witness_map().get(&w2.get_inner()).unwrap(), &result); - prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); - } - - #[test] - fn $sub(x in 0..$u::MAX, y in 0..$u::MAX, z in 0..$u::MAX) { - let lhs = FieldElement::from(x as u128); - let rhs = FieldElement::from(y as u128); - let rhs_z = FieldElement::from(z as u128); - let result = FieldElement::from(((x as u128).wrapping_sub(y as u128) % (1_u128 << $size)).wrapping_sub(z as u128) % (1_u128 << $size)); - let w1 = Witness(1); - let w2 = Witness(2); - let w3 = Witness(3); - let u32_1 = $uint::new(w1); - let u32_2 = $uint::new(w2); - let u32_3 = $uint::new(w3); - let mut opcodes = Vec::new(); - let (w, extra_opcodes, num_witness) = u32_1.sub(&u32_2, 4); - opcodes.extend(extra_opcodes); - let (w2, extra_opcodes, _) = w.sub(&u32_3, num_witness); - opcodes.extend(extra_opcodes); - let witness_assignments = BTreeMap::from([(Witness(1), lhs), (Witness(2), rhs), (Witness(3), rhs_z)]).into(); - let mut acvm = ACVM::new(&StubbedBackend, &opcodes, witness_assignments); - let solver_status = acvm.solve(); - - prop_assert_eq!(acvm.witness_map().get(&w2.get_inner()).unwrap(), &result); - prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); - } - - #[test] - fn $left_shift(x in 0..$u::MAX, y in 0..32_u32) { - let lhs = FieldElement::from(x as u128); - let w1 = Witness(1); - let result = x.overflowing_shl(y).0; - let u32_1 = $uint::new(w1); - let (w, extra_opcodes, _) = u32_1.leftshift(y, 2); - let witness_assignments = BTreeMap::from([(Witness(1), lhs)]).into(); - let mut acvm = ACVM::new(&StubbedBackend, &extra_opcodes, witness_assignments); - let solver_status = acvm.solve(); - - prop_assert_eq!(acvm.witness_map().get(&w.get_inner()).unwrap(), &FieldElement::from(result as u128)); - prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); - } - - #[test] - fn $right_shift(x in 0..$u::MAX, y in 0..32_u32) { - let lhs = FieldElement::from(x as u128); - let w1 = Witness(1); - let result = x.overflowing_shr(y).0; - let u32_1 = $uint::new(w1); - let (w, extra_opcodes, _) = u32_1.rightshift(y, 2); - let witness_assignments = BTreeMap::from([(Witness(1), lhs)]).into(); - let mut acvm = ACVM::new(&StubbedBackend, &extra_opcodes, witness_assignments); - let solver_status = acvm.solve(); - - prop_assert_eq!(acvm.witness_map().get(&w.get_inner()).unwrap(), &FieldElement::from(result as u128)); - prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); - } - - #[test] - fn $less_than(x in 0..$u::MAX, y in 0..$u::MAX) { - let lhs = FieldElement::from(x as u128); - let rhs = FieldElement::from(y as u128); - let w1 = Witness(1); - let w2 = Witness(2); - let result = x < y; - let u32_1 = $uint::new(w1); - let u32_2 = $uint::new(w2); - let (w, extra_opcodes, _) = u32_1.less_than_comparison(&u32_2, 3); - let witness_assignments = BTreeMap::from([(Witness(1), lhs), (Witness(2), rhs)]).into(); - let mut acvm = ACVM::new(&StubbedBackend, &extra_opcodes, witness_assignments); - let solver_status = acvm.solve(); - - prop_assert_eq!(acvm.witness_map().get(&w.get_inner()).unwrap(), &FieldElement::from(result as u128)); - prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); - } - } - }; -} - -test_hashes!(test_sha256, sha256, SHA256, does_not_support_sha256); -test_hashes!(test_blake2s, blake2s, Blake2s, does_not_support_blake2s); -test_hashes!(test_keccak, keccak256, Keccak256, does_not_support_keccak); - -fn does_not_support_sha256(opcode: &Opcode) -> bool { - !matches!(opcode, Opcode::BlackBoxFuncCall(BlackBoxFuncCall::SHA256 { .. })) -} -fn does_not_support_blake2s(opcode: &Opcode) -> bool { - !matches!(opcode, Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Blake2s { .. })) -} -fn does_not_support_keccak(opcode: &Opcode) -> bool { - !matches!(opcode, Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Keccak256 { .. })) -} - -#[macro_export] -macro_rules! test_hashes { - ( - $name:ident, - $hasher:ident, - $opcode:ident, - $opcode_support: ident - ) => { - proptest! { - #![proptest_config(ProptestConfig::with_cases(3))] - #[test] - fn $name(input_values in proptest::collection::vec(0..u8::MAX, 1..50)) { - let mut opcodes = Vec::new(); - let mut witness_assignments = BTreeMap::new(); - let mut input_witnesses: Vec = Vec::new(); - let mut correct_result_witnesses: Vec = Vec::new(); - let mut output_witnesses: Vec = Vec::new(); - - // prepare test data - let mut counter = 0; - let output = $hasher(&input_values).unwrap(); - for inp_v in input_values { - counter += 1; - let function_input = FunctionInput { witness: Witness(counter), num_bits: 8 }; - input_witnesses.push(function_input); - witness_assignments.insert(Witness(counter), FieldElement::from(inp_v as u128)); - } - - for o_v in output { - counter += 1; - correct_result_witnesses.push(Witness(counter)); - witness_assignments.insert(Witness(counter), FieldElement::from(o_v as u128)); - } - - for _ in 0..32 { - counter += 1; - output_witnesses.push(Witness(counter)); - } - let blackbox = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::$opcode { inputs: input_witnesses, outputs: output_witnesses.clone() }); - opcodes.push(blackbox); - - // constrain the output to be the same as the hasher - for i in 0..correct_result_witnesses.len() { - let mut output_constraint = Expression::from(correct_result_witnesses[i]); - output_constraint.push_addition_term(-FieldElement::one(), output_witnesses[i]); - opcodes.push(Opcode::Arithmetic(output_constraint)); - } - - // compile circuit - let circuit = Circuit { - current_witness_index: witness_assignments.len() as u32 + 32, - opcodes, - private_parameters: BTreeSet::new(), // This is not correct but is unused in this test. - ..Circuit::default() - }; - let circuit = compile(circuit, Language::PLONKCSat{ width: 3 }, $opcode_support).unwrap().0; - - // solve witnesses - let mut acvm = ACVM::new(&StubbedBackend, &circuit.opcodes, witness_assignments.into()); - let solver_status = acvm.solve(); - - prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); - } - } - }; -} - -fn does_not_support_hash_to_field(opcode: &Opcode) -> bool { - !matches!(opcode, Opcode::BlackBoxFuncCall(BlackBoxFuncCall::HashToField128Security { .. })) -} - -proptest! { - #![proptest_config(ProptestConfig::with_cases(3))] - #[test] - fn test_hash_to_field(input_values in proptest::collection::vec(0..u8::MAX, 1..50)) { - let mut opcodes = Vec::new(); - let mut witness_assignments = BTreeMap::new(); - let mut input_witnesses: Vec = Vec::new(); - - // prepare test data - let mut counter = 0; - let output = hash_to_field_128_security(&input_values).unwrap(); - for inp_v in input_values { - counter += 1; - let function_input = FunctionInput { witness: Witness(counter), num_bits: 8 }; - input_witnesses.push(function_input); - witness_assignments.insert(Witness(counter), FieldElement::from(inp_v as u128)); - } - - counter += 1; - let correct_result_witnesses: Witness = Witness(counter); - witness_assignments.insert(Witness(counter), output); - - counter += 1; - let output_witness: Witness = Witness(counter); - - let blackbox = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::HashToField128Security { inputs: input_witnesses, output: output_witness }); - opcodes.push(blackbox); - - // constrain the output to be the same as the hasher - let mut output_constraint = Expression::from(correct_result_witnesses); - output_constraint.push_addition_term(-FieldElement::one(), output_witness); - opcodes.push(Opcode::Arithmetic(output_constraint)); - - // compile circuit - let circuit = Circuit { - current_witness_index: witness_assignments.len() as u32 + 1, - opcodes, - private_parameters: BTreeSet::new(), // This is not correct but is unused in this test. - ..Circuit::default() - }; - let circuit = compile(circuit, Language::PLONKCSat{ width: 3 }, does_not_support_hash_to_field).unwrap().0; - - // solve witnesses - let mut acvm = ACVM::new(&StubbedBackend, &circuit.opcodes, witness_assignments.into()); - let solver_status = acvm.solve(); - - prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); - } -} diff --git a/acvm-repo/blackbox_solver/src/lib.rs b/acvm-repo/blackbox_solver/src/lib.rs index 13d0f56241..8b7c634396 100644 --- a/acvm-repo/blackbox_solver/src/lib.rs +++ b/acvm-repo/blackbox_solver/src/lib.rs @@ -16,8 +16,6 @@ use thiserror::Error; #[derive(Clone, PartialEq, Eq, Debug, Error)] pub enum BlackBoxResolutionError { - #[error("unsupported blackbox function: {0}")] - Unsupported(BlackBoxFunc), #[error("failed to solve blackbox function: {0}, reason: {1}")] Failed(BlackBoxFunc, String), } diff --git a/acvm-repo/stdlib/CHANGELOG.md b/acvm-repo/stdlib/CHANGELOG.md deleted file mode 100644 index bea80c95d1..0000000000 --- a/acvm-repo/stdlib/CHANGELOG.md +++ /dev/null @@ -1,350 +0,0 @@ -# Changelog - -## [0.27.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.26.1...acvm_stdlib-v0.27.0) (2023-09-19) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.26.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.26.0...acvm_stdlib-v0.26.1) (2023-09-12) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.26.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.25.0...acvm_stdlib-v0.26.0) (2023-09-07) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.25.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.24.1...acvm_stdlib-v0.25.0) (2023-09-04) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.24.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.24.0...acvm_stdlib-v0.24.1) (2023-09-03) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.24.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.23.0...acvm_stdlib-v0.24.0) (2023-08-31) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.23.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.22.0...acvm_stdlib-v0.23.0) (2023-08-30) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.22.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.21.0...acvm_stdlib-v0.22.0) (2023-08-18) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.21.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.20.1...acvm_stdlib-v0.21.0) (2023-07-26) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.20.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.20.0...acvm_stdlib-v0.20.1) (2023-07-26) - - -### Features - -* add optimisations to fallback black box functions on booleans ([#446](https://github.com/noir-lang/acvm/issues/446)) ([2cfb2a8](https://github.com/noir-lang/acvm/commit/2cfb2a8cf911a81eedbd9da13ab2c616abd67f83)) -* **stdlib:** Add fallback implementation of `Keccak256` black box function ([#445](https://github.com/noir-lang/acvm/issues/445)) ([f7ebb03](https://github.com/noir-lang/acvm/commit/f7ebb03653c971f119700ff8126d9eb5ff01be0f)) - -## [0.20.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.19.1...acvm_stdlib-v0.20.0) (2023-07-20) - - -### Features - -* **stdlib:** Add fallback implementation of `HashToField128Security` black box function ([#435](https://github.com/noir-lang/acvm/issues/435)) ([ed40f22](https://github.com/noir-lang/acvm/commit/ed40f228529e888d1960bfa70cb92b277e24b37f)) - -## [0.19.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.19.0...acvm_stdlib-v0.19.1) (2023-07-17) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.19.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.18.2...acvm_stdlib-v0.19.0) (2023-07-15) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.18.2](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.18.1...acvm_stdlib-v0.18.2) (2023-07-12) - - -### Features - -* **stdlib:** Add fallback implementation of `Blake2s` black box function ([#424](https://github.com/noir-lang/acvm/issues/424)) ([982d940](https://github.com/noir-lang/acvm/commit/982d94087d46092ce7a5e94dbd7e732195f58e42)) - -## [0.18.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.18.0...acvm_stdlib-v0.18.1) (2023-07-12) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.18.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.17.0...acvm_stdlib-v0.18.0) (2023-07-12) - - -### Features - -* **stdlib:** Add fallback implementation of `SHA256` black box function ([#407](https://github.com/noir-lang/acvm/issues/407)) ([040369a](https://github.com/noir-lang/acvm/commit/040369adc8749fa5ec2edd255ff54c105c3140f5)) - -## [0.17.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.16.0...acvm_stdlib-v0.17.0) (2023-07-07) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.16.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.15.1...acvm_stdlib-v0.16.0) (2023-07-06) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.15.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.15.0...acvm_stdlib-v0.15.1) (2023-06-20) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.15.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.14.2...acvm_stdlib-v0.15.0) (2023-06-15) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.14.2](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.14.1...acvm_stdlib-v0.14.2) (2023-06-08) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.14.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.14.0...acvm_stdlib-v0.14.1) (2023-06-07) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.14.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.13.3...acvm_stdlib-v0.14.0) (2023-06-06) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.13.3](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.13.2...acvm_stdlib-v0.13.3) (2023-06-05) - - -### Bug Fixes - -* Empty commit to trigger release-please ([e8f0748](https://github.com/noir-lang/acvm/commit/e8f0748042ef505d59ab63266d3c36c5358ee30d)) - -## [0.13.2](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.13.1...acvm_stdlib-v0.13.2) (2023-06-02) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.13.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.13.0...acvm_stdlib-v0.13.1) (2023-06-01) - - -### Bug Fixes - -* **ci:** Correct typo to avoid `undefined` in changelogs ([#333](https://github.com/noir-lang/acvm/issues/333)) ([d3424c0](https://github.com/noir-lang/acvm/commit/d3424c04fd303c9cbe25d03118d8b358cbb84b83)) - -## [0.13.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.12.0...acvm_stdlib-v0.13.0) (2023-06-01) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.12.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.11.0...acvm_stdlib-v0.12.0) (2023-05-17) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.11.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.10.3...acvm_stdlib-v0.11.0) (2023-05-04) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.10.3](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.10.2...acvm_stdlib-v0.10.3) (2023-04-28) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.10.2](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.10.1...acvm_stdlib-v0.10.2) (2023-04-28) - - -### Bug Fixes - -* add default flag to `acvm_stdlib` ([#242](https://github.com/noir-lang/acvm/issues/242)) ([83b6fa8](https://github.com/noir-lang/acvm/commit/83b6fa8302569add7e3ac8481b2fd2a6a1ff3576)) - -## [0.10.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.10.0...acvm_stdlib-v0.10.1) (2023-04-28) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.10.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.9.0...acvm_stdlib-v0.10.0) (2023-04-26) - - -### ⚠ BREAKING CHANGES - -* organise operator implementations for Expression ([#190](https://github.com/noir-lang/acvm/issues/190)) - -### Bug Fixes - -* prevent `bn254` feature flag always being enabled ([#225](https://github.com/noir-lang/acvm/issues/225)) ([82eee6a](https://github.com/noir-lang/acvm/commit/82eee6ab08ae480f04904ca8571fd88f4466c000)) - - -### Miscellaneous Chores - -* organise operator implementations for Expression ([#190](https://github.com/noir-lang/acvm/issues/190)) ([a619df6](https://github.com/noir-lang/acvm/commit/a619df614bbb9b2518b788b42a7553b069823a0f)) - -## [0.9.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.8.1...acvm_stdlib-v0.9.0) (2023-04-07) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.8.1 to 0.9.0 - -## [0.8.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.8.0...acvm_stdlib-v0.8.1) (2023-03-30) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.8.0 to 0.8.1 - -## [0.8.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.7.1...acvm_stdlib-v0.8.0) (2023-03-28) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.7.1 to 0.8.0 - -## [0.7.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.7.0...acvm_stdlib-v0.7.1) (2023-03-27) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.7.0 to 0.7.1 - -## [0.7.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.6.0...acvm_stdlib-v0.7.0) (2023-03-23) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.6.0 to 0.7.0 - -## [0.6.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.5.0...acvm_stdlib-v0.6.0) (2023-03-03) - - -### ⚠ BREAKING CHANGES - -* **acir:** rename `term_addition` to `push_addition_term` -* **acir:** rename `term_multiplication` to `push_multiplication_term` ([#122](https://github.com/noir-lang/acvm/issues/122)) - -### Miscellaneous Chores - -* **acir:** rename `term_addition` to `push_addition_term` ([d389385](https://github.com/noir-lang/acvm/commit/d38938542851a97dc01727438391e6a65e44c689)) -* **acir:** rename `term_multiplication` to `push_multiplication_term` ([#122](https://github.com/noir-lang/acvm/issues/122)) ([d389385](https://github.com/noir-lang/acvm/commit/d38938542851a97dc01727438391e6a65e44c689)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.5.0 to 0.6.0 - -## [0.5.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.4.1...acvm_stdlib-v0.5.0) (2023-02-22) - - -### ⚠ BREAKING CHANGES - -* refactor ToRadix to ToRadixLe and ToRadixBe ([#58](https://github.com/noir-lang/acvm/issues/58)) - -### Miscellaneous Chores - -* refactor ToRadix to ToRadixLe and ToRadixBe ([#58](https://github.com/noir-lang/acvm/issues/58)) ([2427a27](https://github.com/noir-lang/acvm/commit/2427a275048e598c6d651cce8348a4c55148f235)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.4.1 to 0.5.0 diff --git a/acvm-repo/stdlib/Cargo.toml b/acvm-repo/stdlib/Cargo.toml deleted file mode 100644 index 689411d335..0000000000 --- a/acvm-repo/stdlib/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "acvm_stdlib" -description = "The ACVM standard library." -# x-release-please-start-version -version = "0.37.1" -# x-release-please-end -authors.workspace = true -edition.workspace = true -license.workspace = true -rust-version.workspace = true -repository.workspace = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -acir.workspace = true - -[features] -default = ["bn254"] -bn254 = ["acir/bn254"] -bls12_381 = ["acir/bls12_381"] -testing = ["bn254"] diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/blake2s.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/blake2s.rs deleted file mode 100644 index 92bf93d2d5..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/blake2s.rs +++ /dev/null @@ -1,468 +0,0 @@ -//! Blake2s fallback function. -use super::{ - utils::{byte_decomposition, round_to_nearest_byte}, - UInt32, -}; -use acir::{ - circuit::Opcode, - native_types::{Expression, Witness}, - FieldElement, -}; -use std::vec; - -const BLAKE2S_BLOCKBYTES_USIZE: usize = 64; -const MSG_SCHEDULE_BLAKE2: [[usize; 16]; 10] = [ - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], - [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], - [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], - [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], - [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], - [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], - [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], - [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], - [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], -]; -const INITIAL_H: [u32; 8] = [ - 0x6b08e647, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, -]; -const IV_VALUE: [u32; 8] = [ - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, -]; - -pub fn blake2s( - inputs: Vec<(Expression, u32)>, - outputs: Vec, - mut num_witness: u32, -) -> (u32, Vec) { - let mut new_opcodes = Vec::new(); - let mut new_inputs = Vec::new(); - - // Decompose the input field elements into bytes and collect the resulting witnesses. - for (witness, num_bits) in inputs { - let num_bytes = round_to_nearest_byte(num_bits); - let (extra_opcodes, extra_inputs, updated_witness_counter) = - byte_decomposition(witness, num_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - new_inputs.extend(extra_inputs); - num_witness = updated_witness_counter; - } - - let (result, num_witness, extra_opcodes) = create_blake2s_constraint(new_inputs, num_witness); - new_opcodes.extend(extra_opcodes); - - // constrain the outputs to be the same as the result of the circuit - for i in 0..outputs.len() { - let mut expr = Expression::from(outputs[i]); - expr.push_addition_term(-FieldElement::one(), result[i]); - new_opcodes.push(Opcode::Arithmetic(expr)); - } - (num_witness, new_opcodes) -} - -pub(crate) fn create_blake2s_constraint( - input: Vec, - num_witness: u32, -) -> (Vec, u32, Vec) { - let mut new_opcodes = Vec::new(); - - // prepare constants - let (mut blake2s_state, extra_opcodes, num_witness) = Blake2sState::init(num_witness); - new_opcodes.extend(extra_opcodes); - let (blake2s_constants, extra_opcodes, num_witness) = - Blake2sConstantsInCircuit::init(num_witness); - new_opcodes.extend(extra_opcodes); - let (blake2s_iv, extra_opcodes, mut num_witness) = Blake2sIV::init(num_witness); - new_opcodes.extend(extra_opcodes); - - let mut offset = 0; - let mut size = input.len(); - - while size > BLAKE2S_BLOCKBYTES_USIZE { - let (extra_opcodes, updated_witness_counter) = blake2s_increment_counter( - &mut blake2s_state, - &blake2s_constants.blake2s_blockbytes_uint32, - num_witness, - ); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, updated_witness_counter) = blake2s_compress( - &mut blake2s_state, - &blake2s_iv, - input.get(offset..offset + BLAKE2S_BLOCKBYTES_USIZE).unwrap(), - updated_witness_counter, - ); - new_opcodes.extend(extra_opcodes); - offset += BLAKE2S_BLOCKBYTES_USIZE; - size -= BLAKE2S_BLOCKBYTES_USIZE; - num_witness = updated_witness_counter; - } - - let (u32_max, extra_opcodes, mut num_witness) = UInt32::load_constant(u32::MAX, num_witness); - new_opcodes.extend(extra_opcodes); - blake2s_state.f[0] = u32_max; - - // pad final block - let mut final_block = input.get(offset..).unwrap().to_vec(); - for _ in 0..BLAKE2S_BLOCKBYTES_USIZE - final_block.len() { - let (pad, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(0_u32, num_witness); - new_opcodes.extend(extra_opcodes); - final_block.push(pad.inner); - num_witness = updated_witness_counter; - } - - let (size_w, extra_opcodes, num_witness) = UInt32::load_constant(size as u32, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - blake2s_increment_counter(&mut blake2s_state, &size_w, num_witness); - new_opcodes.extend(extra_opcodes); - - let (extra_opcodes, num_witness) = - blake2s_compress(&mut blake2s_state, &blake2s_iv, &final_block, num_witness); - new_opcodes.extend(extra_opcodes); - - // decompose the result bytes in u32 to u8 - let (extra_opcodes, mut byte1, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[0].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte2, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[1].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte3, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[2].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte4, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[3].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte5, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[4].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte6, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[5].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte7, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[6].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte8, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[7].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - - byte1.reverse(); - byte2.reverse(); - byte3.reverse(); - byte4.reverse(); - byte5.reverse(); - byte6.reverse(); - byte7.reverse(); - byte8.reverse(); - - let result = vec![byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8] - .into_iter() - .flatten() - .collect(); - - (result, num_witness, new_opcodes) -} - -fn blake2s_increment_counter( - state: &mut Blake2sState, - inc: &UInt32, - num_witness: u32, -) -> (Vec, u32) { - let mut new_opcodes = Vec::new(); - - // t0 + inc - let (state_t0, extra_opcodes, num_witness) = state.t[0].add(inc, num_witness); - new_opcodes.extend(extra_opcodes); - state.t[0] = state_t0; - - // t1 + (t0 < inc) - let (to_inc, extra_opcodes, num_witness) = state.t[0].less_than_comparison(inc, num_witness); - new_opcodes.extend(extra_opcodes); - let (state_t1, extra_opcodes, num_witness) = state.t[1].add(&to_inc, num_witness); - new_opcodes.extend(extra_opcodes); - state.t[1] = state_t1; - - (new_opcodes, num_witness) -} - -fn blake2s_compress( - state: &mut Blake2sState, - blake2s_iv: &Blake2sIV, - input: &[Witness], - mut num_witness: u32, -) -> (Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut m = Vec::new(); - let mut v = Vec::new(); - - for i in 0..16 { - let mut mi_bytes = input.get(i * 4..i * 4 + 4).unwrap().to_vec(); - mi_bytes.reverse(); - let (mi, extra_opcodes, updated_witness_counter) = - UInt32::from_witnesses(&mi_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - m.push(mi[0]); - num_witness = updated_witness_counter; - } - - for i in 0..8 { - v.push(state.h[i]); - } - - v.push(blake2s_iv.iv[0]); - v.push(blake2s_iv.iv[1]); - v.push(blake2s_iv.iv[2]); - v.push(blake2s_iv.iv[3]); - let (v12, extra_opcodes, num_witness) = state.t[0].xor(&blake2s_iv.iv[4], num_witness); - new_opcodes.extend(extra_opcodes); - v.push(v12); - let (v13, extra_opcodes, num_witness) = state.t[1].xor(&blake2s_iv.iv[5], num_witness); - new_opcodes.extend(extra_opcodes); - v.push(v13); - let (v14, extra_opcodes, num_witness) = state.f[0].xor(&blake2s_iv.iv[6], num_witness); - new_opcodes.extend(extra_opcodes); - v.push(v14); - let (v15, extra_opcodes, num_witness) = state.f[1].xor(&blake2s_iv.iv[7], num_witness); - new_opcodes.extend(extra_opcodes); - v.push(v15); - - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 0, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 1, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 2, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 3, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 5, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 6, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 7, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 8, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut num_witness) = blake2s_round(&mut v, &m, 9, num_witness); - new_opcodes.extend(extra_opcodes); - - for i in 0..8 { - let (a, extra_opcodes, updated_witness_counter) = state.h[i].xor(&v[i], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_hi, extra_opcodes, updated_witness_counter) = - a.xor(&v[i + 8], updated_witness_counter); - new_opcodes.extend(extra_opcodes); - state.h[i] = state_hi; - num_witness = updated_witness_counter; - } - - (new_opcodes, num_witness) -} - -fn blake2s_round( - state: &mut [UInt32], - msg: &[UInt32], - round: usize, - num_witness: u32, -) -> (Vec, u32) { - let mut new_opcodes = Vec::new(); - let schedule = &MSG_SCHEDULE_BLAKE2[round]; - - // Mix the columns. - let (extra_opcodes, num_witness) = - g(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]], num_witness); - new_opcodes.extend(extra_opcodes); - - // Mix the rows. - let (extra_opcodes, num_witness) = - g(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]], num_witness); - new_opcodes.extend(extra_opcodes); - - (new_opcodes, num_witness) -} - -#[allow(clippy::too_many_arguments)] -fn g( - state: &mut [UInt32], - a: usize, - b: usize, - c: usize, - d: usize, - x: UInt32, - y: UInt32, - num_witness: u32, -) -> (Vec, u32) { - let mut new_opcodes = Vec::new(); - - // calculate state[a] as `state[a] + state[b] + x` - let (state_a_1, extra_opcodes, num_witness) = state[a].add(&state[b], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_a, extra_opcodes, num_witness) = state_a_1.add(&x, num_witness); - new_opcodes.extend(extra_opcodes); - state[a] = state_a; - - // calculate state[d] as `(state[d] ^ state[a]).ror(16)` - let (state_d_1, extra_opcodes, num_witness) = state[d].xor(&state[a], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_d, extra_opcodes, num_witness) = state_d_1.ror(16, num_witness); - new_opcodes.extend(extra_opcodes); - state[d] = state_d; - - // calculate state[c] as `state[c] + state[d]` - let (state_c, extra_opcodes, num_witness) = state[c].add(&state[d], num_witness); - new_opcodes.extend(extra_opcodes); - state[c] = state_c; - - // caclulate state[b] as `(state[b] ^ state[c]).ror(12)` - let (state_b_1, extra_opcodes, num_witness) = state[b].xor(&state[c], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_b, extra_opcodes, num_witness) = state_b_1.ror(12, num_witness); - new_opcodes.extend(extra_opcodes); - state[b] = state_b; - - // calculate state[a] as `state[a] + state[b] + y` - let (state_a_1, extra_opcodes, num_witness) = state[a].add(&state[b], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_a, extra_opcodes, num_witness) = state_a_1.add(&y, num_witness); - new_opcodes.extend(extra_opcodes); - state[a] = state_a; - - // calculate state[d] as `(state[d] ^ state[a]).ror(8)` - let (state_d_1, extra_opcodes, num_witness) = state[d].xor(&state[a], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_d, extra_opcodes, num_witness) = state_d_1.ror(8, num_witness); - new_opcodes.extend(extra_opcodes); - state[d] = state_d; - - // calculate state[c] as `state[c] + state[d]` - let (state_c, extra_opcodes, num_witness) = state[c].add(&state[d], num_witness); - new_opcodes.extend(extra_opcodes); - state[c] = state_c; - - // caclulate state[b] as `(state[b] ^ state[c]).ror(7)` - let (state_b_1, extra_opcodes, num_witness) = state[b].xor(&state[c], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_b, extra_opcodes, num_witness) = state_b_1.ror(7, num_witness); - new_opcodes.extend(extra_opcodes); - state[b] = state_b; - - (new_opcodes, num_witness) -} - -/// Blake2s state `h` `t` and `f` -#[derive(Debug)] -struct Blake2sState { - h: Vec, - t: Vec, - f: Vec, -} - -impl Blake2sState { - fn new(h: Vec, t: Vec, f: Vec) -> Self { - Blake2sState { h, t, f } - } - - /// Initialize internal state of Blake2s - fn init(mut num_witness: u32) -> (Blake2sState, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut h = Vec::new(); - let mut t = Vec::new(); - let mut f = Vec::new(); - - for init_h in INITIAL_H { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(init_h, num_witness); - new_opcodes.extend(extra_opcodes); - h.push(new_witness); - num_witness = updated_witness_counter; - } - - for _ in 0..2 { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(0_u32, num_witness); - new_opcodes.extend(extra_opcodes); - t.push(new_witness); - num_witness = updated_witness_counter; - } - - for _ in 0..2 { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(0_u32, num_witness); - new_opcodes.extend(extra_opcodes); - f.push(new_witness); - num_witness = updated_witness_counter; - } - - let blake2s_state = Blake2sState::new(h, t, f); - - (blake2s_state, new_opcodes, num_witness) - } -} - -/// Blake2s IV (Initialization Vector) -struct Blake2sIV { - iv: Vec, -} - -impl Blake2sIV { - fn new(iv: Vec) -> Self { - Blake2sIV { iv } - } - - /// Initialize IV of Blake2s - fn init(mut num_witness: u32) -> (Blake2sIV, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut iv = Vec::new(); - - for iv_v in IV_VALUE { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(iv_v, num_witness); - new_opcodes.extend(extra_opcodes); - iv.push(new_witness); - num_witness = updated_witness_counter; - } - - let blake2s_iv = Blake2sIV::new(iv); - - (blake2s_iv, new_opcodes, num_witness) - } -} - -struct Blake2sConstantsInCircuit { - blake2s_blockbytes_uint32: UInt32, -} - -impl Blake2sConstantsInCircuit { - fn new(blake2s_blockbytes_uint32: UInt32) -> Self { - Blake2sConstantsInCircuit { blake2s_blockbytes_uint32 } - } - - fn init(num_witness: u32) -> (Blake2sConstantsInCircuit, Vec, u32) { - let mut new_opcodes = Vec::new(); - let (blake2s_blockbytes_uint32, extra_opcodes, num_witness) = - UInt32::load_constant(64_u32, num_witness); - new_opcodes.extend(extra_opcodes); - - (Blake2sConstantsInCircuit::new(blake2s_blockbytes_uint32), new_opcodes, num_witness) - } -} diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/hash_to_field.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/hash_to_field.rs deleted file mode 100644 index 91a7cdd09e..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/hash_to_field.rs +++ /dev/null @@ -1,168 +0,0 @@ -//! HashToField128Security fallback function. -use super::{ - blake2s::create_blake2s_constraint, - utils::{byte_decomposition, round_to_nearest_byte}, - UInt32, -}; -use crate::helpers::VariableStore; -use acir::{ - brillig::{self, RegisterIndex}, - circuit::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, - Opcode, - }, - native_types::{Expression, Witness}, - FieldElement, -}; - -pub fn hash_to_field( - inputs: Vec<(Expression, u32)>, - outputs: Witness, - mut num_witness: u32, -) -> (u32, Vec) { - let mut new_opcodes = Vec::new(); - let mut new_inputs = Vec::new(); - - // Decompose the input field elements into bytes and collect the resulting witnesses. - for (witness, num_bits) in inputs { - let num_bytes = round_to_nearest_byte(num_bits); - let (extra_opcodes, extra_inputs, updated_witness_counter) = - byte_decomposition(witness, num_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - new_inputs.extend(extra_inputs); - num_witness = updated_witness_counter; - } - - let (result, num_witness, extra_opcodes) = create_blake2s_constraint(new_inputs, num_witness); - new_opcodes.extend(extra_opcodes); - - // transform bytes to a single field - let (result, extra_opcodes, num_witness) = field_from_be_bytes(&result, num_witness); - new_opcodes.extend(extra_opcodes); - - // constrain the outputs to be the same as the result of the circuit - let mut expr = Expression::from(outputs); - expr.push_addition_term(-FieldElement::one(), result); - new_opcodes.push(Opcode::Arithmetic(expr)); - (num_witness, new_opcodes) -} - -/// Convert bytes represented by [Witness]es to a single [FieldElement] -fn field_from_be_bytes(result: &[Witness], num_witness: u32) -> (Witness, Vec, u32) { - let mut new_opcodes = Vec::new(); - - // Load `0` and `256` using the load constant function from UInt32 - let (new_witness, extra_opcodes, num_witness) = UInt32::load_constant(0, num_witness); - let mut new_witness = new_witness.inner; - new_opcodes.extend(extra_opcodes); - let (const_256, extra_opcodes, mut num_witness) = UInt32::load_constant(256, num_witness); - let const_256 = const_256.inner; - new_opcodes.extend(extra_opcodes); - - // add byte and multiply 256 each round - for r in result.iter().take(result.len() - 1) { - let (updated_witness, extra_opcodes, updated_witness_counter) = - field_addition(&new_witness, r, num_witness); - new_opcodes.extend(extra_opcodes); - let (updated_witness, extra_opcodes, updated_witness_counter) = - field_mul(&updated_witness, &const_256, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - new_witness = updated_witness; - num_witness = updated_witness_counter; - } - - let (new_witness, extra_opcodes, num_witness) = - field_addition(&new_witness, &result[result.len() - 1], num_witness); - new_opcodes.extend(extra_opcodes); - - (new_witness, new_opcodes, num_witness) -} - -/// Caculate and constrain `self` + `rhs` as field -fn field_addition( - lhs: &Witness, - rhs: &Witness, - mut num_witness: u32, -) -> (Witness, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calculate `self` + `rhs` as field - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), *lhs)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), *rhs)], - q_c: FieldElement::zero(), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::BinaryFieldOp { - op: brillig::BinaryFieldOp::Add, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain addition - let mut add_expr = Expression::from(new_witness); - add_expr.push_addition_term(-FieldElement::one(), *lhs); - add_expr.push_addition_term(-FieldElement::one(), *rhs); - new_opcodes.push(Opcode::Arithmetic(add_expr)); - - (new_witness, new_opcodes, num_witness) -} - -/// Calculate and constrain `self` * `rhs` as field -pub(crate) fn field_mul( - lhs: &Witness, - rhs: &Witness, - mut num_witness: u32, -) -> (Witness, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calulate `self` * `rhs` with overflow - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), *lhs)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), *rhs)], - q_c: FieldElement::zero(), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::BinaryFieldOp { - op: brillig::BinaryFieldOp::Mul, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain mul - let mut mul_constraint = Expression::from(new_witness); - mul_constraint.push_multiplication_term(-FieldElement::one(), *lhs, *rhs); - new_opcodes.push(Opcode::Arithmetic(mul_constraint)); - - (new_witness, new_opcodes, num_witness) -} diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/keccak256.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/keccak256.rs deleted file mode 100644 index d91db3dc2c..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/keccak256.rs +++ /dev/null @@ -1,269 +0,0 @@ -//! Keccak256 fallback function. -use super::{ - sha256::pad, - uint8::UInt8, - utils::{byte_decomposition, round_to_nearest_byte}, - UInt64, -}; -use acir::{ - circuit::Opcode, - native_types::{Expression, Witness}, - FieldElement, -}; - -const STATE_NUM_BYTES: usize = 200; -const BITS: usize = 256; -const WORD_SIZE: usize = 8; -const BLOCK_SIZE: usize = (1600 - BITS * 2) / WORD_SIZE; -const ROUND_CONSTANTS: [u64; 24] = [ - 1, - 0x8082, - 0x800000000000808a, - 0x8000000080008000, - 0x808b, - 0x80000001, - 0x8000000080008081, - 0x8000000000008009, - 0x8a, - 0x88, - 0x80008009, - 0x8000000a, - 0x8000808b, - 0x800000000000008b, - 0x8000000000008089, - 0x8000000000008003, - 0x8000000000008002, - 0x8000000000000080, - 0x800a, - 0x800000008000000a, - 0x8000000080008081, - 0x8000000000008080, - 0x80000001, - 0x8000000080008008, -]; -const RHO: [u32; 24] = - [1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44]; -const PI: [usize; 24] = - [10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1]; - -pub fn keccak256( - inputs: Vec<(Expression, u32)>, - outputs: Vec, - mut num_witness: u32, -) -> (u32, Vec) { - let mut new_opcodes = Vec::new(); - let mut new_inputs = Vec::new(); - - // Decompose the input field elements into bytes and collect the resulting witnesses. - for (witness, num_bits) in inputs { - let num_bytes = round_to_nearest_byte(num_bits); - let (extra_opcodes, extra_inputs, updated_witness_counter) = - byte_decomposition(witness, num_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - new_inputs.extend(extra_inputs); - num_witness = updated_witness_counter; - } - - let (result, num_witness, extra_opcodes) = create_keccak_constraint(new_inputs, num_witness); - new_opcodes.extend(extra_opcodes); - - // constrain the outputs to be the same as the result of the circuit - for i in 0..outputs.len() { - let mut expr = Expression::from(outputs[i]); - expr.push_addition_term(-FieldElement::one(), result[i]); - new_opcodes.push(Opcode::Arithmetic(expr)); - } - (num_witness, new_opcodes) -} - -fn create_keccak_constraint( - input: Vec, - num_witness: u32, -) -> (Vec, u32, Vec) { - let mut new_opcodes = Vec::new(); - let num_blocks = input.len() / BLOCK_SIZE + 1; - - // pad keccak - let (input, extra_opcodes, mut num_witness) = pad_keccak(input, num_blocks, num_witness); - new_opcodes.extend(extra_opcodes); - - // prepare state - let mut state = Vec::with_capacity(200); - for _ in 0..STATE_NUM_BYTES { - let (zero, extra_opcodes, updated_witness_counter) = UInt8::load_constant(0, num_witness); - new_opcodes.extend(extra_opcodes); - state.push(zero); - num_witness = updated_witness_counter; - } - - // process block - for i in 0..num_blocks { - for j in 0..BLOCK_SIZE { - let (new_state, extra_opcodes, updated_witness_counter) = - state[j].xor(&UInt8::new(input[i * BLOCK_SIZE + j]), num_witness); - new_opcodes.extend(extra_opcodes); - state[j] = new_state; - num_witness = updated_witness_counter; - } - let (new_state, extra_opcodes, updated_witness_counter) = keccakf(state, num_witness); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - state = new_state; - } - - let result: Vec = state[..32].iter().map(|x| x.inner).collect(); - (result, num_witness, new_opcodes) -} - -fn keccakf(state: Vec, num_witness: u32) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - - // turn state into UInt64 - let mut state_witnesses: Vec = Vec::new(); - for i in 0..state.len() / 8 { - for j in 0..8 { - state_witnesses.push(state[i * 8 + (7 - j)].inner); - } - } - let (mut state_u64, extra_opcodes, mut num_witness) = - UInt64::from_witnesses(&state_witnesses, num_witness); - new_opcodes.extend(extra_opcodes); - - // process round - for round_constant in ROUND_CONSTANTS { - let (new_state_u64, extra_opcodes, updated_witness_counter) = - keccak_round(state_u64, round_constant, num_witness); - state_u64 = new_state_u64; - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - } - - // turn state back to UInt8 - let state_u64_witnesses: Vec = state_u64.into_iter().map(|x| x.inner).collect(); - let mut state_u8 = Vec::with_capacity(state_u64_witnesses.len()); - for state_u64_witness in state_u64_witnesses { - let (extra_opcodes, mut u8s, updated_witness_counter) = - byte_decomposition(Expression::from(state_u64_witness), 8, num_witness); - new_opcodes.extend(extra_opcodes); - u8s.reverse(); - state_u8.push(u8s); - num_witness = updated_witness_counter; - } - - let state_u8: Vec = state_u8.into_iter().flatten().map(UInt8::new).collect(); - (state_u8, new_opcodes, num_witness) -} - -fn keccak_round( - mut a: Vec, - round_const: u64, - mut num_witness: u32, -) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - - // theta - let mut array = Vec::with_capacity(5); - for _ in 0..5 { - let (zero, extra_opcodes, updated_witness_counter) = UInt64::load_constant(0, num_witness); - array.push(zero); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - } - for x in 0..5 { - for y_count in 0..5 { - let y = y_count * 5; - let (new_array_ele, extra_opcodes, updated_witness_counter) = - array[x].xor(&a[x + y], num_witness); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - array[x] = new_array_ele; - } - } - for x in 0..5 { - for y_count in 0..5 { - let y = y_count * 5; - let (a_ele, extra_opcodes, updated_witness_counter) = - array[(x + 1) % 5].rol(1, num_witness); - new_opcodes.extend(extra_opcodes); - let (b_ele, extra_opcodes, updated_witness_counter) = - array[(x + 4) % 5].xor(&a_ele, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (new_array_ele, extra_opcodes, updated_witness_counter) = - a[x + y].xor(&b_ele, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - a[x + y] = new_array_ele; - } - } - - // rho and pi - let mut last = a[1]; - for x in 0..24 { - array[0] = a[PI[x]]; - let (a_ele, extra_opcodes, updated_witness_counter) = last.rol(RHO[x], num_witness); - new_opcodes.extend(extra_opcodes); - a[PI[x]] = a_ele; - num_witness = updated_witness_counter; - last = array[0]; - } - - // chi - for y_step in 0..5 { - let y = y_step * 5; - - array[..5].copy_from_slice(&a[y..(5 + y)]); - - for x in 0..5 { - let (a_ele, extra_opcodes, updated_witness_counter) = - array[(x + 1) % 5].not(num_witness); - new_opcodes.extend(extra_opcodes); - let (b_ele, extra_opcodes, updated_witness_counter) = - a_ele.and(&array[(x + 2) % 5], updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (c_ele, extra_opcodes, updated_witness_counter) = - array[x].xor(&b_ele, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - a[y + x] = c_ele; - num_witness = updated_witness_counter; - } - } - - // iota - let (rc, extra_opcodes, num_witness) = UInt64::load_constant(round_const, num_witness); - new_opcodes.extend(extra_opcodes); - let (a_ele, extra_opcodes, num_witness) = a[0].xor(&rc, num_witness); - new_opcodes.extend(extra_opcodes); - a[0] = a_ele; - - (a, new_opcodes, num_witness) -} - -fn pad_keccak( - mut input: Vec, - num_blocks: usize, - num_witness: u32, -) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let total_len = BLOCK_SIZE * num_blocks; - - let (mut num_witness, pad_witness, extra_opcodes) = pad(0x01, 8, num_witness); - - new_opcodes.extend(extra_opcodes); - input.push(pad_witness); - for _ in 0..total_len - input.len() { - let (updated_witness_counter, pad_witness, extra_opcodes) = pad(0x00, 8, num_witness); - new_opcodes.extend(extra_opcodes); - input.push(pad_witness); - num_witness = updated_witness_counter; - } - - let (zero_x_80, extra_opcodes, num_witness) = UInt8::load_constant(0x80, num_witness); - new_opcodes.extend(extra_opcodes); - let (final_pad, extra_opcodes, num_witness) = - UInt8::new(input[total_len - 1]).xor(&zero_x_80, num_witness); - new_opcodes.extend(extra_opcodes); - input[total_len - 1] = final_pad.inner; - - (input, new_opcodes, num_witness) -} diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/logic_fallbacks.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/logic_fallbacks.rs deleted file mode 100644 index fa8c1060a2..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/logic_fallbacks.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::{blackbox_fallbacks::utils::mul_with_witness, helpers::VariableStore}; - -use super::utils::{bit_decomposition, boolean_expr}; -use acir::{ - acir_field::FieldElement, - circuit::Opcode, - native_types::{Expression, Witness}, -}; - -// Range constraint -pub fn range(opcode: Expression, bit_size: u32, mut num_witness: u32) -> (u32, Vec) { - if bit_size == 1 { - let mut variables = VariableStore::new(&mut num_witness); - let bit_constraint = Opcode::Arithmetic(boolean_expr(&opcode, &mut variables)); - return (variables.finalize(), vec![bit_constraint]); - } - - let (new_opcodes, _, updated_witness_counter) = - bit_decomposition(opcode, bit_size, num_witness); - (updated_witness_counter, new_opcodes) -} - -/// Returns a set of opcodes which constrain `a & b == result` -/// -/// `a` and `b` are assumed to be constrained to fit within `bit_size` externally. -pub fn and( - a: Expression, - b: Expression, - result: Witness, - bit_size: u32, - mut num_witness: u32, -) -> (u32, Vec) { - if bit_size == 1 { - let mut variables = VariableStore::new(&mut num_witness); - - let mut and_expr = mul_with_witness(&a, &b, &mut variables); - and_expr.push_addition_term(-FieldElement::one(), result); - - return (variables.finalize(), vec![Opcode::Arithmetic(and_expr)]); - } - // Decompose the operands into bits - // - let (extra_opcodes_a, a_bits, updated_witness_counter) = - bit_decomposition(a, bit_size, num_witness); - - let (extra_opcodes_b, b_bits, updated_witness_counter) = - bit_decomposition(b, bit_size, updated_witness_counter); - - assert_eq!(a_bits.len(), b_bits.len()); - assert_eq!(a_bits.len(), bit_size as usize); - - let mut two_pow = FieldElement::one(); - let two = FieldElement::from(2_i128); - - // Build an expression that Multiplies each bit element-wise - // This gives the same truth table as the AND operation - // Additionally, we multiply by a power of 2 to build up the - // expected output; ie result = \sum 2^i x_i * y_i - let mut and_expr = Expression::default(); - for (a_bit, b_bit) in a_bits.into_iter().zip(b_bits) { - and_expr.push_multiplication_term(two_pow, a_bit, b_bit); - two_pow = two * two_pow; - } - and_expr.push_addition_term(-FieldElement::one(), result); - - and_expr.sort(); - - let mut new_opcodes = Vec::new(); - new_opcodes.extend(extra_opcodes_a); - new_opcodes.extend(extra_opcodes_b); - new_opcodes.push(Opcode::Arithmetic(and_expr)); - - (updated_witness_counter, new_opcodes) -} - -/// Returns a set of opcodes which constrain `a ^ b == result` -/// -/// `a` and `b` are assumed to be constrained to fit within `bit_size` externally. -pub fn xor( - a: Expression, - b: Expression, - result: Witness, - bit_size: u32, - mut num_witness: u32, -) -> (u32, Vec) { - if bit_size == 1 { - let mut variables = VariableStore::new(&mut num_witness); - - let product = mul_with_witness(&a, &b, &mut variables); - let mut xor_expr = &(&a + &b) - &product; - xor_expr.push_addition_term(-FieldElement::one(), result); - - return (variables.finalize(), vec![Opcode::Arithmetic(xor_expr)]); - } - - // Decompose the operands into bits - // - let (extra_opcodes_a, a_bits, updated_witness_counter) = - bit_decomposition(a, bit_size, num_witness); - let (extra_opcodes_b, b_bits, updated_witness_counter) = - bit_decomposition(b, bit_size, updated_witness_counter); - - assert_eq!(a_bits.len(), b_bits.len()); - assert_eq!(a_bits.len(), bit_size as usize); - - let mut two_pow = FieldElement::one(); - let two = FieldElement::from(2_i128); - - // Build an xor expression - // TODO: check this is the correct arithmetization - let mut xor_expr = Expression::default(); - for (a_bit, b_bit) in a_bits.into_iter().zip(b_bits) { - xor_expr.push_addition_term(two_pow, a_bit); - xor_expr.push_addition_term(two_pow, b_bit); - two_pow = two * two_pow; - xor_expr.push_multiplication_term(-two_pow, a_bit, b_bit); - } - xor_expr.push_addition_term(-FieldElement::one(), result); - - xor_expr.sort(); - let mut new_opcodes = Vec::new(); - new_opcodes.extend(extra_opcodes_a); - new_opcodes.extend(extra_opcodes_b); - new_opcodes.push(Opcode::Arithmetic(xor_expr)); - - (updated_witness_counter, new_opcodes) -} diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/mod.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/mod.rs deleted file mode 100644 index d2ca3c50fa..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod blake2s; -mod hash_to_field; -mod keccak256; -mod logic_fallbacks; -mod sha256; -#[macro_use] -mod uint; -mod uint32; -mod uint64; -mod uint8; -mod utils; -pub use blake2s::blake2s; -pub use hash_to_field::hash_to_field; -pub use keccak256::keccak256; -pub use logic_fallbacks::{and, range, xor}; -pub use sha256::sha256; -pub use uint32::UInt32; -pub use uint64::UInt64; -pub use uint8::UInt8; diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/sha256.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/sha256.rs deleted file mode 100644 index 1661b030bc..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/sha256.rs +++ /dev/null @@ -1,377 +0,0 @@ -//! Sha256 fallback function. -use super::uint32::UInt32; -use super::utils::{byte_decomposition, round_to_nearest_byte}; -use crate::helpers::VariableStore; -use acir::{ - brillig, - circuit::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, - opcodes::{BlackBoxFuncCall, FunctionInput}, - Opcode, - }, - native_types::{Expression, Witness}, - FieldElement, -}; - -const INIT_CONSTANTS: [u32; 8] = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, -]; - -const ROUND_CONSTANTS: [u32; 64] = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, -]; - -pub fn sha256( - inputs: Vec<(Expression, u32)>, - outputs: Vec, - mut num_witness: u32, -) -> (u32, Vec) { - let mut new_opcodes = Vec::new(); - let mut new_inputs = Vec::new(); - let mut total_num_bytes = 0; - - // Decompose the input field elements into bytes and collect the resulting witnesses. - for (witness, num_bits) in inputs { - let num_bytes = round_to_nearest_byte(num_bits); - total_num_bytes += num_bytes; - let (extra_opcodes, extra_inputs, updated_witness_counter) = - byte_decomposition(witness, num_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - new_inputs.extend(extra_inputs); - num_witness = updated_witness_counter; - } - - let (result, num_witness, extra_opcodes) = - create_sha256_constraint(new_inputs, total_num_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - - // constrain the outputs to be the same as the result of the circuit - for i in 0..outputs.len() { - let mut expr = Expression::from(outputs[i]); - expr.push_addition_term(-FieldElement::one(), result[i]); - new_opcodes.push(Opcode::Arithmetic(expr)); - } - (num_witness, new_opcodes) -} - -fn create_sha256_constraint( - mut input: Vec, - total_num_bytes: u32, - num_witness: u32, -) -> (Vec, u32, Vec) { - let mut new_opcodes = Vec::new(); - - // pad the bytes according to sha256 padding rules - let message_bits = total_num_bytes * 8; - let (mut num_witness, pad_witness, extra_opcodes) = pad(128, 8, num_witness); - new_opcodes.extend(extra_opcodes); - input.push(pad_witness); - let bytes_per_block = 64; - let num_bytes = (input.len() + 8) as u32; - let num_blocks = num_bytes / bytes_per_block + ((num_bytes % bytes_per_block != 0) as u32); - let num_total_bytes = num_blocks * bytes_per_block; - for _ in num_bytes..num_total_bytes { - let (updated_witness_counter, pad_witness, extra_opcodes) = pad(0, 8, num_witness); - num_witness = updated_witness_counter; - new_opcodes.extend(extra_opcodes); - input.push(pad_witness); - } - let (num_witness, pad_witness, extra_opcodes) = pad(message_bits, 64, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, pad_witness, num_witness) = - byte_decomposition(pad_witness.into(), 8, num_witness); - new_opcodes.extend(extra_opcodes); - input.extend(pad_witness); - - // turn witness into u32 and load sha256 state - let (input, extra_opcodes, num_witness) = UInt32::from_witnesses(&input, num_witness); - new_opcodes.extend(extra_opcodes); - let (mut rolling_hash, extra_opcodes, num_witness) = prepare_state_constants(num_witness); - new_opcodes.extend(extra_opcodes); - let (round_constants, extra_opcodes, mut num_witness) = prepare_round_constants(num_witness); - new_opcodes.extend(extra_opcodes); - // split the input into blocks of size 16 - let input: Vec> = input.chunks(16).map(|block| block.to_vec()).collect(); - - // process sha256 blocks - for i in &input { - let (new_rolling_hash, extra_opcodes, updated_witness_counter) = - sha256_block(i, rolling_hash.clone(), round_constants.clone(), num_witness); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - rolling_hash = new_rolling_hash; - } - - // decompose the result bytes in u32 to u8 - let (extra_opcodes, byte1, num_witness) = - byte_decomposition(Expression::from(rolling_hash[0].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte2, num_witness) = - byte_decomposition(Expression::from(rolling_hash[1].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte3, num_witness) = - byte_decomposition(Expression::from(rolling_hash[2].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte4, num_witness) = - byte_decomposition(Expression::from(rolling_hash[3].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte5, num_witness) = - byte_decomposition(Expression::from(rolling_hash[4].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte6, num_witness) = - byte_decomposition(Expression::from(rolling_hash[5].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte7, num_witness) = - byte_decomposition(Expression::from(rolling_hash[6].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte8, num_witness) = - byte_decomposition(Expression::from(rolling_hash[7].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - - let result = vec![byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8] - .into_iter() - .flatten() - .collect(); - - (result, num_witness, new_opcodes) -} - -pub(crate) fn pad(number: u32, bit_size: u32, mut num_witness: u32) -> (u32, Witness, Vec) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let pad = variables.new_variable(); - - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from(number as u128), - })], - outputs: vec![BrilligOutputs::Simple(pad)], - bytecode: vec![brillig::Opcode::Stop], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - - let range = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: pad, num_bits: bit_size }, - }); - new_opcodes.push(range); - - (num_witness, pad, new_opcodes) -} - -fn sha256_block( - input: &[UInt32], - rolling_hash: Vec, - round_constants: Vec, - mut num_witness: u32, -) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut w = Vec::new(); - w.extend(input.to_owned()); - - for i in 16..64 { - // calculate s0 `w[i - 15].ror(7) ^ w[i - 15].ror(18) ^ (w[i - 15] >> 3)` - let (a1, extra_opcodes, updated_witness_counter) = w[i - 15].ror(7, num_witness); - new_opcodes.extend(extra_opcodes); - let (a2, extra_opcodes, updated_witness_counter) = - w[i - 15].ror(18, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (a3, extra_opcodes, updated_witness_counter) = - w[i - 15].rightshift(3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (a4, extra_opcodes, updated_witness_counter) = a1.xor(&a2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (s0, extra_opcodes, updated_witness_counter) = a4.xor(&a3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate s1 `w[i - 2].ror(17) ^ w[i - 2].ror(19) ^ (w[i - 2] >> 10)` - let (b1, extra_opcodes, updated_witness_counter) = - w[i - 2].ror(17, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (b2, extra_opcodes, updated_witness_counter) = - w[i - 2].ror(19, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (b3, extra_opcodes, updated_witness_counter) = - w[i - 2].rightshift(10, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (b4, extra_opcodes, updated_witness_counter) = b1.xor(&b2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (s1, extra_opcodes, updated_witness_counter) = b4.xor(&b3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate w[i] `w[i - 16] + w[i - 7] + s0 + s1` - let (c1, extra_opcodes, updated_witness_counter) = - w[i - 16].add(&w[i - 7], updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (c2, extra_opcodes, updated_witness_counter) = c1.add(&s0, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (c3, extra_opcodes, updated_witness_counter) = c2.add(&s1, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - w.push(c3); - num_witness = updated_witness_counter; - } - - let mut a = rolling_hash[0]; - let mut b = rolling_hash[1]; - let mut c = rolling_hash[2]; - let mut d = rolling_hash[3]; - let mut e = rolling_hash[4]; - let mut f = rolling_hash[5]; - let mut g = rolling_hash[6]; - let mut h = rolling_hash[7]; - - #[allow(non_snake_case)] - for i in 0..64 { - // calculate S1 `e.ror(6) ^ e.ror(11) ^ e.ror(25)` - let (a1, extra_opcodes, updated_witness_counter) = e.ror(6, num_witness); - new_opcodes.extend(extra_opcodes); - let (a2, extra_opcodes, updated_witness_counter) = e.ror(11, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (a3, extra_opcodes, updated_witness_counter) = e.ror(25, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (a4, extra_opcodes, updated_witness_counter) = a1.xor(&a2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (S1, extra_opcodes, updated_witness_counter) = a4.xor(&a3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate ch `(e & f) + (~e & g)` - let (b1, extra_opcodes, updated_witness_counter) = e.and(&f, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (b2, extra_opcodes, updated_witness_counter) = e.not(updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (b3, extra_opcodes, updated_witness_counter) = b2.and(&g, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (ch, extra_opcodes, updated_witness_counter) = b1.add(&b3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // caculate temp1 `h + S1 + ch + round_constants[i] + w[i]` - let (c1, extra_opcodes, updated_witness_counter) = h.add(&S1, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (c2, extra_opcodes, updated_witness_counter) = c1.add(&ch, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (c3, extra_opcodes, updated_witness_counter) = - c2.add(&round_constants[i], updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (temp1, extra_opcodes, updated_witness_counter) = - c3.add(&w[i], updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate S0 `a.ror(2) ^ a.ror(13) ^ a.ror(22)` - let (d1, extra_opcodes, updated_witness_counter) = a.ror(2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (d2, extra_opcodes, updated_witness_counter) = a.ror(13, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (d3, extra_opcodes, updated_witness_counter) = a.ror(22, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (d4, extra_opcodes, updated_witness_counter) = d1.xor(&d2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (S0, extra_opcodes, updated_witness_counter) = d4.xor(&d3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate T0 `b & c` - let (T0, extra_opcodes, updated_witness_counter) = b.and(&c, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate maj `(a & (b + c - (T0 + T0))) + T0` which is the same as `(a & b) ^ (a & c) ^ (b & c)` - let (e1, extra_opcodes, updated_witness_counter) = T0.add(&T0, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (e2, extra_opcodes, updated_witness_counter) = c.sub(&e1, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (e3, extra_opcodes, updated_witness_counter) = b.add(&e2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (e4, extra_opcodes, updated_witness_counter) = a.and(&e3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (maj, extra_opcodes, updated_witness_counter) = e4.add(&T0, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate temp2 `S0 + maj` - let (temp2, extra_opcodes, updated_witness_counter) = S0.add(&maj, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - h = g; - g = f; - f = e; - let (new_e, extra_opcodes, updated_witness_counter) = - d.add(&temp1, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - d = c; - c = b; - b = a; - let (new_a, extra_opcodes, updated_witness_counter) = - temp1.add(&temp2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - a = new_a; - e = new_e; - } - - let mut output = Vec::new(); - let (output0, extra_opcodes, num_witness) = a.add(&rolling_hash[0], num_witness); - new_opcodes.extend(extra_opcodes); - let (output1, extra_opcodes, num_witness) = b.add(&rolling_hash[1], num_witness); - new_opcodes.extend(extra_opcodes); - let (output2, extra_opcodes, num_witness) = c.add(&rolling_hash[2], num_witness); - new_opcodes.extend(extra_opcodes); - let (output3, extra_opcodes, num_witness) = d.add(&rolling_hash[3], num_witness); - new_opcodes.extend(extra_opcodes); - let (output4, extra_opcodes, num_witness) = e.add(&rolling_hash[4], num_witness); - new_opcodes.extend(extra_opcodes); - let (output5, extra_opcodes, num_witness) = f.add(&rolling_hash[5], num_witness); - new_opcodes.extend(extra_opcodes); - let (output6, extra_opcodes, num_witness) = g.add(&rolling_hash[6], num_witness); - new_opcodes.extend(extra_opcodes); - let (output7, extra_opcodes, num_witness) = h.add(&rolling_hash[7], num_witness); - new_opcodes.extend(extra_opcodes); - - output.push(output0); - output.push(output1); - output.push(output2); - output.push(output3); - output.push(output4); - output.push(output5); - output.push(output6); - output.push(output7); - - (output, new_opcodes, num_witness) -} - -/// Load initial state constants of Sha256 -pub(crate) fn prepare_state_constants(mut num_witness: u32) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut new_witnesses = Vec::new(); - - for i in INIT_CONSTANTS { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(i, num_witness); - new_opcodes.extend(extra_opcodes); - new_witnesses.push(new_witness); - num_witness = updated_witness_counter; - } - - (new_witnesses, new_opcodes, num_witness) -} - -/// Load round constants of Sha256 -pub(crate) fn prepare_round_constants(mut num_witness: u32) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut new_witnesses = Vec::new(); - - for i in ROUND_CONSTANTS { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(i, num_witness); - new_opcodes.extend(extra_opcodes); - new_witnesses.push(new_witness); - num_witness = updated_witness_counter; - } - - (new_witnesses, new_opcodes, num_witness) -} diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/uint.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/uint.rs deleted file mode 100644 index 6f4039835f..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/uint.rs +++ /dev/null @@ -1,648 +0,0 @@ -#[macro_export] -macro_rules! impl_uint { - ( - $name:ident, - $type:ty, - $size:expr - ) => { - use acir::{ - brillig::{self, RegisterIndex}, - circuit::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, - directives::QuotientDirective, - opcodes::{BlackBoxFuncCall, FunctionInput}, - Opcode, - }, - native_types::{Expression, Witness}, - FieldElement, - }; - use $crate::helpers::VariableStore; - - /// UInt contains a witness that points to a field element that represents a u32 integer - /// It has a inner field of type [Witness] that points to the field element and width = 32 - #[derive(Copy, Clone, Debug)] - pub struct $name { - pub(crate) inner: Witness, - width: u32, - } - - impl $name { - #[cfg(any(test, feature = "testing"))] - pub fn get_inner(&self) -> Witness { - self.inner - } - } - - impl $name { - /// Initialize A new [UInt] type with a [Witness] - pub fn new(witness: Witness) -> Self { - $name { inner: witness, width: $size } - } - - /// Get u(n) + 1 - pub(crate) fn get_max_plus_one( - &self, - mut num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from(2_u128.pow(self.width)), - })], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::Stop], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Load a constant into the circuit - pub(crate) fn load_constant( - constant: $type, - mut num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from(constant as u128), - })], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::Stop], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Returns the quotient and remainder such that lhs = rhs * quotient + remainder - // This should be the same as its equivalent in the Noir repo - pub fn euclidean_division( - lhs: &$name, - rhs: &$name, - mut num_witness: u32, - ) -> ($name, $name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let q_witness = variables.new_variable(); - let r_witness = variables.new_variable(); - - // compute quotient using directive function - let quotient_opcode = Opcode::Directive( - acir::circuit::directives::Directive::Quotient(QuotientDirective { - a: lhs.inner.into(), - b: rhs.inner.into(), - q: q_witness, - r: r_witness, - predicate: None, - }), - ); - new_opcodes.push(quotient_opcode); - - // make sure r and q are in 32 bit range - let r_range_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: r_witness, num_bits: lhs.width }, - }); - let q_range_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: q_witness, num_bits: lhs.width }, - }); - new_opcodes.push(r_range_opcode); - new_opcodes.push(q_range_opcode); - let num_witness = variables.finalize(); - - // constrain r < rhs - let (rhs_sub_r, extra_opcodes, num_witness) = - rhs.sub_no_overflow(&$name::new(r_witness), num_witness); - new_opcodes.extend(extra_opcodes); - let rhs_sub_r_range_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: rhs_sub_r.inner, num_bits: lhs.width }, - }); - new_opcodes.push(rhs_sub_r_range_opcode); - - // constrain lhs = rhs * quotient + remainder - let rhs_expr = Expression::from(rhs.inner); - let lhs_constraint = Expression::from(lhs.inner); - let rhs_constraint = &rhs_expr * &Expression::from(q_witness); - let rhs_constraint = &rhs_constraint.unwrap() + &Expression::from(r_witness); - let div_euclidean = &lhs_constraint - &rhs_constraint; - new_opcodes.push(Opcode::Arithmetic(div_euclidean)); - - ($name::new(q_witness), $name::new(r_witness), new_opcodes, num_witness) - } - - /// Rotate left `rotation` bits. `(x << rotation) | (x >> (width - rotation))` - // This should be the same as `u32.rotate_left(rotation)` in rust stdlib - pub fn rol(&self, rotation: u32, num_witness: u32) -> ($name, Vec, u32) { - let rotation = rotation % self.width; - let mut new_opcodes = Vec::new(); - let (right_shift, extra_opcodes, num_witness) = - self.rightshift(self.width - rotation, num_witness); - new_opcodes.extend(extra_opcodes); - let (left_shift, extra_opcodes, num_witness) = - self.leftshift(rotation, num_witness); - new_opcodes.extend(extra_opcodes); - let (result, extra_opcodes, num_witness) = left_shift.or(&right_shift, num_witness); - new_opcodes.extend(extra_opcodes); - - (result, new_opcodes, num_witness) - } - - /// Rotate right `rotation` bits. `(x >> rotation) | (x << (width - rotation))` - // This should be the same as `u32.rotate_right(rotation)` in rust stdlib - pub fn ror(&self, rotation: u32, num_witness: u32) -> ($name, Vec, u32) { - let rotation = rotation % self.width; - let mut new_opcodes = Vec::new(); - let (left_shift, extra_opcodes, num_witness) = - self.leftshift(self.width - rotation, num_witness); - new_opcodes.extend(extra_opcodes); - let (right_shift, extra_opcodes, num_witness) = - self.rightshift(rotation, num_witness); - new_opcodes.extend(extra_opcodes); - let (result, extra_opcodes, num_witness) = left_shift.or(&right_shift, num_witness); - new_opcodes.extend(extra_opcodes); - - (result, new_opcodes, num_witness) - } - - /// left shift by `bits` - pub fn leftshift(&self, bits: u32, num_witness: u32) -> ($name, Vec, u32) { - let bits = bits % self.width; - let mut new_opcodes = Vec::new(); - let two: $type = 2; - let (two_pow_rhs, extra_opcodes, num_witness) = - $name::load_constant(two.pow(bits), num_witness); - new_opcodes.extend(extra_opcodes); - let (left_shift, extra_opcodes, num_witness) = self.mul(&two_pow_rhs, num_witness); - new_opcodes.extend(extra_opcodes); - - (left_shift, new_opcodes, num_witness) - } - - /// right shift by `bits` - pub fn rightshift(&self, bits: u32, num_witness: u32) -> ($name, Vec, u32) { - let bits = bits % self.width; - let mut new_opcodes = Vec::new(); - let two: $type = 2; - let (two_pow_rhs, extra_opcodes, num_witness) = - $name::load_constant(two.pow(bits), num_witness); - new_opcodes.extend(extra_opcodes); - let (right_shift, _, extra_opcodes, num_witness) = - $name::euclidean_division(self, &two_pow_rhs, num_witness); - new_opcodes.extend(extra_opcodes); - - (right_shift, new_opcodes, num_witness) - } - - /// Caculate and constrain `self` + `rhs` - pub fn add(&self, rhs: &$name, mut num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calculate `self` + `rhs` with overflow - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), rhs.inner)], - q_c: FieldElement::zero(), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Add, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain addition - let mut add_expr = Expression::from(new_witness); - add_expr.push_addition_term(-FieldElement::one(), self.inner); - add_expr.push_addition_term(-FieldElement::one(), rhs.inner); - new_opcodes.push(Opcode::Arithmetic(add_expr)); - - // mod 2^width to get final result as the remainder - let (two_pow_width, extra_opcodes, num_witness) = - self.get_max_plus_one(num_witness); - new_opcodes.extend(extra_opcodes); - let (_, add_mod, extra_opcodes, num_witness) = $name::euclidean_division( - &$name::new(new_witness), - &two_pow_width, - num_witness, - ); - new_opcodes.extend(extra_opcodes); - - (add_mod, new_opcodes, num_witness) - } - - /// Caculate and constrain `self` - `rhs` - pub fn sub(&self, rhs: &$name, mut num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calculate 2^32 + self - rhs to avoid overflow - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), rhs.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from(1_u128 << self.width), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![ - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Add, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(2), - destination: RegisterIndex::from(0), - }, - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Sub, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }, - ], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain subtraction - let mut sub_constraint = Expression::from(self.inner); - sub_constraint.push_addition_term(-FieldElement::one(), new_witness); - sub_constraint.push_addition_term(-FieldElement::one(), rhs.inner); - sub_constraint.q_c = FieldElement::from(1_u128 << self.width); - new_opcodes.push(Opcode::Arithmetic(sub_constraint)); - - // mod 2^width to get final result as the remainder - let (two_pow_width, extra_opcodes, num_witness) = - self.get_max_plus_one(num_witness); - new_opcodes.extend(extra_opcodes); - let (_, sub_mod, extra_opcodes, num_witness) = $name::euclidean_division( - &$name::new(new_witness), - &two_pow_width, - num_witness, - ); - new_opcodes.extend(extra_opcodes); - - (sub_mod, new_opcodes, num_witness) - } - - /// Calculate and constrain `self` - `rhs` - 1 without allowing overflow - /// This is a helper function to `euclidean_division` - // There is a `-1` because theres a case where rhs = 2^32 and remainder = 0 - pub(crate) fn sub_no_overflow( - &self, - rhs: &$name, - mut num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calculate self - rhs - 1 - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), rhs.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::one(), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![ - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Sub, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }, - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Sub, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(2), - destination: RegisterIndex::from(0), - }, - ], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain subtraction - let mut sub_constraint = Expression::from(self.inner); - sub_constraint.push_addition_term(-FieldElement::one(), new_witness); - sub_constraint.push_addition_term(-FieldElement::one(), rhs.inner); - sub_constraint.q_c = -FieldElement::one(); - new_opcodes.push(Opcode::Arithmetic(sub_constraint)); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Calculate and constrain `self` * `rhs` - pub(crate) fn mul( - &self, - rhs: &$name, - mut num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calulate `self` * `rhs` with overflow - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), rhs.inner)], - q_c: FieldElement::zero(), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::BinaryFieldOp { - op: brillig::BinaryFieldOp::Mul, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain mul - let mut mul_constraint = Expression::from(new_witness); - mul_constraint.push_multiplication_term( - -FieldElement::one(), - self.inner, - rhs.inner, - ); - new_opcodes.push(Opcode::Arithmetic(mul_constraint)); - - // mod 2^width to get final result as the remainder - let (two_pow_rhs, extra_opcodes, num_witness) = self.get_max_plus_one(num_witness); - new_opcodes.extend(extra_opcodes); - let (_, mul_mod, extra_opcodes, num_witness) = - $name::euclidean_division(&$name::new(new_witness), &two_pow_rhs, num_witness); - new_opcodes.extend(extra_opcodes); - - (mul_mod, new_opcodes, num_witness) - } - - /// Calculate and constrain `self` and `rhs` - pub fn and(&self, rhs: &$name, mut num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - let num_witness = variables.finalize(); - let and_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::AND { - lhs: FunctionInput { witness: self.inner, num_bits: self.width }, - rhs: FunctionInput { witness: rhs.inner, num_bits: self.width }, - output: new_witness, - }); - new_opcodes.push(and_opcode); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Calculate and constrain `self` xor `rhs` - pub fn xor(&self, rhs: &$name, mut num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - let num_witness = variables.finalize(); - let xor_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::XOR { - lhs: FunctionInput { witness: self.inner, num_bits: self.width }, - rhs: FunctionInput { witness: rhs.inner, num_bits: self.width }, - output: new_witness, - }); - new_opcodes.push(xor_opcode); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Calculate and constrain `self` or `rhs` - pub fn or(&self, rhs: &$name, num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - - // a | b = (a & b) + (a ^ b) - let (a_and_b, extra_opcodes, num_witness) = self.and(rhs, num_witness); - new_opcodes.extend(extra_opcodes); - let (a_xor_b, extra_opcodes, num_witness) = self.xor(rhs, num_witness); - new_opcodes.extend(extra_opcodes); - let (or, extra_opcodes, num_witness) = a_and_b.add(&a_xor_b, num_witness); - new_opcodes.extend(extra_opcodes); - - (or, new_opcodes, num_witness) - } - - /// Calculate and constrain not `self` - pub(crate) fn not(&self, mut num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from((1_u128 << self.width) - 1), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Sub, - bit_size: self.width, - lhs: RegisterIndex::from(1), - rhs: RegisterIndex::from(0), - destination: RegisterIndex::from(0), - }], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - let mut not_constraint = Expression::from(new_witness); - not_constraint.push_addition_term(FieldElement::one(), self.inner); - not_constraint.q_c = -FieldElement::from((1_u128 << self.width) - 1); - new_opcodes.push(Opcode::Arithmetic(not_constraint)); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Calculate and constrain `self` >= `rhs` - // This should be similar to its equivalent in the Noir repo - pub(crate) fn more_than_eq_comparison( - &self, - rhs: &$name, - mut num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - let q_witness = variables.new_variable(); - let r_witness = variables.new_variable(); - - // calculate 2^32 + self - rhs - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), rhs.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from(1_u128 << self.width), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![ - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Add, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(2), - destination: RegisterIndex::from(0), - }, - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Sub, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }, - ], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain subtraction - let mut sub_constraint = Expression::from(self.inner); - sub_constraint.push_addition_term(-FieldElement::one(), new_witness); - sub_constraint.push_addition_term(-FieldElement::one(), rhs.inner); - sub_constraint.q_c = FieldElement::from(1_u128 << self.width); - new_opcodes.push(Opcode::Arithmetic(sub_constraint)); - - let (two_pow_rhs, extra_opcodes, num_witness) = self.get_max_plus_one(num_witness); - new_opcodes.extend(extra_opcodes); - - // constraint 2^{max_bits} + a - b = q * 2^{max_bits} + r - // q = 1 if a == b - // q = 1 if a > b - // q = 0 if a < b - let quotient_opcode = Opcode::Directive( - acir::circuit::directives::Directive::Quotient(QuotientDirective { - a: new_witness.into(), - b: two_pow_rhs.inner.into(), - q: q_witness, - r: r_witness, - predicate: None, - }), - ); - new_opcodes.push(quotient_opcode); - - // make sure r in 32 bit range and q is 1 bit - let r_range_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: r_witness, num_bits: self.width }, - }); - let q_range_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: q_witness, num_bits: 1 }, - }); - new_opcodes.push(r_range_opcode); - new_opcodes.push(q_range_opcode); - - ($name::new(q_witness), new_opcodes, num_witness) - } - - /// Calculate and constrain `self` < `rhs` - pub fn less_than_comparison( - &self, - rhs: &$name, - num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let (mut comparison, extra_opcodes, num_witness) = - self.more_than_eq_comparison(rhs, num_witness); - new_opcodes.extend(extra_opcodes); - comparison.width = 1; - - // `self` < `rhs` == not `self` >= `rhs` - let (less_than, extra_opcodes, num_witness) = comparison.not(num_witness); - new_opcodes.extend(extra_opcodes); - - (less_than, new_opcodes, num_witness) - } - } - }; -} diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/uint32.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/uint32.rs deleted file mode 100644 index 58314d6ba4..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/uint32.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::impl_uint; - -impl_uint!(UInt32, u32, 32); -impl UInt32 { - /// Load a [UInt32] from four [Witness]es each representing a [u8] - pub(crate) fn from_witnesses( - witnesses: &[Witness], - mut num_witness: u32, - ) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let mut uint = Vec::new(); - - for i in 0..witnesses.len() / 4 { - let new_witness = variables.new_variable(); - uint.push(UInt32::new(new_witness)); - let mut expr = Expression::from(new_witness); - for j in 0..4 { - let scaling_factor_value = 1 << (8 * (3 - j) as u32); - let scaling_factor = FieldElement::from(scaling_factor_value as u128); - expr.push_addition_term(-scaling_factor, witnesses[i * 4 + j]); - } - - new_opcodes.push(Opcode::Arithmetic(expr)); - } - let num_witness = variables.finalize(); - - (uint, new_opcodes, num_witness) - } -} diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/uint64.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/uint64.rs deleted file mode 100644 index cddb23275c..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/uint64.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::impl_uint; - -impl_uint!(UInt64, u64, 64); -impl UInt64 { - /// Load a [UInt64] from eight [Witness]es each representing a [u8] - pub(crate) fn from_witnesses( - witnesses: &[Witness], - mut num_witness: u32, - ) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let mut uint = Vec::new(); - - for i in 0..witnesses.len() / 8 { - let new_witness = variables.new_variable(); - uint.push(UInt64::new(new_witness)); - let mut expr = Expression::from(new_witness); - for j in 0..8 { - let scaling_factor_value: u128 = 1 << (8 * (7 - j) as u32); - let scaling_factor = FieldElement::from(scaling_factor_value); - expr.push_addition_term(-scaling_factor, witnesses[i * 8 + j]); - } - - new_opcodes.push(Opcode::Arithmetic(expr)); - } - let num_witness = variables.finalize(); - - (uint, new_opcodes, num_witness) - } -} diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/uint8.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/uint8.rs deleted file mode 100644 index 2ffc2cae1b..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/uint8.rs +++ /dev/null @@ -1,2 +0,0 @@ -use crate::impl_uint; -impl_uint!(UInt8, u8, 8); diff --git a/acvm-repo/stdlib/src/blackbox_fallbacks/utils.rs b/acvm-repo/stdlib/src/blackbox_fallbacks/utils.rs deleted file mode 100644 index 4921c71c9f..0000000000 --- a/acvm-repo/stdlib/src/blackbox_fallbacks/utils.rs +++ /dev/null @@ -1,175 +0,0 @@ -use crate::helpers::VariableStore; -use acir::{ - circuit::{ - directives::Directive, - opcodes::{BlackBoxFuncCall, FunctionInput}, - Opcode, - }, - native_types::{Expression, Witness}, - FieldElement, -}; - -fn round_to_nearest_mul_8(num_bits: u32) -> u32 { - let remainder = num_bits % 8; - - if remainder == 0 { - return num_bits; - } - - num_bits + 8 - remainder -} - -pub(crate) fn round_to_nearest_byte(num_bits: u32) -> u32 { - round_to_nearest_mul_8(num_bits) / 8 -} - -pub(crate) fn boolean_expr(expr: &Expression, variables: &mut VariableStore) -> Expression { - &mul_with_witness(expr, expr, variables) - expr -} - -/// Returns an expression which represents `lhs * rhs` -/// -/// If one has multiplicative term and the other is of degree one or more, -/// the function creates [intermediate variables][`Witness`] accordingly. -/// There are two cases where we can optimize the multiplication between two expressions: -/// 1. If both expressions have at most a total degree of 1 in each term, then we can just multiply them -/// as each term in the result will be degree-2. -/// 2. If one expression is a constant, then we can just multiply the constant with the other expression -/// -/// (1) is because an [`Expression`] can hold at most a degree-2 univariate polynomial -/// which is what you get when you multiply two degree-1 univariate polynomials. -pub(crate) fn mul_with_witness( - lhs: &Expression, - rhs: &Expression, - variables: &mut VariableStore, -) -> Expression { - use std::borrow::Cow; - let lhs_is_linear = lhs.is_linear(); - let rhs_is_linear = rhs.is_linear(); - - // Case 1: Both expressions have at most a total degree of 1 in each term - if lhs_is_linear && rhs_is_linear { - return (lhs * rhs) - .expect("one of the expressions is a constant and so this should not fail"); - } - - // Case 2: One or both of the sides needs to be reduced to a degree-1 univariate polynomial - let lhs_reduced = if lhs_is_linear { - Cow::Borrowed(lhs) - } else { - Cow::Owned(variables.new_variable().into()) - }; - - // If the lhs and rhs are the same, then we do not need to reduce - // rhs, we only need to square the lhs. - if lhs == rhs { - return (&*lhs_reduced * &*lhs_reduced) - .expect("Both expressions are reduced to be degree<=1"); - }; - - let rhs_reduced = if rhs_is_linear { - Cow::Borrowed(rhs) - } else { - Cow::Owned(variables.new_variable().into()) - }; - - (&*lhs_reduced * &*rhs_reduced).expect("Both expressions are reduced to be degree<=1") -} - -// Generates opcodes and directives to bit decompose the input `opcode` -// Returns the bits and the updated witness counter -// TODO:Ideally, we return the updated witness counter, or we require the input -// TODO to be a VariableStore. We are not doing this because we want migration to -// TODO be less painful -pub(crate) fn bit_decomposition( - opcode: Expression, - bit_size: u32, - mut num_witness: u32, -) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - - // First create a witness for each bit - let mut bit_vector = Vec::with_capacity(bit_size as usize); - for _ in 0..bit_size { - bit_vector.push(variables.new_variable()); - } - - // Next create a directive which computes those bits. - new_opcodes.push(Opcode::Directive(Directive::ToLeRadix { - a: opcode.clone(), - b: bit_vector.clone(), - radix: 2, - })); - - // Now apply constraints to the bits such that they are the bit decomposition - // of the input and each bit is actually a bit - let mut binary_exprs = Vec::new(); - let mut bit_decomp_constraint = opcode; - let mut two_pow: FieldElement = FieldElement::one(); - let two = FieldElement::from(2_i128); - for &bit in &bit_vector { - // Bit constraint to ensure each bit is a zero or one; bit^2 - bit = 0 - let expr = boolean_expr(&bit.into(), &mut variables); - binary_exprs.push(Opcode::Arithmetic(expr)); - - // Constraint to ensure that the bits are constrained to be a bit decomposition - // of the input - // ie \sum 2^i * x_i = input - bit_decomp_constraint.push_addition_term(-two_pow, bit); - two_pow = two * two_pow; - } - - new_opcodes.extend(binary_exprs); - bit_decomp_constraint.sort(); // TODO: we have an issue open to check if this is needed. Ideally, we remove it. - new_opcodes.push(Opcode::Arithmetic(bit_decomp_constraint)); - - (new_opcodes, bit_vector, variables.finalize()) -} - -// TODO: Maybe this can be merged with `bit_decomposition` -pub(crate) fn byte_decomposition( - opcode: Expression, - num_bytes: u32, - mut num_witness: u32, -) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - - // First create a witness for each byte - let mut vector = Vec::with_capacity(num_bytes as usize); - for _ in 0..num_bytes { - vector.push(variables.new_variable()); - } - - // Next create a directive which computes those byte. - new_opcodes.push(Opcode::Directive(Directive::ToLeRadix { - a: opcode.clone(), - b: vector.clone(), - radix: 256, - })); - vector.reverse(); - - // Now apply constraints to the bytes such that they are the byte decomposition - // of the input and each byte is actually a byte - let mut byte_exprs = Vec::new(); - let mut decomp_constraint = opcode; - let byte_shift: u128 = 256; - for (i, v) in vector.iter().enumerate() { - let range = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: *v, num_bits: 8 }, - }); - let scaling_factor_value = byte_shift.pow(num_bytes - 1 - i as u32); - let scaling_factor = FieldElement::from(scaling_factor_value); - - decomp_constraint.push_addition_term(-scaling_factor, *v); - - byte_exprs.push(range); - } - - new_opcodes.extend(byte_exprs); - decomp_constraint.sort(); - new_opcodes.push(Opcode::Arithmetic(decomp_constraint)); - - (new_opcodes, vector, variables.finalize()) -} diff --git a/acvm-repo/stdlib/src/helpers.rs b/acvm-repo/stdlib/src/helpers.rs deleted file mode 100644 index 5ab258368f..0000000000 --- a/acvm-repo/stdlib/src/helpers.rs +++ /dev/null @@ -1,23 +0,0 @@ -use acir::native_types::Witness; - -// Simple helper struct to keep track of the current witness index -// and create variables -pub struct VariableStore<'a> { - witness_index: &'a mut u32, -} - -impl<'a> VariableStore<'a> { - pub fn new(witness_index: &'a mut u32) -> Self { - Self { witness_index } - } - - pub fn new_variable(&mut self) -> Witness { - let witness = Witness(*self.witness_index); - *self.witness_index += 1; - witness - } - - pub fn finalize(self) -> u32 { - *self.witness_index - } -} diff --git a/acvm-repo/stdlib/src/lib.rs b/acvm-repo/stdlib/src/lib.rs deleted file mode 100644 index 9aecde631f..0000000000 --- a/acvm-repo/stdlib/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![forbid(unsafe_code)] -#![warn(unreachable_pub)] -#![warn(clippy::semicolon_if_nothing_returned)] -#![cfg_attr(not(test), warn(unused_crate_dependencies, unused_extern_crates))] - -pub mod blackbox_fallbacks; -pub mod helpers; diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 712913841f..1f85145260 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -1605,28 +1605,28 @@ fn execute_brillig( _signature: &[u8], _message: &[u8], ) -> Result { - Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::SchnorrVerify)) + unimplemented!("SchnorrVerify is not supported") } fn pedersen_commitment( &self, _inputs: &[FieldElement], _domain_separator: u32, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::PedersenCommitment)) + unimplemented!("PedersenCommitment is not supported") } fn pedersen_hash( &self, _inputs: &[FieldElement], _domain_separator: u32, ) -> Result { - Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::PedersenHash)) + unimplemented!("PedersenHash is not supported") } fn fixed_base_scalar_mul( &self, _low: &FieldElement, _high: &FieldElement, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::FixedBaseScalarMul)) + unimplemented!("FixedBaseScalarMul is not supported") } } diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index 13b366819b..2d99963ea1 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -186,8 +186,6 @@ pub fn compile( // For now we default to plonk width = 3, though we can add it as a parameter let np_language = acvm::Language::PLONKCSat { width: 3 }; - #[allow(deprecated)] - let is_opcode_supported = acvm::pwg::default_is_opcode_supported(np_language); if contracts.unwrap_or_default() { let compiled_contract = compile_contract(&mut context, crate_id, &compile_options) @@ -200,9 +198,7 @@ pub fn compile( })? .0; - let optimized_contract = - nargo::ops::optimize_contract(compiled_contract, np_language, &is_opcode_supported) - .expect("Contract optimization failed"); + let optimized_contract = nargo::ops::optimize_contract(compiled_contract, np_language); let compile_output = preprocess_contract(optimized_contract); Ok(JsCompileResult::new(compile_output)) @@ -217,9 +213,7 @@ pub fn compile( })? .0; - let optimized_program = - nargo::ops::optimize_program(compiled_program, np_language, &is_opcode_supported) - .expect("Program optimization failed"); + let optimized_program = nargo::ops::optimize_program(compiled_program, np_language); let compile_output = preprocess_program(optimized_program); Ok(JsCompileResult::new(compile_output)) diff --git a/release-please-config.json b/release-please-config.json index 3c5397c678..e73993ca97 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -65,7 +65,6 @@ "blackbox_solver/Cargo.toml", "brillig/Cargo.toml", "brillig_vm/Cargo.toml", - "stdlib/Cargo.toml", { "type": "json", "path": "acvm_js/package.json", diff --git a/tooling/backend_interface/src/cli/info.rs b/tooling/backend_interface/src/cli/info.rs index d3fd89bd2b..1aa2e640b1 100644 --- a/tooling/backend_interface/src/cli/info.rs +++ b/tooling/backend_interface/src/cli/info.rs @@ -1,9 +1,8 @@ use acvm::Language; use serde::Deserialize; -use std::collections::HashSet; use std::path::{Path, PathBuf}; -use crate::{BackendError, BackendOpcodeSupport}; +use crate::BackendError; use super::string_from_stderr; @@ -14,7 +13,11 @@ pub(crate) struct InfoCommand { #[derive(Deserialize)] struct InfoResponse { language: LanguageResponse, + #[allow(dead_code)] + #[deprecated(note = "This field is deprecated and will be removed in the future")] opcodes_supported: Vec, + #[allow(dead_code)] + #[deprecated(note = "This field is deprecated and will be removed in the future")] black_box_functions_supported: Vec, } @@ -24,20 +27,8 @@ struct LanguageResponse { width: Option, } -impl BackendOpcodeSupport { - fn new(info: InfoResponse) -> Self { - let opcodes: HashSet = info.opcodes_supported.into_iter().collect(); - let black_box_functions: HashSet = - info.black_box_functions_supported.into_iter().collect(); - Self { opcodes, black_box_functions } - } -} - impl InfoCommand { - pub(crate) fn run( - self, - binary_path: &Path, - ) -> Result<(Language, BackendOpcodeSupport), BackendError> { + pub(crate) fn run(self, binary_path: &Path) -> Result { let mut command = std::process::Command::new(binary_path); command.arg("info").arg("-c").arg(self.crs_path).arg("-o").arg("-"); @@ -59,23 +50,18 @@ impl InfoCommand { _ => panic!("Unknown langauge"), }; - Ok((language, BackendOpcodeSupport::new(backend_info))) + Ok(language) } } #[test] fn info_command() -> Result<(), BackendError> { - use acvm::acir::circuit::opcodes::Opcode; - - use acvm::acir::native_types::Expression; - let backend = crate::get_mock_backend()?; let crs_path = backend.backend_directory(); - let (language, opcode_support) = InfoCommand { crs_path }.run(backend.binary_path())?; + let language = InfoCommand { crs_path }.run(backend.binary_path())?; assert!(matches!(language, Language::PLONKCSat { width: 3 })); - assert!(opcode_support.is_opcode_supported(&Opcode::Arithmetic(Expression::default()))); Ok(()) } diff --git a/tooling/backend_interface/src/lib.rs b/tooling/backend_interface/src/lib.rs index d25319e11d..c5232c3473 100644 --- a/tooling/backend_interface/src/lib.rs +++ b/tooling/backend_interface/src/lib.rs @@ -1,14 +1,13 @@ #![warn(unused_crate_dependencies, unused_extern_crates)] #![warn(unreachable_pub)] -use std::{collections::HashSet, path::PathBuf}; +use std::path::PathBuf; mod cli; mod download; mod proof_system; mod smart_contract; -use acvm::acir::circuit::Opcode; use bb_abstraction_leaks::ACVM_BACKEND_BARRETENBERG; use bb_abstraction_leaks::BB_VERSION; use cli::VersionCommand; @@ -135,54 +134,6 @@ impl Backend { } } -pub struct BackendOpcodeSupport { - opcodes: HashSet, - black_box_functions: HashSet, -} - -impl BackendOpcodeSupport { - pub fn is_opcode_supported(&self, opcode: &Opcode) -> bool { - match opcode { - Opcode::Arithmetic(_) => self.opcodes.contains("arithmetic"), - Opcode::Directive(_) => self.opcodes.contains("directive"), - Opcode::Brillig(_) => self.opcodes.contains("brillig"), - Opcode::MemoryInit { .. } => self.opcodes.contains("memory_init"), - Opcode::MemoryOp { .. } => self.opcodes.contains("memory_op"), - Opcode::BlackBoxFuncCall(func) => { - self.black_box_functions.contains(func.get_black_box_func().name()) - } - } - } - - pub fn all() -> BackendOpcodeSupport { - BackendOpcodeSupport { - opcodes: HashSet::from([ - "arithmetic".to_string(), - "directive".to_string(), - "brillig".to_string(), - "memory_init".to_string(), - "memory_op".to_string(), - ]), - black_box_functions: HashSet::from([ - "sha256".to_string(), - "schnorr_verify".to_string(), - "blake2s".to_string(), - "pedersen".to_string(), - "pedersen_hash".to_string(), - "hash_to_field_128_security".to_string(), - "ecdsa_secp256k1".to_string(), - "fixed_base_scalar_mul".to_string(), - "and".to_string(), - "xor".to_string(), - "range".to_string(), - "keccak256".to_string(), - "recursive_aggregation".to_string(), - "ecdsa_secp256r1".to_string(), - ]), - } - } -} - #[cfg(test)] mod backend { use crate::{Backend, BackendError}; diff --git a/tooling/backend_interface/src/proof_system.rs b/tooling/backend_interface/src/proof_system.rs index bb47603bbf..1de4b352bf 100644 --- a/tooling/backend_interface/src/proof_system.rs +++ b/tooling/backend_interface/src/proof_system.rs @@ -11,7 +11,7 @@ use crate::cli::{ GatesCommand, InfoCommand, ProofAsFieldsCommand, ProveCommand, VerifyCommand, VkAsFieldsCommand, WriteVkCommand, }; -use crate::{Backend, BackendError, BackendOpcodeSupport}; +use crate::{Backend, BackendError}; impl Backend { pub fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result { @@ -30,21 +30,20 @@ impl Backend { .run(binary_path) } - pub fn get_backend_info(&self) -> Result<(Language, BackendOpcodeSupport), BackendError> { + pub fn get_backend_info(&self) -> Result { let binary_path = self.assert_binary_exists()?; self.assert_correct_version()?; InfoCommand { crs_path: self.crs_directory() }.run(binary_path) } - /// If we cannot get a valid backend, returns the default backend which supports all the opcodes - /// and uses Plonk with width 3 + /// If we cannot get a valid backend, returns Plonk with width 3 /// The function also prints a message saying we could not find a backend - pub fn get_backend_info_or_default(&self) -> (Language, BackendOpcodeSupport) { - if let Ok(backend_info) = self.get_backend_info() { - (backend_info.0, backend_info.1) + pub fn get_backend_info_or_default(&self) -> Language { + if let Ok(language) = self.get_backend_info() { + language } else { - log::warn!("No valid backend found, defaulting to Plonk with width 3 and all opcodes supported"); - (Language::PLONKCSat { width: 3 }, BackendOpcodeSupport::all()) + log::warn!("No valid backend found, defaulting to Plonk with width 3"); + Language::PLONKCSat { width: 3 } } } diff --git a/tooling/lsp/src/requests/profile_run.rs b/tooling/lsp/src/requests/profile_run.rs index 84888d30ba..231003e1e8 100644 --- a/tooling/lsp/src/requests/profile_run.rs +++ b/tooling/lsp/src/requests/profile_run.rs @@ -3,7 +3,7 @@ use std::{ future::{self, Future}, }; -use acvm::{acir::circuit::Opcode, Language}; +use acvm::Language; use async_lsp::{ErrorCode, ResponseError}; use nargo::artifacts::debug::DebugArtifact; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; @@ -57,8 +57,6 @@ fn on_profile_run_request_inner( .cloned() .partition(|package| package.is_binary()); - // # TODO(#3504): Consider how to incorporate Backend relevant information in wider context. - let is_opcode_supported = |_opcode: &Opcode| true; let np_language = Language::PLONKCSat { width: 3 }; let (compiled_programs, compiled_contracts) = nargo::ops::compile_workspace( @@ -66,7 +64,6 @@ fn on_profile_run_request_inner( &binary_packages, &contract_packages, np_language, - is_opcode_supported, &CompileOptions::default(), ) .map_err(|err| ResponseError::new(ErrorCode::REQUEST_FAILED, err))?; diff --git a/tooling/nargo/src/errors.rs b/tooling/nargo/src/errors.rs index bca8ca2476..c743768bee 100644 --- a/tooling/nargo/src/errors.rs +++ b/tooling/nargo/src/errors.rs @@ -47,12 +47,6 @@ pub enum NargoError { ForeignCallError(#[from] ForeignCallError), } -impl From for NargoError { - fn from(_: acvm::compiler::CompileError) -> Self { - NargoError::CompilationError - } -} - impl NargoError { /// Extracts the user defined failure message from the ExecutionError /// If one exists. @@ -69,7 +63,6 @@ impl NargoError { ExecutionError::AssertionFailed(message, _) => Some(message), ExecutionError::SolvingError(error) => match error { OpcodeResolutionError::IndexOutOfBounds { .. } - | OpcodeResolutionError::UnsupportedBlackBoxFunc(_) | OpcodeResolutionError::OpcodeNotSolvable(_) | OpcodeResolutionError::UnsatisfiedConstrain { .. } => None, OpcodeResolutionError::BrilligFunctionFailed { message, .. } => Some(message), diff --git a/tooling/nargo/src/ops/compile.rs b/tooling/nargo/src/ops/compile.rs index 59ac5672a1..c23ab242ae 100644 --- a/tooling/nargo/src/ops/compile.rs +++ b/tooling/nargo/src/ops/compile.rs @@ -1,4 +1,4 @@ -use acvm::{acir::circuit::Opcode, Language}; +use acvm::Language; use fm::FileManager; use noirc_driver::{CompilationResult, CompileOptions, CompiledContract, CompiledProgram}; @@ -18,22 +18,17 @@ pub fn compile_workspace( binary_packages: &[Package], contract_packages: &[Package], np_language: Language, - is_opcode_supported: impl Fn(&Opcode) -> bool + std::marker::Sync, compile_options: &CompileOptions, ) -> Result<(Vec, Vec), CompileError> { // Compile all of the packages in parallel. let program_results: Vec<(FileManager, CompilationResult)> = binary_packages .par_iter() - .map(|package| { - compile_program(workspace, package, compile_options, np_language, &is_opcode_supported) - }) + .map(|package| compile_program(workspace, package, compile_options, np_language)) .collect(); let contract_results: Vec<(FileManager, CompilationResult)> = contract_packages .par_iter() - .map(|package| { - compile_contract(package, compile_options, np_language, &is_opcode_supported) - }) + .map(|package| compile_contract(package, compile_options, np_language)) .collect(); // Report any warnings/errors which were encountered during compilation. @@ -68,7 +63,6 @@ pub fn compile_program( package: &Package, compile_options: &CompileOptions, np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, ) -> (FileManager, CompilationResult) { let (mut context, crate_id) = prepare_package(package); @@ -85,8 +79,7 @@ pub fn compile_program( }; // Apply backend specific optimizations. - let optimized_program = crate::ops::optimize_program(program, np_language, is_opcode_supported) - .expect("Backend does not support an opcode that is in the IR"); + let optimized_program = crate::ops::optimize_program(program, np_language); (context.file_manager, Ok((optimized_program, warnings))) } @@ -95,7 +88,6 @@ fn compile_contract( package: &Package, compile_options: &CompileOptions, np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, ) -> (FileManager, CompilationResult) { let (mut context, crate_id) = prepare_package(package); let (contract, warnings) = @@ -106,9 +98,7 @@ fn compile_contract( } }; - let optimized_contract = - crate::ops::optimize_contract(contract, np_language, &is_opcode_supported) - .expect("Backend does not support an opcode that is in the IR"); + let optimized_contract = crate::ops::optimize_contract(contract, np_language); (context.file_manager, Ok((optimized_contract, warnings))) } diff --git a/tooling/nargo/src/ops/optimize.rs b/tooling/nargo/src/ops/optimize.rs index 54e2432aa4..6f96a49d04 100644 --- a/tooling/nargo/src/ops/optimize.rs +++ b/tooling/nargo/src/ops/optimize.rs @@ -1,34 +1,23 @@ -use acvm::{acir::circuit::Opcode, Language}; -use iter_extended::try_vecmap; +use acvm::Language; +use iter_extended::vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; -use crate::NargoError; - -pub fn optimize_program( - mut program: CompiledProgram, - np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, -) -> Result { - let (optimized_circuit, location_map) = - acvm::compiler::compile(program.circuit, np_language, is_opcode_supported)?; +pub fn optimize_program(mut program: CompiledProgram, np_language: Language) -> CompiledProgram { + let (optimized_circuit, location_map) = acvm::compiler::compile(program.circuit, np_language); program.circuit = optimized_circuit; program.debug.update_acir(location_map); - Ok(program) + program } -pub fn optimize_contract( - contract: CompiledContract, - np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, -) -> Result { - let functions = try_vecmap(contract.functions, |mut func| { +pub fn optimize_contract(contract: CompiledContract, np_language: Language) -> CompiledContract { + let functions = vecmap(contract.functions, |mut func| { let (optimized_bytecode, location_map) = - acvm::compiler::compile(func.bytecode, np_language, is_opcode_supported)?; + acvm::compiler::compile(func.bytecode, np_language); func.bytecode = optimized_bytecode; func.debug.update_acir(location_map); - Ok::<_, NargoError>(func) - })?; + func + }); - Ok(CompiledContract { functions, ..contract }) + CompiledContract { functions, ..contract } } diff --git a/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs b/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs index 02c83adb59..dfda25043f 100644 --- a/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -7,7 +7,6 @@ use crate::backends::Backend; use crate::errors::CliError; use acvm::Language; -use backend_interface::BackendOpcodeSupport; use bb_abstraction_leaks::ACVM_BACKEND_BARRETENBERG; use clap::Args; use nargo::package::Package; @@ -46,7 +45,7 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; - let (np_language, opcode_support) = backend.get_backend_info()?; + let np_language = backend.get_backend_info()?; for package in &workspace { let smart_contract_string = smart_contract_for_package( &workspace, @@ -54,7 +53,6 @@ pub(crate) fn run( package, &args.compile_options, np_language, - &opcode_support, )?; let contract_dir = workspace.contracts_directory_path(package); @@ -74,10 +72,8 @@ fn smart_contract_for_package( package: &Package, compile_options: &CompileOptions, np_language: Language, - opcode_support: &BackendOpcodeSupport, ) -> Result { - let program = - compile_bin_package(workspace, package, compile_options, np_language, opcode_support)?; + let program = compile_bin_package(workspace, package, compile_options, np_language)?; let mut smart_contract_string = backend.eth_contract(&program.circuit)?; diff --git a/tooling/nargo_cli/src/cli/compile_cmd.rs b/tooling/nargo_cli/src/cli/compile_cmd.rs index 043c084195..f0fb0cc1ec 100644 --- a/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -1,8 +1,6 @@ use std::path::Path; -use acvm::acir::circuit::Opcode; use acvm::Language; -use backend_interface::BackendOpcodeSupport; use fm::FileManager; use iter_extended::vecmap; use nargo::artifacts::contract::PreprocessedContract; @@ -72,13 +70,12 @@ pub(crate) fn run( .cloned() .partition(|package| package.is_binary()); - let (np_language, opcode_support) = backend.get_backend_info_or_default(); + let np_language = backend.get_backend_info_or_default(); let (_, compiled_contracts) = compile_workspace( &workspace, &binary_packages, &contract_packages, np_language, - &opcode_support, &args.compile_options, )?; @@ -95,24 +92,17 @@ pub(super) fn compile_workspace( binary_packages: &[Package], contract_packages: &[Package], np_language: Language, - opcode_support: &BackendOpcodeSupport, compile_options: &CompileOptions, ) -> Result<(Vec, Vec), CliError> { // Compile all of the packages in parallel. let program_results: Vec<(FileManager, CompilationResult)> = binary_packages .par_iter() - .map(|package| { - let is_opcode_supported = |opcode: &_| opcode_support.is_opcode_supported(opcode); - compile_program(workspace, package, compile_options, np_language, &is_opcode_supported) - }) + .map(|package| compile_program(workspace, package, compile_options, np_language)) .collect(); let contract_results: Vec<(FileManager, CompilationResult)> = contract_packages .par_iter() - .map(|package| { - let is_opcode_supported = |opcode: &_| opcode_support.is_opcode_supported(opcode); - compile_contract(package, compile_options, np_language, &is_opcode_supported) - }) + .map(|package| compile_contract(package, compile_options, np_language)) .collect(); // Report any warnings/errors which were encountered during compilation. @@ -147,16 +137,13 @@ pub(crate) fn compile_bin_package( package: &Package, compile_options: &CompileOptions, np_language: Language, - opcode_support: &BackendOpcodeSupport, ) -> Result { if package.is_library() { return Err(CompileError::LibraryCrate(package.name.clone()).into()); } let (file_manager, compilation_result) = - compile_program(workspace, package, compile_options, np_language, &|opcode| { - opcode_support.is_opcode_supported(opcode) - }); + compile_program(workspace, package, compile_options, np_language); let program = report_errors( compilation_result, @@ -173,7 +160,6 @@ fn compile_program( package: &Package, compile_options: &CompileOptions, np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, ) -> (FileManager, CompilationResult) { let (mut context, crate_id) = prepare_package(package); @@ -213,8 +199,7 @@ fn compile_program( }; // Apply backend specific optimizations. - let optimized_program = nargo::ops::optimize_program(program, np_language, is_opcode_supported) - .expect("Backend does not support an opcode that is in the IR"); + let optimized_program = nargo::ops::optimize_program(program, np_language); let only_acir = compile_options.only_acir; save_program(optimized_program.clone(), package, &workspace.target_directory_path(), only_acir); @@ -225,7 +210,6 @@ fn compile_contract( package: &Package, compile_options: &CompileOptions, np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, ) -> (FileManager, CompilationResult) { let (mut context, crate_id) = prepare_package(package); let (contract, warnings) = @@ -236,9 +220,7 @@ fn compile_contract( } }; - let optimized_contract = - nargo::ops::optimize_contract(contract, np_language, &is_opcode_supported) - .expect("Backend does not support an opcode that is in the IR"); + let optimized_contract = nargo::ops::optimize_contract(contract, np_language); (context.file_manager, Ok((optimized_contract, warnings))) } diff --git a/tooling/nargo_cli/src/cli/debug_cmd.rs b/tooling/nargo_cli/src/cli/debug_cmd.rs index 5204e0f122..ba07b3b096 100644 --- a/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -49,7 +49,7 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; let target_dir = &workspace.target_directory_path(); - let (np_language, opcode_support) = backend.get_backend_info()?; + let np_language = backend.get_backend_info()?; let Some(package) = workspace.into_iter().find(|p| p.is_binary()) else { println!( @@ -58,13 +58,8 @@ pub(crate) fn run( return Ok(()); }; - let compiled_program = compile_bin_package( - &workspace, - package, - &args.compile_options, - np_language, - &opcode_support, - )?; + let compiled_program = + compile_bin_package(&workspace, package, &args.compile_options, np_language)?; run_async(package, compiled_program, &args.prover_name, &args.witness_name, target_dir) } diff --git a/tooling/nargo_cli/src/cli/execute_cmd.rs b/tooling/nargo_cli/src/cli/execute_cmd.rs index 2f69b4c7df..ac3d80fe1f 100644 --- a/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -56,15 +56,10 @@ pub(crate) fn run( )?; let target_dir = &workspace.target_directory_path(); - let (np_language, opcode_support) = backend.get_backend_info_or_default(); + let np_language = backend.get_backend_info_or_default(); for package in &workspace { - let compiled_program = compile_bin_package( - &workspace, - package, - &args.compile_options, - np_language, - &opcode_support, - )?; + let compiled_program = + compile_bin_package(&workspace, package, &args.compile_options, np_language)?; let (return_value, solved_witness) = execute_program_and_decode(compiled_program, package, &args.prover_name)?; diff --git a/tooling/nargo_cli/src/cli/info_cmd.rs b/tooling/nargo_cli/src/cli/info_cmd.rs index b0f771bfc1..9c2f10aab8 100644 --- a/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/tooling/nargo_cli/src/cli/info_cmd.rs @@ -67,13 +67,12 @@ pub(crate) fn run( .cloned() .partition(|package| package.is_binary()); - let (np_language, opcode_support) = backend.get_backend_info_or_default(); + let np_language = backend.get_backend_info_or_default(); let (compiled_programs, compiled_contracts) = compile_workspace( &workspace, &binary_packages, &contract_packages, np_language, - &opcode_support, &args.compile_options, )?; diff --git a/tooling/nargo_cli/src/cli/prove_cmd.rs b/tooling/nargo_cli/src/cli/prove_cmd.rs index 54b148ec3a..da8812fc93 100644 --- a/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -57,15 +57,9 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; - let (np_language, opcode_support) = backend.get_backend_info()?; + let np_language = backend.get_backend_info()?; for package in &workspace { - let program = compile_bin_package( - &workspace, - package, - &args.compile_options, - np_language, - &opcode_support, - )?; + let program = compile_bin_package(&workspace, package, &args.compile_options, np_language)?; prove_package( backend, diff --git a/tooling/nargo_cli/src/cli/verify_cmd.rs b/tooling/nargo_cli/src/cli/verify_cmd.rs index 2f8a6efbba..53b046a5b7 100644 --- a/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -48,15 +48,9 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; - let (np_language, opcode_support) = backend.get_backend_info()?; + let np_language = backend.get_backend_info()?; for package in &workspace { - let program = compile_bin_package( - &workspace, - package, - &args.compile_options, - np_language, - &opcode_support, - )?; + let program = compile_bin_package(&workspace, package, &args.compile_options, np_language)?; verify_package(backend, &workspace, package, program, &args.verifier_name)?; }