diff --git a/acir/src/circuit/mod.rs b/acir/src/circuit/mod.rs index f45d7cc2e..90b7bbea2 100644 --- a/acir/src/circuit/mod.rs +++ b/acir/src/circuit/mod.rs @@ -112,10 +112,10 @@ mod tests { use std::collections::BTreeSet; use super::{ - opcodes::{BlackBoxFuncCall, FunctionInput, OracleData}, + opcodes::{BlackBoxFuncCall, FunctionInput}, Circuit, Opcode, PublicInputs, }; - use crate::native_types::{Expression, Witness}; + use crate::native_types::Witness; use acir_field::FieldElement; fn directive_opcode() -> Opcode { @@ -136,25 +136,12 @@ mod tests { input: FunctionInput { witness: Witness(1), num_bits: 8 }, }) } - fn oracle_opcode() -> Opcode { - Opcode::Oracle(OracleData { - name: String::from("oracle-name"), - inputs: vec![Expression { - mul_terms: vec![(FieldElement::from(123u128), Witness(1), Witness(2))], - linear_combinations: vec![(FieldElement::from(456u128), Witness(34))], - q_c: FieldElement::from(12345678u128), - }], - input_values: vec![], - outputs: vec![Witness(1), Witness(2), Witness(3)], - output_values: vec![], - }) - } #[test] fn serialization_roundtrip() { let circuit = Circuit { current_witness_index: 5, - opcodes: vec![and_opcode(), range_opcode(), oracle_opcode(), directive_opcode()], + opcodes: vec![and_opcode(), range_opcode(), directive_opcode()], public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(12)])), return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(4), Witness(12)])), }; @@ -182,7 +169,6 @@ mod tests { }), range_opcode(), and_opcode(), - oracle_opcode(), ], public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])), return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])), diff --git a/acir/src/circuit/opcodes.rs b/acir/src/circuit/opcodes.rs index 59688c628..1e285254e 100644 --- a/acir/src/circuit/opcodes.rs +++ b/acir/src/circuit/opcodes.rs @@ -7,11 +7,9 @@ use serde::{Deserialize, Serialize}; mod black_box_function_call; mod block; -mod oracle_data; pub use black_box_function_call::{BlackBoxFuncCall, FunctionInput}; pub use block::{BlockId, MemOp, MemoryBlock}; -pub use oracle_data::OracleData; #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum Opcode { @@ -37,7 +35,6 @@ pub enum Opcode { // TODO(#319): Review this comment and generalize it to be useful for other backends. // RAM is required for acvm-backend-barretenberg as dynamic memory implementation in Barretenberg requires an initialization phase and can only handle constant values for operations. RAM(MemoryBlock), - Oracle(OracleData), Brillig(Brillig), } @@ -52,7 +49,6 @@ impl Opcode { Opcode::Block(_) => "block", Opcode::RAM(_) => "ram", Opcode::ROM(_) => "rom", - Opcode::Oracle(data) => &data.name, Opcode::Brillig(_) => "brillig", } } @@ -150,10 +146,6 @@ impl std::fmt::Display for Opcode { write!(f, "RAM ")?; write!(f, "(id: {}, len: {}) ", block.id.0, block.trace.len()) } - Opcode::Oracle(data) => { - write!(f, "ORACLE: ")?; - write!(f, "{data}") - } Opcode::Brillig(brillig) => { write!(f, "BRILLIG: ")?; writeln!(f, "inputs: {:?}", brillig.inputs)?; diff --git a/acir/src/circuit/opcodes/oracle_data.rs b/acir/src/circuit/opcodes/oracle_data.rs deleted file mode 100644 index b2843cc1f..000000000 --- a/acir/src/circuit/opcodes/oracle_data.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::native_types::{Expression, Witness}; -use acir_field::FieldElement; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct OracleData { - /// Name of the oracle - pub name: String, - /// Inputs - pub inputs: Vec, - /// Input values - they are progressively computed by the pwg - pub input_values: Vec, - /// Output witness - pub outputs: Vec, - /// Output values - they are computed by the (external) oracle once the input_values are known - pub output_values: Vec, -} - -impl std::fmt::Display for OracleData { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "ORACLE: {}", self.name)?; - let solved = if self.input_values.len() == self.inputs.len() { "solved" } else { "" }; - - if !self.inputs.is_empty() { - write!( - f, - "Inputs: _{}..._{}{solved}", - self.inputs.first().unwrap(), - self.inputs.last().unwrap() - )?; - } - - let solved = if self.output_values.len() == self.outputs.len() { "solved" } else { "" }; - write!( - f, - "Outputs: _{}..._{}{solved}", - self.outputs.first().unwrap().witness_index(), - self.outputs.last().unwrap().witness_index() - ) - } -} diff --git a/acvm/src/compiler/transformers/fallback.rs b/acvm/src/compiler/transformers/fallback.rs index ed5fe7a82..c1ad43061 100644 --- a/acvm/src/compiler/transformers/fallback.rs +++ b/acvm/src/compiler/transformers/fallback.rs @@ -32,10 +32,8 @@ impl FallbackTransformer { | Opcode::Brillig(_) | Opcode::Block(_) | Opcode::ROM(_) - | Opcode::RAM(_) - | Opcode::Oracle { .. } => { + | Opcode::RAM(_) => { // directive, arithmetic expression or blocks are handled by acvm - // The oracle opcode is assumed to be supported. acir_supported_opcodes.push(opcode); continue; } diff --git a/acvm/src/pwg/mod.rs b/acvm/src/pwg/mod.rs index bc653749f..cf3a9f281 100644 --- a/acvm/src/pwg/mod.rs +++ b/acvm/src/pwg/mod.rs @@ -3,16 +3,12 @@ use crate::{Language, PartialWitnessGenerator}; use acir::{ brillig_vm::ForeignCallResult, - circuit::brillig::Brillig, - circuit::opcodes::{Opcode, OracleData}, + circuit::{brillig::Brillig, Opcode}, native_types::{Expression, Witness, WitnessMap}, BlackBoxFunc, FieldElement, }; -use self::{ - arithmetic::ArithmeticSolver, brillig::BrilligSolver, directives::solve_directives, - oracle::OracleSolver, -}; +use self::{arithmetic::ArithmeticSolver, brillig::BrilligSolver, directives::solve_directives}; use thiserror::Error; @@ -25,7 +21,6 @@ mod directives; // black box functions mod blackbox; mod block; -mod oracle; // Re-export `Blocks` so that it can be passed to `pwg::solve` pub use block::Blocks; @@ -36,17 +31,12 @@ pub enum PartialWitnessGeneratorStatus { /// All opcodes have been solved. Solved, - /// The `PartialWitnessGenerator` has encountered a request for [oracle data][Opcode::Oracle] or a Brillig [foreign call][acir::brillig_vm::Opcode::ForeignCall]. - /// - /// Both of these opcodes require information from outside of the ACVM to be inserted before restarting execution. - /// [`Opcode::Oracle`] and [`Opcode::Brillig`] opcodes require the return values to be inserted slightly differently. - /// `Oracle` opcodes expect their return values to be written directly into the witness map whereas a `Brillig` foreign call - /// result is inserted into the `Brillig` opcode which made the call using [`UnresolvedBrilligCall::resolve`]. - /// (Note: this means that the updated opcode must then be passed back into the ACVM to be processed further.) + /// The `PartialWitnessGenerator` has encountered a request for a Brillig [foreign call][acir::brillig_vm::Opcode::ForeignCall] + /// to retrieve information from outside of the ACVM. + /// The result of the foreign call is inserted into the `Brillig` opcode which made the call using [`UnresolvedBrilligCall::resolve`]. /// - /// Once this is done, the `PartialWitnessGenerator` can be restarted to solve the remaining opcodes. - RequiresOracleData { - required_oracle_data: Vec, + /// Once this is done, the `PartialWitnessGenerator` can be restarted to solve the new set of opcodes. + RequiresForeignCall { unsolved_opcodes: Vec, unresolved_brillig_calls: Vec, }, @@ -104,14 +94,12 @@ pub fn solve( mut opcode_to_solve: Vec, ) -> Result { let mut unresolved_opcodes: Vec = Vec::new(); - let mut unresolved_oracles: Vec = Vec::new(); let mut unresolved_brillig_calls: Vec = Vec::new(); - while !opcode_to_solve.is_empty() || !unresolved_oracles.is_empty() { + while !opcode_to_solve.is_empty() { unresolved_opcodes.clear(); let mut stalled = true; let mut opcode_not_solvable = None; for opcode in &opcode_to_solve { - let mut solved_oracle_data = None; let resolution = match opcode { Opcode::Arithmetic(expr) => ArithmeticSolver::solve(initial_witness, expr), Opcode::BlackBoxFuncCall(bb_func) => { @@ -121,12 +109,6 @@ pub fn solve( Opcode::Block(block) | Opcode::ROM(block) | Opcode::RAM(block) => { blocks.solve(block.id, &block.trace, initial_witness) } - Opcode::Oracle(data) => { - let mut data_clone = data.clone(); - let result = OracleSolver::solve(initial_witness, &mut data_clone)?; - solved_oracle_data = Some(data_clone); - Ok(result) - } Opcode::Brillig(brillig) => BrilligSolver::solve(initial_witness, brillig), }; match resolution { @@ -135,12 +117,7 @@ pub fn solve( } Ok(OpcodeResolution::InProgress) => { stalled = false; - // InProgress Oracles must be externally re-solved - if let Some(oracle) = solved_oracle_data { - unresolved_oracles.push(oracle); - } else { - unresolved_opcodes.push(opcode.clone()); - } + unresolved_opcodes.push(opcode.clone()); } Ok(OpcodeResolution::InProgressBrillig(oracle_wait_info)) => { stalled = false; @@ -162,11 +139,7 @@ pub fn solve( // We push those opcodes not solvable to the back as // it could be because the opcodes are out of order, i.e. this assignment // relies on a later opcodes' results - if let Some(oracle_data) = solved_oracle_data { - unresolved_opcodes.push(Opcode::Oracle(oracle_data)); - } else { - unresolved_opcodes.push(opcode.clone()); - } + unresolved_opcodes.push(opcode.clone()); } Err(OpcodeResolutionError::OpcodeNotSolvable(_)) => { unreachable!("ICE - Result should have been converted to GateResolution") @@ -174,10 +147,9 @@ pub fn solve( Err(err) => return Err(err), } } - // We have oracles that must be externally resolved - if !unresolved_oracles.is_empty() || !unresolved_brillig_calls.is_empty() { - return Ok(PartialWitnessGeneratorStatus::RequiresOracleData { - required_oracle_data: unresolved_oracles, + // We have foreign calls that must be externally resolved + if !unresolved_brillig_calls.is_empty() { + return Ok(PartialWitnessGeneratorStatus::RequiresForeignCall { unsolved_opcodes: unresolved_opcodes, unresolved_brillig_calls, }); diff --git a/acvm/src/pwg/oracle.rs b/acvm/src/pwg/oracle.rs deleted file mode 100644 index e6db9221f..000000000 --- a/acvm/src/pwg/oracle.rs +++ /dev/null @@ -1,44 +0,0 @@ -use acir::{circuit::opcodes::OracleData, native_types::WitnessMap}; - -use super::{arithmetic::ArithmeticSolver, insert_value}; -use super::{OpcodeNotSolvable, OpcodeResolution, OpcodeResolutionError}; - -pub(super) struct OracleSolver; - -impl OracleSolver { - /// Derives the rest of the witness based on the initial low level variables - pub(super) fn solve( - initial_witness: &mut WitnessMap, - data: &mut OracleData, - ) -> Result { - // Set input values - for input in data.inputs.iter().skip(data.input_values.len()) { - let solve = ArithmeticSolver::evaluate(input, initial_witness); - if let Some(value) = solve.to_const() { - data.input_values.push(value); - } else { - break; - } - } - - // If all of the inputs to the oracle have assignments - if data.input_values.len() == data.inputs.len() { - if data.output_values.len() == data.outputs.len() { - for (out, value) in data.outputs.iter().zip(data.output_values.iter()) { - insert_value(out, *value, initial_witness)?; - } - Ok(OpcodeResolution::Solved) - } else { - // Missing output values - Ok(OpcodeResolution::InProgress) - } - } else { - Ok(OpcodeResolution::Stalled(OpcodeNotSolvable::ExpressionHasTooManyUnknowns( - data.inputs - .last() - .expect("Infallible: cannot reach this point if no inputs") - .clone(), - ))) - } - } -} diff --git a/acvm/tests/solver.rs b/acvm/tests/solver.rs index 332899947..c8ab3a2aa 100644 --- a/acvm/tests/solver.rs +++ b/acvm/tests/solver.rs @@ -5,7 +5,7 @@ use acir::{ circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, directives::Directive, - opcodes::{FunctionInput, OracleData}, + opcodes::FunctionInput, Opcode, }, native_types::{Expression, Witness, WitnessMap}, @@ -55,79 +55,6 @@ impl PartialWitnessGenerator for StubbedPwg { } } -#[test] -fn inversion_oracle_equivalence() { - // Opcodes below describe the following: - // fn main(x : Field, y : pub Field) { - // let z = x + y; - // constrain 1/z == Oracle("inverse", x + y); - // } - let fe_0 = FieldElement::zero(); - let fe_1 = FieldElement::one(); - let w_x = Witness(1); - let w_y = Witness(2); - let w_oracle = Witness(3); - let w_z = Witness(4); - let w_z_inverse = Witness(5); - let opcodes = vec![ - Opcode::Oracle(OracleData { - name: "invert".into(), - inputs: vec![Expression { - mul_terms: vec![], - linear_combinations: vec![(fe_1, w_x), (fe_1, w_y)], - q_c: fe_0, - }], - input_values: vec![], - outputs: vec![w_oracle], - output_values: vec![], - }), - Opcode::Arithmetic(Expression { - mul_terms: vec![], - linear_combinations: vec![(fe_1, w_x), (fe_1, w_y), (-fe_1, w_z)], - q_c: fe_0, - }), - Opcode::Directive(Directive::Invert { x: w_z, result: w_z_inverse }), - Opcode::Arithmetic(Expression { - mul_terms: vec![(fe_1, w_z, w_z_inverse)], - linear_combinations: vec![], - q_c: -fe_1, - }), - Opcode::Arithmetic(Expression { - mul_terms: vec![], - linear_combinations: vec![(-fe_1, w_oracle), (fe_1, w_z_inverse)], - q_c: fe_0, - }), - ]; - - let backend = StubbedPwg; - - let mut witness_assignments = BTreeMap::from([ - (Witness(1), FieldElement::from(2u128)), - (Witness(2), FieldElement::from(3u128)), - ]) - .into(); - let mut blocks = Blocks::default(); - let solver_status = pwg::solve(&backend, &mut witness_assignments, &mut blocks, opcodes) - .expect("should stall on oracle"); - let PartialWitnessGeneratorStatus::RequiresOracleData { mut required_oracle_data, unsolved_opcodes, .. } = solver_status else { - panic!("Should require oracle data") - }; - assert!(unsolved_opcodes.is_empty(), "oracle should be removed"); - assert_eq!(required_oracle_data.len(), 1, "should have an oracle request"); - let mut oracle_data = required_oracle_data.remove(0); - - assert_eq!(oracle_data.input_values.len(), 1, "Should have solved a single input"); - - // Filling data request and continue solving - oracle_data.output_values = vec![oracle_data.input_values.last().unwrap().inverse()]; - let mut next_opcodes_for_solving = vec![Opcode::Oracle(oracle_data)]; - next_opcodes_for_solving.extend_from_slice(&unsolved_opcodes[..]); - let solver_status = - pwg::solve(&backend, &mut witness_assignments, &mut blocks, next_opcodes_for_solving) - .expect("should be solvable"); - assert_eq!(solver_status, PartialWitnessGeneratorStatus::Solved, "should be fully solved"); -} - #[test] fn inversion_brillig_oracle_equivalence() { // Opcodes below describe the following: @@ -215,7 +142,7 @@ fn inversion_brillig_oracle_equivalence() { // use the partial witness generation solver with our acir program let solver_status = pwg::solve(&backend, &mut witness_assignments, &mut blocks, opcodes) .expect("should stall on oracle"); - let PartialWitnessGeneratorStatus::RequiresOracleData { unsolved_opcodes, mut unresolved_brillig_calls, .. } = solver_status else { + let PartialWitnessGeneratorStatus::RequiresForeignCall { unsolved_opcodes, mut unresolved_brillig_calls, .. } = solver_status else { panic!("Should require oracle data") }; @@ -347,7 +274,7 @@ fn double_inversion_brillig_oracle() { // use the partial witness generation solver with our acir program let solver_status = pwg::solve(&backend, &mut witness_assignments, &mut blocks, opcodes) .expect("should stall on oracle"); - let PartialWitnessGeneratorStatus::RequiresOracleData { unsolved_opcodes, mut unresolved_brillig_calls, .. } = solver_status else { + let PartialWitnessGeneratorStatus::RequiresForeignCall { unsolved_opcodes, mut unresolved_brillig_calls, .. } = solver_status else { panic!("Should require oracle data") }; @@ -368,7 +295,7 @@ fn double_inversion_brillig_oracle() { let solver_status = pwg::solve(&backend, &mut witness_assignments, &mut blocks, next_opcodes_for_solving) .expect("should stall on oracle"); - let PartialWitnessGeneratorStatus::RequiresOracleData { unsolved_opcodes, mut unresolved_brillig_calls, .. } = solver_status else { + let PartialWitnessGeneratorStatus::RequiresForeignCall { unsolved_opcodes, mut unresolved_brillig_calls, .. } = solver_status else { panic!("Should require oracle data") };