From f941c040342477814af789fadb3c97986963106b Mon Sep 17 00:00:00 2001 From: Koby Date: Wed, 7 Feb 2024 19:11:26 +0100 Subject: [PATCH 01/36] feat(lsp): allow function rename --- Cargo.lock | 7 + compiler/noirc_frontend/Cargo.toml | 1 + .../src/hir/resolution/resolver.rs | 30 +++- compiler/noirc_frontend/src/lib.rs | 1 + compiler/noirc_frontend/src/locations.rs | 98 +++++++++++ compiler/noirc_frontend/src/node_interner.rs | 18 +- tooling/lsp/src/lib.rs | 11 +- tooling/lsp/src/requests/mod.rs | 12 +- tooling/lsp/src/requests/rename.rs | 165 ++++++++++++++++++ tooling/lsp/src/types.rs | 7 +- 10 files changed, 338 insertions(+), 12 deletions(-) create mode 100644 compiler/noirc_frontend/src/locations.rs create mode 100644 tooling/lsp/src/requests/rename.rs diff --git a/Cargo.lock b/Cargo.lock index 812cdebde40..dca1eb20fcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2991,6 +2991,7 @@ dependencies = [ "noirc_errors", "noirc_printable_type", "petgraph", + "rangemap", "regex", "rustc-hash", "serde", @@ -3613,6 +3614,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rangemap" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977b1e897f9d764566891689e642653e5ed90c6895106acd005eb4c1d0203991" + [[package]] name = "rayon" version = "1.8.0" diff --git a/compiler/noirc_frontend/Cargo.toml b/compiler/noirc_frontend/Cargo.toml index a3a8d460572..1331ff579ef 100644 --- a/compiler/noirc_frontend/Cargo.toml +++ b/compiler/noirc_frontend/Cargo.toml @@ -24,6 +24,7 @@ small-ord-set = "0.1.3" regex = "1.9.1" tracing.workspace = true petgraph = "0.6" +rangemap = "1.4.0" [dev-dependencies] strum = "0.24" diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index b899a5a325a..468df9fbeec 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -28,8 +28,8 @@ use crate::graph::CrateId; use crate::hir::def_map::{LocalModuleId, ModuleDefId, TryFromModuleDefId, MAIN_FUNCTION}; use crate::hir_def::stmt::{HirAssignStatement, HirForStatement, HirLValue, HirPattern}; use crate::node_interner::{ - DefinitionId, DefinitionKind, ExprId, FuncId, NodeInterner, StmtId, StructId, TraitId, - TraitImplId, TraitMethodId, + DefinitionId, DefinitionKind, DependencyId, ExprId, FuncId, NodeInterner, StmtId, StructId, + TraitId, TraitImplId, TraitMethodId, }; use crate::{ hir::{def_map::CrateDefMap, resolution::path_resolver::PathResolver}, @@ -1406,6 +1406,8 @@ impl<'a> Resolver<'a> { != FunctionVisibility::Public { let span = hir_ident.location.span; + let func_def = self.interner.function_modifiers(&id); + tracing::debug!("Func definition: {:?}", (id, span, func_def)); self.check_can_reference_function( id, span, @@ -1460,10 +1462,30 @@ impl<'a> Resolver<'a> { } ExpressionKind::Call(call_expr) => { // Get the span and name of path for error reporting - let func = self.resolve_expression(*call_expr.func); + let func = self.resolve_expression(*call_expr.clone().func); - let arguments = vecmap(call_expr.arguments, |arg| self.resolve_expression(arg)); + let arguments = + vecmap(call_expr.clone().arguments, |arg| self.resolve_expression(arg)); let location = Location::new(expr.span, self.file); + + if let ExpressionKind::Variable(path) = call_expr.clone().func.kind { + let (hir_ident, _var_scope_index) = self.get_ident_from_path(path); + if hir_ident.id != DefinitionId::dummy_id() { + if let DefinitionKind::Function(func_def_id) = + self.interner.definition(hir_ident.id).kind + { + if let Some(func_meta) = self.interner.func_meta.get(&func_def_id) { + self.interner.add_reference( + (DependencyId::Function(func_def_id), func_meta.location), + ( + DependencyId::CallExpression(func), + Location::new(call_expr.func.span, self.file), + ), + ); + } + } + } + } HirExpression::Call(HirCallExpression { func, arguments, location }) } ExpressionKind::MethodCall(call_expr) => { diff --git a/compiler/noirc_frontend/src/lib.rs b/compiler/noirc_frontend/src/lib.rs index eb00a61adf6..e76eaca4ad6 100644 --- a/compiler/noirc_frontend/src/lib.rs +++ b/compiler/noirc_frontend/src/lib.rs @@ -14,6 +14,7 @@ pub mod ast; pub mod debug; pub mod graph; pub mod lexer; +pub mod locations; pub mod monomorphization; pub mod node_interner; pub mod parser; diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs new file mode 100644 index 00000000000..5415fc8f68f --- /dev/null +++ b/compiler/noirc_frontend/src/locations.rs @@ -0,0 +1,98 @@ +use fm::FileId; +use noirc_errors::Location; +use rangemap::RangeMap; +use rustc_hash::FxHashMap; + +use crate::{macros_api::NodeInterner, node_interner::DependencyId}; +use petgraph::prelude::NodeIndex as PetGraphIndex; + +#[derive(Debug, Default)] +pub(crate) struct LocationStore { + map_file_to_range: FxHashMap>, +} + +impl LocationStore { + pub(crate) fn add_location(&mut self, location: Location, node_index: PetGraphIndex) { + let range_map = self.map_file_to_range.entry(location.file).or_insert_with(RangeMap::new); + range_map.insert(location.span.start()..location.span.end(), node_index); + } + + pub(crate) fn get_node_from_location(&self, location: Location) -> Option { + let range_map = self.map_file_to_range.get(&location.file)?; + Some(*range_map.get(&location.span.start())?) + } +} + +impl NodeInterner { + pub(crate) fn add_reference( + &mut self, + referenced: (DependencyId, Location), + reference: (DependencyId, Location), + ) { + let referenced_index = self.get_or_insert_reference(referenced); + let reference_index = self.get_or_insert_reference(reference); + self.graph_references.update_edge(referenced_index, reference_index, ()); + self.location_store.add_location(referenced.1, referenced_index); + self.location_store.add_location(reference.1, reference_index); + } + + pub(crate) fn get_or_insert_reference( + &mut self, + (id, location): (DependencyId, Location), + ) -> PetGraphIndex { + if let Some(index) = self.graph_references_indices.get(&id) { + return *index; + } + + let index = self.graph_references.add_node((id, location)); + self.graph_references_indices.insert(id, index); + index + } + + pub fn check_rename_possible(&self, location: Location) -> bool { + self.location_store.get_node_from_location(location).is_some() + } + + pub fn find_rename_symbols_at(&self, location: Location) -> Option> { + let node_index = self.location_store.get_node_from_location(location)?; + + let mut edit_locations: Vec = Vec::new(); + + let reference_node = self.graph_references[node_index]; + let found_locations = match reference_node.0 { + DependencyId::Struct(_) => todo!(), + DependencyId::Global(_) => todo!(), + DependencyId::Function(_) => { + edit_locations.extend(self.get_edit_locations(node_index)); + edit_locations + } + DependencyId::Alias(_) => todo!(), + DependencyId::CallExpression(_) => { + if let Some(referenced_node_index) = self + .graph_references + .neighbors_directed(node_index, petgraph::Direction::Incoming) + .next() + { + edit_locations.extend(self.get_edit_locations(referenced_node_index)); + } + edit_locations + } + }; + Some(found_locations) + } + + fn get_edit_locations(&self, referenced_node_index: PetGraphIndex) -> Vec { + let mut edit_locations: Vec = Vec::new(); + let (_referenced_id, referencing_location) = self.graph_references[referenced_node_index]; + edit_locations.push(referencing_location); + + self.graph_references + .neighbors_directed(referenced_node_index, petgraph::Direction::Outgoing) + .for_each(|reference_node_index| { + let (_reference_dependency_id, reference_location) = + self.graph_references[reference_node_index]; + edit_locations.push(reference_location); + }); + edit_locations + } +} diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 53583bb0f17..ded1eef45b7 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -25,6 +25,7 @@ use crate::hir_def::{ function::{FuncMeta, HirFunction}, stmt::HirStatement, }; +use crate::locations::LocationStore; use crate::token::{Attributes, SecondaryAttribute}; use crate::{ BinaryOpKind, ContractFunctionType, FunctionDefinition, FunctionVisibility, Generics, Shared, @@ -164,6 +165,13 @@ pub struct NodeInterner { /// Stores the [Location] of a [Type] reference pub(crate) type_ref_locations: Vec<(Type, Location)>, + + /// Store the location of the references in the graph + pub(crate) graph_references: DiGraph<(DependencyId, Location), ()>, + /// Tracks the index of the references in the graph + pub(crate) graph_references_indices: HashMap, + /// Store the location of the references in the graph + pub(crate) location_store: LocationStore, } /// A dependency in the dependency graph may be a type or a definition. @@ -182,6 +190,7 @@ pub enum DependencyId { Global(StmtId), Function(FuncId), Alias(TypeAliasId), + CallExpression(ExprId), } /// A trait implementation is either a normal implementation that is present in the source @@ -494,6 +503,9 @@ impl Default for NodeInterner { primitive_methods: HashMap::new(), type_alias_ref: Vec::new(), type_ref_locations: Vec::new(), + location_store: LocationStore::default(), + graph_references: petgraph::graph::DiGraph::new(), + graph_references_indices: HashMap::new(), }; // An empty block expression is used often, we add this into the `node` on startup @@ -1464,13 +1476,13 @@ impl NodeInterner { self.add_dependency(DependencyId::Struct(dependent), DependencyId::Global(dependency)); } - fn add_dependency(&mut self, dependent: DependencyId, dependency: DependencyId) { + pub(crate) fn add_dependency(&mut self, dependent: DependencyId, dependency: DependencyId) { let dependent_index = self.get_or_insert_dependency(dependent); let dependency_index = self.get_or_insert_dependency(dependency); self.dependency_graph.update_edge(dependent_index, dependency_index, ()); } - fn get_or_insert_dependency(&mut self, id: DependencyId) -> PetGraphIndex { + pub(crate) fn get_or_insert_dependency(&mut self, id: DependencyId) -> PetGraphIndex { if let Some(index) = self.dependency_graph_indices.get(&id) { return *index; } @@ -1520,6 +1532,7 @@ impl NodeInterner { } // Mutually recursive functions are allowed DependencyId::Function(_) => (), + _ => (), } } } @@ -1547,6 +1560,7 @@ impl NodeInterner { }; Cow::Owned(self.pattern_name_and_location(&let_stmt.pattern).0) } + _ => Cow::Borrowed(""), }; let mut cycle = index_to_string(scc[start_index]).to_string(); diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index a0e024c70fd..b4042a78eea 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -20,7 +20,10 @@ use async_lsp::{ }; use fm::{codespan_files as files, FileManager}; use fxhash::FxHashSet; -use lsp_types::CodeLens; +use lsp_types::{ + request::{PrepareRenameRequest, Rename}, + CodeLens, +}; use nargo::{ package::{Package, PackageType}, parse_all, @@ -43,8 +46,8 @@ use notifications::{ }; use requests::{ on_code_lens_request, on_formatting, on_goto_declaration_request, on_goto_definition_request, - on_goto_type_definition_request, on_initialize, on_profile_run_request, on_shutdown, - on_test_run_request, on_tests_request, + on_goto_type_definition_request, on_initialize, on_prepare_rename_request, + on_profile_run_request, on_rename_request, on_shutdown, on_test_run_request, on_tests_request, }; use serde_json::Value as JsonValue; use thiserror::Error; @@ -113,6 +116,8 @@ impl NargoLspService { .request::(on_goto_definition_request) .request::(on_goto_declaration_request) .request::(on_goto_type_definition_request) + .request::(on_prepare_rename_request) + .request::(on_rename_request) .notification::(on_initialized) .notification::(on_did_change_configuration) .notification::(on_did_open_text_document) diff --git a/tooling/lsp/src/requests/mod.rs b/tooling/lsp/src/requests/mod.rs index ec56cf5045a..e2511ed049d 100644 --- a/tooling/lsp/src/requests/mod.rs +++ b/tooling/lsp/src/requests/mod.rs @@ -5,7 +5,7 @@ use async_lsp::ResponseError; use fm::codespan_files::Error; use lsp_types::{ DeclarationCapability, Location, Position, TextDocumentSyncCapability, TextDocumentSyncKind, - TypeDefinitionProviderCapability, Url, + TypeDefinitionProviderCapability, Url, WorkDoneProgressOptions, }; use nargo_fmt::Config; use serde::{Deserialize, Serialize}; @@ -29,6 +29,7 @@ mod code_lens_request; mod goto_declaration; mod goto_definition; mod profile_run; +mod rename; mod test_run; mod tests; @@ -36,7 +37,8 @@ pub(crate) use { code_lens_request::collect_lenses_for_package, code_lens_request::on_code_lens_request, goto_declaration::on_goto_declaration_request, goto_definition::on_goto_definition_request, goto_definition::on_goto_type_definition_request, profile_run::on_profile_run_request, - test_run::on_test_run_request, tests::on_tests_request, + rename::on_prepare_rename_request, rename::on_rename_request, test_run::on_test_run_request, + tests::on_tests_request, }; /// LSP client will send initialization request after the server has started. @@ -106,6 +108,12 @@ pub(crate) fn on_initialize( definition_provider: Some(lsp_types::OneOf::Left(true)), declaration_provider: Some(DeclarationCapability::Simple(true)), type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)), + rename_provider: Some(lsp_types::OneOf::Right(lsp_types::RenameOptions { + prepare_provider: Some(true), + work_done_progress_options: WorkDoneProgressOptions { + work_done_progress: None, + }, + })), }, server_info: None, }) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs new file mode 100644 index 00000000000..0342f1c78f0 --- /dev/null +++ b/tooling/lsp/src/requests/rename.rs @@ -0,0 +1,165 @@ +use std::{ + collections::HashMap, + future::{self, Future}, +}; + +use async_lsp::{ErrorCode, ResponseError}; +use lsp_types::{ + PrepareRenameResponse, RenameParams, TextDocumentPositionParams, TextEdit, Url, WorkspaceEdit, +}; +use nargo::insert_all_files_for_workspace_into_file_manager; +use noirc_driver::file_manager_with_stdlib; + +use crate::{parse_diff, resolve_workspace_for_source_path, LspState}; + +use super::{position_to_byte_index, to_lsp_location}; + +pub(crate) fn on_prepare_rename_request( + state: &mut LspState, + params: TextDocumentPositionParams, +) -> impl Future, ResponseError>> { + let result = on_prepare_rename_inner(state, params); + future::ready(result) +} + +fn on_prepare_rename_inner( + state: &mut LspState, + params: TextDocumentPositionParams, +) -> Result, ResponseError> { + let file_path = params.text_document.uri.to_file_path().map_err(|_| { + ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path") + })?; + + let workspace = resolve_workspace_for_source_path(file_path.as_path()).unwrap(); + let package = workspace.members.first().unwrap(); + + let package_root_path: String = package.root_dir.as_os_str().to_string_lossy().into(); + + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let parsed_files = parse_diff(&workspace_file_manager, state); + + let (mut context, crate_id) = + nargo::prepare_package(&workspace_file_manager, &parsed_files, package); + + let interner; + if let Some(def_interner) = state.cached_definitions.get(&package_root_path) { + interner = def_interner; + } else { + // We ignore the warnings and errors produced by compilation while resolving the definition + let _ = noirc_driver::check_crate(&mut context, crate_id, false, false); + interner = &context.def_interner; + } + + let files = context.file_manager.as_file_map(); + let file_id = context.file_manager.name_to_id(file_path.clone()).ok_or(ResponseError::new( + ErrorCode::REQUEST_FAILED, + format!("Could not find file in file manager. File path: {:?}", file_path), + ))?; + let byte_index = position_to_byte_index(files, file_id, ¶ms.position).map_err(|err| { + ResponseError::new( + ErrorCode::REQUEST_FAILED, + format!("Could not convert position to byte index. Error: {:?}", err), + ) + })?; + + let search_for_location = noirc_errors::Location { + file: file_id, + span: noirc_errors::Span::single_char(byte_index as u32), + }; + + let rename_possible = interner.check_rename_possible(search_for_location); + + let response = PrepareRenameResponse::DefaultBehavior { default_behavior: rename_possible }; + + Ok(Some(response)) +} + +pub(crate) fn on_rename_request( + state: &mut LspState, + params: RenameParams, +) -> impl Future, ResponseError>> { + let result = on_rename_inner(state, params); + future::ready(result) +} + +fn on_rename_inner( + state: &mut LspState, + params: RenameParams, +) -> Result, ResponseError> { + let file_path = + params.text_document_position.text_document.uri.to_file_path().map_err(|_| { + ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path") + })?; + + let workspace = resolve_workspace_for_source_path(file_path.as_path()).unwrap(); + let package = workspace.members.first().unwrap(); + + let package_root_path: String = package.root_dir.as_os_str().to_string_lossy().into(); + + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let parsed_files = parse_diff(&workspace_file_manager, state); + + let (mut context, crate_id) = + nargo::prepare_package(&workspace_file_manager, &parsed_files, package); + + let interner; + if let Some(def_interner) = state.cached_definitions.get(&package_root_path) { + interner = def_interner; + } else { + // We ignore the warnings and errors produced by compilation while resolving the definition + let _ = noirc_driver::check_crate(&mut context, crate_id, false, false); + interner = &context.def_interner; + } + + let files = context.file_manager.as_file_map(); + let file_id = context.file_manager.name_to_id(file_path.clone()).ok_or(ResponseError::new( + ErrorCode::REQUEST_FAILED, + format!("Could not find file in file manager. File path: {:?}", file_path), + ))?; + let byte_index = + position_to_byte_index(files, file_id, ¶ms.text_document_position.position).map_err( + |err| { + ResponseError::new( + ErrorCode::REQUEST_FAILED, + format!("Could not convert position to byte index. Error: {:?}", err), + ) + }, + )?; + + let search_for_location = noirc_errors::Location { + file: file_id, + span: noirc_errors::Span::single_char(byte_index as u32), + }; + + let rename_changes = interner + .find_rename_symbols_at(search_for_location) + // .get_definition_location_from(search_for_location, false) + .and_then(|locations| { + let rs = locations.iter().fold( + HashMap::new(), + |mut acc: HashMap>, location| { + let file_id = location.file; + let span = location.span; + + let Some(lsp_location) = to_lsp_location(files, file_id, span) else { + return acc; + }; + + let edit = + TextEdit { range: lsp_location.range, new_text: params.new_name.clone() }; + + acc.entry(lsp_location.uri).or_insert_with(Vec::new).push(edit); + + return acc; + }, + ); + Some(rs) + }); + + let response = + WorkspaceEdit { changes: rename_changes, document_changes: None, change_annotations: None }; + + Ok(Some(response)) +} diff --git a/tooling/lsp/src/types.rs b/tooling/lsp/src/types.rs index e3492f21346..7239b1db685 100644 --- a/tooling/lsp/src/types.rs +++ b/tooling/lsp/src/types.rs @@ -1,6 +1,7 @@ use fm::FileId; use lsp_types::{ - DeclarationCapability, DefinitionOptions, OneOf, TypeDefinitionProviderCapability, + DeclarationCapability, DefinitionOptions, OneOf, RenameOptions, + TypeDefinitionProviderCapability, }; use noirc_driver::DebugFile; use noirc_errors::{debug_info::OpCodesCount, Location}; @@ -135,6 +136,10 @@ pub(crate) struct ServerCapabilities { /// The server handles and provides custom nargo messages. #[serde(skip_serializing_if = "Option::is_none")] pub(crate) nargo: Option, + + /// The server provides rename support. + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) rename_provider: Option>, } #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] From e685934caf5e66b5f61437175c35a42485f65582 Mon Sep 17 00:00:00 2001 From: Koby Date: Thu, 8 Feb 2024 13:32:14 +0100 Subject: [PATCH 02/36] chore: move collection point --- .../src/hir/resolution/resolver.rs | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index d7b9ba2fe96..27a6ab04a23 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1125,7 +1125,7 @@ impl<'a> Resolver<'a> { } pub fn resolve_global_let(&mut self, let_stmt: crate::LetStatement) -> HirStatement { - let expression = self.resolve_expression(let_stmt.expression); + let expression = self.resolve_expression(let_stmt.clone().expression); let definition = DefinitionKind::Global(expression); HirStatement::Let(HirLetStatement { @@ -1400,7 +1400,9 @@ impl<'a> Resolver<'a> { // Otherwise, then it is referring to an Identifier // This lookup allows support of such statements: let x = foo::bar::SOME_GLOBAL + 10; // If the expression is a singular indent, we search the resolver's current scope as normal. - let (hir_ident, var_scope_index) = self.get_ident_from_path(path); + let (hir_ident, var_scope_index) = self.get_ident_from_path(path.clone()); + + // tracing::debug!("Resolved variable: {:?}", hir_ident); if hir_ident.id != DefinitionId::dummy_id() { match self.interner.definition(hir_ident.id).kind { @@ -1409,13 +1411,20 @@ impl<'a> Resolver<'a> { != FunctionVisibility::Public { let span = hir_ident.location.span; - let func_def = self.interner.function_modifiers(&id); - tracing::debug!("Func definition: {:?}", (id, span, func_def)); self.check_can_reference_function( id, span, self.interner.function_visibility(id), ); + if let Some(func_meta) = self.interner.func_meta.get(&id) { + self.interner.add_reference( + (DependencyId::Function(id), func_meta.location), + ( + DependencyId::FunctionCall(hir_ident.id), + hir_ident.location, + ), + ); + } } } DefinitionKind::Global(_) => {} @@ -1471,24 +1480,6 @@ impl<'a> Resolver<'a> { vecmap(call_expr.clone().arguments, |arg| self.resolve_expression(arg)); let location = Location::new(expr.span, self.file); - if let ExpressionKind::Variable(path) = call_expr.clone().func.kind { - let (hir_ident, _var_scope_index) = self.get_ident_from_path(path); - if hir_ident.id != DefinitionId::dummy_id() { - if let DefinitionKind::Function(func_def_id) = - self.interner.definition(hir_ident.id).kind - { - if let Some(func_meta) = self.interner.func_meta.get(&func_def_id) { - self.interner.add_reference( - (DependencyId::Function(func_def_id), func_meta.location), - ( - DependencyId::CallExpression(func), - Location::new(call_expr.func.span, self.file), - ), - ); - } - } - } - } HirExpression::Call(HirCallExpression { func, arguments, location }) } ExpressionKind::MethodCall(call_expr) => { From c9ba2528a87cb1ca411cad28e9ee3d5a9ae3008f Mon Sep 17 00:00:00 2001 From: Koby Date: Sun, 11 Feb 2024 19:33:27 +0100 Subject: [PATCH 03/36] feat: add func rename with imports --- .../src/hir/def_collector/dc_crate.rs | 32 ++++++++++++++- .../src/hir/resolution/resolver.rs | 16 ++++---- compiler/noirc_frontend/src/locations.rs | 39 +++++++++++++------ compiler/noirc_frontend/src/node_interner.rs | 8 +++- 4 files changed, 72 insertions(+), 23 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 69743935dc3..debf6863f71 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -15,7 +15,9 @@ use crate::hir::type_check::{type_check_func, TypeCheckError, TypeChecker}; use crate::hir::Context; use crate::macros_api::{MacroError, MacroProcessor}; -use crate::node_interner::{FuncId, NodeInterner, StmtId, StructId, TraitId, TypeAliasId}; +use crate::node_interner::{ + DependencyId, FuncId, NodeInterner, StmtId, StructId, TraitId, TypeAliasId, +}; use crate::parser::{ParserError, SortedModule}; use crate::{ @@ -23,9 +25,10 @@ use crate::{ NoirTypeAlias, Path, PathKind, Type, TypeBindings, UnresolvedGenerics, UnresolvedTraitConstraint, UnresolvedType, }; + use fm::FileId; use iter_extended::vecmap; -use noirc_errors::{CustomDiagnostic, Span}; +use noirc_errors::{CustomDiagnostic, Location, Span}; use std::collections::{BTreeMap, HashMap}; use std::vec; @@ -268,6 +271,7 @@ impl DefCollector { // Resolve unresolved imports collected from the crate, one by one. for collected_import in def_collector.collected_imports { + let module_id = collected_import.module_id; match resolve_import(crate_id, collected_import, &context.def_maps) { Ok(resolved_import) => { // Populate module namespaces according to the imports used @@ -278,6 +282,9 @@ impl DefCollector { let result = current_def_map.modules[resolved_import.module_scope.0] .import(name.clone(), ns, resolved_import.is_prelude); + let file_id = current_def_map.file_id(module_id); + add_import_refrence(ns, &name, &mut context.def_interner, file_id); + if let Err((first_def, second_def)) = result { let err = DefCollectorErrorKind::Duplicate { typ: DuplicateType::Import, @@ -381,6 +388,27 @@ impl DefCollector { } } +fn add_import_refrence( + ns: crate::macros_api::ModuleDefId, + name: &Ident, + interner: &mut NodeInterner, + file_id: FileId, +) { + if name.span().start() == 0 && name.span().end() == 0 { + // We ignore empty spans at 0 lcoation, this must be Stdlib + return; + } + match ns { + crate::macros_api::ModuleDefId::FunctionId(func_id) => { + interner.add_reference_for( + DependencyId::Function(func_id), + (DependencyId::FunctionCall, Location::new(name.span(), file_id)), + ); + } + _ => (), + }; +} + fn inject_prelude( crate_id: CrateId, context: &Context, diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 27a6ab04a23..ed6c25bdc3a 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1416,15 +1416,13 @@ impl<'a> Resolver<'a> { span, self.interner.function_visibility(id), ); - if let Some(func_meta) = self.interner.func_meta.get(&id) { - self.interner.add_reference( - (DependencyId::Function(id), func_meta.location), - ( - DependencyId::FunctionCall(hir_ident.id), - hir_ident.location, - ), - ); - } + } + + if let Some(func_meta) = self.interner.func_meta.get(&id) { + self.interner.add_reference( + (DependencyId::Function(id), func_meta.location), + (DependencyId::FunctionCall, hir_ident.location), + ); } } DefinitionKind::Global(_) => {} diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index 5415fc8f68f..43a2e06febc 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -30,12 +30,30 @@ impl NodeInterner { reference: (DependencyId, Location), ) { let referenced_index = self.get_or_insert_reference(referenced); - let reference_index = self.get_or_insert_reference(reference); - self.graph_references.update_edge(referenced_index, reference_index, ()); + let reference_index = self.graph_references.add_node((reference.0, reference.1)); + self.graph_references.add_edge(referenced_index, reference_index, ()); self.location_store.add_location(referenced.1, referenced_index); self.location_store.add_location(reference.1, reference_index); } + pub(crate) fn add_reference_for( + &mut self, + referenced_id: DependencyId, + reference: (DependencyId, Location), + ) { + let Some(referenced_index) = self.graph_references_indices.get(&referenced_id) else { panic!("Compiler Error: Referenced index not found") }; + + let reference_index = self.graph_references.add_node((reference.0, reference.1)); + self.graph_references.add_edge(*referenced_index, reference_index, ()); + self.location_store.add_location(reference.1, reference_index); + } + + pub(crate) fn add_definiton(&mut self, referenced: (DependencyId, Location)) { + let referenced_index = self.get_or_insert_reference(referenced); + self.location_store.add_location(referenced.1, referenced_index); + } + + #[tracing::instrument(skip(self), ret)] pub(crate) fn get_or_insert_reference( &mut self, (id, location): (DependencyId, Location), @@ -56,18 +74,17 @@ impl NodeInterner { pub fn find_rename_symbols_at(&self, location: Location) -> Option> { let node_index = self.location_store.get_node_from_location(location)?; - let mut edit_locations: Vec = Vec::new(); + // let mut edit_locations: Vec = Vec::new(); let reference_node = self.graph_references[node_index]; - let found_locations = match reference_node.0 { - DependencyId::Struct(_) => todo!(), - DependencyId::Global(_) => todo!(), - DependencyId::Function(_) => { - edit_locations.extend(self.get_edit_locations(node_index)); - edit_locations + let found_locations: Vec = match reference_node.0 { + DependencyId::Alias(_) | DependencyId::Struct(_) | DependencyId::Global(_) => todo!(), + DependencyId::Function(_) | DependencyId::GlobalDefinition(_) => { + self.get_edit_locations(node_index) } - DependencyId::Alias(_) => todo!(), - DependencyId::CallExpression(_) => { + + DependencyId::GlobalReference | DependencyId::FunctionCall => { + let mut edit_locations: Vec = Vec::new(); if let Some(referenced_node_index) = self .graph_references .neighbors_directed(node_index, petgraph::Direction::Incoming) diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index ded1eef45b7..914b353c216 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -188,9 +188,11 @@ pub struct NodeInterner { pub enum DependencyId { Struct(StructId), Global(StmtId), + GlobalDefinition(DefinitionId), + GlobalReference, Function(FuncId), Alias(TypeAliasId), - CallExpression(ExprId), + FunctionCall, } /// A trait implementation is either a normal implementation that is present in the source @@ -767,6 +769,10 @@ impl NodeInterner { contract_function_type: Some(if function.is_open { Open } else { Secret }), is_internal: Some(function.is_internal), }; + self.add_definiton(( + DependencyId::Function(id), + Location::new(function.name.span(), location.file), + )); self.push_function_definition(id, modifiers, module, location) } From df38fb660b9bf045a59e28fdad80e546bb02d7a6 Mon Sep 17 00:00:00 2001 From: Koby Date: Mon, 12 Feb 2024 11:33:32 +0100 Subject: [PATCH 04/36] chore: cleanup --- compiler/noirc_frontend/src/hir/resolution/resolver.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index ed6c25bdc3a..d33ba9ba253 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1472,12 +1472,10 @@ impl<'a> Resolver<'a> { } ExpressionKind::Call(call_expr) => { // Get the span and name of path for error reporting - let func = self.resolve_expression(*call_expr.clone().func); + let func = self.resolve_expression(*call_expr.func); - let arguments = - vecmap(call_expr.clone().arguments, |arg| self.resolve_expression(arg)); + let arguments = vecmap(call_expr.arguments, |arg| self.resolve_expression(arg)); let location = Location::new(expr.span, self.file); - HirExpression::Call(HirCallExpression { func, arguments, location }) } ExpressionKind::MethodCall(call_expr) => { From d73f177a6f4f1d97e5c683a70fbeb12ec5a7b9c7 Mon Sep 17 00:00:00 2001 From: Koby Date: Mon, 12 Feb 2024 11:45:40 +0100 Subject: [PATCH 05/36] Merge remote-tracking branch 'origin/master' into kh-rename-functions --- .github/ISSUE_TEMPLATE/bug_report.yml | 63 +- .github/ISSUE_TEMPLATE/feature_request.yml | 31 +- .github/actions/install-playwright/action.yml | 2 +- .github/actions/nix/action.yml | 27 - ...on-test.sh => integration-test-browser.sh} | 3 +- .github/scripts/integration-test-node.sh | 5 + .github/workflows/docker-test-flow.yml | 59 +- .github/workflows/docs-pr.yml | 4 +- .github/workflows/gates_report.yml | 4 +- .github/workflows/publish-es-packages.yml | 82 +- .github/workflows/publish-nargo.yml | 4 +- .github/workflows/test-js-packages.yml | 183 +- .github/workflows/test-rust-workspace.yml | 82 +- Cargo.lock | 39 +- acvm-repo/acir/codegen/acir.cpp | 4429 +++++++++-------- .../acir/src/circuit/black_box_functions.rs | 6 +- acvm-repo/acir/src/circuit/brillig.rs | 2 + acvm-repo/acir/src/circuit/mod.rs | 29 +- acvm-repo/acir/src/circuit/opcodes.rs | 1 + .../opcodes/black_box_function_call.rs | 8 +- .../src/circuit/opcodes/memory_operation.rs | 2 +- acvm-repo/acir/src/lib.rs | 9 +- .../acir/tests/test_program_serialization.rs | 161 +- acvm-repo/acvm/src/compiler/mod.rs | 4 +- .../compiler/optimizers/redundant_range.rs | 4 +- .../acvm/src/compiler/transformers/mod.rs | 9 +- acvm-repo/acvm/src/lib.rs | 25 - acvm-repo/acvm/src/pwg/blackbox/bigint.rs | 120 + acvm-repo/acvm/src/pwg/blackbox/mod.rs | 22 +- acvm-repo/acvm/src/pwg/brillig.rs | 78 +- acvm-repo/acvm/src/pwg/memory_op.rs | 4 +- acvm-repo/acvm/src/pwg/mod.rs | 35 +- acvm-repo/acvm/tests/solver.rs | 99 +- acvm-repo/acvm_js/test/shared/addition.ts | 10 +- .../test/shared/complex_foreign_call.ts | 12 +- .../test/shared/fixed_base_scalar_mul.ts | 6 +- acvm-repo/acvm_js/test/shared/foreign_call.ts | 8 +- acvm-repo/acvm_js/test/shared/memory_op.ts | 8 +- acvm-repo/acvm_js/test/shared/pedersen.ts | 4 +- .../acvm_js/test/shared/schnorr_verify.ts | 24 +- acvm-repo/brillig/src/black_box.rs | 62 +- acvm-repo/brillig/src/lib.rs | 2 +- acvm-repo/brillig/src/opcodes.rs | 124 +- acvm-repo/brillig/src/value.rs | 4 +- acvm-repo/brillig_vm/src/black_box.rs | 152 +- acvm-repo/brillig_vm/src/lib.rs | 953 ++-- acvm-repo/brillig_vm/src/memory.rs | 40 +- acvm-repo/brillig_vm/src/registers.rs | 43 - aztec_macros/Cargo.toml | 1 + aztec_macros/src/lib.rs | 499 +- compiler/integration-tests/package.json | 4 +- .../test/browser/compile_prove_verify.test.ts | 4 +- .../test/browser/recursion.test.ts | 14 +- .../onchain_recursive_verification.test.ts | 14 +- .../test/node/smart_contract_verifier.test.ts | 4 +- compiler/noirc_driver/src/lib.rs | 8 +- .../brillig/brillig_gen/brillig_black_box.rs | 4 +- .../src/brillig/brillig_gen/brillig_block.rs | 115 +- .../brillig_gen/brillig_block_variables.rs | 4 +- .../brillig/brillig_gen/brillig_directive.rs | 47 +- .../brillig/brillig_gen/brillig_slice_ops.rs | 237 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 260 +- .../src/brillig/brillig_ir/artifact.rs | 2 +- .../brillig/brillig_ir/brillig_variable.rs | 51 +- .../src/brillig/brillig_ir/debug_show.rs | 85 +- .../src/brillig/brillig_ir/entry_point.rs | 622 +-- .../src/brillig/brillig_ir/registers.rs | 22 +- compiler/noirc_evaluator/src/errors.rs | 2 +- compiler/noirc_evaluator/src/ssa.rs | 6 +- .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 78 +- .../ssa/acir_gen/acir_ir/generated_acir.rs | 6 +- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 9 +- .../src/ssa/function_builder/mod.rs | 105 +- .../src/ssa/ir/instruction/binary.rs | 34 +- .../src/ssa/ir/instruction/call.rs | 11 +- .../src/ssa/ir/instruction/constrain.rs | 17 + compiler/noirc_evaluator/src/ssa/ir/types.rs | 2 +- .../src/ssa/opt/flatten_cfg.rs | 117 +- .../ssa/opt/flatten_cfg/capacity_tracker.rs | 150 + .../src/ssa/opt/flatten_cfg/value_merger.rs | 115 +- compiler/noirc_evaluator/src/ssa/opt/mod.rs | 1 + .../src/ssa/opt/remove_bit_shifts.rs | 285 ++ .../src/ssa/ssa_gen/context.rs | 21 +- compiler/noirc_frontend/src/ast/function.rs | 2 + compiler/noirc_frontend/src/ast/mod.rs | 12 +- compiler/noirc_frontend/src/ast/statement.rs | 16 +- compiler/noirc_frontend/src/ast/traits.rs | 4 +- compiler/noirc_frontend/src/debug/mod.rs | 8 +- .../src/hir/def_collector/dc_crate.rs | 22 +- .../src/hir/def_collector/dc_mod.rs | 21 +- .../src/hir/def_map/module_data.rs | 4 +- .../src/hir/def_map/module_def.rs | 18 +- .../src/hir/resolution/errors.rs | 52 +- .../src/hir/resolution/globals.rs | 15 +- .../src/hir/resolution/resolver.rs | 102 +- .../noirc_frontend/src/hir/type_check/expr.rs | 26 +- .../noirc_frontend/src/hir/type_check/mod.rs | 10 +- .../noirc_frontend/src/hir_def/function.rs | 2 +- compiler/noirc_frontend/src/lexer/token.rs | 4 + .../src/monomorphization/ast.rs | 5 + .../src/monomorphization/mod.rs | 13 +- compiler/noirc_frontend/src/node_interner.rs | 213 +- compiler/noirc_frontend/src/parser/parser.rs | 46 +- compiler/noirc_frontend/src/tests.rs | 10 + compiler/wasm/README.md | 25 +- compiler/wasm/package.json | 1 + compiler/wasm/src/compile.rs | 2 +- compiler/wasm/src/compile_new.rs | 4 +- compiler/wasm/src/index.cts | 30 + compiler/wasm/src/index.mts | 30 + compiler/wasm/src/noir/debug.ts | 5 +- .../noir/file-manager/nodejs-file-manager.ts | 5 +- compiler/wasm/src/types/noir_artifact.ts | 2 +- docs/docs/index.mdx | 4 +- docs/docs/noir/concepts/data_types/fields.md | 9 + docs/docs/noir/concepts/globals.md | 72 + .../noir/standard_library/black_box_fns.md | 2 +- docs/docs/noir/standard_library/bn254.md | 46 + docs/docs/tutorials/noirjs_app.md | 4 +- docs/docusaurus.config.ts | 33 +- docs/package.json | 1 - docs/src/css/custom.css | 5 + docs/src/pages/index.jsx | 101 +- docs/versioned_docs/version-v0.23.0/index.mdx | 4 +- .../noir/concepts/data_types/fields.md | 26 + .../noir/concepts/data_types/integers.md | 51 +- .../noir/standard_library/black_box_fns.md | 22 +- .../noir/standard_library/bn254.md | 46 + .../ecdsa_sig_verification.mdx | 22 +- .../cryptographic_primitives/hashes.mdx | 119 +- .../cryptographic_primitives/scalar.mdx | 9 +- .../cryptographic_primitives/schnorr.mdx | 11 +- .../reference/NoirJS/noir_wasm/.nojekyll | 1 + .../NoirJS/noir_wasm/functions/compile.md | 51 + .../noir_wasm/functions/createFileManager.md | 21 + .../functions/inflateDebugSymbols.md | 21 + .../reference/NoirJS/noir_wasm/index.md | 21 + .../type-aliases/CompilationResult.md | 11 + .../NoirJS/noir_wasm/typedoc-sidebar.cjs | 4 + .../version-v0.23.0/tutorials/noirjs_app.md | 4 +- noir_stdlib/src/bigint.nr | 46 +- noir_stdlib/src/field/bn254.nr | 11 + noir_stdlib/src/lib.nr | 2 +- .../assert_statement_recursive/Nargo.toml | 7 + .../assert_statement_recursive/Prover.toml | 2 + .../assert_statement_recursive/src/main.nr | 11 + .../execution_success/bigint/Nargo.toml | 6 + .../execution_success/bigint/Prover.toml | 2 + .../execution_success/bigint/src/main.nr | 21 + .../bit_shifts_runtime/src/main.nr | 1 + .../brillig_bit_shifts_runtime/Nargo.toml | 6 + .../brillig_bit_shifts_runtime/Prover.toml | 2 + .../brillig_bit_shifts_runtime/src/main.nr | 20 + .../brillig_nested_arrays/src/main.nr | 17 +- .../execution_success/debug_logs/src/main.nr | 6 + .../global_consts/src/main.nr | 15 +- .../regression_4202/Nargo.toml | 7 + .../regression_4202/Prover.toml | 1 + .../regression_4202/src/main.nr | 14 + tooling/backend_interface/src/cli/info.rs | 3 +- tooling/backend_interface/src/cli/prove.rs | 7 +- tooling/backend_interface/src/cli/verify.rs | 15 +- tooling/backend_interface/src/proof_system.rs | 21 +- .../backend_interface/src/smart_contract.rs | 4 +- tooling/bb_abstraction_leaks/build.rs | 2 +- tooling/debugger/Cargo.toml | 1 - tooling/debugger/ignored-tests.txt | 1 + tooling/debugger/src/context.rs | 137 +- tooling/debugger/src/dap.rs | 187 +- tooling/debugger/src/repl.rs | 134 +- tooling/debugger/tests/debug.rs | 12 +- tooling/lsp/src/requests/profile_run.rs | 2 +- tooling/nargo/Cargo.toml | 1 - tooling/nargo/src/ops/foreign_calls.rs | 6 +- tooling/nargo/src/ops/transform.rs | 2 +- tooling/nargo_cli/src/cli/dap_cmd.rs | 7 +- tooling/nargo_cli/src/cli/info_cmd.rs | 2 +- tooling/nargo_cli/src/cli/prove_cmd.rs | 5 +- tooling/nargo_cli/src/cli/verify_cmd.rs | 2 +- tooling/nargo_fmt/src/items.rs | 117 + tooling/nargo_fmt/src/lib.rs | 1 + tooling/nargo_fmt/src/rewrite.rs | 2 + tooling/nargo_fmt/src/rewrite/array.rs | 7 +- tooling/nargo_fmt/src/rewrite/imports.rs | 115 + tooling/nargo_fmt/src/rewrite/typ.rs | 2 +- tooling/nargo_fmt/src/utils.rs | 132 +- tooling/nargo_fmt/src/visitor.rs | 2 +- tooling/nargo_fmt/src/visitor/expr.rs | 20 +- tooling/nargo_fmt/src/visitor/item.rs | 71 +- tooling/nargo_fmt/src/visitor/stmt.rs | 5 +- tooling/nargo_fmt/tests/expected/assert.nr | 1 + tooling/nargo_fmt/tests/expected/contract.nr | 22 +- tooling/nargo_fmt/tests/expected/impl.nr | 21 + tooling/nargo_fmt/tests/expected/struct.nr | 4 +- tooling/nargo_fmt/tests/expected/vec.nr | 8 +- tooling/nargo_fmt/tests/input/assert.nr | 1 + tooling/nargo_fmt/tests/input/impl.nr | 21 + tooling/noir_js/src/program.ts | 12 +- tooling/noir_js/test/node/e2e.test.ts | 25 +- .../noir_js_backend_barretenberg/package.json | 2 +- .../noir_js_backend_barretenberg/src/index.ts | 73 +- tooling/noir_js_types/package.json | 3 - tooling/noir_js_types/src/types.ts | 48 +- tooling/noirc_abi_wasm/package.json | 3 + tooling/noirc_abi_wasm/src/js_witness_map.rs | 6 - tooling/noirc_abi_wasm/src/lib.rs | 38 +- yarn.lock | 196 +- 207 files changed, 8049 insertions(+), 5130 deletions(-) delete mode 100644 .github/actions/nix/action.yml rename .github/scripts/{integration-test.sh => integration-test-browser.sh} (52%) create mode 100755 .github/scripts/integration-test-node.sh create mode 100644 acvm-repo/acvm/src/pwg/blackbox/bigint.rs delete mode 100644 acvm-repo/brillig_vm/src/registers.rs create mode 100644 compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs create mode 100644 compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs create mode 100644 docs/docs/noir/concepts/globals.md create mode 100644 docs/docs/noir/standard_library/bn254.md create mode 100644 docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md create mode 100644 docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll create mode 100644 docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md create mode 100644 docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md create mode 100644 docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md create mode 100644 docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md create mode 100644 docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md create mode 100644 docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs create mode 100644 test_programs/execution_success/assert_statement_recursive/Nargo.toml create mode 100644 test_programs/execution_success/assert_statement_recursive/Prover.toml create mode 100644 test_programs/execution_success/assert_statement_recursive/src/main.nr create mode 100644 test_programs/execution_success/bigint/Nargo.toml create mode 100644 test_programs/execution_success/bigint/Prover.toml create mode 100644 test_programs/execution_success/bigint/src/main.nr create mode 100644 test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml create mode 100644 test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml create mode 100644 test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr create mode 100644 test_programs/execution_success/regression_4202/Nargo.toml create mode 100644 test_programs/execution_success/regression_4202/Prover.toml create mode 100644 test_programs/execution_success/regression_4202/src/main.nr create mode 100644 tooling/nargo_fmt/src/items.rs create mode 100644 tooling/nargo_fmt/src/rewrite/imports.rs create mode 100644 tooling/nargo_fmt/tests/expected/impl.nr create mode 100644 tooling/nargo_fmt/tests/input/impl.nr diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 112da342e10..71207793e53 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -6,7 +6,7 @@ body: attributes: value: | # Description - Thanks for taking the time to create the Issue, and welcome to the Noirot family! + Thanks for taking the time to create the Issue and welcome to the Noir community! - type: textarea id: aim attributes: @@ -38,45 +38,69 @@ body: 2. 3. 4. + - type: dropdown + id: impact + attributes: + label: Project Impact + description: How does this affect a project you or others are working on? + options: + - "Nice-to-have" + - "Blocker" + - type: textarea + id: impact_context + attributes: + label: Impact Context + description: If a nice-to-have / blocker, supplement how does this Issue affect the project. + - type: dropdown + id: workaround + attributes: + label: Workaround + description: Is there a workaround for this Issue? + options: + - "Yes" + - type: textarea + id: workaround_description + attributes: + label: Workaround Description + description: If yes, supplement how could the Issue be worked around. + - type: textarea + id: additional + attributes: + label: Additional Context + description: Supplement further information if applicable. - type: markdown attributes: value: | # Environment - Specify your versions of Noir releases used. + Specify your version of Noir tooling used. - type: markdown attributes: value: | - ## Using Nargo? + ## Nargo (CLI) - type: dropdown id: nargo-install attributes: label: Installation Method description: How did you install Nargo? - multiple: false options: - - Binary + - Binary (`noirup` default) - Compiled from source - type: input id: nargo-version attributes: label: Nargo Version - description: What is the output of the `nargo --version` command? - placeholder: "nargo 0.6.0 (git version hash: 0181813203a9e3e46c6d8c3169ad5d25971d4282, is dirty: false)" + description: Output of running `nargo --version` + placeholder: "nargo version = 0.23.0 noirc version = 0.23.0+5be9f9d7e2f39ca228df10e5a530474af0331704 (git version hash: 5be9f9d7e2f39ca228df10e5a530474af0331704, is dirty: false)" - type: markdown attributes: value: | - ## Using TypeScript? - Please await for our new set of packages. - You can find our target release timeframe on the [Noir Roadmap](https://github.com/orgs/noir-lang/projects/1/views/16). - - type: markdown - attributes: - value: | - # Misc - - type: textarea - id: additional + ## NoirJS (JavaScript) + - type: input + id: noirjs-version attributes: - label: Additional Context - description: Supplement further information if applicable. + label: NoirJS Version + description: Version number of `noir_js` in `package.json` + placeholder: "0.23.0" - type: markdown attributes: value: | @@ -87,11 +111,8 @@ body: label: Would you like to submit a PR for this Issue? description: Fellow contributors are happy to provide support where applicable. options: - - "No" - "Maybe" - "Yes" - validations: - required: true - type: textarea id: pr_support attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 979ac75811e..abbfe392454 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -6,7 +6,7 @@ body: attributes: value: | ## Description - Thanks for taking the time to create the Issue, and welcome to the Noirot family! + Thanks for taking the time to create the Issue and welcome to the Noir community! - type: textarea id: problem attributes: @@ -21,11 +21,31 @@ body: description: Describe how you think it should work. Supply pseudocode / step-by-step examples if applicable. validations: required: true + - type: dropdown + id: impact + attributes: + label: Project Impact + description: How does this affect a project you or others are working on? + options: + - "Nice-to-have" + - "Blocker" - type: textarea - id: alternatives + id: impact_context attributes: - label: Alternatives Considered - description: Describe less-happy cases you have considered, if any. + label: Impact Context + description: If a nice-to-have / blocker, supplement how does this Issue affect the project. + - type: dropdown + id: workaround + attributes: + label: Workaround + description: Is there a workaround for this Issue? + options: + - "Yes" + - type: textarea + id: workaround_description + attributes: + label: Workaround Description + description: If yes, supplement how could the Issue be worked around. - type: textarea id: additional attributes: @@ -42,11 +62,8 @@ body: description: Fellow contributors are happy to provide support where applicable. multiple: false options: - - "No" - "Maybe" - "Yes" - validations: - required: true - type: textarea id: pr-support attributes: diff --git a/.github/actions/install-playwright/action.yml b/.github/actions/install-playwright/action.yml index ac412a7dd4a..9579e2dd32d 100644 --- a/.github/actions/install-playwright/action.yml +++ b/.github/actions/install-playwright/action.yml @@ -9,7 +9,7 @@ runs: run: echo "PLAYWRIGHT_VERSION=$(yarn workspace @noir-lang/noirc_abi info @web/test-runner-playwright --json | jq .children.Version | tr -d '"')" >> $GITHUB_ENV - name: Cache playwright binaries - uses: actions/cache@v3 + uses: actions/cache@v4 id: playwright-cache with: path: | diff --git a/.github/actions/nix/action.yml b/.github/actions/nix/action.yml deleted file mode 100644 index 9f008ad0f9d..00000000000 --- a/.github/actions/nix/action.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Setup Nix -description: Installs and setups Nix components - -inputs: - github-token: - description: 'Github Access Token' - required: true - nix-cache-name: - description: 'Name of the Cachix cache to use' - required: true - cachix-auth-token: - description: 'Cachix Auth Token' - required: true - - -runs: - using: composite - steps: - - uses: cachix/install-nix-action@v22 - with: - nix_path: nixpkgs=channel:nixos-23.05 - github_access_token: ${{ inputs.github-token }} - - - uses: cachix/cachix-action@v12 - with: - name: ${{ inputs.nix-cache-name }} - authToken: ${{ inputs.cachix-auth-token }} diff --git a/.github/scripts/integration-test.sh b/.github/scripts/integration-test-browser.sh similarity index 52% rename from .github/scripts/integration-test.sh rename to .github/scripts/integration-test-browser.sh index 4e1b52cedf9..2ace2723a20 100755 --- a/.github/scripts/integration-test.sh +++ b/.github/scripts/integration-test-browser.sh @@ -1,6 +1,5 @@ #!/bin/bash set -eu -apt-get install libc++-dev -y npx playwright install && npx playwright install-deps -yarn workspace integration-tests test \ No newline at end of file +yarn workspace integration-tests test diff --git a/.github/scripts/integration-test-node.sh b/.github/scripts/integration-test-node.sh new file mode 100755 index 00000000000..7260ca4bb0f --- /dev/null +++ b/.github/scripts/integration-test-node.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -eu + +apt-get install libc++-dev -y +yarn workspace integration-tests test diff --git a/.github/workflows/docker-test-flow.yml b/.github/workflows/docker-test-flow.yml index 4b4a2ac2add..f9f4815dd3d 100644 --- a/.github/workflows/docker-test-flow.yml +++ b/.github/workflows/docker-test-flow.yml @@ -720,7 +720,63 @@ jobs: - name: Test working-directory: /usr/src/noir run: | - ./.github/scripts/integration-test.sh + ./.github/scripts/integration-test-node.sh + + test-integration-browser: + name: Integration test browser + runs-on: ubuntu-latest + needs: [ + build-base-js, + build-noir-wasm, + build-noirc-abi, + build-acvm_js, + build-noir-js-types, + build-noir_js, + build-barretenberg-backend + ] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download noir wasm + uses: actions/download-artifact@v4 + with: + name: noir_wasm + path: /usr/src/noir/compiler/wasm + - name: Download noirc abi + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: /usr/src/noir/tooling/noirc_abi_wasm + - name: Download acvm js + uses: actions/download-artifact@v4 + with: + name: acvm_js + path: /usr/src/noir/acvm-repo/acvm_js + - name: Download noir js types + uses: actions/download-artifact@v4 + with: + name: noir-js-types + path: | + /usr/src/noir/tooling/noir_js_types/lib + - name: Download noir js + uses: actions/download-artifact@v4 + with: + name: noir_js + path: + /usr/src/noir/tooling/noir_js/lib + - name: Download Barretenberg backend + uses: actions/download-artifact@v4 + with: + name: barretenberg-backend + path: + /usr/src/noir/tooling/noir_js_backend_barretenberg/lib + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/integration-test-browser.sh tests-end: name: End @@ -733,6 +789,7 @@ jobs: - test-noir-wasm - test-noir-wasm-browser - test-integration + - test-integration-browser - test-noir_codegen - test-acvm_js - test-acvm_js-browser diff --git a/.github/workflows/docs-pr.yml b/.github/workflows/docs-pr.yml index df923890d2c..3cdca177a20 100644 --- a/.github/workflows/docs-pr.yml +++ b/.github/workflows/docs-pr.yml @@ -88,7 +88,7 @@ jobs: yarn workspaces foreach -Rpt --from docs run build - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: docs path: ./docs/build/ @@ -106,7 +106,7 @@ jobs: uses: actions/checkout@v4 - name: Download built docs - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: docs path: ./docs/build diff --git a/.github/workflows/gates_report.yml b/.github/workflows/gates_report.yml index 8e3ef768828..39416e628a9 100644 --- a/.github/workflows/gates_report.yml +++ b/.github/workflows/gates_report.yml @@ -36,7 +36,7 @@ jobs: 7z a -ttar -so -an ./dist/* | 7z a -si ./nargo-x86_64-unknown-linux-gnu.tar.gz - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: nargo path: ./dist/* @@ -53,7 +53,7 @@ jobs: - uses: actions/checkout@v4 - name: Download nargo binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: nargo path: ./nargo diff --git a/.github/workflows/publish-es-packages.yml b/.github/workflows/publish-es-packages.yml index 2c825ffd45f..231a6124785 100644 --- a/.github/workflows/publish-es-packages.yml +++ b/.github/workflows/publish-es-packages.yml @@ -18,31 +18,31 @@ jobs: build-noirc_abi_wasm: runs-on: ubuntu-latest steps: - - name: Checkout sources + - name: Checkout Noir repo uses: actions/checkout@v4 - with: - ref: ${{ inputs.noir-ref }} - - name: Setup Nix - uses: ./.github/actions/nix + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + + - uses: Swatinem/rust-cache@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - nix-cache-name: "noir" - cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} + key: noirc-abi + save-if: false - - name: Build wasm package - run: | - nix build -L .#noirc_abi_wasm + - name: Install Yarn dependencies + uses: ./.github/actions/setup - - uses: actions/upload-artifact@v3 + - name: Build noirc_abi + run: ./.github/scripts/noirc-abi-build.sh + + - name: Upload artifact + uses: actions/upload-artifact@v4 with: name: noirc_abi_wasm - path: | - result/noirc_abi_wasm/nodejs - result/noirc_abi_wasm/web + path: ./tooling/noirc_abi_wasm/outputs/out/noirc_abi_wasm + retention-days: 10 build-noir_wasm: - needs: [build-noirc_abi_wasm] runs-on: ubuntu-latest steps: - name: Checkout sources @@ -58,20 +58,17 @@ jobs: key: noir-wasm save-if: false - - name: Download noirc_abi_wasm package artifact - uses: actions/download-artifact@v3 - with: - name: noirc_abi_wasm - path: ./tooling/noirc_abi_wasm - - name: Install Yarn dependencies uses: ./.github/actions/setup + - name: Build noir_js_types + run: yarn workspace @noir-lang/types build + - name: Build noir_wasm - run: yarn workspace @noir-lang/noir_wasm build + run: ./.github/scripts/noir-wasm-build.sh - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: noir_wasm path: | @@ -84,26 +81,27 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 - with: - ref: ${{ inputs.noir-ref }} - - name: Setup Nix - uses: ./.github/actions/nix + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + + - uses: Swatinem/rust-cache@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - nix-cache-name: "noir" - cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} + key: acvm-js + save-if: false - - name: Build wasm package - run: | - nix build -L .#acvm_js + - name: Install Yarn dependencies + uses: ./.github/actions/setup + + - name: Build acvm_js + run: ./.github/scripts/acvm_js-build.sh - - uses: actions/upload-artifact@v3 + - name: Upload artifact + uses: actions/upload-artifact@v4 with: - name: acvm_js - path: | - result/acvm_js/nodejs - result/acvm_js/web + name: acvm-js + path: ./acvm-repo/acvm_js/outputs/out/acvm_js + retention-days: 3 publish-es-packages: runs-on: ubuntu-latest @@ -114,17 +112,17 @@ jobs: with: ref: ${{ inputs.noir-ref }} - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: acvm_js path: acvm-repo/acvm_js - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: noir_wasm path: compiler/wasm - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: tooling/noirc_abi_wasm diff --git a/.github/workflows/publish-nargo.yml b/.github/workflows/publish-nargo.yml index fc089008657..085ab013e4e 100644 --- a/.github/workflows/publish-nargo.yml +++ b/.github/workflows/publish-nargo.yml @@ -67,7 +67,7 @@ jobs: 7z a -ttar -so -an ./dist/* | 7z a -si ./nargo-${{ matrix.target }}.tar.gz - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: nargo-${{ matrix.target }} path: ./dist/* @@ -145,7 +145,7 @@ jobs: 7z a -ttar -so -an ./dist/* | 7z a -si ./nargo-${{ matrix.target }}.tar.gz - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: nargo-${{ matrix.target }} path: ./dist/* diff --git a/.github/workflows/test-js-packages.yml b/.github/workflows/test-js-packages.yml index 036c582eaa4..15ed303450f 100644 --- a/.github/workflows/test-js-packages.yml +++ b/.github/workflows/test-js-packages.yml @@ -40,19 +40,18 @@ jobs: 7z a -ttar -so -an ./dist/* | 7z a -si ./nargo-x86_64-unknown-linux-gnu.tar.gz - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: nargo path: ./dist/* retention-days: 3 - build-noir-wasm: - needs: [build-noirc-abi] + build-noirc-abi: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - name: Checkout sources + - name: Checkout Noir repo uses: actions/checkout@v4 - name: Setup toolchain @@ -60,32 +59,25 @@ jobs: - uses: Swatinem/rust-cache@v2 with: - key: noir-wasm + key: noirc-abi cache-on-failure: true save-if: ${{ github.event_name != 'merge_group' }} - - name: Download noirc_abi_wasm package artifact - uses: actions/download-artifact@v3 - with: - name: noirc_abi_wasm - path: ./tooling/noirc_abi_wasm - - name: Install Yarn dependencies uses: ./.github/actions/setup - - name: Build noir_wasm - run: yarn workspace @noir-lang/noir_wasm build + - name: Build noirc_abi + run: ./.github/scripts/noirc-abi-build.sh - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: noir_wasm - path: | - ./compiler/wasm/dist - ./compiler/wasm/build - retention-days: 3 + name: noirc_abi_wasm + path: ./tooling/noirc_abi_wasm/outputs/out/noirc_abi_wasm + retention-days: 10 - build-acvm-js: + + build-noir-wasm: runs-on: ubuntu-latest timeout-minutes: 30 @@ -93,55 +85,62 @@ jobs: - name: Checkout sources uses: actions/checkout@v4 - - name: Setup Nix - uses: ./.github/actions/nix + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + + - uses: Swatinem/rust-cache@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - nix-cache-name: "noir" - cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} + key: noir-wasm + cache-on-failure: true + save-if: ${{ github.event_name != 'merge_group' }} - - name: Build acvm-js - run: | - nix build -L .#acvm_js + - name: Install Yarn dependencies + uses: ./.github/actions/setup + + - name: Build noir_js_types + run: yarn workspace @noir-lang/types build - - name: Dereference symlink - run: echo "UPLOAD_PATH=$(readlink -f result/acvm_js)" >> $GITHUB_ENV + - name: Build noir_wasm + run: ./.github/scripts/noir-wasm-build.sh - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: acvm-js - path: ${{ env.UPLOAD_PATH }} + name: noir_wasm + path: | + ./compiler/wasm/dist + ./compiler/wasm/build retention-days: 3 - build-noirc-abi: + build-acvm-js: runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v4 + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 - - name: Setup Nix - uses: ./.github/actions/nix + - uses: Swatinem/rust-cache@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - nix-cache-name: "noir" - cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} + key: acvm-js + cache-on-failure: true + save-if: ${{ github.event_name != 'merge_group' }} - - name: Build noirc_abi_wasm - run: | - nix build -L .#noirc_abi_wasm + - name: Install Yarn dependencies + uses: ./.github/actions/setup - - name: Dereference symlink - run: echo "UPLOAD_PATH=$(readlink -f ./result/noirc_abi_wasm)" >> $GITHUB_ENV + - name: Build acvm_js + run: ./.github/scripts/acvm_js-build.sh - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: noirc_abi_wasm - path: ${{ env.UPLOAD_PATH }} - retention-days: 10 + name: acvm-js + path: ./acvm-repo/acvm_js/outputs/out/acvm_js + retention-days: 3 test-acvm_js-node: needs: [build-acvm-js] @@ -154,7 +153,7 @@ jobs: uses: actions/checkout@v4 - name: Download artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: acvm-js path: ./acvm-repo/acvm_js @@ -176,7 +175,7 @@ jobs: uses: actions/checkout@v4 - name: Download artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: acvm-js path: ./acvm-repo/acvm_js @@ -200,10 +199,10 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download wasm package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: ./tooling/noirc_abi_wasm @@ -231,7 +230,7 @@ jobs: uses: actions/checkout@v4 - name: Download wasm package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: ./tooling/noirc_abi_wasm @@ -257,19 +256,19 @@ jobs: uses: actions/checkout@v4 - name: Download nargo binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: nargo path: ./nargo - name: Download artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: acvm-js path: ./acvm-repo/acvm_js - name: Download wasm package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: ./tooling/noirc_abi_wasm @@ -307,7 +306,7 @@ jobs: uses: actions/checkout@v4 - name: Download wasm package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noir_wasm path: ./compiler/wasm @@ -316,7 +315,7 @@ jobs: uses: ./.github/actions/setup - name: Download nargo binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: nargo path: ./nargo @@ -351,19 +350,19 @@ jobs: uses: actions/checkout@v4 - name: Download nargo binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: nargo path: ./nargo - name: Download acvm_js package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: acvm-js path: ./acvm-repo/acvm_js - name: Download noirc_abi package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: ./tooling/noirc_abi_wasm @@ -388,8 +387,8 @@ jobs: - name: Run noir_codegen tests run: yarn workspace @noir-lang/noir_codegen test - test-integration: - name: Integration Tests + test-integration-node: + name: Integration Tests (Node) runs-on: ubuntu-latest needs: [build-acvm-js, build-noir-wasm, build-nargo, build-noirc-abi] timeout-minutes: 30 @@ -399,25 +398,25 @@ jobs: uses: actions/checkout@v4 - name: Download nargo binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: nargo path: ./nargo - name: Download acvm_js package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: acvm-js path: ./acvm-repo/acvm_js - name: Download noir_wasm package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noir_wasm path: ./compiler/wasm - name: Download noirc_abi package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: ./tooling/noirc_abi_wasm @@ -433,6 +432,48 @@ jobs: - name: Install Yarn dependencies uses: ./.github/actions/setup + - name: Setup `integration-tests` + run: | + # Note the lack of spaces between package names. + PACKAGES_TO_BUILD="@noir-lang/types,@noir-lang/backend_barretenberg,@noir-lang/noir_js" + yarn workspaces foreach -vtp --from "{$PACKAGES_TO_BUILD}" run build + + - name: Run `integration-tests` + working-directory: ./compiler/integration-tests + run: | + yarn test:node + + test-integration-browser: + name: Integration Tests (Browser) + runs-on: ubuntu-latest + needs: [build-acvm-js, build-noir-wasm, build-nargo, build-noirc-abi] + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download acvm_js package artifact + uses: actions/download-artifact@v4 + with: + name: acvm-js + path: ./acvm-repo/acvm_js + + - name: Download noir_wasm package artifact + uses: actions/download-artifact@v4 + with: + name: noir_wasm + path: ./compiler/wasm + + - name: Download noirc_abi package artifact + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: ./tooling/noirc_abi_wasm + + - name: Install Yarn dependencies + uses: ./.github/actions/setup + - name: Install Playwright uses: ./.github/actions/install-playwright @@ -443,8 +484,9 @@ jobs: yarn workspaces foreach -vtp --from "{$PACKAGES_TO_BUILD}" run build - name: Run `integration-tests` + working-directory: ./compiler/integration-tests run: | - yarn test:integration + yarn test:browser # This is a job which depends on all test jobs and reports the overall status. # This allows us to add/remove test jobs without having to update the required workflows. @@ -461,7 +503,8 @@ jobs: - test-noir-js - test-noir-wasm - test-noir-codegen - - test-integration + - test-integration-node + - test-integration-browser steps: - name: Report overall success diff --git a/.github/workflows/test-rust-workspace.yml b/.github/workflows/test-rust-workspace.yml index eccd7585fcf..be6e587dc15 100644 --- a/.github/workflows/test-rust-workspace.yml +++ b/.github/workflows/test-rust-workspace.yml @@ -13,19 +13,11 @@ concurrency: cancel-in-progress: true jobs: - test: - name: Test on ${{ matrix.os }} - runs-on: ${{ matrix.runner }} + build-test-artifacts: + name: Build test artifacts + runs-on: ubuntu-latest timeout-minutes: 30 - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu - runner: ubuntu-latest - target: x86_64-unknown-linux-gnu - steps: - name: Checkout uses: actions/checkout@v4 @@ -33,13 +25,75 @@ jobs: - name: Setup toolchain uses: dtolnay/rust-toolchain@1.71.1 with: - targets: ${{ matrix.target }} + targets: x86_64-unknown-linux-gnu - uses: Swatinem/rust-cache@v2 with: - key: ${{ matrix.target }} + key: x86_64-unknown-linux-gnu cache-on-failure: true save-if: ${{ github.event_name != 'merge_group' }} + - name: Install nextest + uses: taiki-e/install-action@v2 + with: + tool: nextest@0.9.67 + + - name: Build and archive tests + run: cargo nextest archive --workspace --release --archive-file nextest-archive.tar.zst + + - name: Upload archive to workflow + uses: actions/upload-artifact@v4 + with: + name: nextest-archive + path: nextest-archive.tar.zst + + run-tests: + name: "Run tests (partition ${{matrix.partition}})" + runs-on: ubuntu-latest + needs: [build-test-artifacts] + strategy: + matrix: + partition: [1, 2, 3, 4] + steps: + - uses: actions/checkout@v4 + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + with: + targets: x86_64-unknown-linux-gnu + + - name: Install nextest + uses: taiki-e/install-action@v2 + with: + tool: nextest@0.9.67 + + - name: Download archive + uses: actions/download-artifact@v4 + with: + name: nextest-archive - name: Run tests - run: cargo test --workspace --locked --release + run: | + cargo nextest run --archive-file nextest-archive.tar.zst \ + --partition count:${{ matrix.partition }}/4 + + # This is a job which depends on all test jobs and reports the overall status. + # This allows us to add/remove test jobs without having to update the required workflows. + tests-end: + name: Rust End + runs-on: ubuntu-latest + # We want this job to always run (even if the dependant jobs fail) as we want this job to fail rather than skipping. + if: ${{ always() }} + needs: + - run-tests + + steps: + - name: Report overall success + run: | + if [[ $FAIL == true ]]; then + exit 1 + else + exit 0 + fi + env: + # We treat any skipped or failing jobs as a failure for the workflow as a whole. + FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'skipped') }} diff --git a/Cargo.lock b/Cargo.lock index 612295a84e0..f3eb44cd4e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -418,6 +418,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" name = "aztec_macros" version = "0.23.0" dependencies = [ + "convert_case 0.6.0", "iter-extended", "noirc_frontend", ] @@ -1011,6 +1012,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -1376,7 +1386,7 @@ version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "convert_case", + "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version", @@ -2671,7 +2681,6 @@ dependencies = [ "rayon", "rustc_version", "serde", - "serial_test", "tempfile", "thiserror", "tracing", @@ -2834,7 +2843,6 @@ dependencies = [ "rexpect", "serde_json", "tempfile", - "test-binary", "thiserror", ] @@ -4277,31 +4285,6 @@ dependencies = [ "syn 2.0.32", ] -[[package]] -name = "serial_test" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" -dependencies = [ - "dashmap", - "futures 0.3.28", - "lazy_static", - "log", - "parking_lot 0.12.1", - "serial_test_derive", -] - -[[package]] -name = "serial_test_derive" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", -] - [[package]] name = "sha2" version = "0.10.7" diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index 24c8eebceb4..d51fe8de910 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -5,221 +5,307 @@ namespace Circuit { - struct Witness { - uint32_t value; - - friend bool operator==(const Witness&, const Witness&); - std::vector bincodeSerialize() const; - static Witness bincodeDeserialize(std::vector); - }; - - struct FunctionInput { - Circuit::Witness witness; - uint32_t num_bits; - - friend bool operator==(const FunctionInput&, const FunctionInput&); - std::vector bincodeSerialize() const; - static FunctionInput bincodeDeserialize(std::vector); - }; - - struct BlackBoxFuncCall { - - struct AND { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + struct BinaryFieldOp { - friend bool operator==(const AND&, const AND&); + struct Add { + friend bool operator==(const Add&, const Add&); std::vector bincodeSerialize() const; - static AND bincodeDeserialize(std::vector); + static Add bincodeDeserialize(std::vector); }; - struct XOR { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + struct Sub { + friend bool operator==(const Sub&, const Sub&); + std::vector bincodeSerialize() const; + static Sub bincodeDeserialize(std::vector); + }; - friend bool operator==(const XOR&, const XOR&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); std::vector bincodeSerialize() const; - static XOR bincodeDeserialize(std::vector); + static Mul bincodeDeserialize(std::vector); }; - struct RANGE { - Circuit::FunctionInput input; + struct Div { + friend bool operator==(const Div&, const Div&); + std::vector bincodeSerialize() const; + static Div bincodeDeserialize(std::vector); + }; - friend bool operator==(const RANGE&, const RANGE&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static RANGE bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - struct SHA256 { - std::vector inputs; - std::vector outputs; + std::variant value; - friend bool operator==(const SHA256&, const SHA256&); + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + std::vector bincodeSerialize() const; + static BinaryFieldOp bincodeDeserialize(std::vector); + }; + + struct BinaryIntOp { + + struct Add { + friend bool operator==(const Add&, const Add&); std::vector bincodeSerialize() const; - static SHA256 bincodeDeserialize(std::vector); + static Add bincodeDeserialize(std::vector); }; - struct Blake2s { - std::vector inputs; - std::vector outputs; + struct Sub { + friend bool operator==(const Sub&, const Sub&); + std::vector bincodeSerialize() const; + static Sub bincodeDeserialize(std::vector); + }; - friend bool operator==(const Blake2s&, const Blake2s&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); std::vector bincodeSerialize() const; - static Blake2s bincodeDeserialize(std::vector); + static Mul bincodeDeserialize(std::vector); }; - struct Blake3 { - std::vector inputs; - std::vector outputs; + struct SignedDiv { + friend bool operator==(const SignedDiv&, const SignedDiv&); + std::vector bincodeSerialize() const; + static SignedDiv bincodeDeserialize(std::vector); + }; - friend bool operator==(const Blake3&, const Blake3&); + struct UnsignedDiv { + friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); std::vector bincodeSerialize() const; - static Blake3 bincodeDeserialize(std::vector); + static UnsignedDiv bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Circuit::FunctionInput public_key_x; - Circuit::FunctionInput public_key_y; - std::vector signature; - std::vector message; - Circuit::Witness output; + struct Equals { + friend bool operator==(const Equals&, const Equals&); + std::vector bincodeSerialize() const; + static Equals bincodeDeserialize(std::vector); + }; - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static LessThan bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - std::vector inputs; - uint32_t domain_separator; - std::array outputs; + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); + std::vector bincodeSerialize() const; + static LessThanEquals bincodeDeserialize(std::vector); + }; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + struct And { + friend bool operator==(const And&, const And&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static And bincodeDeserialize(std::vector); }; - struct PedersenHash { - std::vector inputs; - uint32_t domain_separator; - Circuit::Witness output; + struct Or { + friend bool operator==(const Or&, const Or&); + std::vector bincodeSerialize() const; + static Or bincodeDeserialize(std::vector); + }; - friend bool operator==(const PedersenHash&, const PedersenHash&); + struct Xor { + friend bool operator==(const Xor&, const Xor&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Xor bincodeDeserialize(std::vector); }; - struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + struct Shl { + friend bool operator==(const Shl&, const Shl&); + std::vector bincodeSerialize() const; + static Shl bincodeDeserialize(std::vector); + }; - friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); + struct Shr { + friend bool operator==(const Shr&, const Shr&); std::vector bincodeSerialize() const; - static EcdsaSecp256k1 bincodeDeserialize(std::vector); + static Shr bincodeDeserialize(std::vector); }; - struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + std::variant value; - friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + std::vector bincodeSerialize() const; + static BinaryIntOp bincodeDeserialize(std::vector); + }; + + struct MemoryAddress { + uint64_t value; + + friend bool operator==(const MemoryAddress&, const MemoryAddress&); + std::vector bincodeSerialize() const; + static MemoryAddress bincodeDeserialize(std::vector); + }; + + struct HeapArray { + Circuit::MemoryAddress pointer; + uint64_t size; + + friend bool operator==(const HeapArray&, const HeapArray&); + std::vector bincodeSerialize() const; + static HeapArray bincodeDeserialize(std::vector); + }; + + struct HeapVector { + Circuit::MemoryAddress pointer; + Circuit::MemoryAddress size; + + friend bool operator==(const HeapVector&, const HeapVector&); + std::vector bincodeSerialize() const; + static HeapVector bincodeDeserialize(std::vector); + }; + + struct BlackBoxOp { + + struct Sha256 { + Circuit::HeapVector message; + Circuit::HeapArray output; + + friend bool operator==(const Sha256&, const Sha256&); std::vector bincodeSerialize() const; - static EcdsaSecp256r1 bincodeDeserialize(std::vector); + static Sha256 bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Circuit::FunctionInput low; - Circuit::FunctionInput high; - std::array outputs; + struct Blake2s { + Circuit::HeapVector message; + Circuit::HeapArray output; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static Blake2s bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Circuit::FunctionInput input1_x; - Circuit::FunctionInput input1_y; - Circuit::FunctionInput input2_x; - Circuit::FunctionInput input2_y; - std::array outputs; + struct Blake3 { + Circuit::HeapVector message; + Circuit::HeapArray output; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static Blake3 bincodeDeserialize(std::vector); }; struct Keccak256 { - std::vector inputs; - std::vector outputs; + Circuit::HeapVector message; + Circuit::HeapArray output; friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; static Keccak256 bincodeDeserialize(std::vector); }; - struct Keccak256VariableLength { - std::vector inputs; - Circuit::FunctionInput var_message_size; - std::vector outputs; - - friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); - std::vector bincodeSerialize() const; - static Keccak256VariableLength bincodeDeserialize(std::vector); - }; - struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + Circuit::HeapVector message; + Circuit::HeapArray output; friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; static Keccakf1600 bincodeDeserialize(std::vector); }; - struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Circuit::FunctionInput key_hash; + struct EcdsaSecp256k1 { + Circuit::HeapVector hashed_msg; + Circuit::HeapArray public_key_x; + Circuit::HeapArray public_key_y; + Circuit::HeapArray signature; + Circuit::MemoryAddress result; - friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); + friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; - static RecursiveAggregation bincodeDeserialize(std::vector); + static EcdsaSecp256k1 bincodeDeserialize(std::vector); }; - struct BigIntAdd { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct EcdsaSecp256r1 { + Circuit::HeapVector hashed_msg; + Circuit::HeapArray public_key_x; + Circuit::HeapArray public_key_y; + Circuit::HeapArray signature; + Circuit::MemoryAddress result; + + friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + std::vector bincodeSerialize() const; + static EcdsaSecp256r1 bincodeDeserialize(std::vector); + }; + + struct SchnorrVerify { + Circuit::MemoryAddress public_key_x; + Circuit::MemoryAddress public_key_y; + Circuit::HeapVector message; + Circuit::HeapVector signature; + Circuit::MemoryAddress result; + + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + std::vector bincodeSerialize() const; + static SchnorrVerify bincodeDeserialize(std::vector); + }; + + struct PedersenCommitment { + Circuit::HeapVector inputs; + Circuit::MemoryAddress domain_separator; + Circuit::HeapArray output; + + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + std::vector bincodeSerialize() const; + static PedersenCommitment bincodeDeserialize(std::vector); + }; + + struct PedersenHash { + Circuit::HeapVector inputs; + Circuit::MemoryAddress domain_separator; + Circuit::MemoryAddress output; + + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); + }; + + struct FixedBaseScalarMul { + Circuit::MemoryAddress low; + Circuit::MemoryAddress high; + Circuit::HeapArray result; + + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + std::vector bincodeSerialize() const; + static FixedBaseScalarMul bincodeDeserialize(std::vector); + }; + + struct EmbeddedCurveAdd { + Circuit::MemoryAddress input1_x; + Circuit::MemoryAddress input1_y; + Circuit::MemoryAddress input2_x; + Circuit::MemoryAddress input2_y; + Circuit::HeapArray result; + + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + std::vector bincodeSerialize() const; + static EmbeddedCurveAdd bincodeDeserialize(std::vector); + }; + + struct BigIntAdd { + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; static BigIntAdd bincodeDeserialize(std::vector); }; - struct BigIntNeg { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct BigIntSub { + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; - friend bool operator==(const BigIntNeg&, const BigIntNeg&); + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static BigIntNeg bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; struct BigIntMul { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -227,9 +313,9 @@ namespace Circuit { }; struct BigIntDiv { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -237,9 +323,9 @@ namespace Circuit { }; struct BigIntFromLeBytes { - std::vector inputs; - std::vector modulus; - uint32_t output; + Circuit::HeapVector inputs; + Circuit::HeapVector modulus; + Circuit::MemoryAddress output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -247,8 +333,8 @@ namespace Circuit { }; struct BigIntToLeBytes { - uint32_t input; - std::vector outputs; + Circuit::MemoryAddress input; + Circuit::HeapVector output; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -256,9 +342,9 @@ namespace Circuit { }; struct Poseidon2Permutation { - std::vector inputs; - std::vector outputs; - uint32_t len; + Circuit::HeapVector message; + Circuit::HeapArray output; + Circuit::MemoryAddress len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; @@ -266,231 +352,310 @@ namespace Circuit { }; struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; + Circuit::HeapVector input; + Circuit::HeapVector hash_values; + Circuit::HeapArray output; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); - std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); - }; - - struct BlockId { - uint32_t value; - - friend bool operator==(const BlockId&, const BlockId&); - std::vector bincodeSerialize() const; - static BlockId bincodeDeserialize(std::vector); - }; - - struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; - std::string q_c; + std::variant value; - friend bool operator==(const Expression&, const Expression&); + friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; - static Expression bincodeDeserialize(std::vector); + static BlackBoxOp bincodeDeserialize(std::vector); }; - struct BrilligInputs { + struct HeapValueType; - struct Single { - Circuit::Expression value; + struct HeapValueType { - friend bool operator==(const Single&, const Single&); + struct Simple { + friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; - static Single bincodeDeserialize(std::vector); + static Simple bincodeDeserialize(std::vector); }; struct Array { - std::vector value; + std::vector value_types; + uint64_t size; friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; static Array bincodeDeserialize(std::vector); }; - std::variant value; + struct Vector { + std::vector value_types; - friend bool operator==(const BrilligInputs&, const BrilligInputs&); + friend bool operator==(const Vector&, const Vector&); + std::vector bincodeSerialize() const; + static Vector bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const HeapValueType&, const HeapValueType&); std::vector bincodeSerialize() const; - static BrilligInputs bincodeDeserialize(std::vector); + static HeapValueType bincodeDeserialize(std::vector); }; - struct BinaryFieldOp { + struct Value { + std::string inner; - struct Add { - friend bool operator==(const Add&, const Add&); - std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); - }; + friend bool operator==(const Value&, const Value&); + std::vector bincodeSerialize() const; + static Value bincodeDeserialize(std::vector); + }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); - std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); - }; + struct ValueOrArray { - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct MemoryAddress { + Circuit::MemoryAddress value; + + friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static MemoryAddress bincodeDeserialize(std::vector); }; - struct Div { - friend bool operator==(const Div&, const Div&); + struct HeapArray { + Circuit::HeapArray value; + + friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); + static HeapArray bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct HeapVector { + Circuit::HeapVector value; + + friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static HeapVector bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + friend bool operator==(const ValueOrArray&, const ValueOrArray&); std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); + static ValueOrArray bincodeDeserialize(std::vector); }; - struct BinaryIntOp { + struct BrilligOpcode { - struct Add { - friend bool operator==(const Add&, const Add&); + struct BinaryFieldOp { + Circuit::MemoryAddress destination; + Circuit::BinaryFieldOp op; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + struct BinaryIntOp { + Circuit::MemoryAddress destination; + Circuit::BinaryIntOp op; + uint32_t bit_size; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static BinaryIntOp bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct JumpIfNot { + Circuit::MemoryAddress condition; + uint64_t location; + + friend bool operator==(const JumpIfNot&, const JumpIfNot&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static JumpIfNot bincodeDeserialize(std::vector); }; - struct SignedDiv { - friend bool operator==(const SignedDiv&, const SignedDiv&); + struct JumpIf { + Circuit::MemoryAddress condition; + uint64_t location; + + friend bool operator==(const JumpIf&, const JumpIf&); std::vector bincodeSerialize() const; - static SignedDiv bincodeDeserialize(std::vector); + static JumpIf bincodeDeserialize(std::vector); }; - struct UnsignedDiv { - friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); + struct Jump { + uint64_t location; + + friend bool operator==(const Jump&, const Jump&); std::vector bincodeSerialize() const; - static UnsignedDiv bincodeDeserialize(std::vector); + static Jump bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct CalldataCopy { + Circuit::MemoryAddress destination_address; + uint64_t size; + uint64_t offset; + + friend bool operator==(const CalldataCopy&, const CalldataCopy&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static CalldataCopy bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); + struct Call { + uint64_t location; + + friend bool operator==(const Call&, const Call&); std::vector bincodeSerialize() const; - static LessThan bincodeDeserialize(std::vector); + static Call bincodeDeserialize(std::vector); }; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); + struct Const { + Circuit::MemoryAddress destination; + uint32_t bit_size; + Circuit::Value value; + + friend bool operator==(const Const&, const Const&); std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); + static Const bincodeDeserialize(std::vector); }; - struct And { - friend bool operator==(const And&, const And&); + struct Return { + friend bool operator==(const Return&, const Return&); std::vector bincodeSerialize() const; - static And bincodeDeserialize(std::vector); + static Return bincodeDeserialize(std::vector); }; - struct Or { - friend bool operator==(const Or&, const Or&); + struct ForeignCall { + std::string function; + std::vector destinations; + std::vector destination_value_types; + std::vector inputs; + std::vector input_value_types; + + friend bool operator==(const ForeignCall&, const ForeignCall&); std::vector bincodeSerialize() const; - static Or bincodeDeserialize(std::vector); + static ForeignCall bincodeDeserialize(std::vector); }; - struct Xor { - friend bool operator==(const Xor&, const Xor&); + struct Mov { + Circuit::MemoryAddress destination; + Circuit::MemoryAddress source; + + friend bool operator==(const Mov&, const Mov&); std::vector bincodeSerialize() const; - static Xor bincodeDeserialize(std::vector); + static Mov bincodeDeserialize(std::vector); }; - struct Shl { - friend bool operator==(const Shl&, const Shl&); + struct Load { + Circuit::MemoryAddress destination; + Circuit::MemoryAddress source_pointer; + + friend bool operator==(const Load&, const Load&); std::vector bincodeSerialize() const; - static Shl bincodeDeserialize(std::vector); + static Load bincodeDeserialize(std::vector); }; - struct Shr { - friend bool operator==(const Shr&, const Shr&); + struct Store { + Circuit::MemoryAddress destination_pointer; + Circuit::MemoryAddress source; + + friend bool operator==(const Store&, const Store&); std::vector bincodeSerialize() const; - static Shr bincodeDeserialize(std::vector); + static Store bincodeDeserialize(std::vector); }; - std::variant value; + struct BlackBox { + Circuit::BlackBoxOp value; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); - std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); - }; + friend bool operator==(const BlackBox&, const BlackBox&); + std::vector bincodeSerialize() const; + static BlackBox bincodeDeserialize(std::vector); + }; - struct RegisterIndex { - uint64_t value; + struct Trap { + friend bool operator==(const Trap&, const Trap&); + std::vector bincodeSerialize() const; + static Trap bincodeDeserialize(std::vector); + }; + + struct Stop { + uint64_t return_data_offset; + uint64_t return_data_size; - friend bool operator==(const RegisterIndex&, const RegisterIndex&); + friend bool operator==(const Stop&, const Stop&); + std::vector bincodeSerialize() const; + static Stop bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); std::vector bincodeSerialize() const; - static RegisterIndex bincodeDeserialize(std::vector); + static BrilligOpcode bincodeDeserialize(std::vector); }; - struct HeapArray { - Circuit::RegisterIndex pointer; - uint64_t size; + struct Witness { + uint32_t value; - friend bool operator==(const HeapArray&, const HeapArray&); + friend bool operator==(const Witness&, const Witness&); std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); + static Witness bincodeDeserialize(std::vector); }; - struct HeapVector { - Circuit::RegisterIndex pointer; - Circuit::RegisterIndex size; + struct FunctionInput { + Circuit::Witness witness; + uint32_t num_bits; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const FunctionInput&, const FunctionInput&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static FunctionInput bincodeDeserialize(std::vector); }; - struct BlackBoxOp { + struct BlackBoxFuncCall { - struct Sha256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct AND { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; - friend bool operator==(const Sha256&, const Sha256&); + friend bool operator==(const AND&, const AND&); std::vector bincodeSerialize() const; - static Sha256 bincodeDeserialize(std::vector); + static AND bincodeDeserialize(std::vector); + }; + + struct XOR { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; + + friend bool operator==(const XOR&, const XOR&); + std::vector bincodeSerialize() const; + static XOR bincodeDeserialize(std::vector); + }; + + struct RANGE { + Circuit::FunctionInput input; + + friend bool operator==(const RANGE&, const RANGE&); + std::vector bincodeSerialize() const; + static RANGE bincodeDeserialize(std::vector); + }; + + struct SHA256 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const SHA256&, const SHA256&); + std::vector bincodeSerialize() const; + static SHA256 bincodeDeserialize(std::vector); }; struct Blake2s { - Circuit::HeapVector message; - Circuit::HeapArray output; + std::vector inputs; + std::vector outputs; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -498,38 +663,52 @@ namespace Circuit { }; struct Blake3 { - Circuit::HeapVector message; - Circuit::HeapArray output; + std::vector inputs; + std::vector outputs; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; static Blake3 bincodeDeserialize(std::vector); }; - struct Keccak256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct SchnorrVerify { + Circuit::FunctionInput public_key_x; + Circuit::FunctionInput public_key_y; + std::vector signature; + std::vector message; + Circuit::Witness output; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct PedersenCommitment { + std::vector inputs; + uint32_t domain_separator; + std::array outputs; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); + }; + + struct PedersenHash { + std::vector inputs; + uint32_t domain_separator; + Circuit::Witness output; + + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); }; struct EcdsaSecp256k1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::RegisterIndex result; + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -537,95 +716,102 @@ namespace Circuit { }; struct EcdsaSecp256r1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::RegisterIndex result; + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Circuit::RegisterIndex public_key_x; - Circuit::RegisterIndex public_key_y; - Circuit::HeapVector message; - Circuit::HeapVector signature; - Circuit::RegisterIndex result; + struct FixedBaseScalarMul { + Circuit::FunctionInput low; + Circuit::FunctionInput high; + std::array outputs; - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - Circuit::HeapVector inputs; - Circuit::RegisterIndex domain_separator; - Circuit::HeapArray output; + struct EmbeddedCurveAdd { + Circuit::FunctionInput input1_x; + Circuit::FunctionInput input1_y; + Circuit::FunctionInput input2_x; + Circuit::FunctionInput input2_y; + std::array outputs; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - struct PedersenHash { - Circuit::HeapVector inputs; - Circuit::RegisterIndex domain_separator; - Circuit::RegisterIndex output; + struct Keccak256 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const PedersenHash&, const PedersenHash&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Circuit::RegisterIndex low; - Circuit::RegisterIndex high; - Circuit::HeapArray result; + struct Keccak256VariableLength { + std::vector inputs; + Circuit::FunctionInput var_message_size; + std::vector outputs; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static Keccak256VariableLength bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Circuit::RegisterIndex input1_x; - Circuit::RegisterIndex input1_y; - Circuit::RegisterIndex input2_x; - Circuit::RegisterIndex input2_y; - Circuit::HeapArray result; + struct Keccakf1600 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); + }; + + struct RecursiveAggregation { + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Circuit::FunctionInput key_hash; + + friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); + std::vector bincodeSerialize() const; + static RecursiveAggregation bincodeDeserialize(std::vector); }; struct BigIntAdd { - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; - Circuit::RegisterIndex output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; static BigIntAdd bincodeDeserialize(std::vector); }; - struct BigIntNeg { - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; - Circuit::RegisterIndex output; + struct BigIntSub { + uint32_t lhs; + uint32_t rhs; + uint32_t output; - friend bool operator==(const BigIntNeg&, const BigIntNeg&); + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static BigIntNeg bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; struct BigIntMul { - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; - Circuit::RegisterIndex output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -633,9 +819,9 @@ namespace Circuit { }; struct BigIntDiv { - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; - Circuit::RegisterIndex output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -643,9 +829,9 @@ namespace Circuit { }; struct BigIntFromLeBytes { - Circuit::HeapVector inputs; - Circuit::HeapVector modulus; - Circuit::RegisterIndex output; + std::vector inputs; + std::vector modulus; + uint32_t output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -653,8 +839,8 @@ namespace Circuit { }; struct BigIntToLeBytes { - Circuit::RegisterIndex input; - Circuit::HeapVector output; + uint32_t input; + std::vector outputs; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -662,9 +848,9 @@ namespace Circuit { }; struct Poseidon2Permutation { - Circuit::HeapVector message; - Circuit::HeapArray output; - Circuit::RegisterIndex len; + std::vector inputs; + std::vector outputs; + uint32_t len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; @@ -672,199 +858,71 @@ namespace Circuit { }; struct Sha256Compression { - Circuit::HeapVector input; - Circuit::HeapVector hash_values; - Circuit::HeapArray output; + std::vector inputs; + std::vector hash_values; + std::vector outputs; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); + friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; - static BlackBoxOp bincodeDeserialize(std::vector); + static BlackBoxFuncCall bincodeDeserialize(std::vector); }; - struct RegisterOrMemory { - - struct RegisterIndex { - Circuit::RegisterIndex value; + struct BlockId { + uint32_t value; - friend bool operator==(const RegisterIndex&, const RegisterIndex&); - std::vector bincodeSerialize() const; - static RegisterIndex bincodeDeserialize(std::vector); - }; + friend bool operator==(const BlockId&, const BlockId&); + std::vector bincodeSerialize() const; + static BlockId bincodeDeserialize(std::vector); + }; - struct HeapArray { - Circuit::HeapArray value; - - friend bool operator==(const HeapArray&, const HeapArray&); - std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); - }; - - struct HeapVector { - Circuit::HeapVector value; - - friend bool operator==(const HeapVector&, const HeapVector&); - std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); - }; - - std::variant value; - - friend bool operator==(const RegisterOrMemory&, const RegisterOrMemory&); - std::vector bincodeSerialize() const; - static RegisterOrMemory bincodeDeserialize(std::vector); - }; - - struct Value { - std::string inner; + struct Expression { + std::vector> mul_terms; + std::vector> linear_combinations; + std::string q_c; - friend bool operator==(const Value&, const Value&); + friend bool operator==(const Expression&, const Expression&); std::vector bincodeSerialize() const; - static Value bincodeDeserialize(std::vector); + static Expression bincodeDeserialize(std::vector); }; - struct BrilligOpcode { - - struct BinaryFieldOp { - Circuit::RegisterIndex destination; - Circuit::BinaryFieldOp op; - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; - - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); - std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); - }; - - struct BinaryIntOp { - Circuit::RegisterIndex destination; - Circuit::BinaryIntOp op; - uint32_t bit_size; - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; - - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); - std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); - }; - - struct JumpIfNot { - Circuit::RegisterIndex condition; - uint64_t location; - - friend bool operator==(const JumpIfNot&, const JumpIfNot&); - std::vector bincodeSerialize() const; - static JumpIfNot bincodeDeserialize(std::vector); - }; - - struct JumpIf { - Circuit::RegisterIndex condition; - uint64_t location; - - friend bool operator==(const JumpIf&, const JumpIf&); - std::vector bincodeSerialize() const; - static JumpIf bincodeDeserialize(std::vector); - }; - - struct Jump { - uint64_t location; - - friend bool operator==(const Jump&, const Jump&); - std::vector bincodeSerialize() const; - static Jump bincodeDeserialize(std::vector); - }; - - struct Call { - uint64_t location; - - friend bool operator==(const Call&, const Call&); - std::vector bincodeSerialize() const; - static Call bincodeDeserialize(std::vector); - }; - - struct Const { - Circuit::RegisterIndex destination; - Circuit::Value value; - - friend bool operator==(const Const&, const Const&); - std::vector bincodeSerialize() const; - static Const bincodeDeserialize(std::vector); - }; - - struct Return { - friend bool operator==(const Return&, const Return&); - std::vector bincodeSerialize() const; - static Return bincodeDeserialize(std::vector); - }; - - struct ForeignCall { - std::string function; - std::vector destinations; - std::vector inputs; - - friend bool operator==(const ForeignCall&, const ForeignCall&); - std::vector bincodeSerialize() const; - static ForeignCall bincodeDeserialize(std::vector); - }; - - struct Mov { - Circuit::RegisterIndex destination; - Circuit::RegisterIndex source; - - friend bool operator==(const Mov&, const Mov&); - std::vector bincodeSerialize() const; - static Mov bincodeDeserialize(std::vector); - }; - - struct Load { - Circuit::RegisterIndex destination; - Circuit::RegisterIndex source_pointer; - - friend bool operator==(const Load&, const Load&); - std::vector bincodeSerialize() const; - static Load bincodeDeserialize(std::vector); - }; + struct BrilligInputs { - struct Store { - Circuit::RegisterIndex destination_pointer; - Circuit::RegisterIndex source; + struct Single { + Circuit::Expression value; - friend bool operator==(const Store&, const Store&); + friend bool operator==(const Single&, const Single&); std::vector bincodeSerialize() const; - static Store bincodeDeserialize(std::vector); + static Single bincodeDeserialize(std::vector); }; - struct BlackBox { - Circuit::BlackBoxOp value; + struct Array { + std::vector value; - friend bool operator==(const BlackBox&, const BlackBox&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static BlackBox bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct Trap { - friend bool operator==(const Trap&, const Trap&); - std::vector bincodeSerialize() const; - static Trap bincodeDeserialize(std::vector); - }; + struct MemoryArray { + Circuit::BlockId value; - struct Stop { - friend bool operator==(const Stop&, const Stop&); + friend bool operator==(const MemoryArray&, const MemoryArray&); std::vector bincodeSerialize() const; - static Stop bincodeDeserialize(std::vector); + static MemoryArray bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); + friend bool operator==(const BrilligInputs&, const BrilligInputs&); std::vector bincodeSerialize() const; - static BrilligOpcode bincodeDeserialize(std::vector); + static BrilligInputs bincodeDeserialize(std::vector); }; struct BrilligOutputs { @@ -961,103 +1019,456 @@ namespace Circuit { struct Brillig { Circuit::Brillig value; - friend bool operator==(const Brillig&, const Brillig&); - std::vector bincodeSerialize() const; - static Brillig bincodeDeserialize(std::vector); - }; + friend bool operator==(const Brillig&, const Brillig&); + std::vector bincodeSerialize() const; + static Brillig bincodeDeserialize(std::vector); + }; + + struct MemoryOp { + Circuit::BlockId block_id; + Circuit::MemOp op; + std::optional predicate; + + friend bool operator==(const MemoryOp&, const MemoryOp&); + std::vector bincodeSerialize() const; + static MemoryOp bincodeDeserialize(std::vector); + }; + + struct MemoryInit { + Circuit::BlockId block_id; + std::vector init; + + friend bool operator==(const MemoryInit&, const MemoryInit&); + std::vector bincodeSerialize() const; + static MemoryInit bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const Opcode&, const Opcode&); + std::vector bincodeSerialize() const; + static Opcode bincodeDeserialize(std::vector); + }; + + struct ExpressionWidth { + + struct Unbounded { + friend bool operator==(const Unbounded&, const Unbounded&); + std::vector bincodeSerialize() const; + static Unbounded bincodeDeserialize(std::vector); + }; + + struct Bounded { + uint64_t width; + + friend bool operator==(const Bounded&, const Bounded&); + std::vector bincodeSerialize() const; + static Bounded bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const ExpressionWidth&, const ExpressionWidth&); + std::vector bincodeSerialize() const; + static ExpressionWidth bincodeDeserialize(std::vector); + }; + + struct OpcodeLocation { + + struct Acir { + uint64_t value; + + friend bool operator==(const Acir&, const Acir&); + std::vector bincodeSerialize() const; + static Acir bincodeDeserialize(std::vector); + }; + + struct Brillig { + uint64_t acir_index; + uint64_t brillig_index; + + friend bool operator==(const Brillig&, const Brillig&); + std::vector bincodeSerialize() const; + static Brillig bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const OpcodeLocation&, const OpcodeLocation&); + std::vector bincodeSerialize() const; + static OpcodeLocation bincodeDeserialize(std::vector); + }; + + struct PublicInputs { + std::vector value; + + friend bool operator==(const PublicInputs&, const PublicInputs&); + std::vector bincodeSerialize() const; + static PublicInputs bincodeDeserialize(std::vector); + }; + + struct Circuit { + uint32_t current_witness_index; + std::vector opcodes; + Circuit::ExpressionWidth expression_width; + std::vector private_parameters; + Circuit::PublicInputs public_parameters; + Circuit::PublicInputs return_values; + std::vector> assert_messages; + bool recursive; + + friend bool operator==(const Circuit&, const Circuit&); + std::vector bincodeSerialize() const; + static Circuit bincodeDeserialize(std::vector); + }; + +} // end of namespace Circuit + + +namespace Circuit { + + inline bool operator==(const BinaryFieldOp &lhs, const BinaryFieldOp &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector BinaryFieldOp::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryFieldOp BinaryFieldOp::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Circuit::BinaryFieldOp serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::BinaryFieldOp obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Circuit { + + inline bool operator==(const BinaryFieldOp::Add &lhs, const BinaryFieldOp::Add &rhs) { + return true; + } + + inline std::vector BinaryFieldOp::Add::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryFieldOp::Add BinaryFieldOp::Add::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Add &obj, Serializer &serializer) { +} + +template <> +template +Circuit::BinaryFieldOp::Add serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryFieldOp::Add obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const BinaryFieldOp::Sub &lhs, const BinaryFieldOp::Sub &rhs) { + return true; + } + + inline std::vector BinaryFieldOp::Sub::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryFieldOp::Sub BinaryFieldOp::Sub::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Sub &obj, Serializer &serializer) { +} + +template <> +template +Circuit::BinaryFieldOp::Sub serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryFieldOp::Sub obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const BinaryFieldOp::Mul &lhs, const BinaryFieldOp::Mul &rhs) { + return true; + } + + inline std::vector BinaryFieldOp::Mul::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryFieldOp::Mul BinaryFieldOp::Mul::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Mul &obj, Serializer &serializer) { +} + +template <> +template +Circuit::BinaryFieldOp::Mul serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryFieldOp::Mul obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const BinaryFieldOp::Div &lhs, const BinaryFieldOp::Div &rhs) { + return true; + } + + inline std::vector BinaryFieldOp::Div::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryFieldOp::Div BinaryFieldOp::Div::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Div &obj, Serializer &serializer) { +} + +template <> +template +Circuit::BinaryFieldOp::Div serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryFieldOp::Div obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const BinaryFieldOp::Equals &lhs, const BinaryFieldOp::Equals &rhs) { + return true; + } + + inline std::vector BinaryFieldOp::Equals::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryFieldOp::Equals BinaryFieldOp::Equals::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Equals &obj, Serializer &serializer) { +} + +template <> +template +Circuit::BinaryFieldOp::Equals serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryFieldOp::Equals obj; + return obj; +} + +namespace Circuit { - struct MemoryOp { - Circuit::BlockId block_id; - Circuit::MemOp op; - std::optional predicate; + inline bool operator==(const BinaryIntOp &lhs, const BinaryIntOp &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } - friend bool operator==(const MemoryOp&, const MemoryOp&); - std::vector bincodeSerialize() const; - static MemoryOp bincodeDeserialize(std::vector); - }; + inline std::vector BinaryIntOp::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } - struct MemoryInit { - Circuit::BlockId block_id; - std::vector init; + inline BinaryIntOp BinaryIntOp::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } - friend bool operator==(const MemoryInit&, const MemoryInit&); - std::vector bincodeSerialize() const; - static MemoryInit bincodeDeserialize(std::vector); - }; +} // end of namespace Circuit - std::variant value; +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryIntOp &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} - friend bool operator==(const Opcode&, const Opcode&); - std::vector bincodeSerialize() const; - static Opcode bincodeDeserialize(std::vector); - }; +template <> +template +Circuit::BinaryIntOp serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::BinaryIntOp obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} - struct OpcodeLocation { +namespace Circuit { - struct Acir { - uint64_t value; + inline bool operator==(const BinaryIntOp::Add &lhs, const BinaryIntOp::Add &rhs) { + return true; + } - friend bool operator==(const Acir&, const Acir&); - std::vector bincodeSerialize() const; - static Acir bincodeDeserialize(std::vector); - }; + inline std::vector BinaryIntOp::Add::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } - struct Brillig { - uint64_t acir_index; - uint64_t brillig_index; + inline BinaryIntOp::Add BinaryIntOp::Add::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } - friend bool operator==(const Brillig&, const Brillig&); - std::vector bincodeSerialize() const; - static Brillig bincodeDeserialize(std::vector); - }; +} // end of namespace Circuit - std::variant value; +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Add &obj, Serializer &serializer) { +} - friend bool operator==(const OpcodeLocation&, const OpcodeLocation&); - std::vector bincodeSerialize() const; - static OpcodeLocation bincodeDeserialize(std::vector); - }; +template <> +template +Circuit::BinaryIntOp::Add serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::Add obj; + return obj; +} - struct PublicInputs { - std::vector value; +namespace Circuit { - friend bool operator==(const PublicInputs&, const PublicInputs&); - std::vector bincodeSerialize() const; - static PublicInputs bincodeDeserialize(std::vector); - }; + inline bool operator==(const BinaryIntOp::Sub &lhs, const BinaryIntOp::Sub &rhs) { + return true; + } - struct Circuit { - uint32_t current_witness_index; - std::vector opcodes; - std::vector private_parameters; - Circuit::PublicInputs public_parameters; - Circuit::PublicInputs return_values; - std::vector> assert_messages; + inline std::vector BinaryIntOp::Sub::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } - friend bool operator==(const Circuit&, const Circuit&); - std::vector bincodeSerialize() const; - static Circuit bincodeDeserialize(std::vector); - }; + inline BinaryIntOp::Sub BinaryIntOp::Sub::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } } // end of namespace Circuit +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Sub &obj, Serializer &serializer) { +} + +template <> +template +Circuit::BinaryIntOp::Sub serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::Sub obj; + return obj; +} namespace Circuit { - inline bool operator==(const BinaryFieldOp &lhs, const BinaryFieldOp &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const BinaryIntOp::Mul &lhs, const BinaryIntOp::Mul &rhs) { return true; } - inline std::vector BinaryFieldOp::bincodeSerialize() const { + inline std::vector BinaryIntOp::Mul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryFieldOp BinaryFieldOp::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::Mul BinaryIntOp::Mul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1068,37 +1479,31 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Mul &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::BinaryFieldOp obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); +Circuit::BinaryIntOp::Mul serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::Mul obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryFieldOp::Add &lhs, const BinaryFieldOp::Add &rhs) { + inline bool operator==(const BinaryIntOp::SignedDiv &lhs, const BinaryIntOp::SignedDiv &rhs) { return true; } - inline std::vector BinaryFieldOp::Add::bincodeSerialize() const { + inline std::vector BinaryIntOp::SignedDiv::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryFieldOp::Add BinaryFieldOp::Add::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::SignedDiv BinaryIntOp::SignedDiv::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1109,31 +1514,31 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Add &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BinaryIntOp::SignedDiv &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::Add serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::Add obj; +Circuit::BinaryIntOp::SignedDiv serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::SignedDiv obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryFieldOp::Sub &lhs, const BinaryFieldOp::Sub &rhs) { + inline bool operator==(const BinaryIntOp::UnsignedDiv &lhs, const BinaryIntOp::UnsignedDiv &rhs) { return true; } - inline std::vector BinaryFieldOp::Sub::bincodeSerialize() const { + inline std::vector BinaryIntOp::UnsignedDiv::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryFieldOp::Sub BinaryFieldOp::Sub::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::UnsignedDiv BinaryIntOp::UnsignedDiv::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1144,31 +1549,31 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Sub &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BinaryIntOp::UnsignedDiv &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::Sub serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::Sub obj; +Circuit::BinaryIntOp::UnsignedDiv serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::UnsignedDiv obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryFieldOp::Mul &lhs, const BinaryFieldOp::Mul &rhs) { + inline bool operator==(const BinaryIntOp::Equals &lhs, const BinaryIntOp::Equals &rhs) { return true; } - inline std::vector BinaryFieldOp::Mul::bincodeSerialize() const { + inline std::vector BinaryIntOp::Equals::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryFieldOp::Mul BinaryFieldOp::Mul::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::Equals BinaryIntOp::Equals::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1179,31 +1584,31 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Mul &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Equals &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::Mul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::Mul obj; +Circuit::BinaryIntOp::Equals serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::Equals obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryFieldOp::Div &lhs, const BinaryFieldOp::Div &rhs) { + inline bool operator==(const BinaryIntOp::LessThan &lhs, const BinaryIntOp::LessThan &rhs) { return true; } - inline std::vector BinaryFieldOp::Div::bincodeSerialize() const { + inline std::vector BinaryIntOp::LessThan::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryFieldOp::Div BinaryFieldOp::Div::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::LessThan BinaryIntOp::LessThan::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1214,31 +1619,31 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Div &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BinaryIntOp::LessThan &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::Div serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::Div obj; +Circuit::BinaryIntOp::LessThan serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::LessThan obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryFieldOp::Equals &lhs, const BinaryFieldOp::Equals &rhs) { + inline bool operator==(const BinaryIntOp::LessThanEquals &lhs, const BinaryIntOp::LessThanEquals &rhs) { return true; } - inline std::vector BinaryFieldOp::Equals::bincodeSerialize() const { + inline std::vector BinaryIntOp::LessThanEquals::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryFieldOp::Equals BinaryFieldOp::Equals::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::LessThanEquals BinaryIntOp::LessThanEquals::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1249,32 +1654,31 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Equals &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BinaryIntOp::LessThanEquals &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::Equals serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::Equals obj; +Circuit::BinaryIntOp::LessThanEquals serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::LessThanEquals obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp &lhs, const BinaryIntOp &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const BinaryIntOp::And &lhs, const BinaryIntOp::And &rhs) { return true; } - inline std::vector BinaryIntOp::bincodeSerialize() const { + inline std::vector BinaryIntOp::And::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp BinaryIntOp::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::And BinaryIntOp::And::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1285,37 +1689,31 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize(const Circuit::BinaryIntOp::And &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::BinaryIntOp obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); +Circuit::BinaryIntOp::And serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::And obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::Add &lhs, const BinaryIntOp::Add &rhs) { + inline bool operator==(const BinaryIntOp::Or &lhs, const BinaryIntOp::Or &rhs) { return true; } - inline std::vector BinaryIntOp::Add::bincodeSerialize() const { + inline std::vector BinaryIntOp::Or::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Add BinaryIntOp::Add::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::Or BinaryIntOp::Or::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1326,31 +1724,31 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Add &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Or &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Add serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Add obj; +Circuit::BinaryIntOp::Or serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::Or obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::Sub &lhs, const BinaryIntOp::Sub &rhs) { + inline bool operator==(const BinaryIntOp::Xor &lhs, const BinaryIntOp::Xor &rhs) { return true; } - inline std::vector BinaryIntOp::Sub::bincodeSerialize() const { + inline std::vector BinaryIntOp::Xor::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Sub BinaryIntOp::Sub::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::Xor BinaryIntOp::Xor::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1361,31 +1759,31 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Sub &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Xor &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Sub serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Sub obj; +Circuit::BinaryIntOp::Xor serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::Xor obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::Mul &lhs, const BinaryIntOp::Mul &rhs) { + inline bool operator==(const BinaryIntOp::Shl &lhs, const BinaryIntOp::Shl &rhs) { return true; } - inline std::vector BinaryIntOp::Mul::bincodeSerialize() const { + inline std::vector BinaryIntOp::Shl::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Mul BinaryIntOp::Mul::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::Shl BinaryIntOp::Shl::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1396,31 +1794,31 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Mul &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shl &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Mul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Mul obj; +Circuit::BinaryIntOp::Shl serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::Shl obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::SignedDiv &lhs, const BinaryIntOp::SignedDiv &rhs) { + inline bool operator==(const BinaryIntOp::Shr &lhs, const BinaryIntOp::Shr &rhs) { return true; } - inline std::vector BinaryIntOp::SignedDiv::bincodeSerialize() const { + inline std::vector BinaryIntOp::Shr::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::SignedDiv BinaryIntOp::SignedDiv::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::Shr BinaryIntOp::Shr::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1431,31 +1829,32 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::SignedDiv &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shr &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::SignedDiv serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::SignedDiv obj; +Circuit::BinaryIntOp::Shr serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::Shr obj; return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::UnsignedDiv &lhs, const BinaryIntOp::UnsignedDiv &rhs) { + inline bool operator==(const BlackBoxFuncCall &lhs, const BlackBoxFuncCall &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BinaryIntOp::UnsignedDiv::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::UnsignedDiv BinaryIntOp::UnsignedDiv::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall BlackBoxFuncCall::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1466,31 +1865,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::UnsignedDiv &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BinaryIntOp::UnsignedDiv serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::UnsignedDiv obj; +Circuit::BlackBoxFuncCall serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::BlackBoxFuncCall obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::Equals &lhs, const BinaryIntOp::Equals &rhs) { + inline bool operator==(const BlackBoxFuncCall::AND &lhs, const BlackBoxFuncCall::AND &rhs) { + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BinaryIntOp::Equals::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::AND::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Equals BinaryIntOp::Equals::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::AND BlackBoxFuncCall::AND::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1501,31 +1909,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Equals &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::AND &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BinaryIntOp::Equals serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Equals obj; +Circuit::BlackBoxFuncCall::AND serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::AND obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::LessThan &lhs, const BinaryIntOp::LessThan &rhs) { + inline bool operator==(const BlackBoxFuncCall::XOR &lhs, const BlackBoxFuncCall::XOR &rhs) { + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BinaryIntOp::LessThan::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::XOR::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::LessThan BinaryIntOp::LessThan::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::XOR BlackBoxFuncCall::XOR::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1536,31 +1953,38 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::LessThan &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::XOR &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BinaryIntOp::LessThan serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::LessThan obj; +Circuit::BlackBoxFuncCall::XOR serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::XOR obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::LessThanEquals &lhs, const BinaryIntOp::LessThanEquals &rhs) { + inline bool operator==(const BlackBoxFuncCall::RANGE &lhs, const BlackBoxFuncCall::RANGE &rhs) { + if (!(lhs.input == rhs.input)) { return false; } return true; } - inline std::vector BinaryIntOp::LessThanEquals::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::RANGE::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::LessThanEquals BinaryIntOp::LessThanEquals::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::RANGE BlackBoxFuncCall::RANGE::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1571,31 +1995,35 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::LessThanEquals &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::RANGE &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.input, serializer); } template <> template -Circuit::BinaryIntOp::LessThanEquals serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::LessThanEquals obj; +Circuit::BlackBoxFuncCall::RANGE serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::RANGE obj; + obj.input = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::And &lhs, const BinaryIntOp::And &rhs) { + inline bool operator==(const BlackBoxFuncCall::SHA256 &lhs, const BlackBoxFuncCall::SHA256 &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } - inline std::vector BinaryIntOp::And::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::SHA256::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::And BinaryIntOp::And::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::SHA256 BlackBoxFuncCall::SHA256::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1606,31 +2034,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::And &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::SHA256 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BinaryIntOp::And serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::And obj; +Circuit::BlackBoxFuncCall::SHA256 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::SHA256 obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::Or &lhs, const BinaryIntOp::Or &rhs) { + inline bool operator==(const BlackBoxFuncCall::Blake2s &lhs, const BlackBoxFuncCall::Blake2s &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } - inline std::vector BinaryIntOp::Or::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::Blake2s::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Or BinaryIntOp::Or::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::Blake2s BlackBoxFuncCall::Blake2s::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1641,31 +2075,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Or &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake2s &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BinaryIntOp::Or serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Or obj; +Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::Blake2s obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::Xor &lhs, const BinaryIntOp::Xor &rhs) { + inline bool operator==(const BlackBoxFuncCall::Blake3 &lhs, const BlackBoxFuncCall::Blake3 &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } - inline std::vector BinaryIntOp::Xor::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::Blake3::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Xor BinaryIntOp::Xor::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::Blake3 BlackBoxFuncCall::Blake3::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1676,31 +2116,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Xor &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake3 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BinaryIntOp::Xor serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Xor obj; +Circuit::BlackBoxFuncCall::Blake3 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::Blake3 obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::Shl &lhs, const BinaryIntOp::Shl &rhs) { + inline bool operator==(const BlackBoxFuncCall::SchnorrVerify &lhs, const BlackBoxFuncCall::SchnorrVerify &rhs) { + if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } + if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } + if (!(lhs.signature == rhs.signature)) { return false; } + if (!(lhs.message == rhs.message)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BinaryIntOp::Shl::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::SchnorrVerify::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Shl BinaryIntOp::Shl::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::SchnorrVerify BlackBoxFuncCall::SchnorrVerify::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1711,31 +2160,44 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shl &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::SchnorrVerify &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.message, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BinaryIntOp::Shl serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Shl obj; +Circuit::BlackBoxFuncCall::SchnorrVerify serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::SchnorrVerify obj; + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.message = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BinaryIntOp::Shr &lhs, const BinaryIntOp::Shr &rhs) { + inline bool operator==(const BlackBoxFuncCall::PedersenCommitment &lhs, const BlackBoxFuncCall::PedersenCommitment &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } - inline std::vector BinaryIntOp::Shr::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::PedersenCommitment::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Shr BinaryIntOp::Shr::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::PedersenCommitment BlackBoxFuncCall::PedersenCommitment::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1746,32 +2208,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shr &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::PedersenCommitment &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BinaryIntOp::Shr serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Shr obj; +Circuit::BlackBoxFuncCall::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::PedersenCommitment obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.domain_separator = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall &lhs, const BlackBoxFuncCall &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const BlackBoxFuncCall::PedersenHash &lhs, const BlackBoxFuncCall::PedersenHash &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::PedersenHash::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall BlackBoxFuncCall::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::PedersenHash BlackBoxFuncCall::PedersenHash::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1782,40 +2252,42 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::PedersenHash &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::BlackBoxFuncCall obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); +Circuit::BlackBoxFuncCall::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::PedersenHash obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.domain_separator = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::AND &lhs, const BlackBoxFuncCall::AND &rhs) { - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } + inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256k1 &lhs, const BlackBoxFuncCall::EcdsaSecp256k1 &rhs) { + if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } + if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } + if (!(lhs.signature == rhs.signature)) { return false; } + if (!(lhs.hashed_message == rhs.hashed_message)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::AND::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::EcdsaSecp256k1::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::AND BlackBoxFuncCall::AND::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::EcdsaSecp256k1 BlackBoxFuncCall::EcdsaSecp256k1::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1826,40 +2298,46 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::AND &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::EcdsaSecp256k1 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.hashed_message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::AND serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::AND obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::EcdsaSecp256k1 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::EcdsaSecp256k1 obj; + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.hashed_message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::XOR &lhs, const BlackBoxFuncCall::XOR &rhs) { - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } + inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256r1 &lhs, const BlackBoxFuncCall::EcdsaSecp256r1 &rhs) { + if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } + if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } + if (!(lhs.signature == rhs.signature)) { return false; } + if (!(lhs.hashed_message == rhs.hashed_message)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::XOR::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::EcdsaSecp256r1::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::XOR BlackBoxFuncCall::XOR::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::EcdsaSecp256r1 BlackBoxFuncCall::EcdsaSecp256r1::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1870,38 +2348,44 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::XOR &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::EcdsaSecp256r1 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.hashed_message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::XOR serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::XOR obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::EcdsaSecp256r1 obj; + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.hashed_message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::RANGE &lhs, const BlackBoxFuncCall::RANGE &rhs) { - if (!(lhs.input == rhs.input)) { return false; } + inline bool operator==(const BlackBoxFuncCall::FixedBaseScalarMul &lhs, const BlackBoxFuncCall::FixedBaseScalarMul &rhs) { + if (!(lhs.low == rhs.low)) { return false; } + if (!(lhs.high == rhs.high)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::RANGE::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::FixedBaseScalarMul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::RANGE BlackBoxFuncCall::RANGE::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::FixedBaseScalarMul BlackBoxFuncCall::FixedBaseScalarMul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1912,35 +2396,42 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::RANGE &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.input, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::FixedBaseScalarMul &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.low, serializer); + serde::Serializable::serialize(obj.high, serializer); + serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::RANGE serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::RANGE obj; - obj.input = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::FixedBaseScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::FixedBaseScalarMul obj; + obj.low = serde::Deserializable::deserialize(deserializer); + obj.high = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::SHA256 &lhs, const BlackBoxFuncCall::SHA256 &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } + inline bool operator==(const BlackBoxFuncCall::EmbeddedCurveAdd &lhs, const BlackBoxFuncCall::EmbeddedCurveAdd &rhs) { + if (!(lhs.input1_x == rhs.input1_x)) { return false; } + if (!(lhs.input1_y == rhs.input1_y)) { return false; } + if (!(lhs.input2_x == rhs.input2_x)) { return false; } + if (!(lhs.input2_y == rhs.input2_y)) { return false; } if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::SHA256::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::EmbeddedCurveAdd::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::SHA256 BlackBoxFuncCall::SHA256::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::EmbeddedCurveAdd BlackBoxFuncCall::EmbeddedCurveAdd::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1951,37 +2442,43 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::SHA256 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::EmbeddedCurveAdd &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.input1_x, serializer); + serde::Serializable::serialize(obj.input1_y, serializer); + serde::Serializable::serialize(obj.input2_x, serializer); + serde::Serializable::serialize(obj.input2_y, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::SHA256 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::SHA256 obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::EmbeddedCurveAdd obj; + obj.input1_x = serde::Deserializable::deserialize(deserializer); + obj.input1_y = serde::Deserializable::deserialize(deserializer); + obj.input2_x = serde::Deserializable::deserialize(deserializer); + obj.input2_y = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::Blake2s &lhs, const BlackBoxFuncCall::Blake2s &rhs) { + inline bool operator==(const BlackBoxFuncCall::Keccak256 &lhs, const BlackBoxFuncCall::Keccak256 &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::Blake2s::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::Keccak256::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::Blake2s BlackBoxFuncCall::Blake2s::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::Keccak256 BlackBoxFuncCall::Keccak256::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1992,15 +2489,15 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake2s &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Keccak256 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Blake2s obj; +Circuit::BlackBoxFuncCall::Keccak256 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::Keccak256 obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; @@ -2008,21 +2505,22 @@ Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable BlackBoxFuncCall::Blake3::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::Keccak256VariableLength::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::Blake3 BlackBoxFuncCall::Blake3::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::Keccak256VariableLength BlackBoxFuncCall::Keccak256VariableLength::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2033,40 +2531,39 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake3 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Keccak256VariableLength &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.var_message_size, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Blake3 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Blake3 obj; +Circuit::BlackBoxFuncCall::Keccak256VariableLength serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::Keccak256VariableLength obj; obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.var_message_size = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::SchnorrVerify &lhs, const BlackBoxFuncCall::SchnorrVerify &rhs) { - if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } - if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } - if (!(lhs.signature == rhs.signature)) { return false; } - if (!(lhs.message == rhs.message)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } + inline bool operator==(const BlackBoxFuncCall::Keccakf1600 &lhs, const BlackBoxFuncCall::Keccakf1600 &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::SchnorrVerify::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::Keccakf1600::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::SchnorrVerify BlackBoxFuncCall::SchnorrVerify::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::Keccakf1600 BlackBoxFuncCall::Keccakf1600::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2077,44 +2574,39 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::SchnorrVerify &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.output, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Keccakf1600 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::SchnorrVerify serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::SchnorrVerify obj; - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.message = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::Keccakf1600 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::Keccakf1600 obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::PedersenCommitment &lhs, const BlackBoxFuncCall::PedersenCommitment &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { return false; } + inline bool operator==(const BlackBoxFuncCall::RecursiveAggregation &lhs, const BlackBoxFuncCall::RecursiveAggregation &rhs) { + if (!(lhs.verification_key == rhs.verification_key)) { return false; } + if (!(lhs.proof == rhs.proof)) { return false; } + if (!(lhs.public_inputs == rhs.public_inputs)) { return false; } + if (!(lhs.key_hash == rhs.key_hash)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::PedersenCommitment::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::RecursiveAggregation::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::PedersenCommitment BlackBoxFuncCall::PedersenCommitment::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::RecursiveAggregation BlackBoxFuncCall::RecursiveAggregation::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2125,40 +2617,42 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::PedersenCommitment &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); - serde::Serializable::serialize(obj.outputs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::RecursiveAggregation &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.verification_key, serializer); + serde::Serializable::serialize(obj.proof, serializer); + serde::Serializable::serialize(obj.public_inputs, serializer); + serde::Serializable::serialize(obj.key_hash, serializer); } template <> template -Circuit::BlackBoxFuncCall::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::PedersenCommitment obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::RecursiveAggregation obj; + obj.verification_key = serde::Deserializable::deserialize(deserializer); + obj.proof = serde::Deserializable::deserialize(deserializer); + obj.public_inputs = serde::Deserializable::deserialize(deserializer); + obj.key_hash = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::PedersenHash &lhs, const BlackBoxFuncCall::PedersenHash &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } + inline bool operator==(const BlackBoxFuncCall::BigIntAdd &lhs, const BlackBoxFuncCall::BigIntAdd &rhs) { + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::PedersenHash::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::BigIntAdd::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::PedersenHash BlackBoxFuncCall::PedersenHash::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::BigIntAdd BlackBoxFuncCall::BigIntAdd::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2169,42 +2663,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::PedersenHash &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntAdd &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::PedersenHash obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::BigIntAdd serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::BigIntAdd obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256k1 &lhs, const BlackBoxFuncCall::EcdsaSecp256k1 &rhs) { - if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } - if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } - if (!(lhs.signature == rhs.signature)) { return false; } - if (!(lhs.hashed_message == rhs.hashed_message)) { return false; } + inline bool operator==(const BlackBoxFuncCall::BigIntSub &lhs, const BlackBoxFuncCall::BigIntSub &rhs) { + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::EcdsaSecp256k1::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::BigIntSub::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::EcdsaSecp256k1 BlackBoxFuncCall::EcdsaSecp256k1::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::BigIntSub BlackBoxFuncCall::BigIntSub::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2215,46 +2707,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::EcdsaSecp256k1 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.hashed_message, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntSub &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::EcdsaSecp256k1 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::EcdsaSecp256k1 obj; - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.hashed_message = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::BigIntSub serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::BigIntSub obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256r1 &lhs, const BlackBoxFuncCall::EcdsaSecp256r1 &rhs) { - if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } - if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } - if (!(lhs.signature == rhs.signature)) { return false; } - if (!(lhs.hashed_message == rhs.hashed_message)) { return false; } + inline bool operator==(const BlackBoxFuncCall::BigIntMul &lhs, const BlackBoxFuncCall::BigIntMul &rhs) { + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::EcdsaSecp256r1::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::BigIntMul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::EcdsaSecp256r1 BlackBoxFuncCall::EcdsaSecp256r1::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::BigIntMul BlackBoxFuncCall::BigIntMul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2265,44 +2751,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::EcdsaSecp256r1 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.hashed_message, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntMul &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::EcdsaSecp256r1 obj; - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.hashed_message = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::BigIntMul serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::BigIntMul obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::FixedBaseScalarMul &lhs, const BlackBoxFuncCall::FixedBaseScalarMul &rhs) { - if (!(lhs.low == rhs.low)) { return false; } - if (!(lhs.high == rhs.high)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { return false; } + inline bool operator==(const BlackBoxFuncCall::BigIntDiv &lhs, const BlackBoxFuncCall::BigIntDiv &rhs) { + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::FixedBaseScalarMul::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::BigIntDiv::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::FixedBaseScalarMul BlackBoxFuncCall::FixedBaseScalarMul::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::BigIntDiv BlackBoxFuncCall::BigIntDiv::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2313,42 +2795,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::FixedBaseScalarMul &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.low, serializer); - serde::Serializable::serialize(obj.high, serializer); - serde::Serializable::serialize(obj.outputs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntDiv &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::FixedBaseScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::FixedBaseScalarMul obj; - obj.low = serde::Deserializable::deserialize(deserializer); - obj.high = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::BigIntDiv serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::BigIntDiv obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::EmbeddedCurveAdd &lhs, const BlackBoxFuncCall::EmbeddedCurveAdd &rhs) { - if (!(lhs.input1_x == rhs.input1_x)) { return false; } - if (!(lhs.input1_y == rhs.input1_y)) { return false; } - if (!(lhs.input2_x == rhs.input2_x)) { return false; } - if (!(lhs.input2_y == rhs.input2_y)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { return false; } + inline bool operator==(const BlackBoxFuncCall::BigIntFromLeBytes &lhs, const BlackBoxFuncCall::BigIntFromLeBytes &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.modulus == rhs.modulus)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::EmbeddedCurveAdd::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::BigIntFromLeBytes::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::EmbeddedCurveAdd BlackBoxFuncCall::EmbeddedCurveAdd::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::BigIntFromLeBytes BlackBoxFuncCall::BigIntFromLeBytes::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2359,43 +2839,39 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::EmbeddedCurveAdd &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.input1_x, serializer); - serde::Serializable::serialize(obj.input1_y, serializer); - serde::Serializable::serialize(obj.input2_x, serializer); - serde::Serializable::serialize(obj.input2_y, serializer); - serde::Serializable::serialize(obj.outputs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntFromLeBytes &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.modulus, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::EmbeddedCurveAdd obj; - obj.input1_x = serde::Deserializable::deserialize(deserializer); - obj.input1_y = serde::Deserializable::deserialize(deserializer); - obj.input2_x = serde::Deserializable::deserialize(deserializer); - obj.input2_y = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::BigIntFromLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::BigIntFromLeBytes obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.modulus = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::Keccak256 &lhs, const BlackBoxFuncCall::Keccak256 &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } + inline bool operator==(const BlackBoxFuncCall::BigIntToLeBytes &lhs, const BlackBoxFuncCall::BigIntToLeBytes &rhs) { + if (!(lhs.input == rhs.input)) { return false; } if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::Keccak256::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::BigIntToLeBytes::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::Keccak256 BlackBoxFuncCall::Keccak256::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::BigIntToLeBytes BlackBoxFuncCall::BigIntToLeBytes::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2406,38 +2882,38 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Keccak256 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntToLeBytes &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Keccak256 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Keccak256 obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxFuncCall::BigIntToLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::BigIntToLeBytes obj; + obj.input = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::Keccak256VariableLength &lhs, const BlackBoxFuncCall::Keccak256VariableLength &rhs) { + inline bool operator==(const BlackBoxFuncCall::Poseidon2Permutation &lhs, const BlackBoxFuncCall::Poseidon2Permutation &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.var_message_size == rhs.var_message_size)) { return false; } if (!(lhs.outputs == rhs.outputs)) { return false; } + if (!(lhs.len == rhs.len)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::Keccak256VariableLength::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::Poseidon2Permutation::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::Keccak256VariableLength BlackBoxFuncCall::Keccak256VariableLength::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::Poseidon2Permutation BlackBoxFuncCall::Poseidon2Permutation::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2448,39 +2924,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Keccak256VariableLength &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Poseidon2Permutation &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.var_message_size, serializer); serde::Serializable::serialize(obj.outputs, serializer); + serde::Serializable::serialize(obj.len, serializer); } template <> template -Circuit::BlackBoxFuncCall::Keccak256VariableLength serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Keccak256VariableLength obj; +Circuit::BlackBoxFuncCall::Poseidon2Permutation serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::Poseidon2Permutation obj; obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.var_message_size = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); + obj.len = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::Keccakf1600 &lhs, const BlackBoxFuncCall::Keccakf1600 &rhs) { + inline bool operator==(const BlackBoxFuncCall::Sha256Compression &lhs, const BlackBoxFuncCall::Sha256Compression &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.hash_values == rhs.hash_values)) { return false; } if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::Keccakf1600::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::Sha256Compression::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::Keccakf1600 BlackBoxFuncCall::Keccakf1600::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::Sha256Compression BlackBoxFuncCall::Sha256Compression::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2491,39 +2968,38 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Keccakf1600 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Sha256Compression &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.hash_values, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Keccakf1600 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Keccakf1600 obj; +Circuit::BlackBoxFuncCall::Sha256Compression serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::Sha256Compression obj; obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.hash_values = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::RecursiveAggregation &lhs, const BlackBoxFuncCall::RecursiveAggregation &rhs) { - if (!(lhs.verification_key == rhs.verification_key)) { return false; } - if (!(lhs.proof == rhs.proof)) { return false; } - if (!(lhs.public_inputs == rhs.public_inputs)) { return false; } - if (!(lhs.key_hash == rhs.key_hash)) { return false; } + inline bool operator==(const BlackBoxOp &lhs, const BlackBoxOp &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::RecursiveAggregation::bincodeSerialize() const { + inline std::vector BlackBoxOp::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::RecursiveAggregation BlackBoxFuncCall::RecursiveAggregation::bincodeDeserialize(std::vector input) { + inline BlackBoxOp BlackBoxOp::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2534,42 +3010,39 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::RecursiveAggregation &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.verification_key, serializer); - serde::Serializable::serialize(obj.proof, serializer); - serde::Serializable::serialize(obj.public_inputs, serializer); - serde::Serializable::serialize(obj.key_hash, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::RecursiveAggregation obj; - obj.verification_key = serde::Deserializable::deserialize(deserializer); - obj.proof = serde::Deserializable::deserialize(deserializer); - obj.public_inputs = serde::Deserializable::deserialize(deserializer); - obj.key_hash = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::BlackBoxOp obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::BigIntAdd &lhs, const BlackBoxFuncCall::BigIntAdd &rhs) { - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } + inline bool operator==(const BlackBoxOp::Sha256 &lhs, const BlackBoxOp::Sha256 &rhs) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::BigIntAdd::bincodeSerialize() const { + inline std::vector BlackBoxOp::Sha256::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::BigIntAdd BlackBoxFuncCall::BigIntAdd::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::Sha256 BlackBoxOp::Sha256::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2580,40 +3053,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntAdd &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Sha256 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntAdd serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntAdd obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::Sha256 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::Sha256 obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::BigIntNeg &lhs, const BlackBoxFuncCall::BigIntNeg &rhs) { - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } + inline bool operator==(const BlackBoxOp::Blake2s &lhs, const BlackBoxOp::Blake2s &rhs) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::BigIntNeg::bincodeSerialize() const { + inline std::vector BlackBoxOp::Blake2s::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::BigIntNeg BlackBoxFuncCall::BigIntNeg::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::Blake2s BlackBoxOp::Blake2s::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2624,40 +3094,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntNeg &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake2s &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntNeg serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntNeg obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::Blake2s serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::Blake2s obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::BigIntMul &lhs, const BlackBoxFuncCall::BigIntMul &rhs) { - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } + inline bool operator==(const BlackBoxOp::Blake3 &lhs, const BlackBoxOp::Blake3 &rhs) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::BigIntMul::bincodeSerialize() const { + inline std::vector BlackBoxOp::Blake3::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::BigIntMul BlackBoxFuncCall::BigIntMul::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::Blake3 BlackBoxOp::Blake3::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2668,40 +3135,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntMul &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake3 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntMul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntMul obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::Blake3 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::Blake3 obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::BigIntDiv &lhs, const BlackBoxFuncCall::BigIntDiv &rhs) { - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } + inline bool operator==(const BlackBoxOp::Keccak256 &lhs, const BlackBoxOp::Keccak256 &rhs) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::BigIntDiv::bincodeSerialize() const { + inline std::vector BlackBoxOp::Keccak256::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::BigIntDiv BlackBoxFuncCall::BigIntDiv::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::Keccak256 BlackBoxOp::Keccak256::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2712,40 +3176,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntDiv &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccak256 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntDiv serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntDiv obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::Keccak256 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::Keccak256 obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::BigIntFromLeBytes &lhs, const BlackBoxFuncCall::BigIntFromLeBytes &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.modulus == rhs.modulus)) { return false; } + inline bool operator==(const BlackBoxOp::Keccakf1600 &lhs, const BlackBoxOp::Keccakf1600 &rhs) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::BigIntFromLeBytes::bincodeSerialize() const { + inline std::vector BlackBoxOp::Keccakf1600::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::BigIntFromLeBytes BlackBoxFuncCall::BigIntFromLeBytes::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::Keccakf1600 BlackBoxOp::Keccakf1600::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2756,39 +3217,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntFromLeBytes &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.modulus, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccakf1600 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntFromLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntFromLeBytes obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.modulus = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::Keccakf1600 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::Keccakf1600 obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::BigIntToLeBytes &lhs, const BlackBoxFuncCall::BigIntToLeBytes &rhs) { - if (!(lhs.input == rhs.input)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { return false; } + inline bool operator==(const BlackBoxOp::EcdsaSecp256k1 &lhs, const BlackBoxOp::EcdsaSecp256k1 &rhs) { + if (!(lhs.hashed_msg == rhs.hashed_msg)) { return false; } + if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } + if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } + if (!(lhs.signature == rhs.signature)) { return false; } + if (!(lhs.result == rhs.result)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::BigIntToLeBytes::bincodeSerialize() const { + inline std::vector BlackBoxOp::EcdsaSecp256k1::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::BigIntToLeBytes BlackBoxFuncCall::BigIntToLeBytes::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::EcdsaSecp256k1 BlackBoxOp::EcdsaSecp256k1::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2799,38 +3261,46 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntToLeBytes &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.input, serializer); - serde::Serializable::serialize(obj.outputs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256k1 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.hashed_msg, serializer); + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.result, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntToLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntToLeBytes obj; - obj.input = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::EcdsaSecp256k1 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::EcdsaSecp256k1 obj; + obj.hashed_msg = serde::Deserializable::deserialize(deserializer); + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.result = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::Poseidon2Permutation &lhs, const BlackBoxFuncCall::Poseidon2Permutation &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { return false; } - if (!(lhs.len == rhs.len)) { return false; } + inline bool operator==(const BlackBoxOp::EcdsaSecp256r1 &lhs, const BlackBoxOp::EcdsaSecp256r1 &rhs) { + if (!(lhs.hashed_msg == rhs.hashed_msg)) { return false; } + if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } + if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } + if (!(lhs.signature == rhs.signature)) { return false; } + if (!(lhs.result == rhs.result)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::Poseidon2Permutation::bincodeSerialize() const { + inline std::vector BlackBoxOp::EcdsaSecp256r1::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::Poseidon2Permutation BlackBoxFuncCall::Poseidon2Permutation::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::EcdsaSecp256r1 BlackBoxOp::EcdsaSecp256r1::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2841,40 +3311,46 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Poseidon2Permutation &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.outputs, serializer); - serde::Serializable::serialize(obj.len, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256r1 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.hashed_msg, serializer); + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.result, serializer); } template <> template -Circuit::BlackBoxFuncCall::Poseidon2Permutation serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Poseidon2Permutation obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); - obj.len = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::EcdsaSecp256r1 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::EcdsaSecp256r1 obj; + obj.hashed_msg = serde::Deserializable::deserialize(deserializer); + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.result = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxFuncCall::Sha256Compression &lhs, const BlackBoxFuncCall::Sha256Compression &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.hash_values == rhs.hash_values)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { return false; } + inline bool operator==(const BlackBoxOp::SchnorrVerify &lhs, const BlackBoxOp::SchnorrVerify &rhs) { + if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } + if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } + if (!(lhs.message == rhs.message)) { return false; } + if (!(lhs.signature == rhs.signature)) { return false; } + if (!(lhs.result == rhs.result)) { return false; } return true; } - inline std::vector BlackBoxFuncCall::Sha256Compression::bincodeSerialize() const { + inline std::vector BlackBoxOp::SchnorrVerify::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::Sha256Compression BlackBoxFuncCall::Sha256Compression::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::SchnorrVerify BlackBoxOp::SchnorrVerify::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2885,38 +3361,44 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Sha256Compression &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.hash_values, serializer); - serde::Serializable::serialize(obj.outputs, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::SchnorrVerify &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.message, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.result, serializer); } template <> template -Circuit::BlackBoxFuncCall::Sha256Compression serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Sha256Compression obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.hash_values = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::SchnorrVerify serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::SchnorrVerify obj; + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.message = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.result = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp &lhs, const BlackBoxOp &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const BlackBoxOp::PedersenCommitment &lhs, const BlackBoxOp::PedersenCommitment &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxOp::bincodeSerialize() const { + inline std::vector BlackBoxOp::PedersenCommitment::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp BlackBoxOp::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::PedersenCommitment BlackBoxOp::PedersenCommitment::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2927,39 +3409,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenCommitment &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::BlackBoxOp obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); +Circuit::BlackBoxOp::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::PedersenCommitment obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.domain_separator = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::Sha256 &lhs, const BlackBoxOp::Sha256 &rhs) { - if (!(lhs.message == rhs.message)) { return false; } + inline bool operator==(const BlackBoxOp::PedersenHash &lhs, const BlackBoxOp::PedersenHash &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxOp::Sha256::bincodeSerialize() const { + inline std::vector BlackBoxOp::PedersenHash::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::Sha256 BlackBoxOp::Sha256::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::PedersenHash BlackBoxOp::PedersenHash::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2970,37 +3453,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Sha256 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.message, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenHash &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.domain_separator, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Sha256 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Sha256 obj; - obj.message = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::PedersenHash obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::Blake2s &lhs, const BlackBoxOp::Blake2s &rhs) { - if (!(lhs.message == rhs.message)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } + inline bool operator==(const BlackBoxOp::FixedBaseScalarMul &lhs, const BlackBoxOp::FixedBaseScalarMul &rhs) { + if (!(lhs.low == rhs.low)) { return false; } + if (!(lhs.high == rhs.high)) { return false; } + if (!(lhs.result == rhs.result)) { return false; } return true; } - inline std::vector BlackBoxOp::Blake2s::bincodeSerialize() const { + inline std::vector BlackBoxOp::FixedBaseScalarMul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::Blake2s BlackBoxOp::Blake2s::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::FixedBaseScalarMul BlackBoxOp::FixedBaseScalarMul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3011,37 +3497,42 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake2s &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.output, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::FixedBaseScalarMul &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.low, serializer); + serde::Serializable::serialize(obj.high, serializer); + serde::Serializable::serialize(obj.result, serializer); } template <> template -Circuit::BlackBoxOp::Blake2s serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Blake2s obj; - obj.message = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::FixedBaseScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::FixedBaseScalarMul obj; + obj.low = serde::Deserializable::deserialize(deserializer); + obj.high = serde::Deserializable::deserialize(deserializer); + obj.result = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::Blake3 &lhs, const BlackBoxOp::Blake3 &rhs) { - if (!(lhs.message == rhs.message)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } + inline bool operator==(const BlackBoxOp::EmbeddedCurveAdd &lhs, const BlackBoxOp::EmbeddedCurveAdd &rhs) { + if (!(lhs.input1_x == rhs.input1_x)) { return false; } + if (!(lhs.input1_y == rhs.input1_y)) { return false; } + if (!(lhs.input2_x == rhs.input2_x)) { return false; } + if (!(lhs.input2_y == rhs.input2_y)) { return false; } + if (!(lhs.result == rhs.result)) { return false; } return true; } - inline std::vector BlackBoxOp::Blake3::bincodeSerialize() const { + inline std::vector BlackBoxOp::EmbeddedCurveAdd::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::Blake3 BlackBoxOp::Blake3::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::EmbeddedCurveAdd BlackBoxOp::EmbeddedCurveAdd::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3052,37 +3543,44 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake3 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.output, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::EmbeddedCurveAdd &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.input1_x, serializer); + serde::Serializable::serialize(obj.input1_y, serializer); + serde::Serializable::serialize(obj.input2_x, serializer); + serde::Serializable::serialize(obj.input2_y, serializer); + serde::Serializable::serialize(obj.result, serializer); } template <> template -Circuit::BlackBoxOp::Blake3 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Blake3 obj; - obj.message = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::EmbeddedCurveAdd obj; + obj.input1_x = serde::Deserializable::deserialize(deserializer); + obj.input1_y = serde::Deserializable::deserialize(deserializer); + obj.input2_x = serde::Deserializable::deserialize(deserializer); + obj.input2_y = serde::Deserializable::deserialize(deserializer); + obj.result = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::Keccak256 &lhs, const BlackBoxOp::Keccak256 &rhs) { - if (!(lhs.message == rhs.message)) { return false; } + inline bool operator==(const BlackBoxOp::BigIntAdd &lhs, const BlackBoxOp::BigIntAdd &rhs) { + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxOp::Keccak256::bincodeSerialize() const { + inline std::vector BlackBoxOp::BigIntAdd::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::Keccak256 BlackBoxOp::Keccak256::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::BigIntAdd BlackBoxOp::BigIntAdd::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3093,37 +3591,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccak256 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.message, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntAdd &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Keccak256 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Keccak256 obj; - obj.message = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::BigIntAdd serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::BigIntAdd obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::Keccakf1600 &lhs, const BlackBoxOp::Keccakf1600 &rhs) { - if (!(lhs.message == rhs.message)) { return false; } + inline bool operator==(const BlackBoxOp::BigIntSub &lhs, const BlackBoxOp::BigIntSub &rhs) { + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxOp::Keccakf1600::bincodeSerialize() const { + inline std::vector BlackBoxOp::BigIntSub::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::Keccakf1600 BlackBoxOp::Keccakf1600::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::BigIntSub BlackBoxOp::BigIntSub::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3134,40 +3635,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccakf1600 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.message, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntSub &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Keccakf1600 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Keccakf1600 obj; - obj.message = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::BigIntSub serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::BigIntSub obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::EcdsaSecp256k1 &lhs, const BlackBoxOp::EcdsaSecp256k1 &rhs) { - if (!(lhs.hashed_msg == rhs.hashed_msg)) { return false; } - if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } - if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } - if (!(lhs.signature == rhs.signature)) { return false; } - if (!(lhs.result == rhs.result)) { return false; } + inline bool operator==(const BlackBoxOp::BigIntMul &lhs, const BlackBoxOp::BigIntMul &rhs) { + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxOp::EcdsaSecp256k1::bincodeSerialize() const { + inline std::vector BlackBoxOp::BigIntMul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::EcdsaSecp256k1 BlackBoxOp::EcdsaSecp256k1::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::BigIntMul BlackBoxOp::BigIntMul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3178,46 +3679,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256k1 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.hashed_msg, serializer); - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.result, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntMul &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::EcdsaSecp256k1 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::EcdsaSecp256k1 obj; - obj.hashed_msg = serde::Deserializable::deserialize(deserializer); - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::BigIntMul serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::BigIntMul obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::EcdsaSecp256r1 &lhs, const BlackBoxOp::EcdsaSecp256r1 &rhs) { - if (!(lhs.hashed_msg == rhs.hashed_msg)) { return false; } - if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } - if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } - if (!(lhs.signature == rhs.signature)) { return false; } - if (!(lhs.result == rhs.result)) { return false; } + inline bool operator==(const BlackBoxOp::BigIntDiv &lhs, const BlackBoxOp::BigIntDiv &rhs) { + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxOp::EcdsaSecp256r1::bincodeSerialize() const { + inline std::vector BlackBoxOp::BigIntDiv::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::EcdsaSecp256r1 BlackBoxOp::EcdsaSecp256r1::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::BigIntDiv BlackBoxOp::BigIntDiv::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3228,46 +3723,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256r1 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.hashed_msg, serializer); - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.result, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntDiv &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::EcdsaSecp256r1 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::EcdsaSecp256r1 obj; - obj.hashed_msg = serde::Deserializable::deserialize(deserializer); - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::BigIntDiv serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::BigIntDiv obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::SchnorrVerify &lhs, const BlackBoxOp::SchnorrVerify &rhs) { - if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } - if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } - if (!(lhs.message == rhs.message)) { return false; } - if (!(lhs.signature == rhs.signature)) { return false; } - if (!(lhs.result == rhs.result)) { return false; } + inline bool operator==(const BlackBoxOp::BigIntFromLeBytes &lhs, const BlackBoxOp::BigIntFromLeBytes &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.modulus == rhs.modulus)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxOp::SchnorrVerify::bincodeSerialize() const { + inline std::vector BlackBoxOp::BigIntFromLeBytes::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::SchnorrVerify BlackBoxOp::SchnorrVerify::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::BigIntFromLeBytes BlackBoxOp::BigIntFromLeBytes::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3278,44 +3767,39 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::SchnorrVerify &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.result, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntFromLeBytes &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.modulus, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::SchnorrVerify serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::SchnorrVerify obj; - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.message = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::BigIntFromLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::BigIntFromLeBytes obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.modulus = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::PedersenCommitment &lhs, const BlackBoxOp::PedersenCommitment &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } + inline bool operator==(const BlackBoxOp::BigIntToLeBytes &lhs, const BlackBoxOp::BigIntToLeBytes &rhs) { + if (!(lhs.input == rhs.input)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxOp::PedersenCommitment::bincodeSerialize() const { + inline std::vector BlackBoxOp::BigIntToLeBytes::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::PedersenCommitment BlackBoxOp::PedersenCommitment::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::BigIntToLeBytes BlackBoxOp::BigIntToLeBytes::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3326,40 +3810,38 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenCommitment &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntToLeBytes &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::PedersenCommitment obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::BigIntToLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::BigIntToLeBytes obj; + obj.input = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::PedersenHash &lhs, const BlackBoxOp::PedersenHash &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } + inline bool operator==(const BlackBoxOp::Poseidon2Permutation &lhs, const BlackBoxOp::Poseidon2Permutation &rhs) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { return false; } + if (!(lhs.len == rhs.len)) { return false; } return true; } - inline std::vector BlackBoxOp::PedersenHash::bincodeSerialize() const { + inline std::vector BlackBoxOp::Poseidon2Permutation::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::PedersenHash BlackBoxOp::PedersenHash::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::Poseidon2Permutation BlackBoxOp::Poseidon2Permutation::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3370,40 +3852,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenHash &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Poseidon2Permutation &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); + serde::Serializable::serialize(obj.len, serializer); } template <> template -Circuit::BlackBoxOp::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::PedersenHash obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::Poseidon2Permutation serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::Poseidon2Permutation obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); + obj.len = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::FixedBaseScalarMul &lhs, const BlackBoxOp::FixedBaseScalarMul &rhs) { - if (!(lhs.low == rhs.low)) { return false; } - if (!(lhs.high == rhs.high)) { return false; } - if (!(lhs.result == rhs.result)) { return false; } + inline bool operator==(const BlackBoxOp::Sha256Compression &lhs, const BlackBoxOp::Sha256Compression &rhs) { + if (!(lhs.input == rhs.input)) { return false; } + if (!(lhs.hash_values == rhs.hash_values)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxOp::FixedBaseScalarMul::bincodeSerialize() const { + inline std::vector BlackBoxOp::Sha256Compression::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::FixedBaseScalarMul BlackBoxOp::FixedBaseScalarMul::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::Sha256Compression BlackBoxOp::Sha256Compression::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3414,42 +3896,38 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::FixedBaseScalarMul &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.low, serializer); - serde::Serializable::serialize(obj.high, serializer); - serde::Serializable::serialize(obj.result, serializer); +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Sha256Compression &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.input, serializer); + serde::Serializable::serialize(obj.hash_values, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::FixedBaseScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::FixedBaseScalarMul obj; - obj.low = serde::Deserializable::deserialize(deserializer); - obj.high = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); +Circuit::BlackBoxOp::Sha256Compression serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::Sha256Compression obj; + obj.input = serde::Deserializable::deserialize(deserializer); + obj.hash_values = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::EmbeddedCurveAdd &lhs, const BlackBoxOp::EmbeddedCurveAdd &rhs) { - if (!(lhs.input1_x == rhs.input1_x)) { return false; } - if (!(lhs.input1_y == rhs.input1_y)) { return false; } - if (!(lhs.input2_x == rhs.input2_x)) { return false; } - if (!(lhs.input2_y == rhs.input2_y)) { return false; } - if (!(lhs.result == rhs.result)) { return false; } + inline bool operator==(const BlockId &lhs, const BlockId &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BlackBoxOp::EmbeddedCurveAdd::bincodeSerialize() const { + inline std::vector BlockId::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::EmbeddedCurveAdd BlackBoxOp::EmbeddedCurveAdd::bincodeDeserialize(std::vector input) { + inline BlockId BlockId::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3460,44 +3938,41 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::EmbeddedCurveAdd &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.input1_x, serializer); - serde::Serializable::serialize(obj.input1_y, serializer); - serde::Serializable::serialize(obj.input2_x, serializer); - serde::Serializable::serialize(obj.input2_y, serializer); - serde::Serializable::serialize(obj.result, serializer); +void serde::Serializable::serialize(const Circuit::BlockId &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::EmbeddedCurveAdd obj; - obj.input1_x = serde::Deserializable::deserialize(deserializer); - obj.input1_y = serde::Deserializable::deserialize(deserializer); - obj.input2_x = serde::Deserializable::deserialize(deserializer); - obj.input2_y = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); +Circuit::BlockId serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::BlockId obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::BigIntAdd &lhs, const BlackBoxOp::BigIntAdd &rhs) { - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } + inline bool operator==(const Brillig &lhs, const Brillig &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } + if (!(lhs.bytecode == rhs.bytecode)) { return false; } + if (!(lhs.predicate == rhs.predicate)) { return false; } return true; } - inline std::vector BlackBoxOp::BigIntAdd::bincodeSerialize() const { + inline std::vector Brillig::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::BigIntAdd BlackBoxOp::BigIntAdd::bincodeDeserialize(std::vector input) { + inline Brillig Brillig::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3508,40 +3983,44 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntAdd &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); - serde::Serializable::serialize(obj.output, serializer); +void serde::Serializable::serialize(const Circuit::Brillig &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); + serde::Serializable::serialize(obj.bytecode, serializer); + serde::Serializable::serialize(obj.predicate, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BlackBoxOp::BigIntAdd serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntAdd obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); +Circuit::Brillig serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::Brillig obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + obj.bytecode = serde::Deserializable::deserialize(deserializer); + obj.predicate = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::BigIntNeg &lhs, const BlackBoxOp::BigIntNeg &rhs) { - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } + inline bool operator==(const BrilligInputs &lhs, const BrilligInputs &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BlackBoxOp::BigIntNeg::bincodeSerialize() const { + inline std::vector BrilligInputs::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::BigIntNeg BlackBoxOp::BigIntNeg::bincodeDeserialize(std::vector input) { + inline BrilligInputs BrilligInputs::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3552,40 +4031,38 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntNeg &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); - serde::Serializable::serialize(obj.output, serializer); +void serde::Serializable::serialize(const Circuit::BrilligInputs &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BlackBoxOp::BigIntNeg serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntNeg obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligInputs serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::BrilligInputs obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::BigIntMul &lhs, const BlackBoxOp::BigIntMul &rhs) { - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } + inline bool operator==(const BrilligInputs::Single &lhs, const BrilligInputs::Single &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BlackBoxOp::BigIntMul::bincodeSerialize() const { + inline std::vector BrilligInputs::Single::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::BigIntMul BlackBoxOp::BigIntMul::bincodeDeserialize(std::vector input) { + inline BrilligInputs::Single BrilligInputs::Single::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3596,40 +4073,34 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntMul &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); - serde::Serializable::serialize(obj.output, serializer); +void serde::Serializable::serialize(const Circuit::BrilligInputs::Single &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BlackBoxOp::BigIntMul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntMul obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligInputs::Single serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligInputs::Single obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::BigIntDiv &lhs, const BlackBoxOp::BigIntDiv &rhs) { - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } + inline bool operator==(const BrilligInputs::Array &lhs, const BrilligInputs::Array &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BlackBoxOp::BigIntDiv::bincodeSerialize() const { + inline std::vector BrilligInputs::Array::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::BigIntDiv BlackBoxOp::BigIntDiv::bincodeDeserialize(std::vector input) { + inline BrilligInputs::Array BrilligInputs::Array::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3640,40 +4111,34 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntDiv &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); - serde::Serializable::serialize(obj.output, serializer); +void serde::Serializable::serialize(const Circuit::BrilligInputs::Array &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BlackBoxOp::BigIntDiv serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntDiv obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligInputs::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligInputs::Array obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::BigIntFromLeBytes &lhs, const BlackBoxOp::BigIntFromLeBytes &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.modulus == rhs.modulus)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } + inline bool operator==(const BrilligInputs::MemoryArray &lhs, const BrilligInputs::MemoryArray &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BlackBoxOp::BigIntFromLeBytes::bincodeSerialize() const { + inline std::vector BrilligInputs::MemoryArray::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::BigIntFromLeBytes BlackBoxOp::BigIntFromLeBytes::bincodeDeserialize(std::vector input) { + inline BrilligInputs::MemoryArray BrilligInputs::MemoryArray::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3684,39 +4149,34 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntFromLeBytes &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.modulus, serializer); - serde::Serializable::serialize(obj.output, serializer); +void serde::Serializable::serialize(const Circuit::BrilligInputs::MemoryArray &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BlackBoxOp::BigIntFromLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntFromLeBytes obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.modulus = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligInputs::MemoryArray serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligInputs::MemoryArray obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::BigIntToLeBytes &lhs, const BlackBoxOp::BigIntToLeBytes &rhs) { - if (!(lhs.input == rhs.input)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } + inline bool operator==(const BrilligOpcode &lhs, const BrilligOpcode &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BlackBoxOp::BigIntToLeBytes::bincodeSerialize() const { + inline std::vector BrilligOpcode::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::BigIntToLeBytes BlackBoxOp::BigIntToLeBytes::bincodeDeserialize(std::vector input) { + inline BrilligOpcode BrilligOpcode::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3727,38 +4187,41 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntToLeBytes &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.input, serializer); - serde::Serializable::serialize(obj.output, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BlackBoxOp::BigIntToLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntToLeBytes obj; - obj.input = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::BrilligOpcode obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::Poseidon2Permutation &lhs, const BlackBoxOp::Poseidon2Permutation &rhs) { - if (!(lhs.message == rhs.message)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } - if (!(lhs.len == rhs.len)) { return false; } + inline bool operator==(const BrilligOpcode::BinaryFieldOp &lhs, const BrilligOpcode::BinaryFieldOp &rhs) { + if (!(lhs.destination == rhs.destination)) { return false; } + if (!(lhs.op == rhs.op)) { return false; } + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } return true; } - inline std::vector BlackBoxOp::Poseidon2Permutation::bincodeSerialize() const { + inline std::vector BrilligOpcode::BinaryFieldOp::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::Poseidon2Permutation BlackBoxOp::Poseidon2Permutation::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::BinaryFieldOp BrilligOpcode::BinaryFieldOp::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3769,40 +4232,44 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Poseidon2Permutation &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.output, serializer); - serde::Serializable::serialize(obj.len, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::BinaryFieldOp &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.op, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); } template <> template -Circuit::BlackBoxOp::Poseidon2Permutation serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Poseidon2Permutation obj; - obj.message = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); - obj.len = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::BinaryFieldOp serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::BinaryFieldOp obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.op = serde::Deserializable::deserialize(deserializer); + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlackBoxOp::Sha256Compression &lhs, const BlackBoxOp::Sha256Compression &rhs) { - if (!(lhs.input == rhs.input)) { return false; } - if (!(lhs.hash_values == rhs.hash_values)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } + inline bool operator==(const BrilligOpcode::BinaryIntOp &lhs, const BrilligOpcode::BinaryIntOp &rhs) { + if (!(lhs.destination == rhs.destination)) { return false; } + if (!(lhs.op == rhs.op)) { return false; } + if (!(lhs.bit_size == rhs.bit_size)) { return false; } + if (!(lhs.lhs == rhs.lhs)) { return false; } + if (!(lhs.rhs == rhs.rhs)) { return false; } return true; } - inline std::vector BlackBoxOp::Sha256Compression::bincodeSerialize() const { + inline std::vector BrilligOpcode::BinaryIntOp::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::Sha256Compression BlackBoxOp::Sha256Compression::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::BinaryIntOp BrilligOpcode::BinaryIntOp::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3813,38 +4280,43 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Sha256Compression &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.input, serializer); - serde::Serializable::serialize(obj.hash_values, serializer); - serde::Serializable::serialize(obj.output, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::BinaryIntOp &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.op, serializer); + serde::Serializable::serialize(obj.bit_size, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); } template <> template -Circuit::BlackBoxOp::Sha256Compression serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Sha256Compression obj; - obj.input = serde::Deserializable::deserialize(deserializer); - obj.hash_values = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::BinaryIntOp serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::BinaryIntOp obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.op = serde::Deserializable::deserialize(deserializer); + obj.bit_size = serde::Deserializable::deserialize(deserializer); + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BlockId &lhs, const BlockId &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const BrilligOpcode::JumpIfNot &lhs, const BrilligOpcode::JumpIfNot &rhs) { + if (!(lhs.condition == rhs.condition)) { return false; } + if (!(lhs.location == rhs.location)) { return false; } return true; } - inline std::vector BlockId::bincodeSerialize() const { + inline std::vector BrilligOpcode::JumpIfNot::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlockId BlockId::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::JumpIfNot BrilligOpcode::JumpIfNot::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3855,41 +4327,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlockId &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIfNot &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.condition, serializer); + serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::BlockId serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::BlockId obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); +Circuit::BrilligOpcode::JumpIfNot serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::JumpIfNot obj; + obj.condition = serde::Deserializable::deserialize(deserializer); + obj.location = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const Brillig &lhs, const Brillig &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { return false; } - if (!(lhs.bytecode == rhs.bytecode)) { return false; } - if (!(lhs.predicate == rhs.predicate)) { return false; } + inline bool operator==(const BrilligOpcode::JumpIf &lhs, const BrilligOpcode::JumpIf &rhs) { + if (!(lhs.condition == rhs.condition)) { return false; } + if (!(lhs.location == rhs.location)) { return false; } return true; } - inline std::vector Brillig::bincodeSerialize() const { + inline std::vector BrilligOpcode::JumpIf::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline Brillig Brillig::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::JumpIf BrilligOpcode::JumpIf::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3900,44 +4368,36 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::Brillig &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.outputs, serializer); - serde::Serializable::serialize(obj.bytecode, serializer); - serde::Serializable::serialize(obj.predicate, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIf &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.condition, serializer); + serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::Brillig serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::Brillig obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); - obj.bytecode = serde::Deserializable::deserialize(deserializer); - obj.predicate = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); +Circuit::BrilligOpcode::JumpIf serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::JumpIf obj; + obj.condition = serde::Deserializable::deserialize(deserializer); + obj.location = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligInputs &lhs, const BrilligInputs &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const BrilligOpcode::Jump &lhs, const BrilligOpcode::Jump &rhs) { + if (!(lhs.location == rhs.location)) { return false; } return true; } - inline std::vector BrilligInputs::bincodeSerialize() const { + inline std::vector BrilligOpcode::Jump::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligInputs BrilligInputs::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::Jump BrilligOpcode::Jump::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3948,38 +4408,36 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Jump &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::BrilligInputs serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::BrilligInputs obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); +Circuit::BrilligOpcode::Jump serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::Jump obj; + obj.location = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligInputs::Single &lhs, const BrilligInputs::Single &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const BrilligOpcode::CalldataCopy &lhs, const BrilligOpcode::CalldataCopy &rhs) { + if (!(lhs.destination_address == rhs.destination_address)) { return false; } + if (!(lhs.size == rhs.size)) { return false; } + if (!(lhs.offset == rhs.offset)) { return false; } return true; } - inline std::vector BrilligInputs::Single::bincodeSerialize() const { + inline std::vector BrilligOpcode::CalldataCopy::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligInputs::Single BrilligInputs::Single::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::CalldataCopy BrilligOpcode::CalldataCopy::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3990,34 +4448,38 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::Single &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.value, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::CalldataCopy &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.destination_address, serializer); + serde::Serializable::serialize(obj.size, serializer); + serde::Serializable::serialize(obj.offset, serializer); } template <> template -Circuit::BrilligInputs::Single serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligInputs::Single obj; - obj.value = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::CalldataCopy serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::CalldataCopy obj; + obj.destination_address = serde::Deserializable::deserialize(deserializer); + obj.size = serde::Deserializable::deserialize(deserializer); + obj.offset = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligInputs::Array &lhs, const BrilligInputs::Array &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const BrilligOpcode::Call &lhs, const BrilligOpcode::Call &rhs) { + if (!(lhs.location == rhs.location)) { return false; } return true; } - inline std::vector BrilligInputs::Array::bincodeSerialize() const { + inline std::vector BrilligOpcode::Call::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligInputs::Array BrilligInputs::Array::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::Call BrilligOpcode::Call::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4028,34 +4490,36 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::Array &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.value, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Call &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::BrilligInputs::Array serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligInputs::Array obj; - obj.value = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::Call serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::Call obj; + obj.location = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode &lhs, const BrilligOpcode &rhs) { + inline bool operator==(const BrilligOpcode::Const &lhs, const BrilligOpcode::Const &rhs) { + if (!(lhs.destination == rhs.destination)) { return false; } + if (!(lhs.bit_size == rhs.bit_size)) { return false; } if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BrilligOpcode::bincodeSerialize() const { + inline std::vector BrilligOpcode::Const::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode BrilligOpcode::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::Const BrilligOpcode::Const::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4066,41 +4530,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode &obj, Serializer &serializer) { - serializer.increase_container_depth(); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Const &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.bit_size, serializer); serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); } template <> template -Circuit::BrilligOpcode serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::BrilligOpcode obj; +Circuit::BrilligOpcode::Const serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::Const obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.bit_size = serde::Deserializable::deserialize(deserializer); obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::BinaryFieldOp &lhs, const BrilligOpcode::BinaryFieldOp &rhs) { - if (!(lhs.destination == rhs.destination)) { return false; } - if (!(lhs.op == rhs.op)) { return false; } - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } + inline bool operator==(const BrilligOpcode::Return &lhs, const BrilligOpcode::Return &rhs) { return true; } - inline std::vector BrilligOpcode::BinaryFieldOp::bincodeSerialize() const { + inline std::vector BrilligOpcode::Return::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::BinaryFieldOp BrilligOpcode::BinaryFieldOp::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::Return BrilligOpcode::Return::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4111,44 +4571,36 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::BinaryFieldOp &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.destination, serializer); - serde::Serializable::serialize(obj.op, serializer); - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Return &obj, Serializer &serializer) { } template <> template -Circuit::BrilligOpcode::BinaryFieldOp serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::BinaryFieldOp obj; - obj.destination = serde::Deserializable::deserialize(deserializer); - obj.op = serde::Deserializable::deserialize(deserializer); - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::Return serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::Return obj; return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::BinaryIntOp &lhs, const BrilligOpcode::BinaryIntOp &rhs) { - if (!(lhs.destination == rhs.destination)) { return false; } - if (!(lhs.op == rhs.op)) { return false; } - if (!(lhs.bit_size == rhs.bit_size)) { return false; } - if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { return false; } + inline bool operator==(const BrilligOpcode::ForeignCall &lhs, const BrilligOpcode::ForeignCall &rhs) { + if (!(lhs.function == rhs.function)) { return false; } + if (!(lhs.destinations == rhs.destinations)) { return false; } + if (!(lhs.destination_value_types == rhs.destination_value_types)) { return false; } + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.input_value_types == rhs.input_value_types)) { return false; } return true; } - inline std::vector BrilligOpcode::BinaryIntOp::bincodeSerialize() const { + inline std::vector BrilligOpcode::ForeignCall::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::BinaryIntOp BrilligOpcode::BinaryIntOp::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::ForeignCall BrilligOpcode::ForeignCall::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4159,43 +4611,43 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::BinaryIntOp &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.destination, serializer); - serde::Serializable::serialize(obj.op, serializer); - serde::Serializable::serialize(obj.bit_size, serializer); - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::ForeignCall &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.function, serializer); + serde::Serializable::serialize(obj.destinations, serializer); + serde::Serializable::serialize(obj.destination_value_types, serializer); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.input_value_types, serializer); } template <> template -Circuit::BrilligOpcode::BinaryIntOp serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::BinaryIntOp obj; - obj.destination = serde::Deserializable::deserialize(deserializer); - obj.op = serde::Deserializable::deserialize(deserializer); - obj.bit_size = serde::Deserializable::deserialize(deserializer); - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::ForeignCall serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::ForeignCall obj; + obj.function = serde::Deserializable::deserialize(deserializer); + obj.destinations = serde::Deserializable::deserialize(deserializer); + obj.destination_value_types = serde::Deserializable::deserialize(deserializer); + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.input_value_types = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::JumpIfNot &lhs, const BrilligOpcode::JumpIfNot &rhs) { - if (!(lhs.condition == rhs.condition)) { return false; } - if (!(lhs.location == rhs.location)) { return false; } + inline bool operator==(const BrilligOpcode::Mov &lhs, const BrilligOpcode::Mov &rhs) { + if (!(lhs.destination == rhs.destination)) { return false; } + if (!(lhs.source == rhs.source)) { return false; } return true; } - inline std::vector BrilligOpcode::JumpIfNot::bincodeSerialize() const { + inline std::vector BrilligOpcode::Mov::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::JumpIfNot BrilligOpcode::JumpIfNot::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::Mov BrilligOpcode::Mov::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4206,37 +4658,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIfNot &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.condition, serializer); - serde::Serializable::serialize(obj.location, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Mov &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.source, serializer); } template <> template -Circuit::BrilligOpcode::JumpIfNot serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::JumpIfNot obj; - obj.condition = serde::Deserializable::deserialize(deserializer); - obj.location = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::Mov serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::Mov obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.source = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::JumpIf &lhs, const BrilligOpcode::JumpIf &rhs) { - if (!(lhs.condition == rhs.condition)) { return false; } - if (!(lhs.location == rhs.location)) { return false; } + inline bool operator==(const BrilligOpcode::Load &lhs, const BrilligOpcode::Load &rhs) { + if (!(lhs.destination == rhs.destination)) { return false; } + if (!(lhs.source_pointer == rhs.source_pointer)) { return false; } return true; } - inline std::vector BrilligOpcode::JumpIf::bincodeSerialize() const { + inline std::vector BrilligOpcode::Load::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::JumpIf BrilligOpcode::JumpIf::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::Load BrilligOpcode::Load::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4247,36 +4699,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIf &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.condition, serializer); - serde::Serializable::serialize(obj.location, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Load &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.source_pointer, serializer); } template <> template -Circuit::BrilligOpcode::JumpIf serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::JumpIf obj; - obj.condition = serde::Deserializable::deserialize(deserializer); - obj.location = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::Load serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::Load obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.source_pointer = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::Jump &lhs, const BrilligOpcode::Jump &rhs) { - if (!(lhs.location == rhs.location)) { return false; } + inline bool operator==(const BrilligOpcode::Store &lhs, const BrilligOpcode::Store &rhs) { + if (!(lhs.destination_pointer == rhs.destination_pointer)) { return false; } + if (!(lhs.source == rhs.source)) { return false; } return true; } - inline std::vector BrilligOpcode::Jump::bincodeSerialize() const { + inline std::vector BrilligOpcode::Store::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::Jump BrilligOpcode::Jump::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::Store BrilligOpcode::Store::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4287,34 +4740,36 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Jump &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.location, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Store &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.destination_pointer, serializer); + serde::Serializable::serialize(obj.source, serializer); } template <> template -Circuit::BrilligOpcode::Jump serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Jump obj; - obj.location = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::Store serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::Store obj; + obj.destination_pointer = serde::Deserializable::deserialize(deserializer); + obj.source = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::Call &lhs, const BrilligOpcode::Call &rhs) { - if (!(lhs.location == rhs.location)) { return false; } + inline bool operator==(const BrilligOpcode::BlackBox &lhs, const BrilligOpcode::BlackBox &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BrilligOpcode::Call::bincodeSerialize() const { + inline std::vector BrilligOpcode::BlackBox::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::Call BrilligOpcode::Call::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::BlackBox BrilligOpcode::BlackBox::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4325,35 +4780,33 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Call &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.location, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::BlackBox &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); } -template <> -template -Circuit::BrilligOpcode::Call serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Call obj; - obj.location = serde::Deserializable::deserialize(deserializer); +template <> +template +Circuit::BrilligOpcode::BlackBox serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::BlackBox obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::Const &lhs, const BrilligOpcode::Const &rhs) { - if (!(lhs.destination == rhs.destination)) { return false; } - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const BrilligOpcode::Trap &lhs, const BrilligOpcode::Trap &rhs) { return true; } - inline std::vector BrilligOpcode::Const::bincodeSerialize() const { + inline std::vector BrilligOpcode::Trap::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::Const BrilligOpcode::Const::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::Trap BrilligOpcode::Trap::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4364,35 +4817,33 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Const &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.destination, serializer); - serde::Serializable::serialize(obj.value, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Trap &obj, Serializer &serializer) { } template <> template -Circuit::BrilligOpcode::Const serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Const obj; - obj.destination = serde::Deserializable::deserialize(deserializer); - obj.value = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::Trap serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::Trap obj; return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::Return &lhs, const BrilligOpcode::Return &rhs) { + inline bool operator==(const BrilligOpcode::Stop &lhs, const BrilligOpcode::Stop &rhs) { + if (!(lhs.return_data_offset == rhs.return_data_offset)) { return false; } + if (!(lhs.return_data_size == rhs.return_data_size)) { return false; } return true; } - inline std::vector BrilligOpcode::Return::bincodeSerialize() const { + inline std::vector BrilligOpcode::Stop::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::Return BrilligOpcode::Return::bincodeDeserialize(std::vector input) { + inline BrilligOpcode::Stop BrilligOpcode::Stop::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4403,34 +4854,36 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Return &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Stop &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.return_data_offset, serializer); + serde::Serializable::serialize(obj.return_data_size, serializer); } template <> template -Circuit::BrilligOpcode::Return serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Return obj; +Circuit::BrilligOpcode::Stop serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::Stop obj; + obj.return_data_offset = serde::Deserializable::deserialize(deserializer); + obj.return_data_size = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::ForeignCall &lhs, const BrilligOpcode::ForeignCall &rhs) { - if (!(lhs.function == rhs.function)) { return false; } - if (!(lhs.destinations == rhs.destinations)) { return false; } - if (!(lhs.inputs == rhs.inputs)) { return false; } + inline bool operator==(const BrilligOutputs &lhs, const BrilligOutputs &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BrilligOpcode::ForeignCall::bincodeSerialize() const { + inline std::vector BrilligOutputs::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::ForeignCall BrilligOpcode::ForeignCall::bincodeDeserialize(std::vector input) { + inline BrilligOutputs BrilligOutputs::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4441,39 +4894,38 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::ForeignCall &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.function, serializer); - serde::Serializable::serialize(obj.destinations, serializer); - serde::Serializable::serialize(obj.inputs, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOutputs &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BrilligOpcode::ForeignCall serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::ForeignCall obj; - obj.function = serde::Deserializable::deserialize(deserializer); - obj.destinations = serde::Deserializable::deserialize(deserializer); - obj.inputs = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOutputs serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::BrilligOutputs obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::Mov &lhs, const BrilligOpcode::Mov &rhs) { - if (!(lhs.destination == rhs.destination)) { return false; } - if (!(lhs.source == rhs.source)) { return false; } + inline bool operator==(const BrilligOutputs::Simple &lhs, const BrilligOutputs::Simple &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BrilligOpcode::Mov::bincodeSerialize() const { + inline std::vector BrilligOutputs::Simple::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::Mov BrilligOpcode::Mov::bincodeDeserialize(std::vector input) { + inline BrilligOutputs::Simple BrilligOutputs::Simple::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4484,37 +4936,34 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Mov &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.destination, serializer); - serde::Serializable::serialize(obj.source, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOutputs::Simple &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligOpcode::Mov serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Mov obj; - obj.destination = serde::Deserializable::deserialize(deserializer); - obj.source = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOutputs::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOutputs::Simple obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::Load &lhs, const BrilligOpcode::Load &rhs) { - if (!(lhs.destination == rhs.destination)) { return false; } - if (!(lhs.source_pointer == rhs.source_pointer)) { return false; } + inline bool operator==(const BrilligOutputs::Array &lhs, const BrilligOutputs::Array &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BrilligOpcode::Load::bincodeSerialize() const { + inline std::vector BrilligOutputs::Array::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::Load BrilligOpcode::Load::bincodeDeserialize(std::vector input) { + inline BrilligOutputs::Array BrilligOutputs::Array::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4525,37 +4974,41 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Load &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.destination, serializer); - serde::Serializable::serialize(obj.source_pointer, serializer); +void serde::Serializable::serialize(const Circuit::BrilligOutputs::Array &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligOpcode::Load serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Load obj; - obj.destination = serde::Deserializable::deserialize(deserializer); - obj.source_pointer = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOutputs::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOutputs::Array obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::Store &lhs, const BrilligOpcode::Store &rhs) { - if (!(lhs.destination_pointer == rhs.destination_pointer)) { return false; } - if (!(lhs.source == rhs.source)) { return false; } + inline bool operator==(const Circuit &lhs, const Circuit &rhs) { + if (!(lhs.current_witness_index == rhs.current_witness_index)) { return false; } + if (!(lhs.opcodes == rhs.opcodes)) { return false; } + if (!(lhs.expression_width == rhs.expression_width)) { return false; } + if (!(lhs.private_parameters == rhs.private_parameters)) { return false; } + if (!(lhs.public_parameters == rhs.public_parameters)) { return false; } + if (!(lhs.return_values == rhs.return_values)) { return false; } + if (!(lhs.assert_messages == rhs.assert_messages)) { return false; } + if (!(lhs.recursive == rhs.recursive)) { return false; } return true; } - inline std::vector BrilligOpcode::Store::bincodeSerialize() const { + inline std::vector Circuit::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::Store BrilligOpcode::Store::bincodeDeserialize(std::vector input) { + inline Circuit Circuit::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4566,36 +5019,52 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Store &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.destination_pointer, serializer); - serde::Serializable::serialize(obj.source, serializer); +void serde::Serializable::serialize(const Circuit::Circuit &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.current_witness_index, serializer); + serde::Serializable::serialize(obj.opcodes, serializer); + serde::Serializable::serialize(obj.expression_width, serializer); + serde::Serializable::serialize(obj.private_parameters, serializer); + serde::Serializable::serialize(obj.public_parameters, serializer); + serde::Serializable::serialize(obj.return_values, serializer); + serde::Serializable::serialize(obj.assert_messages, serializer); + serde::Serializable::serialize(obj.recursive, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BrilligOpcode::Store serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Store obj; - obj.destination_pointer = serde::Deserializable::deserialize(deserializer); - obj.source = serde::Deserializable::deserialize(deserializer); +Circuit::Circuit serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::Circuit obj; + obj.current_witness_index = serde::Deserializable::deserialize(deserializer); + obj.opcodes = serde::Deserializable::deserialize(deserializer); + obj.expression_width = serde::Deserializable::deserialize(deserializer); + obj.private_parameters = serde::Deserializable::deserialize(deserializer); + obj.public_parameters = serde::Deserializable::deserialize(deserializer); + obj.return_values = serde::Deserializable::deserialize(deserializer); + obj.assert_messages = serde::Deserializable::deserialize(deserializer); + obj.recursive = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::BlackBox &lhs, const BrilligOpcode::BlackBox &rhs) { + inline bool operator==(const Directive &lhs, const Directive &rhs) { if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BrilligOpcode::BlackBox::bincodeSerialize() const { + inline std::vector Directive::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::BlackBox BrilligOpcode::BlackBox::bincodeDeserialize(std::vector input) { + inline Directive Directive::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4606,33 +5075,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::BlackBox &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::Directive &obj, Serializer &serializer) { + serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BrilligOpcode::BlackBox serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::BlackBox obj; +Circuit::Directive serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::Directive obj; obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::Trap &lhs, const BrilligOpcode::Trap &rhs) { + inline bool operator==(const Directive::ToLeRadix &lhs, const Directive::ToLeRadix &rhs) { + if (!(lhs.a == rhs.a)) { return false; } + if (!(lhs.b == rhs.b)) { return false; } + if (!(lhs.radix == rhs.radix)) { return false; } return true; } - inline std::vector BrilligOpcode::Trap::bincodeSerialize() const { + inline std::vector Directive::ToLeRadix::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::Trap BrilligOpcode::Trap::bincodeDeserialize(std::vector input) { + inline Directive::ToLeRadix Directive::ToLeRadix::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4643,31 +5119,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Trap &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::Directive::ToLeRadix &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.a, serializer); + serde::Serializable::serialize(obj.b, serializer); + serde::Serializable::serialize(obj.radix, serializer); } template <> template -Circuit::BrilligOpcode::Trap serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Trap obj; +Circuit::Directive::ToLeRadix serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::Directive::ToLeRadix obj; + obj.a = serde::Deserializable::deserialize(deserializer); + obj.b = serde::Deserializable::deserialize(deserializer); + obj.radix = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const BrilligOpcode::Stop &lhs, const BrilligOpcode::Stop &rhs) { + inline bool operator==(const Expression &lhs, const Expression &rhs) { + if (!(lhs.mul_terms == rhs.mul_terms)) { return false; } + if (!(lhs.linear_combinations == rhs.linear_combinations)) { return false; } + if (!(lhs.q_c == rhs.q_c)) { return false; } return true; } - inline std::vector BrilligOpcode::Stop::bincodeSerialize() const { + inline std::vector Expression::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOpcode::Stop BrilligOpcode::Stop::bincodeDeserialize(std::vector input) { + inline Expression Expression::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4678,32 +5163,42 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Stop &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::Expression &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.mul_terms, serializer); + serde::Serializable::serialize(obj.linear_combinations, serializer); + serde::Serializable::serialize(obj.q_c, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BrilligOpcode::Stop serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Stop obj; +Circuit::Expression serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::Expression obj; + obj.mul_terms = serde::Deserializable::deserialize(deserializer); + obj.linear_combinations = serde::Deserializable::deserialize(deserializer); + obj.q_c = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const BrilligOutputs &lhs, const BrilligOutputs &rhs) { + inline bool operator==(const ExpressionWidth &lhs, const ExpressionWidth &rhs) { if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BrilligOutputs::bincodeSerialize() const { + inline std::vector ExpressionWidth::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOutputs BrilligOutputs::bincodeDeserialize(std::vector input) { + inline ExpressionWidth ExpressionWidth::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4714,7 +5209,7 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::ExpressionWidth &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -4722,9 +5217,9 @@ void serde::Serializable::serialize(const Circuit::Bril template <> template -Circuit::BrilligOutputs serde::Deserializable::deserialize(Deserializer &deserializer) { +Circuit::ExpressionWidth serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::BrilligOutputs obj; + Circuit::ExpressionWidth obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; @@ -4732,20 +5227,19 @@ Circuit::BrilligOutputs serde::Deserializable::deserial namespace Circuit { - inline bool operator==(const BrilligOutputs::Simple &lhs, const BrilligOutputs::Simple &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const ExpressionWidth::Unbounded &lhs, const ExpressionWidth::Unbounded &rhs) { return true; } - inline std::vector BrilligOutputs::Simple::bincodeSerialize() const { + inline std::vector ExpressionWidth::Unbounded::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOutputs::Simple BrilligOutputs::Simple::bincodeDeserialize(std::vector input) { + inline ExpressionWidth::Unbounded ExpressionWidth::Unbounded::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4756,34 +5250,32 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs::Simple &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.value, serializer); +void serde::Serializable::serialize(const Circuit::ExpressionWidth::Unbounded &obj, Serializer &serializer) { } template <> template -Circuit::BrilligOutputs::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOutputs::Simple obj; - obj.value = serde::Deserializable::deserialize(deserializer); +Circuit::ExpressionWidth::Unbounded serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::ExpressionWidth::Unbounded obj; return obj; } namespace Circuit { - inline bool operator==(const BrilligOutputs::Array &lhs, const BrilligOutputs::Array &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const ExpressionWidth::Bounded &lhs, const ExpressionWidth::Bounded &rhs) { + if (!(lhs.width == rhs.width)) { return false; } return true; } - inline std::vector BrilligOutputs::Array::bincodeSerialize() const { + inline std::vector ExpressionWidth::Bounded::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligOutputs::Array BrilligOutputs::Array::bincodeDeserialize(std::vector input) { + inline ExpressionWidth::Bounded ExpressionWidth::Bounded::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4794,39 +5286,35 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs::Array &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.value, serializer); +void serde::Serializable::serialize(const Circuit::ExpressionWidth::Bounded &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.width, serializer); } template <> template -Circuit::BrilligOutputs::Array serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOutputs::Array obj; - obj.value = serde::Deserializable::deserialize(deserializer); +Circuit::ExpressionWidth::Bounded serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::ExpressionWidth::Bounded obj; + obj.width = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const Circuit &lhs, const Circuit &rhs) { - if (!(lhs.current_witness_index == rhs.current_witness_index)) { return false; } - if (!(lhs.opcodes == rhs.opcodes)) { return false; } - if (!(lhs.private_parameters == rhs.private_parameters)) { return false; } - if (!(lhs.public_parameters == rhs.public_parameters)) { return false; } - if (!(lhs.return_values == rhs.return_values)) { return false; } - if (!(lhs.assert_messages == rhs.assert_messages)) { return false; } + inline bool operator==(const FunctionInput &lhs, const FunctionInput &rhs) { + if (!(lhs.witness == rhs.witness)) { return false; } + if (!(lhs.num_bits == rhs.num_bits)) { return false; } return true; } - inline std::vector Circuit::bincodeSerialize() const { + inline std::vector FunctionInput::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline Circuit Circuit::bincodeDeserialize(std::vector input) { + inline FunctionInput FunctionInput::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4837,48 +5325,41 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::Circuit &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::FunctionInput &obj, Serializer &serializer) { serializer.increase_container_depth(); - serde::Serializable::serialize(obj.current_witness_index, serializer); - serde::Serializable::serialize(obj.opcodes, serializer); - serde::Serializable::serialize(obj.private_parameters, serializer); - serde::Serializable::serialize(obj.public_parameters, serializer); - serde::Serializable::serialize(obj.return_values, serializer); - serde::Serializable::serialize(obj.assert_messages, serializer); + serde::Serializable::serialize(obj.witness, serializer); + serde::Serializable::serialize(obj.num_bits, serializer); serializer.decrease_container_depth(); } template <> template -Circuit::Circuit serde::Deserializable::deserialize(Deserializer &deserializer) { +Circuit::FunctionInput serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::Circuit obj; - obj.current_witness_index = serde::Deserializable::deserialize(deserializer); - obj.opcodes = serde::Deserializable::deserialize(deserializer); - obj.private_parameters = serde::Deserializable::deserialize(deserializer); - obj.public_parameters = serde::Deserializable::deserialize(deserializer); - obj.return_values = serde::Deserializable::deserialize(deserializer); - obj.assert_messages = serde::Deserializable::deserialize(deserializer); + Circuit::FunctionInput obj; + obj.witness = serde::Deserializable::deserialize(deserializer); + obj.num_bits = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const Directive &lhs, const Directive &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const HeapArray &lhs, const HeapArray &rhs) { + if (!(lhs.pointer == rhs.pointer)) { return false; } + if (!(lhs.size == rhs.size)) { return false; } return true; } - inline std::vector Directive::bincodeSerialize() const { + inline std::vector HeapArray::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline Directive Directive::bincodeDeserialize(std::vector input) { + inline HeapArray HeapArray::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4889,40 +5370,40 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::Directive &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::HeapArray &obj, Serializer &serializer) { serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); + serde::Serializable::serialize(obj.pointer, serializer); + serde::Serializable::serialize(obj.size, serializer); serializer.decrease_container_depth(); } template <> template -Circuit::Directive serde::Deserializable::deserialize(Deserializer &deserializer) { +Circuit::HeapArray serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::Directive obj; - obj.value = serde::Deserializable::deserialize(deserializer); + Circuit::HeapArray obj; + obj.pointer = serde::Deserializable::deserialize(deserializer); + obj.size = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const Directive::ToLeRadix &lhs, const Directive::ToLeRadix &rhs) { - if (!(lhs.a == rhs.a)) { return false; } - if (!(lhs.b == rhs.b)) { return false; } - if (!(lhs.radix == rhs.radix)) { return false; } + inline bool operator==(const HeapValueType &lhs, const HeapValueType &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector Directive::ToLeRadix::bincodeSerialize() const { + inline std::vector HeapValueType::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline Directive::ToLeRadix Directive::ToLeRadix::bincodeDeserialize(std::vector input) { + inline HeapValueType HeapValueType::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4933,40 +5414,37 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::Directive::ToLeRadix &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.a, serializer); - serde::Serializable::serialize(obj.b, serializer); - serde::Serializable::serialize(obj.radix, serializer); +void serde::Serializable::serialize(const Circuit::HeapValueType &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::Directive::ToLeRadix serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::Directive::ToLeRadix obj; - obj.a = serde::Deserializable::deserialize(deserializer); - obj.b = serde::Deserializable::deserialize(deserializer); - obj.radix = serde::Deserializable::deserialize(deserializer); +Circuit::HeapValueType serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::HeapValueType obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const Expression &lhs, const Expression &rhs) { - if (!(lhs.mul_terms == rhs.mul_terms)) { return false; } - if (!(lhs.linear_combinations == rhs.linear_combinations)) { return false; } - if (!(lhs.q_c == rhs.q_c)) { return false; } + inline bool operator==(const HeapValueType::Simple &lhs, const HeapValueType::Simple &rhs) { return true; } - inline std::vector Expression::bincodeSerialize() const { + inline std::vector HeapValueType::Simple::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline Expression Expression::bincodeDeserialize(std::vector input) { + inline HeapValueType::Simple HeapValueType::Simple::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4977,43 +5455,33 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::Expression &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.mul_terms, serializer); - serde::Serializable::serialize(obj.linear_combinations, serializer); - serde::Serializable::serialize(obj.q_c, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize(const Circuit::HeapValueType::Simple &obj, Serializer &serializer) { } template <> template -Circuit::Expression serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::Expression obj; - obj.mul_terms = serde::Deserializable::deserialize(deserializer); - obj.linear_combinations = serde::Deserializable::deserialize(deserializer); - obj.q_c = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); +Circuit::HeapValueType::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Simple obj; return obj; } namespace Circuit { - inline bool operator==(const FunctionInput &lhs, const FunctionInput &rhs) { - if (!(lhs.witness == rhs.witness)) { return false; } - if (!(lhs.num_bits == rhs.num_bits)) { return false; } + inline bool operator==(const HeapValueType::Array &lhs, const HeapValueType::Array &rhs) { + if (!(lhs.value_types == rhs.value_types)) { return false; } + if (!(lhs.size == rhs.size)) { return false; } return true; } - inline std::vector FunctionInput::bincodeSerialize() const { + inline std::vector HeapValueType::Array::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline FunctionInput FunctionInput::bincodeDeserialize(std::vector input) { + inline HeapValueType::Array HeapValueType::Array::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -5024,41 +5492,36 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::FunctionInput &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.witness, serializer); - serde::Serializable::serialize(obj.num_bits, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize(const Circuit::HeapValueType::Array &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value_types, serializer); + serde::Serializable::serialize(obj.size, serializer); } template <> template -Circuit::FunctionInput serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::FunctionInput obj; - obj.witness = serde::Deserializable::deserialize(deserializer); - obj.num_bits = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); +Circuit::HeapValueType::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Array obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); + obj.size = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const HeapArray &lhs, const HeapArray &rhs) { - if (!(lhs.pointer == rhs.pointer)) { return false; } - if (!(lhs.size == rhs.size)) { return false; } + inline bool operator==(const HeapValueType::Vector &lhs, const HeapValueType::Vector &rhs) { + if (!(lhs.value_types == rhs.value_types)) { return false; } return true; } - inline std::vector HeapArray::bincodeSerialize() const { + inline std::vector HeapValueType::Vector::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline HeapArray HeapArray::bincodeDeserialize(std::vector input) { + inline HeapValueType::Vector HeapValueType::Vector::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -5069,21 +5532,15 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::HeapArray &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.pointer, serializer); - serde::Serializable::serialize(obj.size, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize(const Circuit::HeapValueType::Vector &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value_types, serializer); } template <> template -Circuit::HeapArray serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::HeapArray obj; - obj.pointer = serde::Deserializable::deserialize(deserializer); - obj.size = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); +Circuit::HeapValueType::Vector serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Vector obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); return obj; } @@ -5180,6 +5637,48 @@ Circuit::MemOp serde::Deserializable::deserialize(Deserializer & return obj; } +namespace Circuit { + + inline bool operator==(const MemoryAddress &lhs, const MemoryAddress &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector MemoryAddress::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline MemoryAddress MemoryAddress::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::MemoryAddress &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Circuit::MemoryAddress serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::MemoryAddress obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + namespace Circuit { inline bool operator==(const Opcode &lhs, const Opcode &rhs) { @@ -5624,20 +6123,20 @@ Circuit::PublicInputs serde::Deserializable::deserialize( namespace Circuit { - inline bool operator==(const RegisterIndex &lhs, const RegisterIndex &rhs) { - if (!(lhs.value == rhs.value)) { return false; } + inline bool operator==(const Value &lhs, const Value &rhs) { + if (!(lhs.inner == rhs.inner)) { return false; } return true; } - inline std::vector RegisterIndex::bincodeSerialize() const { + inline std::vector Value::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline RegisterIndex RegisterIndex::bincodeDeserialize(std::vector input) { + inline Value Value::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -5648,38 +6147,38 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::RegisterIndex &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::Value &obj, Serializer &serializer) { serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); + serde::Serializable::serialize(obj.inner, serializer); serializer.decrease_container_depth(); } template <> template -Circuit::RegisterIndex serde::Deserializable::deserialize(Deserializer &deserializer) { +Circuit::Value serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::RegisterIndex obj; - obj.value = serde::Deserializable::deserialize(deserializer); + Circuit::Value obj; + obj.inner = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } namespace Circuit { - inline bool operator==(const RegisterOrMemory &lhs, const RegisterOrMemory &rhs) { + inline bool operator==(const ValueOrArray &lhs, const ValueOrArray &rhs) { if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector RegisterOrMemory::bincodeSerialize() const { + inline std::vector ValueOrArray::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline RegisterOrMemory RegisterOrMemory::bincodeDeserialize(std::vector input) { + inline ValueOrArray ValueOrArray::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -5690,7 +6189,7 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::RegisterOrMemory &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::ValueOrArray &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -5698,9 +6197,9 @@ void serde::Serializable::serialize(const Circuit::Re template <> template -Circuit::RegisterOrMemory serde::Deserializable::deserialize(Deserializer &deserializer) { +Circuit::ValueOrArray serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::RegisterOrMemory obj; + Circuit::ValueOrArray obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; @@ -5708,20 +6207,20 @@ Circuit::RegisterOrMemory serde::Deserializable::dese namespace Circuit { - inline bool operator==(const RegisterOrMemory::RegisterIndex &lhs, const RegisterOrMemory::RegisterIndex &rhs) { + inline bool operator==(const ValueOrArray::MemoryAddress &lhs, const ValueOrArray::MemoryAddress &rhs) { if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector RegisterOrMemory::RegisterIndex::bincodeSerialize() const { + inline std::vector ValueOrArray::MemoryAddress::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline RegisterOrMemory::RegisterIndex RegisterOrMemory::RegisterIndex::bincodeDeserialize(std::vector input) { + inline ValueOrArray::MemoryAddress ValueOrArray::MemoryAddress::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -5732,34 +6231,34 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::RegisterOrMemory::RegisterIndex &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::ValueOrArray::MemoryAddress &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::RegisterOrMemory::RegisterIndex serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::RegisterOrMemory::RegisterIndex obj; +Circuit::ValueOrArray::MemoryAddress serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::ValueOrArray::MemoryAddress obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const RegisterOrMemory::HeapArray &lhs, const RegisterOrMemory::HeapArray &rhs) { + inline bool operator==(const ValueOrArray::HeapArray &lhs, const ValueOrArray::HeapArray &rhs) { if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector RegisterOrMemory::HeapArray::bincodeSerialize() const { + inline std::vector ValueOrArray::HeapArray::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline RegisterOrMemory::HeapArray RegisterOrMemory::HeapArray::bincodeDeserialize(std::vector input) { + inline ValueOrArray::HeapArray ValueOrArray::HeapArray::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -5770,34 +6269,34 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::RegisterOrMemory::HeapArray &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::ValueOrArray::HeapArray &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::RegisterOrMemory::HeapArray serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::RegisterOrMemory::HeapArray obj; +Circuit::ValueOrArray::HeapArray serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::ValueOrArray::HeapArray obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { - inline bool operator==(const RegisterOrMemory::HeapVector &lhs, const RegisterOrMemory::HeapVector &rhs) { + inline bool operator==(const ValueOrArray::HeapVector &lhs, const ValueOrArray::HeapVector &rhs) { if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector RegisterOrMemory::HeapVector::bincodeSerialize() const { + inline std::vector ValueOrArray::HeapVector::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline RegisterOrMemory::HeapVector RegisterOrMemory::HeapVector::bincodeDeserialize(std::vector input) { + inline ValueOrArray::HeapVector ValueOrArray::HeapVector::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -5808,60 +6307,18 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::RegisterOrMemory::HeapVector &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::ValueOrArray::HeapVector &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::RegisterOrMemory::HeapVector serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::RegisterOrMemory::HeapVector obj; +Circuit::ValueOrArray::HeapVector serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::ValueOrArray::HeapVector obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { - - inline bool operator==(const Value &lhs, const Value &rhs) { - if (!(lhs.inner == rhs.inner)) { return false; } - return true; - } - - inline std::vector Value::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline Value Value::bincodeDeserialize(std::vector input) { - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw serde::deserialization_error("Some input bytes were not read"); - } - return value; - } - -} // end of namespace Circuit - -template <> -template -void serde::Serializable::serialize(const Circuit::Value &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.inner, serializer); - serializer.decrease_container_depth(); -} - -template <> -template -Circuit::Value serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Circuit::Value obj; - obj.inner = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); - return obj; -} - namespace Circuit { inline bool operator==(const Witness &lhs, const Witness &rhs) { diff --git a/acvm-repo/acir/src/circuit/black_box_functions.rs b/acvm-repo/acir/src/circuit/black_box_functions.rs index 97b4759d350..0a7ee244a5e 100644 --- a/acvm-repo/acir/src/circuit/black_box_functions.rs +++ b/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -50,7 +50,7 @@ pub enum BlackBoxFunc { /// BigInt addition BigIntAdd, /// BigInt subtraction - BigIntNeg, + BigIntSub, /// BigInt multiplication BigIntMul, /// BigInt division @@ -91,7 +91,7 @@ impl BlackBoxFunc { BlackBoxFunc::RecursiveAggregation => "recursive_aggregation", BlackBoxFunc::EcdsaSecp256r1 => "ecdsa_secp256r1", BlackBoxFunc::BigIntAdd => "bigint_add", - BlackBoxFunc::BigIntNeg => "bigint_neg", + BlackBoxFunc::BigIntSub => "bigint_sub", BlackBoxFunc::BigIntMul => "bigint_mul", BlackBoxFunc::BigIntDiv => "bigint_div", BlackBoxFunc::BigIntFromLeBytes => "bigint_from_le_bytes", @@ -120,7 +120,7 @@ impl BlackBoxFunc { "keccakf1600" => Some(BlackBoxFunc::Keccakf1600), "recursive_aggregation" => Some(BlackBoxFunc::RecursiveAggregation), "bigint_add" => Some(BlackBoxFunc::BigIntAdd), - "bigint_neg" => Some(BlackBoxFunc::BigIntNeg), + "bigint_sub" => Some(BlackBoxFunc::BigIntSub), "bigint_mul" => Some(BlackBoxFunc::BigIntMul), "bigint_div" => Some(BlackBoxFunc::BigIntDiv), "bigint_from_le_bytes" => Some(BlackBoxFunc::BigIntFromLeBytes), diff --git a/acvm-repo/acir/src/circuit/brillig.rs b/acvm-repo/acir/src/circuit/brillig.rs index 63c6ad2a3d4..f394a46ff82 100644 --- a/acvm-repo/acir/src/circuit/brillig.rs +++ b/acvm-repo/acir/src/circuit/brillig.rs @@ -1,3 +1,4 @@ +use super::opcodes::BlockId; use crate::native_types::{Expression, Witness}; use brillig::Opcode as BrilligOpcode; use serde::{Deserialize, Serialize}; @@ -8,6 +9,7 @@ use serde::{Deserialize, Serialize}; pub enum BrilligInputs { Single(Expression), Array(Vec), + MemoryArray(BlockId), } /// Outputs for the Brillig VM. Once the VM has completed diff --git a/acvm-repo/acir/src/circuit/mod.rs b/acvm-repo/acir/src/circuit/mod.rs index dcb09d429eb..7e6cbf23803 100644 --- a/acvm-repo/acir/src/circuit/mod.rs +++ b/acvm-repo/acir/src/circuit/mod.rs @@ -15,12 +15,30 @@ use serde::{de::Error as DeserializationError, Deserialize, Deserializer, Serial use std::collections::BTreeSet; +/// Specifies the maximum width of the expressions which will be constrained. +/// +/// Unbounded Expressions are useful if you are eventually going to pass the ACIR +/// into a proving system which supports R1CS. +/// +/// Bounded Expressions are useful if you are eventually going to pass the ACIR +/// into a proving system which supports PLONK, where arithmetic expressions have a +/// finite fan-in. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] +pub enum ExpressionWidth { + #[default] + Unbounded, + Bounded { + width: usize, + }, +} + #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)] pub struct Circuit { // current_witness_index is the highest witness index in the circuit. The next witness to be added to this circuit // will take on this value. (The value is cached here as an optimization.) pub current_witness_index: u32, pub opcodes: Vec, + pub expression_width: ExpressionWidth, /// The set of private inputs to the circuit. pub private_parameters: BTreeSet, @@ -43,6 +61,11 @@ pub struct Circuit { // TODO: We should move towards having all the checks being evaluated in the same manner // TODO: as runtime assert messages specified by the user. This will also be a breaking change as the `Circuit` structure will change. pub assert_messages: Vec<(OpcodeLocation, String)>, + + /// States whether the backend should use a SNARK recursion friendly prover. + /// If implemented by a backend, this means that proofs generated with this circuit + /// will be friendly for recursively verifying inside of another SNARK. + pub recursive: bool, } impl Circuit { @@ -239,7 +262,7 @@ mod tests { opcodes::{BlackBoxFuncCall, FunctionInput}, Circuit, Compression, Opcode, PublicInputs, }; - use crate::native_types::Witness; + use crate::{circuit::ExpressionWidth, native_types::Witness}; use acir_field::FieldElement; fn and_opcode() -> Opcode { @@ -317,11 +340,13 @@ mod tests { fn serialization_roundtrip() { let circuit = Circuit { current_witness_index: 5, + expression_width: ExpressionWidth::Unbounded, opcodes: vec![and_opcode(), range_opcode()], private_parameters: BTreeSet::new(), public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(12)])), return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(4), Witness(12)])), assert_messages: Default::default(), + recursive: false, }; fn read_write(circuit: Circuit) -> (Circuit, Circuit) { @@ -338,6 +363,7 @@ mod tests { fn test_serialize() { let circuit = Circuit { current_witness_index: 0, + expression_width: ExpressionWidth::Unbounded, opcodes: vec![ Opcode::AssertZero(crate::native_types::Expression { mul_terms: vec![], @@ -352,6 +378,7 @@ mod tests { public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])), return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])), assert_messages: Default::default(), + recursive: false, }; let json = serde_json::to_string_pretty(&circuit).unwrap(); diff --git a/acvm-repo/acir/src/circuit/opcodes.rs b/acvm-repo/acir/src/circuit/opcodes.rs index f9ac48c37af..f725ba8c32a 100644 --- a/acvm-repo/acir/src/circuit/opcodes.rs +++ b/acvm-repo/acir/src/circuit/opcodes.rs @@ -8,6 +8,7 @@ mod memory_operation; pub use black_box_function_call::{BlackBoxFuncCall, FunctionInput}; pub use memory_operation::{BlockId, MemOp}; +#[allow(clippy::large_enum_variant)] #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum Opcode { AssertZero(Expression), diff --git a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index ba4964c8912..f73417a4b5b 100644 --- a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -120,7 +120,7 @@ pub enum BlackBoxFuncCall { rhs: u32, output: u32, }, - BigIntNeg { + BigIntSub { lhs: u32, rhs: u32, output: u32, @@ -193,7 +193,7 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::Keccakf1600 { .. } => BlackBoxFunc::Keccakf1600, BlackBoxFuncCall::RecursiveAggregation { .. } => BlackBoxFunc::RecursiveAggregation, BlackBoxFuncCall::BigIntAdd { .. } => BlackBoxFunc::BigIntAdd, - BlackBoxFuncCall::BigIntNeg { .. } => BlackBoxFunc::BigIntNeg, + BlackBoxFuncCall::BigIntSub { .. } => BlackBoxFunc::BigIntSub, BlackBoxFuncCall::BigIntMul { .. } => BlackBoxFunc::BigIntMul, BlackBoxFuncCall::BigIntDiv { .. } => BlackBoxFunc::BigIntDiv, BlackBoxFuncCall::BigIntFromLeBytes { .. } => BlackBoxFunc::BigIntFromLeBytes, @@ -223,7 +223,7 @@ impl BlackBoxFuncCall { vec![*lhs, *rhs] } BlackBoxFuncCall::BigIntAdd { .. } - | BlackBoxFuncCall::BigIntNeg { .. } + | BlackBoxFuncCall::BigIntSub { .. } | BlackBoxFuncCall::BigIntMul { .. } | BlackBoxFuncCall::BigIntDiv { .. } | BlackBoxFuncCall::BigIntToLeBytes { .. } => Vec::new(), @@ -328,7 +328,7 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::RecursiveAggregation { .. } | BlackBoxFuncCall::BigIntFromLeBytes { .. } | BlackBoxFuncCall::BigIntAdd { .. } - | BlackBoxFuncCall::BigIntNeg { .. } + | BlackBoxFuncCall::BigIntSub { .. } | BlackBoxFuncCall::BigIntMul { .. } | BlackBoxFuncCall::BigIntDiv { .. } => { vec![] diff --git a/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs b/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs index 9e45dc4ee8c..0e94c0f051e 100644 --- a/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs +++ b/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs @@ -1,7 +1,7 @@ use crate::native_types::{Expression, Witness}; use serde::{Deserialize, Serialize}; -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Copy, Default)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash, Copy, Default)] pub struct BlockId(pub u32); /// Operation on a block of memory diff --git a/acvm-repo/acir/src/lib.rs b/acvm-repo/acir/src/lib.rs index b7bcaa0c5c0..c7be5026850 100644 --- a/acvm-repo/acir/src/lib.rs +++ b/acvm-repo/acir/src/lib.rs @@ -32,7 +32,8 @@ mod reflection { }; use brillig::{ - BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode, RegisterOrMemory, + BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, Opcode as BrilligOpcode, + ValueOrArray, }; use serde_reflection::{Tracer, TracerConfig}; @@ -41,7 +42,7 @@ mod reflection { brillig::{BrilligInputs, BrilligOutputs}, directives::Directive, opcodes::BlackBoxFuncCall, - Circuit, Opcode, OpcodeLocation, + Circuit, ExpressionWidth, Opcode, OpcodeLocation, }, native_types::{Witness, WitnessMap}, }; @@ -59,6 +60,7 @@ mod reflection { let mut tracer = Tracer::new(TracerConfig::default()); tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); @@ -69,7 +71,8 @@ mod reflection { tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); - tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); let registry = tracer.registry().unwrap(); diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index 7d3b7b32d35..6a73522c822 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -20,7 +20,7 @@ use acir::{ native_types::{Expression, Witness}, }; use acir_field::FieldElement; -use brillig::{HeapArray, RegisterIndex, RegisterOrMemory}; +use brillig::{HeapArray, HeapValueType, MemoryAddress, ValueOrArray}; #[test] fn addition_circuit() { @@ -45,12 +45,12 @@ fn addition_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 187, 13, 192, 32, 12, 68, 249, 100, 32, 27, - 219, 96, 119, 89, 37, 40, 176, 255, 8, 17, 18, 5, 74, 202, 240, 154, 235, 158, 238, 238, - 112, 206, 121, 247, 37, 206, 60, 103, 194, 63, 208, 111, 116, 133, 197, 69, 144, 153, 91, - 73, 13, 9, 47, 72, 86, 85, 128, 165, 102, 69, 69, 81, 185, 147, 18, 53, 101, 45, 86, 173, - 128, 33, 83, 195, 46, 70, 125, 202, 226, 190, 94, 16, 166, 103, 108, 13, 203, 151, 254, - 245, 233, 224, 1, 1, 52, 166, 127, 120, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 208, 49, 14, 192, 32, 8, 5, 80, 212, 30, 8, 4, 20, + 182, 94, 165, 166, 122, 255, 35, 52, 77, 28, 76, 58, 214, 191, 124, 166, 23, 242, 15, 0, 8, + 240, 77, 154, 125, 206, 198, 127, 161, 176, 209, 138, 139, 197, 88, 68, 122, 205, 157, 152, + 46, 204, 222, 76, 81, 180, 21, 35, 35, 53, 189, 179, 49, 119, 19, 171, 222, 188, 162, 147, + 112, 167, 161, 206, 99, 98, 105, 223, 95, 248, 26, 113, 90, 97, 185, 97, 217, 56, 173, 35, + 63, 243, 81, 87, 163, 125, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -75,9 +75,9 @@ fn fixed_base_scalar_mul_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 215, 46, 189, - 163, 175, 165, 10, 21, 36, 10, 57, 192, 160, 146, 188, 226, 139, 78, 113, 69, 183, 190, 61, - 111, 218, 182, 231, 124, 122, 8, 177, 65, 92, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 32, 16, 2, 109, 171, 175, 46, 221, + 209, 247, 229, 130, 130, 140, 200, 92, 0, 11, 157, 228, 35, 127, 212, 200, 29, 61, 116, 76, + 220, 217, 250, 171, 91, 113, 160, 66, 104, 242, 97, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -102,9 +102,9 @@ fn pedersen_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 9, 10, 0, 64, 8, 2, 103, 15, 232, 255, 31, 142, - 138, 10, 34, 65, 84, 198, 15, 28, 82, 145, 178, 182, 86, 191, 238, 183, 24, 131, 205, 79, - 203, 0, 166, 242, 158, 93, 92, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 135, 9, 0, 48, 8, 75, 171, 224, 255, 15, 139, + 27, 196, 64, 200, 100, 0, 15, 133, 80, 57, 89, 219, 127, 39, 173, 126, 235, 236, 247, 151, + 48, 224, 71, 90, 33, 97, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -143,22 +143,22 @@ fn schnorr_verify_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 87, 78, 2, 1, 20, 134, 209, 177, 247, 222, 123, - 71, 68, 68, 68, 68, 68, 68, 68, 68, 68, 221, 133, 251, 95, 130, 145, 27, 206, 36, 78, 50, - 57, 16, 94, 200, 253, 191, 159, 36, 73, 134, 146, 193, 19, 142, 243, 183, 255, 14, 179, - 233, 247, 145, 254, 59, 217, 127, 71, 57, 198, 113, 78, 48, 125, 167, 56, 205, 25, 206, - 114, 142, 243, 92, 224, 34, 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184, - 205, 29, 238, 114, 143, 251, 60, 224, 33, 143, 120, 204, 19, 158, 242, 140, 25, 158, 51, - 203, 11, 230, 120, 201, 60, 175, 88, 224, 53, 139, 188, 97, 137, 183, 44, 243, 142, 21, - 222, 179, 202, 7, 214, 248, 200, 58, 159, 216, 224, 51, 155, 124, 97, 235, 223, 142, 241, - 188, 250, 222, 230, 27, 59, 124, 103, 151, 31, 236, 241, 147, 95, 252, 246, 57, 158, 104, - 47, 186, 139, 214, 162, 179, 104, 44, 250, 74, 219, 154, 242, 63, 162, 165, 232, 40, 26, - 138, 126, 162, 157, 232, 38, 154, 137, 94, 162, 149, 232, 36, 26, 137, 62, 162, 141, 232, - 34, 154, 136, 30, 162, 133, 232, 32, 26, 136, 253, 99, 251, 195, 100, 176, 121, 236, 29, - 91, 159, 218, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, 182, - 42, 219, 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, 55, 111, 185, 113, - 219, 109, 59, 110, 218, 117, 203, 158, 27, 166, 55, 75, 239, 150, 184, 101, 250, 252, 1, - 55, 204, 92, 74, 220, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 7, 74, 3, 1, 20, 69, 209, 177, 247, 222, 123, + 239, 189, 119, 141, 93, 99, 220, 133, 251, 95, 130, 152, 103, 78, 32, 3, 195, 33, 4, 66, + 248, 239, 254, 20, 69, 209, 84, 212, 158, 216, 206, 223, 234, 219, 204, 146, 239, 91, 170, + 111, 103, 245, 109, 101, 27, 219, 217, 193, 250, 219, 197, 110, 246, 176, 151, 125, 236, + 231, 0, 7, 57, 196, 97, 142, 112, 148, 99, 28, 231, 4, 39, 57, 197, 105, 206, 112, 150, + 115, 156, 231, 2, 23, 185, 196, 101, 174, 112, 149, 107, 92, 231, 6, 55, 185, 197, 109, + 238, 112, 151, 123, 220, 231, 1, 15, 121, 196, 99, 158, 240, 148, 103, 60, 231, 5, 47, 121, + 197, 107, 222, 240, 150, 119, 188, 231, 3, 75, 124, 228, 83, 195, 142, 121, 158, 125, 126, + 225, 43, 223, 248, 206, 15, 126, 178, 204, 47, 86, 248, 237, 119, 43, 76, 127, 105, 47, + 189, 165, 181, 116, 150, 198, 234, 125, 117, 249, 47, 233, 41, 45, 165, 163, 52, 148, 126, + 210, 78, 186, 73, 51, 233, 37, 173, 164, 147, 52, 146, 62, 210, 70, 186, 72, 19, 233, 33, + 45, 164, 131, 52, 144, 253, 23, 139, 218, 238, 217, 60, 123, 103, 235, 236, 156, 141, 179, + 239, 166, 93, 183, 237, 185, 107, 199, 125, 251, 29, 218, 237, 216, 94, 167, 118, 58, 183, + 207, 165, 93, 174, 237, 113, 107, 135, 123, 247, 47, 185, 251, 147, 59, 191, 184, 239, 155, + 187, 126, 184, 103, 217, 29, 235, 55, 171, 223, 173, 104, 184, 231, 255, 243, 7, 236, 52, + 239, 128, 225, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -173,15 +173,25 @@ fn simple_brillig_foreign_call() { inputs: vec![ BrilligInputs::Single(w_input.into()), // Input Register 0, ], - // This tells the BrilligSolver which witnesses its output registers correspond to + // This tells the BrilligSolver which witnesses its output values correspond to outputs: vec![ BrilligOutputs::Simple(w_inverted), // Output Register 1 ], - bytecode: vec![brillig::Opcode::ForeignCall { - function: "invert".into(), - destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], - inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], - }], + bytecode: vec![ + brillig::Opcode::CalldataCopy { + destination_address: MemoryAddress(0), + size: 1, + offset: 0, + }, + brillig::Opcode::ForeignCall { + function: "invert".into(), + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], + }, + brillig::Opcode::Stop { return_data_offset: 0, return_data_size: 1 }, + ], predicate: None, }; @@ -196,10 +206,11 @@ fn simple_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 49, 10, 64, 33, 12, 67, 99, 63, 124, 60, 142, - 222, 192, 203, 56, 184, 56, 136, 120, 126, 5, 21, 226, 160, 139, 62, 40, 13, 45, 132, 68, - 3, 80, 232, 124, 164, 153, 121, 115, 99, 155, 59, 172, 122, 231, 101, 56, 175, 80, 86, 221, - 230, 31, 58, 196, 226, 83, 62, 53, 91, 16, 122, 10, 246, 84, 99, 243, 0, 30, 59, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 215, 148, 150, 246, + 212, 175, 216, 31, 244, 51, 61, 244, 226, 65, 196, 247, 171, 24, 33, 136, 122, 209, 129, + 144, 176, 132, 101, 247, 4, 160, 144, 217, 196, 45, 41, 218, 203, 91, 207, 241, 168, 117, + 94, 90, 230, 37, 238, 144, 216, 27, 249, 11, 87, 156, 131, 239, 223, 248, 207, 186, 81, + 235, 150, 67, 173, 221, 189, 95, 18, 34, 97, 64, 0, 116, 135, 40, 214, 136, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -221,39 +232,64 @@ fn complex_brillig_foreign_call() { let brillig_data = Brillig { inputs: vec![ - // Input Register 0 + // Input 0,1,2 BrilligInputs::Array(vec![ Expression::from(a), Expression::from(b), Expression::from(c), ]), - // Input Register 1 + // Input 3 BrilligInputs::Single(Expression { mul_terms: vec![], linear_combinations: vec![(fe_1, a), (fe_1, b), (fe_1, c)], q_c: fe_0, }), ], - // This tells the BrilligSolver which witnesses its output registers correspond to + // This tells the BrilligSolver which witnesses its output values correspond to outputs: vec![ - BrilligOutputs::Array(vec![a_times_2, b_times_3, c_times_4]), // Output Register 0 - BrilligOutputs::Simple(a_plus_b_plus_c), // Output Register 1 - BrilligOutputs::Simple(a_plus_b_plus_c_times_2), // Output Register 2 + BrilligOutputs::Array(vec![a_times_2, b_times_3, c_times_4]), // Output 0,1,2 + BrilligOutputs::Simple(a_plus_b_plus_c), // Output 3 + BrilligOutputs::Simple(a_plus_b_plus_c_times_2), // Output 4 ], bytecode: vec![ + brillig::Opcode::CalldataCopy { + destination_address: MemoryAddress(32), + size: 3, + offset: 0, + }, + brillig::Opcode::Const { + destination: MemoryAddress(0), + value: brillig::Value::from(32_usize), + bit_size: 32, + }, + brillig::Opcode::CalldataCopy { + destination_address: MemoryAddress(1), + size: 1, + offset: 3, + }, // Oracles are named 'foreign calls' in brillig brillig::Opcode::ForeignCall { function: "complex".into(), inputs: vec![ - RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), - RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)), + ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), + ValueOrArray::MemoryAddress(MemoryAddress::from(1)), + ], + input_value_types: vec![ + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, + HeapValueType::Simple, ], destinations: vec![ - RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), - RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)), - RegisterOrMemory::RegisterIndex(RegisterIndex::from(2)), + ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), + ValueOrArray::MemoryAddress(MemoryAddress::from(35)), + ValueOrArray::MemoryAddress(MemoryAddress::from(36)), + ], + destination_value_types: vec![ + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, + HeapValueType::Simple, + HeapValueType::Simple, ], }, + brillig::Opcode::Stop { return_data_offset: 32, return_data_size: 5 }, ], predicate: None, }; @@ -269,13 +305,15 @@ fn complex_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 219, 10, 128, 48, 8, 117, 174, 139, 159, 179, - 254, 160, 127, 137, 222, 138, 122, 236, 243, 19, 114, 32, 22, 244, 144, 131, 118, 64, 156, - 178, 29, 14, 59, 74, 0, 16, 224, 66, 228, 64, 57, 7, 169, 53, 242, 189, 81, 114, 250, 134, - 33, 248, 113, 165, 82, 26, 177, 2, 141, 177, 128, 198, 60, 15, 63, 245, 219, 211, 23, 215, - 255, 139, 15, 251, 211, 112, 180, 28, 157, 212, 189, 100, 82, 179, 64, 170, 63, 109, 235, - 190, 204, 135, 166, 178, 150, 216, 62, 154, 252, 250, 70, 147, 35, 220, 119, 93, 227, 4, - 182, 131, 81, 25, 36, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 73, 14, 131, 48, 12, 28, 147, 166, 165, 167, + 126, 161, 82, 251, 128, 180, 47, 224, 47, 85, 111, 32, 56, 242, 124, 130, 24, 68, 176, 2, + 23, 130, 4, 35, 89, 206, 50, 137, 71, 182, 147, 28, 128, 96, 128, 241, 150, 113, 44, 156, + 135, 24, 121, 5, 189, 219, 134, 143, 164, 187, 203, 237, 165, 49, 59, 129, 70, 179, 131, + 198, 177, 31, 14, 90, 239, 148, 117, 73, 154, 63, 19, 121, 63, 23, 111, 214, 219, 149, 243, + 27, 125, 206, 117, 208, 63, 85, 222, 161, 248, 32, 167, 72, 162, 245, 235, 44, 166, 94, 20, + 21, 251, 30, 196, 253, 213, 85, 83, 254, 91, 163, 168, 90, 234, 43, 24, 191, 213, 190, 172, + 156, 235, 17, 126, 59, 49, 142, 68, 120, 75, 220, 7, 166, 84, 90, 68, 72, 194, 139, 180, + 136, 25, 58, 46, 103, 45, 188, 25, 5, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -307,11 +345,10 @@ fn memory_op_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 146, 49, 14, 0, 32, 8, 3, 139, 192, 127, 240, 7, - 254, 255, 85, 198, 136, 9, 131, 155, 48, 216, 165, 76, 77, 57, 80, 0, 140, 45, 117, 111, - 238, 228, 179, 224, 174, 225, 110, 111, 234, 213, 185, 148, 156, 203, 121, 89, 86, 13, 215, - 126, 131, 43, 153, 187, 115, 40, 185, 62, 153, 3, 136, 83, 60, 30, 96, 2, 12, 235, 225, - 124, 14, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 145, 187, 17, 0, 32, 8, 67, 195, 111, 31, 220, 192, + 253, 167, 178, 144, 2, 239, 236, 132, 194, 52, 129, 230, 93, 8, 6, 64, 176, 101, 225, 28, + 78, 49, 43, 238, 154, 225, 254, 166, 209, 205, 165, 98, 174, 212, 177, 188, 187, 92, 255, + 173, 92, 173, 190, 93, 82, 80, 78, 123, 14, 127, 60, 97, 1, 210, 144, 46, 242, 19, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm-repo/acvm/src/compiler/mod.rs b/acvm-repo/acvm/src/compiler/mod.rs index ccb043914d6..6543c70958b 100644 --- a/acvm-repo/acvm/src/compiler/mod.rs +++ b/acvm-repo/acvm/src/compiler/mod.rs @@ -1,8 +1,6 @@ use std::collections::HashMap; -use acir::circuit::{Circuit, OpcodeLocation}; - -use crate::ExpressionWidth; +use acir::circuit::{Circuit, ExpressionWidth, OpcodeLocation}; // The various passes that we can use over ACIR mod optimizers; diff --git a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs index ecabd98b3b1..64fe5291cc6 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs @@ -148,7 +148,7 @@ mod tests { use acir::{ circuit::{ opcodes::{BlackBoxFuncCall, FunctionInput}, - Circuit, Opcode, PublicInputs, + Circuit, ExpressionWidth, Opcode, PublicInputs, }, native_types::{Expression, Witness}, }; @@ -167,11 +167,13 @@ mod tests { Circuit { current_witness_index: 1, + expression_width: ExpressionWidth::Bounded { width: 3 }, opcodes, private_parameters: BTreeSet::new(), public_parameters: PublicInputs::default(), return_values: PublicInputs::default(), assert_messages: Default::default(), + recursive: false, } } diff --git a/acvm-repo/acvm/src/compiler/transformers/mod.rs b/acvm-repo/acvm/src/compiler/transformers/mod.rs index 12156a0a723..214243d9360 100644 --- a/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -1,12 +1,10 @@ use acir::{ - circuit::{brillig::BrilligOutputs, directives::Directive, Circuit, Opcode}, + circuit::{brillig::BrilligOutputs, directives::Directive, Circuit, ExpressionWidth, Opcode}, native_types::{Expression, Witness}, FieldElement, }; use indexmap::IndexMap; -use crate::ExpressionWidth; - mod csat; mod r1cs; @@ -44,11 +42,11 @@ pub(super) fn transform_internal( acir_opcode_positions: Vec, ) -> (Circuit, Vec) { let mut transformer = match &expression_width { - crate::ExpressionWidth::Unbounded => { + ExpressionWidth::Unbounded => { let transformer = R1CSTransformer::new(acir); return (transformer.transform(), acir_opcode_positions); } - crate::ExpressionWidth::Bounded { width } => { + ExpressionWidth::Bounded { width } => { let mut csat = CSatTransformer::new(*width); for value in acir.circuit_arguments() { csat.mark_solvable(value); @@ -154,6 +152,7 @@ pub(super) fn transform_internal( let acir = Circuit { current_witness_index, + expression_width, opcodes: transformed_opcodes, // The transformer does not add new public inputs ..acir diff --git a/acvm-repo/acvm/src/lib.rs b/acvm-repo/acvm/src/lib.rs index 264479d8a12..00a253fde07 100644 --- a/acvm-repo/acvm/src/lib.rs +++ b/acvm-repo/acvm/src/lib.rs @@ -7,7 +7,6 @@ pub mod compiler; pub mod pwg; pub use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; -use core::fmt::Debug; use pwg::OpcodeResolutionError; // re-export acir @@ -17,27 +16,3 @@ pub use acir::FieldElement; pub use brillig_vm; // re-export blackbox solver pub use acvm_blackbox_solver as blackbox_solver; - -/// Specifies the maximum width of the expressions which will be constrained. -/// -/// Unbounded Expressions are useful if you are eventually going to pass the ACIR -/// into a proving system which supports R1CS. -/// -/// Bounded Expressions are useful if you are eventually going to pass the ACIR -/// into a proving system which supports PLONK, where arithmetic expressions have a -/// finite fan-in. -#[derive(Debug, Clone, Copy)] -pub enum ExpressionWidth { - Unbounded, - Bounded { width: usize }, -} - -impl From for ExpressionWidth { - fn from(width: usize) -> ExpressionWidth { - if width == 0 { - ExpressionWidth::Unbounded - } else { - ExpressionWidth::Bounded { width } - } - } -} diff --git a/acvm-repo/acvm/src/pwg/blackbox/bigint.rs b/acvm-repo/acvm/src/pwg/blackbox/bigint.rs new file mode 100644 index 00000000000..986afaa3ce7 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/bigint.rs @@ -0,0 +1,120 @@ +use std::collections::HashMap; + +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + BlackBoxFunc, FieldElement, +}; + +use num_bigint::BigUint; + +use crate::pwg::OpcodeResolutionError; + +/// Resolve BigInt opcodes by storing BigInt values (and their moduli) by their ID in a HashMap: +/// - When it encounters a bigint operation opcode, it performs the operation on the stored values +/// and store the result using the provided ID. +/// - When it gets a to_bytes opcode, it simply looks up the value and resolves the output witness accordingly. +#[derive(Default)] +pub(crate) struct BigIntSolver { + bigint_id_to_value: HashMap, + bigint_id_to_modulus: HashMap, +} + +impl BigIntSolver { + pub(crate) fn get_bigint( + &self, + id: u32, + func: BlackBoxFunc, + ) -> Result { + self.bigint_id_to_value + .get(&id) + .ok_or(OpcodeResolutionError::BlackBoxFunctionFailed( + func, + format!("could not find bigint of id {id}"), + )) + .cloned() + } + + pub(crate) fn get_modulus( + &self, + id: u32, + func: BlackBoxFunc, + ) -> Result { + self.bigint_id_to_modulus + .get(&id) + .ok_or(OpcodeResolutionError::BlackBoxFunctionFailed( + func, + format!("could not find bigint of id {id}"), + )) + .cloned() + } + pub(crate) fn bigint_from_bytes( + &mut self, + inputs: &[FunctionInput], + modulus: &[u8], + output: u32, + initial_witness: &mut WitnessMap, + ) -> Result<(), OpcodeResolutionError> { + let bytes = inputs + .iter() + .map(|input| initial_witness.get(&input.witness).unwrap().to_u128() as u8) + .collect::>(); + let bigint = BigUint::from_bytes_le(&bytes); + self.bigint_id_to_value.insert(output, bigint); + let modulus = BigUint::from_bytes_le(modulus); + self.bigint_id_to_modulus.insert(output, modulus); + Ok(()) + } + + pub(crate) fn bigint_to_bytes( + &self, + input: u32, + outputs: &Vec, + initial_witness: &mut WitnessMap, + ) -> Result<(), OpcodeResolutionError> { + let bigint = self.get_bigint(input, BlackBoxFunc::BigIntToLeBytes)?; + + let mut bytes = bigint.to_bytes_le(); + while bytes.len() < outputs.len() { + bytes.push(0); + } + bytes.iter().zip(outputs.iter()).for_each(|(byte, output)| { + initial_witness.insert(*output, FieldElement::from(*byte as u128)); + }); + Ok(()) + } + + pub(crate) fn bigint_op( + &mut self, + lhs: u32, + rhs: u32, + output: u32, + func: BlackBoxFunc, + ) -> Result<(), OpcodeResolutionError> { + let modulus = self.get_modulus(lhs, func)?; + let lhs = self.get_bigint(lhs, func)?; + let rhs = self.get_bigint(rhs, func)?; + let mut result = match func { + BlackBoxFunc::BigIntAdd => lhs + rhs, + BlackBoxFunc::BigIntSub => { + if lhs >= rhs { + &lhs - &rhs + } else { + &lhs + &modulus - &rhs + } + } + BlackBoxFunc::BigIntMul => lhs * rhs, + BlackBoxFunc::BigIntDiv => { + lhs * rhs.modpow(&(&modulus - BigUint::from(1_u32)), &modulus) + } //TODO ensure that modulus is prime + _ => unreachable!("ICE - bigint_op must be called for an operation"), + }; + if result > modulus { + let q = &result / &modulus; + result -= q * &modulus; + } + self.bigint_id_to_value.insert(output, result); + self.bigint_id_to_modulus.insert(output, modulus); + Ok(()) + } +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/acvm-repo/acvm/src/pwg/blackbox/mod.rs index 0f026cd274a..7146dff87e0 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -5,11 +5,12 @@ use acir::{ }; use acvm_blackbox_solver::{blake2s, blake3, keccak256, keccakf1600, sha256}; -use self::pedersen::pedersen_hash; +use self::{bigint::BigIntSolver, pedersen::pedersen_hash}; use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError}; use crate::{pwg::witness_to_value, BlackBoxFunctionSolver}; +pub(crate) mod bigint; mod fixed_base_scalar_mul; mod hash; mod logic; @@ -53,6 +54,7 @@ pub(crate) fn solve( backend: &impl BlackBoxFunctionSolver, initial_witness: &mut WitnessMap, bb_func: &BlackBoxFuncCall, + bigint_solver: &mut BigIntSolver, ) -> Result<(), OpcodeResolutionError> { let inputs = bb_func.get_inputs_vec(); if !contains_all_inputs(initial_witness, &inputs) { @@ -190,12 +192,18 @@ pub(crate) fn solve( } // Recursive aggregation will be entirely handled by the backend and is not solved by the ACVM BlackBoxFuncCall::RecursiveAggregation { .. } => Ok(()), - BlackBoxFuncCall::BigIntAdd { .. } => todo!(), - BlackBoxFuncCall::BigIntNeg { .. } => todo!(), - BlackBoxFuncCall::BigIntMul { .. } => todo!(), - BlackBoxFuncCall::BigIntDiv { .. } => todo!(), - BlackBoxFuncCall::BigIntFromLeBytes { .. } => todo!(), - BlackBoxFuncCall::BigIntToLeBytes { .. } => todo!(), + BlackBoxFuncCall::BigIntAdd { lhs, rhs, output } + | BlackBoxFuncCall::BigIntSub { lhs, rhs, output } + | BlackBoxFuncCall::BigIntMul { lhs, rhs, output } + | BlackBoxFuncCall::BigIntDiv { lhs, rhs, output } => { + bigint_solver.bigint_op(*lhs, *rhs, *output, bb_func.get_black_box_func()) + } + BlackBoxFuncCall::BigIntFromLeBytes { inputs, modulus, output } => { + bigint_solver.bigint_from_bytes(inputs, modulus, *output, initial_witness) + } + BlackBoxFuncCall::BigIntToLeBytes { input, outputs } => { + bigint_solver.bigint_to_bytes(*input, outputs, initial_witness) + } BlackBoxFuncCall::Poseidon2Permutation { .. } => todo!(), BlackBoxFuncCall::Sha256Compression { .. } => todo!(), } diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 0db38c776e2..b0fb7469fd9 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -1,18 +1,21 @@ +use std::collections::HashMap; + use acir::{ - brillig::{ForeignCallParam, ForeignCallResult, RegisterIndex, Value}, + brillig::{ForeignCallParam, ForeignCallResult, Value}, circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, + opcodes::BlockId, OpcodeLocation, }, native_types::WitnessMap, FieldElement, }; use acvm_blackbox_solver::BlackBoxFunctionSolver; -use brillig_vm::{Registers, VMStatus, VM}; +use brillig_vm::{VMStatus, VM}; use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError}; -use super::{get_value, insert_value}; +use super::{get_value, insert_value, memory_op::MemoryOpSolver}; #[derive(Debug)] pub enum BrilligSolverStatus { @@ -64,21 +67,21 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { /// witness. pub(super) fn new( initial_witness: &WitnessMap, + memory: &HashMap, brillig: &'b Brillig, bb_solver: &'b B, acir_index: usize, ) -> Result { // Set input values - let mut input_register_values: Vec = Vec::new(); - let mut input_memory: Vec = Vec::new(); + let mut calldata: Vec = Vec::new(); // Each input represents an expression or array of expressions to evaluate. // Iterate over each input and evaluate the expression(s) associated with it. - // Push the results into registers and/or memory. + // Push the results into memory. // If a certain expression is not solvable, we stall the ACVM and do not proceed with Brillig VM execution. for input in &brillig.inputs { match input { BrilligInputs::Single(expr) => match get_value(expr, initial_witness) { - Ok(value) => input_register_values.push(value.into()), + Ok(value) => calldata.push(value.into()), Err(_) => { return Err(OpcodeResolutionError::OpcodeNotSolvable( OpcodeNotSolvable::ExpressionHasTooManyUnknowns(expr.clone()), @@ -87,10 +90,9 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { }, BrilligInputs::Array(expr_arr) => { // Attempt to fetch all array input values - let memory_pointer = input_memory.len(); for expr in expr_arr.iter() { match get_value(expr, initial_witness) { - Ok(value) => input_memory.push(value.into()), + Ok(value) => calldata.push(value.into()), Err(_) => { return Err(OpcodeResolutionError::OpcodeNotSolvable( OpcodeNotSolvable::ExpressionHasTooManyUnknowns(expr.clone()), @@ -98,28 +100,28 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { } } } - - // Push value of the array pointer as a register - input_register_values.push(Value::from(memory_pointer)); + } + BrilligInputs::MemoryArray(block_id) => { + let memory_block = memory + .get(block_id) + .ok_or(OpcodeNotSolvable::MissingMemoryBlock(block_id.0))?; + for memory_index in 0..memory_block.block_len { + let memory_value = memory_block + .block_value + .get(&memory_index) + .expect("All memory is initialized on creation"); + calldata.push((*memory_value).into()); + } } } } - // Instantiate a Brillig VM given the solved input registers and memory + // Instantiate a Brillig VM given the solved calldata // along with the Brillig bytecode. - let input_registers = Registers::load(input_register_values); - let vm = VM::new(input_registers, input_memory, &brillig.bytecode, vec![], bb_solver); + let vm = VM::new(calldata, &brillig.bytecode, vec![], bb_solver); Ok(Self { vm, acir_index }) } - pub fn get_registers(&self) -> &Registers { - self.vm.get_registers() - } - - pub fn set_register(&mut self, register_index: usize, value: Value) { - self.vm.set_register(RegisterIndex(register_index), value); - } - pub fn get_memory(&self) -> &[Value] { self.vm.get_memory() } @@ -128,6 +130,10 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { self.vm.write_memory_at(ptr, value); } + pub fn get_call_stack(&self) -> Vec { + self.vm.get_call_stack() + } + pub(super) fn solve(&mut self) -> Result { let status = self.vm.process_opcodes(); self.handle_vm_status(status) @@ -151,7 +157,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { // Return the "resolution" to the caller who may choose to make subsequent calls // (when it gets foreign call results for example). match vm_status { - VMStatus::Finished => Ok(BrilligSolverStatus::Finished), + VMStatus::Finished { .. } => Ok(BrilligSolverStatus::Finished), VMStatus::InProgress => Ok(BrilligSolverStatus::InProgress), VMStatus::Failure { message, call_stack } => { Err(OpcodeResolutionError::BrilligFunctionFailed { @@ -179,8 +185,8 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { // Finish the Brillig execution by writing the outputs to the witness map let vm_status = self.vm.get_status(); match vm_status { - VMStatus::Finished => { - self.write_brillig_outputs(witness, brillig)?; + VMStatus::Finished { return_data_offset, return_data_size } => { + self.write_brillig_outputs(witness, return_data_offset, return_data_size, brillig)?; Ok(()) } _ => panic!("Brillig VM has not completed execution"), @@ -190,24 +196,32 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { fn write_brillig_outputs( &self, witness_map: &mut WitnessMap, + return_data_offset: usize, + return_data_size: usize, brillig: &Brillig, ) -> Result<(), OpcodeResolutionError> { // Write VM execution results into the witness map - for (i, output) in brillig.outputs.iter().enumerate() { - let register_value = self.vm.get_registers().get(RegisterIndex::from(i)); + let memory = self.vm.get_memory(); + let mut current_ret_data_idx = return_data_offset; + for output in brillig.outputs.iter() { match output { BrilligOutputs::Simple(witness) => { - insert_value(witness, register_value.to_field(), witness_map)?; + insert_value(witness, memory[current_ret_data_idx].to_field(), witness_map)?; + current_ret_data_idx += 1; } BrilligOutputs::Array(witness_arr) => { - // Treat the register value as a pointer to memory - for (i, witness) in witness_arr.iter().enumerate() { - let value = &self.vm.get_memory()[register_value.to_usize() + i]; + for witness in witness_arr.iter() { + let value = memory[current_ret_data_idx]; insert_value(witness, value.to_field(), witness_map)?; + current_ret_data_idx += 1; } } } } + assert!( + current_ret_data_idx == return_data_offset + return_data_size, + "Brillig VM did not write the expected number of return values" + ); Ok(()) } diff --git a/acvm-repo/acvm/src/pwg/memory_op.rs b/acvm-repo/acvm/src/pwg/memory_op.rs index c1da2cd95cf..49ec652289e 100644 --- a/acvm-repo/acvm/src/pwg/memory_op.rs +++ b/acvm-repo/acvm/src/pwg/memory_op.rs @@ -14,8 +14,8 @@ type MemoryIndex = u32; /// Maintains the state for solving [`MemoryInit`][`acir::circuit::Opcode::MemoryInit`] and [`MemoryOp`][`acir::circuit::Opcode::MemoryOp`] opcodes. #[derive(Default)] pub(super) struct MemoryOpSolver { - block_value: HashMap, - block_len: u32, + pub(super) block_value: HashMap, + pub(super) block_len: u32, } impl MemoryOpSolver { diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index 41b96572658..2ee39a289e7 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -10,7 +10,10 @@ use acir::{ }; use acvm_blackbox_solver::BlackBoxResolutionError; -use self::{arithmetic::ExpressionSolver, directives::solve_directives, memory_op::MemoryOpSolver}; +use self::{ + arithmetic::ExpressionSolver, blackbox::bigint::BigIntSolver, directives::solve_directives, + memory_op::MemoryOpSolver, +}; use crate::BlackBoxFunctionSolver; use thiserror::Error; @@ -76,6 +79,8 @@ pub enum StepResult<'a, B: BlackBoxFunctionSolver> { pub enum OpcodeNotSolvable { #[error("missing assignment for witness index {0}")] MissingAssignment(u32), + #[error("Attempted to load uninitialized memory block")] + MissingMemoryBlock(u32), #[error("expression has too many unknowns {0}")] ExpressionHasTooManyUnknowns(Expression), } @@ -132,6 +137,8 @@ pub struct ACVM<'a, B: BlackBoxFunctionSolver> { /// Stores the solver for memory operations acting on blocks of memory disambiguated by [block][`BlockId`]. block_solvers: HashMap, + bigint_solver: BigIntSolver, + /// A list of opcodes which are to be executed by the ACVM. opcodes: &'a [Opcode], /// Index of the next opcode to be executed. @@ -149,6 +156,7 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { status, backend, block_solvers: HashMap::default(), + bigint_solver: BigIntSolver::default(), opcodes, instruction_pointer: 0, witness_map: initial_witness, @@ -254,9 +262,12 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { let resolution = match opcode { Opcode::AssertZero(expr) => ExpressionSolver::solve(&mut self.witness_map, expr), - Opcode::BlackBoxFuncCall(bb_func) => { - blackbox::solve(self.backend, &mut self.witness_map, bb_func) - } + Opcode::BlackBoxFuncCall(bb_func) => blackbox::solve( + self.backend, + &mut self.witness_map, + bb_func, + &mut self.bigint_solver, + ), Opcode::Directive(directive) => solve_directives(&mut self.witness_map, directive), Opcode::MemoryInit { block_id, init } => { let solver = self.block_solvers.entry(*block_id).or_default(); @@ -327,7 +338,13 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { // there will be a cached `BrilligSolver` to avoid recomputation. let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() { Some(solver) => solver, - None => BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer)?, + None => BrilligSolver::new( + witness, + &self.block_solvers, + brillig, + self.backend, + self.instruction_pointer, + )?, }; match solver.solve()? { BrilligSolverStatus::ForeignCallWait(foreign_call) => { @@ -362,7 +379,13 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { return StepResult::Status(self.handle_opcode_resolution(resolution)); } - let solver = BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer); + let solver = BrilligSolver::new( + witness, + &self.block_solvers, + brillig, + self.backend, + self.instruction_pointer, + ); match solver { Ok(solver) => StepResult::IntoBrillig(solver), Err(..) => StepResult::Status(self.handle_opcode_resolution(solver.map(|_| ()))), diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 486e04d5bf1..b267c3005a8 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use acir::{ - brillig::{BinaryFieldOp, Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory, Value}, + brillig::{BinaryFieldOp, MemoryAddress, Opcode as BrilligOpcode, Value, ValueOrArray}, circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, opcodes::{BlockId, MemOp}, @@ -13,6 +13,7 @@ use acir::{ use acvm::pwg::{ACVMStatus, ErrorLocation, ForeignCallWaitInfo, OpcodeResolutionError, ACVM}; use acvm_blackbox_solver::StubbedBlackBoxSolver; +use brillig_vm::brillig::HeapValueType; // Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib. @@ -37,9 +38,9 @@ fn inversion_brillig_oracle_equivalence() { let equal_opcode = BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Equals, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(2), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(2), }; let brillig_data = Brillig { @@ -52,20 +53,28 @@ fn inversion_brillig_oracle_equivalence() { }), BrilligInputs::Single(Expression::default()), // Input Register 1 ], - // This tells the BrilligSolver which witnesses its output registers correspond to + // This tells the BrilligSolver which witnesses its output values correspond to outputs: vec![ BrilligOutputs::Simple(w_x_plus_y), // Output Register 0 - from input BrilligOutputs::Simple(w_oracle), // Output Register 1 BrilligOutputs::Simple(w_equal_res), // Output Register 2 ], bytecode: vec![ + BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress(0), + size: 2, + offset: 0, + }, equal_opcode, // Oracles are named 'foreign calls' in brillig BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], - inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 3 }, ], predicate: None, }; @@ -151,9 +160,9 @@ fn double_inversion_brillig_oracle() { let equal_opcode = BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Equals, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(4), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(4), }; let brillig_data = Brillig { @@ -180,18 +189,28 @@ fn double_inversion_brillig_oracle() { BrilligOutputs::Simple(w_equal_res), // Output Register 4 ], bytecode: vec![ + BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress(0), + size: 3, + offset: 0, + }, equal_opcode, // Oracles are named 'foreign calls' in brillig BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], - inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(3))], - inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(2))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], + input_value_types: vec![HeapValueType::Simple], }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 5 }, ], predicate: None, }; @@ -306,17 +325,27 @@ fn oracle_dependent_execution() { BrilligOutputs::Simple(w_y_inv), // Output Register 3 ], bytecode: vec![ + BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress(0), + size: 3, + offset: 0, + }, // Oracles are named 'foreign calls' in brillig BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], - inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(3))], - inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(2))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], + input_value_types: vec![HeapValueType::Simple], }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 4 }, ], predicate: None, }; @@ -404,9 +433,9 @@ fn brillig_oracle_predicate() { let equal_opcode = BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Equals, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(2), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(2), }; let brillig_opcode = Opcode::Brillig(Brillig { @@ -425,12 +454,19 @@ fn brillig_oracle_predicate() { BrilligOutputs::Simple(w_lt_res), ], bytecode: vec![ + BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress(0), + size: 2, + offset: 0, + }, equal_opcode, // Oracles are named 'foreign calls' in brillig BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], - inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: Some(Expression::default()), @@ -502,21 +538,24 @@ fn unsatisfied_opcode_resolved_brillig() { let w_y = Witness(5); let w_result = Witness(6); + let calldata_copy_opcode = + BrilligOpcode::CalldataCopy { destination_address: MemoryAddress(0), size: 2, offset: 0 }; + let equal_opcode = BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Equals, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(2), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(2), }; // Jump pass the trap if the values are equal, else // jump to the trap let location_of_stop = 3; let jmp_if_opcode = - BrilligOpcode::JumpIf { condition: RegisterIndex::from(2), location: location_of_stop }; + BrilligOpcode::JumpIf { condition: MemoryAddress::from(2), location: location_of_stop }; let trap_opcode = BrilligOpcode::Trap; - let stop_opcode = BrilligOpcode::Stop; + let stop_opcode = BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }; let brillig_opcode = Opcode::Brillig(Brillig { inputs: vec![ @@ -532,7 +571,7 @@ fn unsatisfied_opcode_resolved_brillig() { }), ], outputs: vec![BrilligOutputs::Simple(w_result)], - bytecode: vec![equal_opcode, jmp_if_opcode, trap_opcode, stop_opcode], + bytecode: vec![calldata_copy_opcode, equal_opcode, jmp_if_opcode, trap_opcode, stop_opcode], predicate: Some(Expression::one()), }); @@ -564,7 +603,7 @@ fn unsatisfied_opcode_resolved_brillig() { solver_status, ACVMStatus::Failure(OpcodeResolutionError::BrilligFunctionFailed { message: "explicit trap hit in brillig".to_string(), - call_stack: vec![OpcodeLocation::Brillig { acir_index: 0, brillig_index: 2 }] + call_stack: vec![OpcodeLocation::Brillig { acir_index: 0, brillig_index: 3 }] }), "The first opcode is not satisfiable, expected an error indicating this" ); diff --git a/acvm-repo/acvm_js/test/shared/addition.ts b/acvm-repo/acvm_js/test/shared/addition.ts index 982b9b685ce..217902bdea6 100644 --- a/acvm-repo/acvm_js/test/shared/addition.ts +++ b/acvm-repo/acvm_js/test/shared/addition.ts @@ -2,11 +2,11 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `addition_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 187, 13, 192, 32, 12, 68, 249, 100, 32, 27, 219, 96, 119, 89, 37, 40, - 176, 255, 8, 17, 18, 5, 74, 202, 240, 154, 235, 158, 238, 238, 112, 206, 121, 247, 37, 206, 60, 103, 194, 63, 208, - 111, 116, 133, 197, 69, 144, 153, 91, 73, 13, 9, 47, 72, 86, 85, 128, 165, 102, 69, 69, 81, 185, 147, 18, 53, 101, 45, - 86, 173, 128, 33, 83, 195, 46, 70, 125, 202, 226, 190, 94, 16, 166, 103, 108, 13, 203, 151, 254, 245, 233, 224, 1, 1, - 52, 166, 127, 120, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 208, 49, 14, 192, 32, 8, 5, 80, 212, 30, 8, 4, 20, 182, 94, 165, 166, 122, + 255, 35, 52, 77, 28, 76, 58, 214, 191, 124, 166, 23, 242, 15, 0, 8, 240, 77, 154, 125, 206, 198, 127, 161, 176, 209, + 138, 139, 197, 88, 68, 122, 205, 157, 152, 46, 204, 222, 76, 81, 180, 21, 35, 35, 53, 189, 179, 49, 119, 19, 171, 222, + 188, 162, 147, 112, 167, 161, 206, 99, 98, 105, 223, 95, 248, 26, 113, 90, 97, 185, 97, 217, 56, 173, 35, 63, 243, 81, + 87, 163, 125, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ diff --git a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index 1b6f5e4319a..07c343c5ba0 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,11 +2,13 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 219, 10, 128, 48, 8, 117, 174, 139, 159, 179, 254, 160, 127, 137, 222, - 138, 122, 236, 243, 19, 114, 32, 22, 244, 144, 131, 118, 64, 156, 178, 29, 14, 59, 74, 0, 16, 224, 66, 228, 64, 57, 7, - 169, 53, 242, 189, 81, 114, 250, 134, 33, 248, 113, 165, 82, 26, 177, 2, 141, 177, 128, 198, 60, 15, 63, 245, 219, - 211, 23, 215, 255, 139, 15, 251, 211, 112, 180, 28, 157, 212, 189, 100, 82, 179, 64, 170, 63, 109, 235, 190, 204, 135, - 166, 178, 150, 216, 62, 154, 252, 250, 70, 147, 35, 220, 119, 93, 227, 4, 182, 131, 81, 25, 36, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 73, 14, 131, 48, 12, 28, 147, 166, 165, 167, 126, 161, 82, 251, 128, 180, + 47, 224, 47, 85, 111, 32, 56, 242, 124, 130, 24, 68, 176, 2, 23, 130, 4, 35, 89, 206, 50, 137, 71, 182, 147, 28, 128, + 96, 128, 241, 150, 113, 44, 156, 135, 24, 121, 5, 189, 219, 134, 143, 164, 187, 203, 237, 165, 49, 59, 129, 70, 179, + 131, 198, 177, 31, 14, 90, 239, 148, 117, 73, 154, 63, 19, 121, 63, 23, 111, 214, 219, 149, 243, 27, 125, 206, 117, + 208, 63, 85, 222, 161, 248, 32, 167, 72, 162, 245, 235, 44, 166, 94, 20, 21, 251, 30, 196, 253, 213, 85, 83, 254, 91, + 163, 168, 90, 234, 43, 24, 191, 213, 190, 172, 156, 235, 17, 126, 59, 49, 142, 68, 120, 75, 220, 7, 166, 84, 90, 68, + 72, 194, 139, 180, 136, 25, 58, 46, 103, 45, 188, 25, 5, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts b/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts index 0437bebc369..c0859f50135 100644 --- a/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts +++ b/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts @@ -1,8 +1,8 @@ // See `fixed_base_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 215, 46, 189, 163, 175, 165, 10, 21, 36, - 10, 57, 192, 160, 146, 188, 226, 139, 78, 113, 69, 183, 190, 61, 111, 218, 182, 231, 124, 122, 8, 177, 65, 92, 0, 0, - 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 32, 16, 2, 109, 171, 175, 46, 221, 209, 247, 229, 130, 130, + 140, 200, 92, 0, 11, 157, 228, 35, 127, 212, 200, 29, 61, 116, 76, 220, 217, 250, 171, 91, 113, 160, 66, 104, 242, 97, + 0, 0, 0, ]); export const initialWitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/acvm-repo/acvm_js/test/shared/foreign_call.ts b/acvm-repo/acvm_js/test/shared/foreign_call.ts index 178ec3a09d1..cfa7c679b18 100644 --- a/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,10 +2,10 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 49, 10, 64, 33, 12, 67, 99, 63, 124, 60, 142, 222, 192, 203, 56, 184, 56, - 136, 120, 126, 5, 21, 226, 160, 139, 62, 40, 13, 45, 132, 68, 3, 80, 232, 124, 164, 153, 121, 115, 99, 155, 59, 172, - 122, 231, 101, 56, 175, 80, 86, 221, 230, 31, 58, 196, 226, 83, 62, 53, 91, 16, 122, 10, 246, 84, 99, 243, 0, 30, 59, - 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 215, 148, 150, 246, 212, 175, 216, 31, 244, 51, + 61, 244, 226, 65, 196, 247, 171, 24, 33, 136, 122, 209, 129, 144, 176, 132, 101, 247, 4, 160, 144, 217, 196, 45, 41, + 218, 203, 91, 207, 241, 168, 117, 94, 90, 230, 37, 238, 144, 216, 27, 249, 11, 87, 156, 131, 239, 223, 248, 207, 186, + 81, 235, 150, 67, 173, 221, 189, 95, 18, 34, 97, 64, 0, 116, 135, 40, 214, 136, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/acvm-repo/acvm_js/test/shared/memory_op.ts b/acvm-repo/acvm_js/test/shared/memory_op.ts index ce88f491893..b5ab64b3447 100644 --- a/acvm-repo/acvm_js/test/shared/memory_op.ts +++ b/acvm-repo/acvm_js/test/shared/memory_op.ts @@ -1,9 +1,9 @@ // See `memory_op_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 146, 49, 14, 0, 32, 8, 3, 139, 192, 127, 240, 7, 254, 255, 85, 198, 136, 9, - 131, 155, 48, 216, 165, 76, 77, 57, 80, 0, 140, 45, 117, 111, 238, 228, 179, 224, 174, 225, 110, 111, 234, 213, 185, - 148, 156, 203, 121, 89, 86, 13, 215, 126, 131, 43, 153, 187, 115, 40, 185, 62, 153, 3, 136, 83, 60, 30, 96, 2, 12, - 235, 225, 124, 14, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 145, 187, 17, 0, 32, 8, 67, 195, 111, 31, 220, 192, 253, 167, 178, 144, 2, + 239, 236, 132, 194, 52, 129, 230, 93, 8, 6, 64, 176, 101, 225, 28, 78, 49, 43, 238, 154, 225, 254, 166, 209, 205, 165, + 98, 174, 212, 177, 188, 187, 92, 255, 173, 92, 173, 190, 93, 82, 80, 78, 123, 14, 127, 60, 97, 1, 210, 144, 46, 242, + 19, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/acvm-repo/acvm_js/test/shared/pedersen.ts b/acvm-repo/acvm_js/test/shared/pedersen.ts index e35893fc355..5150d24131c 100644 --- a/acvm-repo/acvm_js/test/shared/pedersen.ts +++ b/acvm-repo/acvm_js/test/shared/pedersen.ts @@ -1,7 +1,7 @@ // See `pedersen_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 9, 10, 0, 64, 8, 2, 103, 15, 232, 255, 31, 142, 138, 10, 34, 65, 84, 198, - 15, 28, 82, 145, 178, 182, 86, 191, 238, 183, 24, 131, 205, 79, 203, 0, 166, 242, 158, 93, 92, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 135, 9, 0, 48, 8, 75, 171, 224, 255, 15, 139, 27, 196, 64, 200, 100, 0, 15, + 133, 80, 57, 89, 219, 127, 39, 173, 126, 235, 236, 247, 151, 48, 224, 71, 90, 33, 97, 0, 0, 0, ]); export const initialWitnessMap = new Map([[1, '0x0000000000000000000000000000000000000000000000000000000000000001']]); diff --git a/acvm-repo/acvm_js/test/shared/schnorr_verify.ts b/acvm-repo/acvm_js/test/shared/schnorr_verify.ts index 5716cbd30f8..2127de66f69 100644 --- a/acvm-repo/acvm_js/test/shared/schnorr_verify.ts +++ b/acvm-repo/acvm_js/test/shared/schnorr_verify.ts @@ -1,17 +1,17 @@ // See `schnorr_verify_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 87, 78, 2, 1, 20, 134, 209, 177, 247, 222, 123, 71, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 221, 133, 251, 95, 130, 145, 27, 206, 36, 78, 50, 57, 16, 94, 200, 253, 191, 159, 36, 73, 134, 146, - 193, 19, 142, 243, 183, 255, 14, 179, 233, 247, 145, 254, 59, 217, 127, 71, 57, 198, 113, 78, 48, 125, 167, 56, 205, - 25, 206, 114, 142, 243, 92, 224, 34, 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184, 205, 29, 238, 114, - 143, 251, 60, 224, 33, 143, 120, 204, 19, 158, 242, 140, 25, 158, 51, 203, 11, 230, 120, 201, 60, 175, 88, 224, 53, - 139, 188, 97, 137, 183, 44, 243, 142, 21, 222, 179, 202, 7, 214, 248, 200, 58, 159, 216, 224, 51, 155, 124, 97, 235, - 223, 142, 241, 188, 250, 222, 230, 27, 59, 124, 103, 151, 31, 236, 241, 147, 95, 252, 246, 57, 158, 104, 47, 186, 139, - 214, 162, 179, 104, 44, 250, 74, 219, 154, 242, 63, 162, 165, 232, 40, 26, 138, 126, 162, 157, 232, 38, 154, 137, 94, - 162, 149, 232, 36, 26, 137, 62, 162, 141, 232, 34, 154, 136, 30, 162, 133, 232, 32, 26, 136, 253, 99, 251, 195, 100, - 176, 121, 236, 29, 91, 159, 218, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, 182, 42, 219, - 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, 55, 111, 185, 113, 219, 109, 59, 110, 218, 117, 203, - 158, 27, 166, 55, 75, 239, 150, 184, 101, 250, 252, 1, 55, 204, 92, 74, 220, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 7, 74, 3, 1, 20, 69, 209, 177, 247, 222, 123, 239, 189, 119, 141, 93, 99, + 220, 133, 251, 95, 130, 152, 103, 78, 32, 3, 195, 33, 4, 66, 248, 239, 254, 20, 69, 209, 84, 212, 158, 216, 206, 223, + 234, 219, 204, 146, 239, 91, 170, 111, 103, 245, 109, 101, 27, 219, 217, 193, 250, 219, 197, 110, 246, 176, 151, 125, + 236, 231, 0, 7, 57, 196, 97, 142, 112, 148, 99, 28, 231, 4, 39, 57, 197, 105, 206, 112, 150, 115, 156, 231, 2, 23, + 185, 196, 101, 174, 112, 149, 107, 92, 231, 6, 55, 185, 197, 109, 238, 112, 151, 123, 220, 231, 1, 15, 121, 196, 99, + 158, 240, 148, 103, 60, 231, 5, 47, 121, 197, 107, 222, 240, 150, 119, 188, 231, 3, 75, 124, 228, 83, 195, 142, 121, + 158, 125, 126, 225, 43, 223, 248, 206, 15, 126, 178, 204, 47, 86, 248, 237, 119, 43, 76, 127, 105, 47, 189, 165, 181, + 116, 150, 198, 234, 125, 117, 249, 47, 233, 41, 45, 165, 163, 52, 148, 126, 210, 78, 186, 73, 51, 233, 37, 173, 164, + 147, 52, 146, 62, 210, 70, 186, 72, 19, 233, 33, 45, 164, 131, 52, 144, 253, 23, 139, 218, 238, 217, 60, 123, 103, + 235, 236, 156, 141, 179, 239, 166, 93, 183, 237, 185, 107, 199, 125, 251, 29, 218, 237, 216, 94, 167, 118, 58, 183, + 207, 165, 93, 174, 237, 113, 107, 135, 123, 247, 47, 185, 251, 147, 59, 191, 184, 239, 155, 187, 126, 184, 103, 217, + 29, 235, 55, 171, 223, 173, 104, 184, 231, 255, 243, 7, 236, 52, 239, 128, 225, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/acvm-repo/brillig/src/black_box.rs b/acvm-repo/brillig/src/black_box.rs index 22fac6f3ba3..29861d0fd84 100644 --- a/acvm-repo/brillig/src/black_box.rs +++ b/acvm-repo/brillig/src/black_box.rs @@ -1,4 +1,4 @@ -use crate::{opcodes::HeapVector, HeapArray, RegisterIndex}; +use crate::{opcodes::HeapVector, HeapArray, MemoryAddress}; use serde::{Deserialize, Serialize}; /// These opcodes provide an equivalent of ACIR blackbox functions. @@ -36,7 +36,7 @@ pub enum BlackBoxOp { public_key_x: HeapArray, public_key_y: HeapArray, signature: HeapArray, - result: RegisterIndex, + result: MemoryAddress, }, /// Verifies a ECDSA signature over the secp256r1 curve. EcdsaSecp256r1 { @@ -44,75 +44,75 @@ pub enum BlackBoxOp { public_key_x: HeapArray, public_key_y: HeapArray, signature: HeapArray, - result: RegisterIndex, + result: MemoryAddress, }, /// Verifies a Schnorr signature over a curve which is "pairing friendly" with the curve on which the Brillig bytecode is defined. SchnorrVerify { - public_key_x: RegisterIndex, - public_key_y: RegisterIndex, + public_key_x: MemoryAddress, + public_key_y: MemoryAddress, message: HeapVector, signature: HeapVector, - result: RegisterIndex, + result: MemoryAddress, }, /// Calculates a Pedersen commitment to the inputs. PedersenCommitment { inputs: HeapVector, - domain_separator: RegisterIndex, + domain_separator: MemoryAddress, output: HeapArray, }, /// Calculates a Pedersen hash to the inputs. PedersenHash { inputs: HeapVector, - domain_separator: RegisterIndex, - output: RegisterIndex, + domain_separator: MemoryAddress, + output: MemoryAddress, }, /// Performs scalar multiplication over the embedded curve. FixedBaseScalarMul { - low: RegisterIndex, - high: RegisterIndex, + low: MemoryAddress, + high: MemoryAddress, result: HeapArray, }, /// Performs addition over the embedded curve. EmbeddedCurveAdd { - input1_x: RegisterIndex, - input1_y: RegisterIndex, - input2_x: RegisterIndex, - input2_y: RegisterIndex, + input1_x: MemoryAddress, + input1_y: MemoryAddress, + input2_x: MemoryAddress, + input2_y: MemoryAddress, result: HeapArray, }, BigIntAdd { - lhs: RegisterIndex, - rhs: RegisterIndex, - output: RegisterIndex, + lhs: MemoryAddress, + rhs: MemoryAddress, + output: MemoryAddress, }, - BigIntNeg { - lhs: RegisterIndex, - rhs: RegisterIndex, - output: RegisterIndex, + BigIntSub { + lhs: MemoryAddress, + rhs: MemoryAddress, + output: MemoryAddress, }, BigIntMul { - lhs: RegisterIndex, - rhs: RegisterIndex, - output: RegisterIndex, + lhs: MemoryAddress, + rhs: MemoryAddress, + output: MemoryAddress, }, BigIntDiv { - lhs: RegisterIndex, - rhs: RegisterIndex, - output: RegisterIndex, + lhs: MemoryAddress, + rhs: MemoryAddress, + output: MemoryAddress, }, BigIntFromLeBytes { inputs: HeapVector, modulus: HeapVector, - output: RegisterIndex, + output: MemoryAddress, }, BigIntToLeBytes { - input: RegisterIndex, + input: MemoryAddress, output: HeapVector, }, Poseidon2Permutation { message: HeapVector, output: HeapArray, - len: RegisterIndex, + len: MemoryAddress, }, Sha256Compression { input: HeapVector, diff --git a/acvm-repo/brillig/src/lib.rs b/acvm-repo/brillig/src/lib.rs index 5e033e3c792..0661e794360 100644 --- a/acvm-repo/brillig/src/lib.rs +++ b/acvm-repo/brillig/src/lib.rs @@ -18,7 +18,7 @@ mod value; pub use black_box::BlackBoxOp; pub use foreign_call::{ForeignCallParam, ForeignCallResult}; pub use opcodes::{ - BinaryFieldOp, BinaryIntOp, HeapArray, HeapVector, RegisterIndex, RegisterOrMemory, + BinaryFieldOp, BinaryIntOp, HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray, }; pub use opcodes::{BrilligOpcode as Opcode, Label}; pub use value::Typ; diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index 79295cc6e5d..06c8fdc04eb 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -4,100 +4,128 @@ use serde::{Deserialize, Serialize}; pub type Label = usize; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct RegisterIndex(pub usize); +pub struct MemoryAddress(pub usize); -/// `RegisterIndex` refers to the index in VM register space. -impl RegisterIndex { +/// `MemoryAddress` refers to the index in VM memory. +impl MemoryAddress { pub fn to_usize(self) -> usize { self.0 } } -impl From for RegisterIndex { +impl From for MemoryAddress { fn from(value: usize) -> Self { - RegisterIndex(value) + MemoryAddress(value) } } -/// A fixed-sized array starting from a Brillig register memory location. +/// Describes the memory layout for an array/vector element +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub enum HeapValueType { + // A single field element is enough to represent the value + Simple, + // The value read should be interpreted as a pointer to a heap array, which + // consists of a pointer to a slice of memory of size elements, and a + // reference count + Array { value_types: Vec, size: usize }, + // The value read should be interpreted as a pointer to a heap vector, which + // consists of a pointer to a slice of memory, a number of elements in that + // slice, and a reference count + Vector { value_types: Vec }, +} + +impl HeapValueType { + pub fn all_simple(types: &[HeapValueType]) -> bool { + types.iter().all(|typ| matches!(typ, HeapValueType::Simple)) + } +} + +/// A fixed-sized array starting from a Brillig memory location. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub struct HeapArray { - pub pointer: RegisterIndex, + pub pointer: MemoryAddress, pub size: usize, } -/// A register-sized vector passed starting from a Brillig register memory location and with a register-held size +/// A memory-sized vector passed starting from a Brillig memory location and with a memory-held size #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub struct HeapVector { - pub pointer: RegisterIndex, - pub size: RegisterIndex, + pub pointer: MemoryAddress, + pub size: MemoryAddress, } /// Lays out various ways an external foreign call's input and output data may be interpreted inside Brillig. -/// This data can either be an individual register value or memory. +/// This data can either be an individual value or memory. /// /// While we are usually agnostic to how memory is passed within Brillig, /// this needs to be encoded somehow when dealing with an external system. /// For simplicity, the extra type information is given right in the ForeignCall instructions. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] -pub enum RegisterOrMemory { - /// A single register value passed to or from an external call - /// It is an 'immediate' value - used without dereferencing memory. - /// For a foreign call input, the value is read directly from the register. - /// For a foreign call output, the value is written directly to the register. - RegisterIndex(RegisterIndex), +pub enum ValueOrArray { + /// A single value passed to or from an external call + /// It is an 'immediate' value - used without dereferencing. + /// For a foreign call input, the value is read directly from memory. + /// For a foreign call output, the value is written directly to memory. + MemoryAddress(MemoryAddress), /// An array passed to or from an external call /// In the case of a foreign call input, the array is read from this Brillig memory location + usize more cells. /// In the case of a foreign call output, the array is written to this Brillig memory location with the usize being here just as a sanity check for the size write. HeapArray(HeapArray), /// A vector passed to or from an external call - /// In the case of a foreign call input, the vector is read from this Brillig memory location + as many cells as the 2nd register indicates. - /// In the case of a foreign call output, the vector is written to this Brillig memory location and as 'size' cells, with size being stored in the second register. + /// In the case of a foreign call input, the vector is read from this Brillig memory location + as many cells as the 2nd address indicates. + /// In the case of a foreign call output, the vector is written to this Brillig memory location and as 'size' cells, with size being stored in the second address. HeapVector(HeapVector), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum BrilligOpcode { - /// Takes the fields in registers `lhs` and `rhs` + /// Takes the fields in addresses `lhs` and `rhs` /// Performs the specified binary operation - /// and stores the value in the `result` register. + /// and stores the value in the `result` address. BinaryFieldOp { - destination: RegisterIndex, + destination: MemoryAddress, op: BinaryFieldOp, - lhs: RegisterIndex, - rhs: RegisterIndex, + lhs: MemoryAddress, + rhs: MemoryAddress, }, - /// Takes the `bit_size` size integers in registers `lhs` and `rhs` + /// Takes the `bit_size` size integers in addresses `lhs` and `rhs` /// Performs the specified binary operation - /// and stores the value in the `result` register. + /// and stores the value in the `result` address. BinaryIntOp { - destination: RegisterIndex, + destination: MemoryAddress, op: BinaryIntOp, bit_size: u32, - lhs: RegisterIndex, - rhs: RegisterIndex, + lhs: MemoryAddress, + rhs: MemoryAddress, }, JumpIfNot { - condition: RegisterIndex, + condition: MemoryAddress, location: Label, }, /// Sets the program counter to the value located at `destination` /// If the value at `condition` is non-zero JumpIf { - condition: RegisterIndex, + condition: MemoryAddress, location: Label, }, /// Sets the program counter to the label. Jump { location: Label, }, + /// Copies calldata after the offset to the specified address and length + CalldataCopy { + destination_address: MemoryAddress, + size: usize, + offset: usize, + }, /// We don't support dynamic jumps or calls /// See https://github.com/ethereum/aleth/issues/3404 for reasoning Call { location: Label, }, Const { - destination: RegisterIndex, + destination: MemoryAddress, + bit_size: u32, value: Value, }, Return, @@ -109,28 +137,36 @@ pub enum BrilligOpcode { /// Interpreted by caller context, ie this will have different meanings depending on /// who the caller is. function: String, - /// Destination registers (may be single values or memory pointers). - destinations: Vec, - /// Input registers (may be single values or memory pointers). - inputs: Vec, + /// Destination addresses (may be single values or memory pointers). + destinations: Vec, + /// Destination value types + destination_value_types: Vec, + /// Input addresses (may be single values or memory pointers). + inputs: Vec, + /// Input value types (for heap allocated structures indicates how to + /// retrieve the elements) + input_value_types: Vec, }, Mov { - destination: RegisterIndex, - source: RegisterIndex, + destination: MemoryAddress, + source: MemoryAddress, }, Load { - destination: RegisterIndex, - source_pointer: RegisterIndex, + destination: MemoryAddress, + source_pointer: MemoryAddress, }, Store { - destination_pointer: RegisterIndex, - source: RegisterIndex, + destination_pointer: MemoryAddress, + source: MemoryAddress, }, BlackBox(BlackBoxOp), /// Used to denote execution failure Trap, - /// Stop execution - Stop, + /// Stop execution, returning data after the offset + Stop { + return_data_offset: usize, + return_data_size: usize, + }, } /// Binary fixed-length field expressions diff --git a/acvm-repo/brillig/src/value.rs b/acvm-repo/brillig/src/value.rs index 73a7d897eb7..5a532cbc1a7 100644 --- a/acvm-repo/brillig/src/value.rs +++ b/acvm-repo/brillig/src/value.rs @@ -37,8 +37,8 @@ impl Value { /// Panics: If `Value` cannot fit into a u64 or `Value` does //// not fit into a usize. pub fn to_usize(&self) -> usize { - usize::try_from(self.inner.try_to_u64().expect("register does not fit into u64")) - .expect("register does not fit into usize") + usize::try_from(self.inner.try_to_u64().expect("value does not fit into u64")) + .expect("value does not fit into usize") } } diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index e9c25200c47..04aa2bcf9af 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -5,23 +5,14 @@ use acvm_blackbox_solver::{ sha256, BlackBoxFunctionSolver, BlackBoxResolutionError, }; -use crate::{Memory, Registers}; +use crate::Memory; -fn read_heap_vector<'a>( - memory: &'a Memory, - registers: &Registers, - vector: &HeapVector, -) -> &'a [Value] { - memory - .read_slice(registers.get(vector.pointer).to_usize(), registers.get(vector.size).to_usize()) +fn read_heap_vector<'a>(memory: &'a Memory, vector: &HeapVector) -> &'a [Value] { + memory.read_slice(memory.read_ref(vector.pointer), memory.read(vector.size).to_usize()) } -fn read_heap_array<'a>( - memory: &'a Memory, - registers: &Registers, - array: &HeapArray, -) -> &'a [Value] { - memory.read_slice(registers.get(array.pointer).to_usize(), array.size) +fn read_heap_array<'a>(memory: &'a Memory, array: &HeapArray) -> &'a [Value] { + memory.read_slice(memory.read_ref(array.pointer), array.size) } /// Extracts the last byte of every value @@ -42,36 +33,35 @@ fn to_value_vec(input: &[u8]) -> Vec { pub(crate) fn evaluate_black_box( op: &BlackBoxOp, solver: &Solver, - registers: &mut Registers, memory: &mut Memory, ) -> Result<(), BlackBoxResolutionError> { match op { BlackBoxOp::Sha256 { message, output } => { - let message = to_u8_vec(read_heap_vector(memory, registers, message)); + let message = to_u8_vec(read_heap_vector(memory, message)); let bytes = sha256(message.as_slice())?; - memory.write_slice(registers.get(output.pointer).to_usize(), &to_value_vec(&bytes)); + memory.write_slice(memory.read_ref(output.pointer), &to_value_vec(&bytes)); Ok(()) } BlackBoxOp::Blake2s { message, output } => { - let message = to_u8_vec(read_heap_vector(memory, registers, message)); + let message = to_u8_vec(read_heap_vector(memory, message)); let bytes = blake2s(message.as_slice())?; - memory.write_slice(registers.get(output.pointer).to_usize(), &to_value_vec(&bytes)); + memory.write_slice(memory.read_ref(output.pointer), &to_value_vec(&bytes)); Ok(()) } BlackBoxOp::Blake3 { message, output } => { - let message = to_u8_vec(read_heap_vector(memory, registers, message)); + let message = to_u8_vec(read_heap_vector(memory, message)); let bytes = blake3(message.as_slice())?; - memory.write_slice(registers.get(output.pointer).to_usize(), &to_value_vec(&bytes)); + memory.write_slice(memory.read_ref(output.pointer), &to_value_vec(&bytes)); Ok(()) } BlackBoxOp::Keccak256 { message, output } => { - let message = to_u8_vec(read_heap_vector(memory, registers, message)); + let message = to_u8_vec(read_heap_vector(memory, message)); let bytes = keccak256(message.as_slice())?; - memory.write_slice(registers.get(output.pointer).to_usize(), &to_value_vec(&bytes)); + memory.write_slice(memory.read_ref(output.pointer), &to_value_vec(&bytes)); Ok(()) } BlackBoxOp::Keccakf1600 { message, output } => { - let state_vec: Vec = read_heap_vector(memory, registers, message) + let state_vec: Vec = read_heap_vector(memory, message) .iter() .map(|value| value.to_field().try_to_u64().unwrap()) .collect(); @@ -81,7 +71,7 @@ pub(crate) fn evaluate_black_box( let new_state: Vec = new_state.into_iter().map(|x| Value::from(x as usize)).collect(); - memory.write_slice(registers.get(output.pointer).to_usize(), &new_state); + memory.write_slice(memory.read_ref(output.pointer), &new_state); Ok(()) } BlackBoxOp::EcdsaSecp256k1 { @@ -89,42 +79,37 @@ pub(crate) fn evaluate_black_box( public_key_x, public_key_y, signature, - result: result_register, + result: result_address, } | BlackBoxOp::EcdsaSecp256r1 { hashed_msg, public_key_x, public_key_y, signature, - result: result_register, + result: result_address, } => { let bb_func = black_box_function_from_op(op); - let public_key_x: [u8; 32] = to_u8_vec(read_heap_array( - memory, - registers, - public_key_x, - )) - .try_into() - .map_err(|_| { - BlackBoxResolutionError::Failed(bb_func, "Invalid public key x length".to_string()) - })?; - let public_key_y: [u8; 32] = to_u8_vec(read_heap_array( - memory, - registers, - public_key_y, - )) - .try_into() - .map_err(|_| { - BlackBoxResolutionError::Failed(bb_func, "Invalid public key y length".to_string()) - })?; - let signature: [u8; 64] = to_u8_vec(read_heap_array(memory, registers, signature)) - .try_into() - .map_err(|_| { + let public_key_x: [u8; 32] = + to_u8_vec(read_heap_array(memory, public_key_x)).try_into().map_err(|_| { + BlackBoxResolutionError::Failed( + bb_func, + "Invalid public key x length".to_string(), + ) + })?; + let public_key_y: [u8; 32] = + to_u8_vec(read_heap_array(memory, public_key_y)).try_into().map_err(|_| { + BlackBoxResolutionError::Failed( + bb_func, + "Invalid public key y length".to_string(), + ) + })?; + let signature: [u8; 64] = + to_u8_vec(read_heap_array(memory, signature)).try_into().map_err(|_| { BlackBoxResolutionError::Failed(bb_func, "Invalid signature length".to_string()) })?; - let hashed_msg = to_u8_vec(read_heap_vector(memory, registers, hashed_msg)); + let hashed_msg = to_u8_vec(read_heap_vector(memory, hashed_msg)); let result = match op { BlackBoxOp::EcdsaSecp256k1 { .. } => { @@ -136,65 +121,65 @@ pub(crate) fn evaluate_black_box( _ => unreachable!("`BlackBoxOp` is guarded against being a non-ecdsa operation"), }; - registers.set(*result_register, result.into()); + memory.write(*result_address, result.into()); Ok(()) } BlackBoxOp::SchnorrVerify { public_key_x, public_key_y, message, signature, result } => { - let public_key_x = registers.get(*public_key_x).to_field(); - let public_key_y = registers.get(*public_key_y).to_field(); - let message: Vec = to_u8_vec(read_heap_vector(memory, registers, message)); - let signature: Vec = to_u8_vec(read_heap_vector(memory, registers, signature)); + let public_key_x = memory.read(*public_key_x).to_field(); + let public_key_y = memory.read(*public_key_y).to_field(); + let message: Vec = to_u8_vec(read_heap_vector(memory, message)); + let signature: Vec = to_u8_vec(read_heap_vector(memory, signature)); let verified = solver.schnorr_verify(&public_key_x, &public_key_y, &signature, &message)?; - registers.set(*result, verified.into()); + memory.write(*result, verified.into()); Ok(()) } BlackBoxOp::FixedBaseScalarMul { low, high, result } => { - let low = registers.get(*low).to_field(); - let high = registers.get(*high).to_field(); + let low = memory.read(*low).to_field(); + let high = memory.read(*high).to_field(); let (x, y) = solver.fixed_base_scalar_mul(&low, &high)?; - memory.write_slice(registers.get(result.pointer).to_usize(), &[x.into(), y.into()]); + memory.write_slice(memory.read_ref(result.pointer), &[x.into(), y.into()]); Ok(()) } BlackBoxOp::EmbeddedCurveAdd { input1_x, input1_y, input2_x, input2_y, result } => { - let input1_x = registers.get(*input1_x).to_field(); - let input1_y = registers.get(*input1_y).to_field(); - let input2_x = registers.get(*input2_x).to_field(); - let input2_y = registers.get(*input2_y).to_field(); + let input1_x = memory.read(*input1_x).to_field(); + let input1_y = memory.read(*input1_y).to_field(); + let input2_x = memory.read(*input2_x).to_field(); + let input2_y = memory.read(*input2_y).to_field(); let (x, y) = solver.ec_add(&input1_x, &input1_y, &input2_x, &input2_y)?; - memory.write_slice(registers.get(result.pointer).to_usize(), &[x.into(), y.into()]); + memory.write_slice(memory.read_ref(result.pointer), &[x.into(), y.into()]); Ok(()) } BlackBoxOp::PedersenCommitment { inputs, domain_separator, output } => { let inputs: Vec = - read_heap_vector(memory, registers, inputs).iter().map(|x| x.to_field()).collect(); + read_heap_vector(memory, inputs).iter().map(|x| x.to_field()).collect(); let domain_separator: u32 = - registers.get(*domain_separator).to_u128().try_into().map_err(|_| { + memory.read(*domain_separator).to_u128().try_into().map_err(|_| { BlackBoxResolutionError::Failed( BlackBoxFunc::PedersenCommitment, "Invalid signature length".to_string(), ) })?; let (x, y) = solver.pedersen_commitment(&inputs, domain_separator)?; - memory.write_slice(registers.get(output.pointer).to_usize(), &[x.into(), y.into()]); + memory.write_slice(memory.read_ref(output.pointer), &[x.into(), y.into()]); Ok(()) } BlackBoxOp::PedersenHash { inputs, domain_separator, output } => { let inputs: Vec = - read_heap_vector(memory, registers, inputs).iter().map(|x| x.to_field()).collect(); + read_heap_vector(memory, inputs).iter().map(|x| x.to_field()).collect(); let domain_separator: u32 = - registers.get(*domain_separator).to_u128().try_into().map_err(|_| { + memory.read(*domain_separator).to_u128().try_into().map_err(|_| { BlackBoxResolutionError::Failed( BlackBoxFunc::PedersenCommitment, "Invalid signature length".to_string(), ) })?; let hash = solver.pedersen_hash(&inputs, domain_separator)?; - registers.set(*output, hash.into()); + memory.write(*output, hash.into()); Ok(()) } BlackBoxOp::BigIntAdd { .. } => todo!(), - BlackBoxOp::BigIntNeg { .. } => todo!(), + BlackBoxOp::BigIntSub { .. } => todo!(), BlackBoxOp::BigIntMul { .. } => todo!(), BlackBoxOp::BigIntDiv { .. } => todo!(), BlackBoxOp::BigIntFromLeBytes { .. } => todo!(), @@ -219,7 +204,7 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { BlackBoxOp::FixedBaseScalarMul { .. } => BlackBoxFunc::FixedBaseScalarMul, BlackBoxOp::EmbeddedCurveAdd { .. } => BlackBoxFunc::EmbeddedCurveAdd, BlackBoxOp::BigIntAdd { .. } => BlackBoxFunc::BigIntAdd, - BlackBoxOp::BigIntNeg { .. } => BlackBoxFunc::BigIntNeg, + BlackBoxOp::BigIntSub { .. } => BlackBoxFunc::BigIntSub, BlackBoxOp::BigIntMul { .. } => BlackBoxFunc::BigIntMul, BlackBoxOp::BigIntDiv { .. } => BlackBoxFunc::BigIntDiv, BlackBoxOp::BigIntFromLeBytes { .. } => BlackBoxFunc::BigIntFromLeBytes, @@ -231,11 +216,11 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { #[cfg(test)] mod test { - use acir::brillig::BlackBoxOp; + use acir::brillig::{BlackBoxOp, MemoryAddress}; use crate::{ black_box::{evaluate_black_box, to_u8_vec, to_value_vec}, - DummyBlackBoxSolver, HeapArray, HeapVector, Memory, Registers, Value, + DummyBlackBoxSolver, HeapArray, HeapVector, Memory, }; #[test] @@ -243,27 +228,22 @@ mod test { let message: Vec = b"hello world".to_vec(); let message_length = message.len(); - let mut memory = Memory::from(vec![]); - let message_pointer = 0; + let mut memory = Memory::default(); + let message_pointer = 3; let result_pointer = message_pointer + message_length; - memory.write_slice(message_pointer, to_value_vec(&message).as_slice()); - - let mut registers = Registers { - inner: vec![ - Value::from(message_pointer), - Value::from(message_length), - Value::from(result_pointer), - ], - }; + memory.write(MemoryAddress(0), message_pointer.into()); + memory.write(MemoryAddress(1), message_length.into()); + memory.write(MemoryAddress(2), result_pointer.into()); + memory.write_slice(MemoryAddress(message_pointer), to_value_vec(&message).as_slice()); let op = BlackBoxOp::Sha256 { message: HeapVector { pointer: 0.into(), size: 1.into() }, output: HeapArray { pointer: 2.into(), size: 32 }, }; - evaluate_black_box(&op, &DummyBlackBoxSolver, &mut registers, &mut memory).unwrap(); + evaluate_black_box(&op, &DummyBlackBoxSolver, &mut memory).unwrap(); - let result = memory.read_slice(result_pointer, 32); + let result = memory.read_slice(MemoryAddress(result_pointer), 32); assert_eq!( to_u8_vec(result), diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 38a562e65a1..1dd197112d8 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -12,8 +12,8 @@ //! [acvm]: https://crates.io/crates/acvm use acir::brillig::{ - BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapVector, Opcode, - RegisterIndex, RegisterOrMemory, Value, + BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapValueType, + HeapVector, MemoryAddress, Opcode, Value, ValueOrArray, }; use acir::FieldElement; // Re-export `brillig`. @@ -22,7 +22,6 @@ pub use acir::brillig; mod arithmetic; mod black_box; mod memory; -mod registers; use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; use arithmetic::{evaluate_binary_bigint_op, evaluate_binary_field_op}; @@ -30,14 +29,16 @@ use black_box::evaluate_black_box; pub use memory::Memory; use num_bigint::BigUint; -pub use registers::Registers; /// The error call stack contains the opcode indexes of the call stack at the time of failure, plus the index of the opcode that failed. pub type ErrorCallStack = Vec; #[derive(Debug, PartialEq, Eq, Clone)] pub enum VMStatus { - Finished, + Finished { + return_data_offset: usize, + return_data_size: usize, + }, InProgress, Failure { message: String, @@ -61,8 +62,8 @@ pub enum VMStatus { #[derive(Debug, PartialEq, Eq, Clone)] /// VM encapsulates the state of the Brillig VM during execution. pub struct VM<'a, B: BlackBoxFunctionSolver> { - /// Register storage - registers: Registers, + /// Calldata to the brillig function + calldata: Vec, /// Instruction pointer program_counter: usize, /// A counter maintained throughout a Brillig process that determines @@ -86,20 +87,19 @@ pub struct VM<'a, B: BlackBoxFunctionSolver> { impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { /// Constructs a new VM instance pub fn new( - inputs: Registers, - memory: Vec, + calldata: Vec, bytecode: &'a [Opcode], foreign_call_results: Vec, black_box_solver: &'a B, ) -> Self { Self { - registers: inputs, + calldata, program_counter: 0, foreign_call_counter: 0, foreign_call_results, bytecode, status: VMStatus::InProgress, - memory: memory.into(), + memory: Memory::default(), call_stack: Vec::new(), black_box_solver, } @@ -117,8 +117,8 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { } /// Sets the current status of the VM to Finished (completed execution). - fn finish(&mut self) -> VMStatus { - self.status(VMStatus::Finished) + fn finish(&mut self, return_data_offset: usize, return_data_size: usize) -> VMStatus { + self.status(VMStatus::Finished { return_data_offset, return_data_size }) } /// Sets the status of the VM to `ForeignCallWait`. @@ -154,26 +154,27 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { pub fn process_opcodes(&mut self) -> VMStatus { while !matches!( self.process_opcode(), - VMStatus::Finished | VMStatus::Failure { .. } | VMStatus::ForeignCallWait { .. } + VMStatus::Finished { .. } | VMStatus::Failure { .. } | VMStatus::ForeignCallWait { .. } ) {} self.status.clone() } - /// Returns all of the registers in the VM. - pub fn get_registers(&self) -> &Registers { - &self.registers - } - - pub fn set_register(&mut self, register_index: RegisterIndex, value: Value) { - self.registers.set(register_index, value); - } - pub fn get_memory(&self) -> &[Value] { self.memory.values() } pub fn write_memory_at(&mut self, ptr: usize, value: Value) { - self.memory.write(ptr, value); + self.memory.write(MemoryAddress(ptr), value); + } + + /// Returns the VM's current call stack, including the actual program + /// counter in the last position of the returned vector. + pub fn get_call_stack(&self) -> Vec { + self.call_stack + .iter() + .map(|program_counter| program_counter.to_usize()) + .chain(std::iter::once(self.program_counter)) + .collect() } /// Process a single opcode and modify the program counter. @@ -196,27 +197,41 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { Opcode::JumpIf { condition, location: destination } => { // Check if condition is true // We use 0 to mean false and any other value to mean true - let condition_value = self.registers.get(*condition); + let condition_value = self.memory.read(*condition); if !condition_value.is_zero() { return self.set_program_counter(*destination); } self.increment_program_counter() } Opcode::JumpIfNot { condition, location: destination } => { - let condition_value = self.registers.get(*condition); + let condition_value = self.memory.read(*condition); if condition_value.is_zero() { return self.set_program_counter(*destination); } self.increment_program_counter() } + Opcode::CalldataCopy { destination_address, size, offset } => { + let values = &self.calldata[*offset..(*offset + size)]; + self.memory.write_slice(*destination_address, values); + self.increment_program_counter() + } Opcode::Return => { - if let Some(register) = self.call_stack.pop() { - self.set_program_counter(register.to_usize() + 1) + if let Some(return_location) = self.call_stack.pop() { + self.set_program_counter(return_location.to_usize() + 1) } else { self.fail("return opcode hit, but callstack already empty".to_string()) } } - Opcode::ForeignCall { function, destinations, inputs } => { + Opcode::ForeignCall { + function, + destinations, + destination_value_types, + inputs, + input_value_types, + } => { + assert!(inputs.len() == input_value_types.len()); + assert!(destinations.len() == destination_value_types.len()); + if self.foreign_call_counter >= self.foreign_call_results.len() { // When this opcode is called, it is possible that the results of a foreign call are // not yet known (not enough entries in `foreign_call_results`). @@ -227,7 +242,8 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { // but has the necessary results to proceed with execution. let resolved_inputs = inputs .iter() - .map(|input| self.get_register_value_or_memory_values(*input)) + .zip(input_value_types) + .map(|(input, input_type)| self.get_memory_values(*input, input_type)) .collect::>(); return self.wait_for_foreign_call(function.clone(), resolved_inputs); } @@ -235,48 +251,69 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { let values = &self.foreign_call_results[self.foreign_call_counter].values; let mut invalid_foreign_call_result = false; - for (destination, output) in destinations.iter().zip(values) { - match destination { - RegisterOrMemory::RegisterIndex(value_index) => match output { - ForeignCallParam::Single(value) => { - self.registers.set(*value_index, *value); - } - _ => unreachable!( - "Function result size does not match brillig bytecode. Expected 1 result but got {output:?}" - ), - }, - RegisterOrMemory::HeapArray(HeapArray { pointer: pointer_index, size }) => { + for ((destination, value_type), output) in + destinations.iter().zip(destination_value_types).zip(values) + { + match (destination, value_type) { + (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple) => { match output { - ForeignCallParam::Array(values) => { - if values.len() != *size { - invalid_foreign_call_result = true; - break; - } - // Convert the destination pointer to a usize - let destination = self.registers.get(*pointer_index).to_usize(); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") + ForeignCallParam::Single(value) => { + self.memory.write(*value_index, *value); } + _ => unreachable!( + "Function result size does not match brillig bytecode. Expected 1 result but got {output:?}" + ), } } - RegisterOrMemory::HeapVector(HeapVector { pointer: pointer_index, size: size_index }) => { - match output { - ForeignCallParam::Array(values) => { - // Set our size in the size register - self.registers.set(*size_index, Value::from(values.len())); - // Convert the destination pointer to a usize - let destination = self.registers.get(*pointer_index).to_usize(); - // Write to our destination memory - self.memory.write_slice(destination, values); + ( + ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), + HeapValueType::Array { value_types, size: type_size }, + ) if size == type_size => { + if HeapValueType::all_simple(value_types) { + match output { + ForeignCallParam::Array(values) => { + if values.len() != *size { + invalid_foreign_call_result = true; + break; + } + // Convert the destination pointer to a usize + let destination = self.memory.read_ref(*pointer_index); + // Write to our destination memory + self.memory.write_slice(destination, values); + } + _ => { + unreachable!("Function result size does not match brillig bytecode size") + } } - _ => { - unreachable!("Function result size does not match brillig bytecode size") + } else { + unimplemented!("deflattening heap arrays from foreign calls"); + } + } + ( + ValueOrArray::HeapVector(HeapVector {pointer: pointer_index, size: size_index }), + HeapValueType::Vector { value_types }, + ) => { + if HeapValueType::all_simple(value_types) { + match output { + ForeignCallParam::Array(values) => { + // Set our size in the size address + self.memory.write(*size_index, Value::from(values.len())); + // Convert the destination pointer to a usize + let destination = self.memory.read_ref(*pointer_index); + // Write to our destination memory + self.memory.write_slice(destination, values); + } + _ => { + unreachable!("Function result size does not match brillig bytecode size") + } } + } else { + unimplemented!("deflattening heap vectors from foreign calls"); } } + _ => { + unreachable!("Unexpected value type {value_type:?} for destination {destination:?}"); + } } } @@ -291,26 +328,28 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.foreign_call_counter += 1; self.increment_program_counter() } - Opcode::Mov { destination: destination_register, source: source_register } => { - let source_value = self.registers.get(*source_register); - self.registers.set(*destination_register, source_value); + Opcode::Mov { destination: destination_address, source: source_address } => { + let source_value = self.memory.read(*source_address); + self.memory.write(*destination_address, source_value); self.increment_program_counter() } Opcode::Trap => self.fail("explicit trap hit in brillig".to_string()), - Opcode::Stop => self.finish(), - Opcode::Load { destination: destination_register, source_pointer } => { - // Convert our source_pointer to a usize - let source = self.registers.get(*source_pointer); + Opcode::Stop { return_data_offset, return_data_size } => { + self.finish(*return_data_offset, *return_data_size) + } + Opcode::Load { destination: destination_address, source_pointer } => { + // Convert our source_pointer to an address + let source = self.memory.read_ref(*source_pointer); // Use our usize source index to lookup the value in memory - let value = &self.memory.read(source.to_usize()); - self.registers.set(*destination_register, *value); + let value = &self.memory.read(source); + self.memory.write(*destination_address, *value); self.increment_program_counter() } - Opcode::Store { destination_pointer, source: source_register } => { - // Convert our destination_pointer to a usize - let destination = self.registers.get(*destination_pointer).to_usize(); + Opcode::Store { destination_pointer, source: source_address } => { + // Convert our destination_pointer to an address + let destination = self.memory.read_ref(*destination_pointer); // Use our usize destination index to set the value in memory - self.memory.write(destination, self.registers.get(*source_register)); + self.memory.write(destination, self.memory.read(*source_address)); self.increment_program_counter() } Opcode::Call { location } => { @@ -318,17 +357,12 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.call_stack.push(Value::from(self.program_counter)); self.set_program_counter(*location) } - Opcode::Const { destination, value } => { - self.registers.set(*destination, *value); + Opcode::Const { destination, value, bit_size: _ } => { + self.memory.write(*destination, *value); self.increment_program_counter() } Opcode::BlackBox(black_box_op) => { - match evaluate_black_box( - black_box_op, - self.black_box_solver, - &mut self.registers, - &mut self.memory, - ) { + match evaluate_black_box(black_box_op, self.black_box_solver, &mut self.memory) { Ok(()) => self.increment_program_counter(), Err(e) => self.fail(e.to_string()), } @@ -353,45 +387,106 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { assert!(self.program_counter < self.bytecode.len()); self.program_counter = value; if self.program_counter >= self.bytecode.len() { - self.status = VMStatus::Finished; + self.status = VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }; } self.status.clone() } - fn get_register_value_or_memory_values(&self, input: RegisterOrMemory) -> ForeignCallParam { - match input { - RegisterOrMemory::RegisterIndex(value_index) => self.registers.get(value_index).into(), - RegisterOrMemory::HeapArray(HeapArray { pointer: pointer_index, size }) => { - let start = self.registers.get(pointer_index); - self.memory.read_slice(start.to_usize(), size).to_vec().into() + fn get_memory_values( + &self, + input: ValueOrArray, + value_type: &HeapValueType, + ) -> ForeignCallParam { + match (input, value_type) { + (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple) => { + self.memory.read(value_index).into() + } + ( + ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), + HeapValueType::Array { value_types, size: type_size }, + ) if *type_size == size => { + let start = self.memory.read_ref(pointer_index); + self.read_slice_of_values_from_memory(start, size, value_types).into() + } + ( + ValueOrArray::HeapVector(HeapVector { pointer: pointer_index, size: size_index }), + HeapValueType::Vector { value_types }, + ) => { + let start = self.memory.read_ref(pointer_index); + let size = self.memory.read(size_index).to_usize(); + self.read_slice_of_values_from_memory(start, size, value_types).into() } - RegisterOrMemory::HeapVector(HeapVector { - pointer: pointer_index, - size: size_index, - }) => { - let start = self.registers.get(pointer_index); - let size = self.registers.get(size_index); - self.memory.read_slice(start.to_usize(), size.to_usize()).to_vec().into() + _ => { + unreachable!("Unexpected value type {value_type:?} for input {input:?}"); } } } + /// Reads an array/vector from memory but recursively reads pointers to + /// nested arrays/vectors according to the sequence of value types. + fn read_slice_of_values_from_memory( + &self, + start: MemoryAddress, + size: usize, + value_types: &[HeapValueType], + ) -> Vec { + if HeapValueType::all_simple(value_types) { + self.memory.read_slice(start, size).to_vec() + } else { + // Check that the sequence of value types fit an integer number of + // times inside the given size. + assert!( + 0 == size % value_types.len(), + "array/vector does not contain a whole number of elements" + ); + (0..size) + .zip(value_types.iter().cycle()) + .flat_map(|(i, value_type)| { + let value_address: MemoryAddress = (start.to_usize() + i).into(); + match value_type { + HeapValueType::Simple => { + let value = self.memory.read(value_address); + vec![value] + } + HeapValueType::Array { value_types, size } => { + let array_address = self.memory.read_ref(value_address); + let array_start = self.memory.read_ref(array_address); + self.read_slice_of_values_from_memory(array_start, *size, value_types) + } + HeapValueType::Vector { value_types } => { + let vector_address = self.memory.read_ref(value_address); + let vector_start = self.memory.read_ref(vector_address); + let size_address: MemoryAddress = + (vector_address.to_usize() + 1).into(); + let vector_size = self.memory.read(size_address).to_usize(); + self.read_slice_of_values_from_memory( + vector_start, + vector_size, + value_types, + ) + } + } + }) + .collect::>() + } + } + /// Process a binary operation. /// This method will not modify the program counter. fn process_binary_field_op( &mut self, op: BinaryFieldOp, - lhs: RegisterIndex, - rhs: RegisterIndex, - result: RegisterIndex, + lhs: MemoryAddress, + rhs: MemoryAddress, + result: MemoryAddress, ) { - let lhs_value = self.registers.get(lhs); - let rhs_value = self.registers.get(rhs); + let lhs_value = self.memory.read(lhs); + let rhs_value = self.memory.read(rhs); let result_value = evaluate_binary_field_op(&op, lhs_value.to_field(), rhs_value.to_field()); - self.registers.set(result, result_value.into()); + self.memory.write(result, result_value.into()); } /// Process a binary operation. @@ -400,20 +495,20 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { &mut self, op: BinaryIntOp, bit_size: u32, - lhs: RegisterIndex, - rhs: RegisterIndex, - result: RegisterIndex, + lhs: MemoryAddress, + rhs: MemoryAddress, + result: MemoryAddress, ) -> Result<(), String> { - let lhs_value = self.registers.get(lhs); - let rhs_value = self.registers.get(rhs); + let lhs_value = self.memory.read(lhs); + let rhs_value = self.memory.read(rhs); // Convert to big integers let lhs_big = BigUint::from_bytes_be(&lhs_value.to_field().to_be_bytes()); let rhs_big = BigUint::from_bytes_be(&rhs_value.to_field().to_be_bytes()); let result_value = evaluate_binary_bigint_op(&op, lhs_big, rhs_big, bit_size)?; // Convert back to field element - self.registers - .set(result, FieldElement::from_be_bytes_reduce(&result_value.to_bytes_be()).into()); + self.memory + .write(result, FieldElement::from_be_bytes_reduce(&result_value.to_bytes_be()).into()); Ok(()) } } @@ -468,111 +563,123 @@ mod tests { #[test] fn add_single_step_smoke() { - // Load values into registers and initialize the registers that - // will be used during bytecode processing - let input_registers = - Registers::load(vec![Value::from(1u128), Value::from(2u128), Value::from(0u128)]); - - // Add opcode to add the value in register `0` and `1` - // and place the output in register `2` - let opcode = Opcode::BinaryIntOp { - op: BinaryIntOp::Add, - bit_size: 2, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(2), + let calldata = vec![Value::from(27u128)]; + + // Add opcode to add the value in address `0` and `1` + // and place the output in address `2` + let calldata_copy = Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: 1, + offset: 0, }; // Start VM - let opcodes = [opcode]; - let mut vm = VM::new(input_registers, vec![], &opcodes, vec![], &DummyBlackBoxSolver); + let opcodes = [calldata_copy]; + let mut vm = VM::new(calldata, &opcodes, vec![], &DummyBlackBoxSolver); // Process a single VM opcode // // After processing a single opcode, we should have // the vm status as finished since there is only one opcode let status = vm.process_opcode(); - assert_eq!(status, VMStatus::Finished); + assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); - // The register at index `2` should have the value of 3 since we had an + // The address at index `2` should have the value of 3 since we had an // add opcode - let VM { registers, .. } = vm; - let output_value = registers.get(RegisterIndex::from(2)); + let VM { memory, .. } = vm; + let output_value = memory.read(MemoryAddress::from(0)); - assert_eq!(output_value, Value::from(3u128)); + assert_eq!(output_value, Value::from(27u128)); } #[test] fn jmpif_opcode() { - let mut registers = vec![]; + let mut calldata = vec![]; let mut opcodes = vec![]; let lhs = { - registers.push(Value::from(2u128)); - RegisterIndex::from(registers.len() - 1) + calldata.push(Value::from(2u128)); + MemoryAddress::from(calldata.len() - 1) }; let rhs = { - registers.push(Value::from(2u128)); - RegisterIndex::from(registers.len() - 1) + calldata.push(Value::from(2u128)); + MemoryAddress::from(calldata.len() - 1) }; - let destination = { - registers.push(Value::from(0u128)); - RegisterIndex::from(registers.len() - 1) - }; + let destination = MemoryAddress::from(calldata.len()); + opcodes.push(Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: 2, + offset: 0, + }); let equal_cmp_opcode = Opcode::BinaryIntOp { op: BinaryIntOp::Equals, bit_size: 1, lhs, rhs, destination }; opcodes.push(equal_cmp_opcode); - opcodes.push(Opcode::Jump { location: 2 }); - opcodes.push(Opcode::JumpIf { condition: RegisterIndex::from(2), location: 3 }); + opcodes.push(Opcode::Jump { location: 3 }); + opcodes.push(Opcode::JumpIf { condition: MemoryAddress::from(2), location: 4 }); + + let mut vm = VM::new(calldata, &opcodes, vec![], &DummyBlackBoxSolver); - let mut vm = - VM::new(Registers::load(registers), vec![], &opcodes, vec![], &DummyBlackBoxSolver); + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let output_cmp_value = vm.registers.get(RegisterIndex::from(2)); + let output_cmp_value = vm.memory.read(MemoryAddress::from(2)); assert_eq!(output_cmp_value, Value::from(true)); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); let status = vm.process_opcode(); - assert_eq!(status, VMStatus::Finished); + assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); } #[test] fn jmpifnot_opcode() { - let input_registers = - Registers::load(vec![Value::from(1u128), Value::from(2u128), Value::from(0u128)]); + let calldata = vec![Value::from(1u128), Value::from(2u128)]; + + let calldata_copy = Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: 2, + offset: 0, + }; + + let jump_opcode = Opcode::Jump { location: 3 }; let trap_opcode = Opcode::Trap; let not_equal_cmp_opcode = Opcode::BinaryFieldOp { op: BinaryFieldOp::Equals, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(2), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(2), }; - let jump_opcode = Opcode::Jump { location: 2 }; - let jump_if_not_opcode = - Opcode::JumpIfNot { condition: RegisterIndex::from(2), location: 1 }; + Opcode::JumpIfNot { condition: MemoryAddress::from(2), location: 2 }; let add_opcode = Opcode::BinaryFieldOp { op: BinaryFieldOp::Add, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(2), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(2), }; - let opcodes = - [jump_opcode, trap_opcode, not_equal_cmp_opcode, jump_if_not_opcode, add_opcode]; - let mut vm = VM::new(input_registers, vec![], &opcodes, vec![], &DummyBlackBoxSolver); + let opcodes = [ + calldata_copy, + jump_opcode, + trap_opcode, + not_equal_cmp_opcode, + jump_if_not_opcode, + add_opcode, + ]; + let mut vm = VM::new(calldata, &opcodes, vec![], &DummyBlackBoxSolver); + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -580,7 +687,7 @@ mod tests { let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let output_cmp_value = vm.registers.get(RegisterIndex::from(2)); + let output_cmp_value = vm.memory.read(MemoryAddress::from(2)); assert_eq!(output_cmp_value, Value::from(false)); let status = vm.process_opcode(); @@ -591,107 +698,130 @@ mod tests { status, VMStatus::Failure { message: "explicit trap hit in brillig".to_string(), - call_stack: vec![1] + call_stack: vec![2] } ); - // The register at index `2` should have not changed as we jumped over the add opcode - let VM { registers, .. } = vm; - let output_value = registers.get(RegisterIndex::from(2)); + // The address at index `2` should have not changed as we jumped over the add opcode + let VM { memory, .. } = vm; + let output_value = memory.read(MemoryAddress::from(2)); assert_eq!(output_value, Value::from(false)); } #[test] fn mov_opcode() { - let input_registers = - Registers::load(vec![Value::from(1u128), Value::from(2u128), Value::from(3u128)]); + let calldata = vec![Value::from(1u128), Value::from(2u128), Value::from(3u128)]; + + let calldata_copy = Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: 3, + offset: 0, + }; let mov_opcode = - Opcode::Mov { destination: RegisterIndex::from(2), source: RegisterIndex::from(0) }; + Opcode::Mov { destination: MemoryAddress::from(2), source: MemoryAddress::from(0) }; + + let opcodes = &[calldata_copy, mov_opcode]; + let mut vm = VM::new(calldata, opcodes, vec![], &DummyBlackBoxSolver); - let opcodes = &[mov_opcode]; - let mut vm = VM::new(input_registers, vec![], opcodes, vec![], &DummyBlackBoxSolver); + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); let status = vm.process_opcode(); - assert_eq!(status, VMStatus::Finished); + assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); - let VM { registers, .. } = vm; + let VM { memory, .. } = vm; - let destination_value = registers.get(RegisterIndex::from(2)); + let destination_value = memory.read(MemoryAddress::from(2)); assert_eq!(destination_value, Value::from(1u128)); - let source_value = registers.get(RegisterIndex::from(0)); + let source_value = memory.read(MemoryAddress::from(0)); assert_eq!(source_value, Value::from(1u128)); } #[test] fn cmp_binary_ops() { let bit_size = 32; - let input_registers = Registers::load(vec![ + let calldata = vec![ Value::from(2u128), Value::from(2u128), Value::from(0u128), Value::from(5u128), Value::from(6u128), - ]); + ]; + + let calldata_copy = Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: 5, + offset: 0, + }; let equal_opcode = Opcode::BinaryIntOp { bit_size, op: BinaryIntOp::Equals, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(2), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(2), }; let not_equal_opcode = Opcode::BinaryIntOp { bit_size, op: BinaryIntOp::Equals, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(3), - destination: RegisterIndex::from(2), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(3), + destination: MemoryAddress::from(2), }; let less_than_opcode = Opcode::BinaryIntOp { bit_size, op: BinaryIntOp::LessThan, - lhs: RegisterIndex::from(3), - rhs: RegisterIndex::from(4), - destination: RegisterIndex::from(2), + lhs: MemoryAddress::from(3), + rhs: MemoryAddress::from(4), + destination: MemoryAddress::from(2), }; let less_than_equal_opcode = Opcode::BinaryIntOp { bit_size, op: BinaryIntOp::LessThanEquals, - lhs: RegisterIndex::from(3), - rhs: RegisterIndex::from(4), - destination: RegisterIndex::from(2), + lhs: MemoryAddress::from(3), + rhs: MemoryAddress::from(4), + destination: MemoryAddress::from(2), }; - let opcodes = [equal_opcode, not_equal_opcode, less_than_opcode, less_than_equal_opcode]; - let mut vm = VM::new(input_registers, vec![], &opcodes, vec![], &DummyBlackBoxSolver); + let opcodes = [ + calldata_copy, + equal_opcode, + not_equal_opcode, + less_than_opcode, + less_than_equal_opcode, + ]; + let mut vm = VM::new(calldata, &opcodes, vec![], &DummyBlackBoxSolver); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let output_eq_value = vm.registers.get(RegisterIndex::from(2)); + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + + let output_eq_value = vm.memory.read(MemoryAddress::from(2)); assert_eq!(output_eq_value, Value::from(true)); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let output_neq_value = vm.registers.get(RegisterIndex::from(2)); + let output_neq_value = vm.memory.read(MemoryAddress::from(2)); assert_eq!(output_neq_value, Value::from(false)); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let lt_value = vm.registers.get(RegisterIndex::from(2)); + let lt_value = vm.memory.read(MemoryAddress::from(2)); assert_eq!(lt_value, Value::from(true)); let status = vm.process_opcode(); - assert_eq!(status, VMStatus::Finished); + assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); - let lte_value = vm.registers.get(RegisterIndex::from(2)); + let lte_value = vm.memory.read(MemoryAddress::from(2)); assert_eq!(lte_value, Value::from(true)); } #[test] @@ -703,22 +833,30 @@ mod tests { /// memory[i] = i as Value; /// i += 1; /// } - fn brillig_write_memory(memory: Vec) -> Vec { + fn brillig_write_memory(item_count: usize) -> Vec { let bit_size = 32; - let r_i = RegisterIndex::from(0); - let r_len = RegisterIndex::from(1); - let r_tmp = RegisterIndex::from(2); + let r_i = MemoryAddress::from(0); + let r_len = MemoryAddress::from(1); + let r_tmp = MemoryAddress::from(2); + let r_pointer = MemoryAddress::from(3); + let start = [ // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into() }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, // len = memory.len() (approximation) - Opcode::Const { destination: r_len, value: Value::from(memory.len() as u128) }, + Opcode::Const { + destination: r_len, + value: Value::from(item_count as u128), + bit_size: 32, + }, + // pointer = free_memory_ptr + Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size: 32 }, ]; let loop_body = [ // *i = i - Opcode::Store { destination_pointer: r_i, source: r_i }, + Opcode::Store { destination_pointer: r_pointer, source: r_i }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into() }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -727,6 +865,14 @@ mod tests { rhs: r_tmp, bit_size, }, + // pointer = pointer + 1 + Opcode::BinaryIntOp { + destination: r_pointer, + lhs: r_pointer, + op: BinaryIntOp::Add, + rhs: r_tmp, + bit_size, + }, // tmp = i < len Opcode::BinaryIntOp { destination: r_tmp, @@ -740,11 +886,11 @@ mod tests { ]; let opcodes = [&start[..], &loop_body[..]].concat(); - let vm = brillig_execute_and_get_vm(memory, &opcodes); - vm.get_memory().to_vec() + let vm = brillig_execute_and_get_vm(vec![], &opcodes); + vm.get_memory()[4..].to_vec() } - let memory = brillig_write_memory(vec![Value::from(0u128); 5]); + let memory = brillig_write_memory(5); let expected = vec![ Value::from(0u128), Value::from(1u128), @@ -754,7 +900,7 @@ mod tests { ]; assert_eq!(memory, expected); - let memory = brillig_write_memory(vec![Value::from(0u128); 1024]); + let memory = brillig_write_memory(1024); let expected: Vec = (0..1024).map(|i| Value::from(i as u128)).collect(); assert_eq!(memory, expected); } @@ -771,21 +917,34 @@ mod tests { /// } fn brillig_sum_memory(memory: Vec) -> Value { let bit_size = 32; - let r_i = RegisterIndex::from(0); - let r_len = RegisterIndex::from(1); - let r_sum = RegisterIndex::from(2); - let r_tmp = RegisterIndex::from(3); + let r_i = MemoryAddress::from(0); + let r_len = MemoryAddress::from(1); + let r_sum = MemoryAddress::from(2); + let r_tmp = MemoryAddress::from(3); + let r_pointer = MemoryAddress::from(4); + let start = [ // sum = 0 - Opcode::Const { destination: r_sum, value: 0u128.into() }, + Opcode::Const { destination: r_sum, value: 0u128.into(), bit_size: 32 }, // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into() }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, // len = array.len() (approximation) - Opcode::Const { destination: r_len, value: Value::from(memory.len() as u128) }, + Opcode::Const { + destination: r_len, + value: Value::from(memory.len() as u128), + bit_size: 32, + }, + // pointer = array_ptr + Opcode::Const { destination: r_pointer, value: 5u128.into(), bit_size: 32 }, + Opcode::CalldataCopy { + destination_address: MemoryAddress(5), + size: memory.len(), + offset: 0, + }, ]; let loop_body = [ // tmp = *i - Opcode::Load { destination: r_tmp, source_pointer: r_i }, + Opcode::Load { destination: r_tmp, source_pointer: r_pointer }, // sum = sum + tmp Opcode::BinaryIntOp { destination: r_sum, @@ -795,7 +954,7 @@ mod tests { bit_size, }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into() }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -804,6 +963,14 @@ mod tests { rhs: r_tmp, bit_size, }, + // pointer = pointer + 1 + Opcode::BinaryIntOp { + destination: r_pointer, + lhs: r_pointer, + op: BinaryIntOp::Add, + rhs: r_tmp, + bit_size, + }, // tmp = i < len Opcode::BinaryIntOp { destination: r_tmp, @@ -818,7 +985,7 @@ mod tests { let opcodes = [&start[..], &loop_body[..]].concat(); let vm = brillig_execute_and_get_vm(memory, &opcodes); - vm.registers.get(r_sum) + vm.memory.read(r_sum) } assert_eq!( @@ -844,21 +1011,24 @@ mod tests { /// memory[i as usize] = i as Value; /// recursive_write(memory, i + 1, len); /// } - /// Note we represent a 100% in-register optimized form in brillig - fn brillig_recursive_write_memory(memory: Vec) -> Vec { + /// Note we represent a 100% in-stack optimized form in brillig + fn brillig_recursive_write_memory(size: usize) -> Vec { let bit_size = 32; - let r_i = RegisterIndex::from(0); - let r_len = RegisterIndex::from(1); - let r_tmp = RegisterIndex::from(2); + let r_i = MemoryAddress::from(0); + let r_len = MemoryAddress::from(1); + let r_tmp = MemoryAddress::from(2); + let r_pointer = MemoryAddress::from(3); let start = [ // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into() }, - // len = memory.len() (approximation) - Opcode::Const { destination: r_len, value: Value::from(memory.len() as u128) }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, + // len = size + Opcode::Const { destination: r_len, value: size.into(), bit_size: 32 }, + // pointer = free_memory_ptr + Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size: 32 }, // call recursive_fn Opcode::Call { - location: 4, // Call after 'start' + location: 5, // Call after 'start' }, // end program by jumping to end Opcode::Jump { location: 100 }, @@ -876,12 +1046,12 @@ mod tests { // if !tmp, goto end Opcode::JumpIf { condition: r_tmp, - location: start.len() + 6, // 7 ops in recursive_fn, go to 'Return' + location: start.len() + 7, // 8 ops in recursive_fn, go to 'Return' }, // *i = i - Opcode::Store { destination_pointer: r_i, source: r_i }, + Opcode::Store { destination_pointer: r_pointer, source: r_i }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into() }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -890,17 +1060,25 @@ mod tests { rhs: r_tmp, bit_size, }, + // pointer = pointer + 1 + Opcode::BinaryIntOp { + destination: r_pointer, + lhs: r_pointer, + op: BinaryIntOp::Add, + rhs: r_tmp, + bit_size, + }, // call recursive_fn Opcode::Call { location: start.len() }, Opcode::Return {}, ]; let opcodes = [&start[..], &recursive_fn[..]].concat(); - let vm = brillig_execute_and_get_vm(memory, &opcodes); - vm.get_memory().to_vec() + let vm = brillig_execute_and_get_vm(vec![], &opcodes); + vm.get_memory()[4..].to_vec() } - let memory = brillig_recursive_write_memory(vec![Value::from(0u128); 5]); + let memory = brillig_recursive_write_memory(5); let expected = vec![ Value::from(0u128), Value::from(1u128), @@ -910,20 +1088,17 @@ mod tests { ]; assert_eq!(memory, expected); - let memory = brillig_recursive_write_memory(vec![Value::from(0u128); 1024]); + let memory = brillig_recursive_write_memory(1024); let expected: Vec = (0..1024).map(|i| Value::from(i as u128)).collect(); assert_eq!(memory, expected); } - fn empty_registers() -> Registers { - Registers::load(vec![Value::from(0u128); 16]) - } /// Helper to execute brillig code fn brillig_execute_and_get_vm( - memory: Vec, + calldata: Vec, opcodes: &[Opcode], ) -> VM<'_, DummyBlackBoxSolver> { - let mut vm = VM::new(empty_registers(), memory, opcodes, vec![], &DummyBlackBoxSolver); + let mut vm = VM::new(calldata, opcodes, vec![], &DummyBlackBoxSolver); brillig_execute(&mut vm); assert_eq!(vm.call_stack, vec![]); vm @@ -932,7 +1107,7 @@ mod tests { fn brillig_execute(vm: &mut VM) { loop { let status = vm.process_opcode(); - if matches!(status, VMStatus::Finished | VMStatus::ForeignCallWait { .. }) { + if matches!(status, VMStatus::Finished { .. } | VMStatus::ForeignCallWait { .. }) { break; } assert_eq!(status, VMStatus::InProgress); @@ -940,18 +1115,20 @@ mod tests { } #[test] - fn foreign_call_opcode_register_result() { - let r_input = RegisterIndex::from(0); - let r_result = RegisterIndex::from(1); + fn foreign_call_opcode_simple_result() { + let r_input = MemoryAddress::from(0); + let r_result = MemoryAddress::from(1); let double_program = vec![ - // Load input register with value 5 - Opcode::Const { destination: r_input, value: Value::from(5u128) }, - // Call foreign function "double" with the input register + // Load input address with value 5 + Opcode::Const { destination: r_input, value: Value::from(5u128), bit_size: 32 }, + // Call foreign function "double" with the input address Opcode::ForeignCall { function: "double".into(), - destinations: vec![RegisterOrMemory::RegisterIndex(r_result)], - inputs: vec![RegisterOrMemory::RegisterIndex(r_input)], + destinations: vec![ValueOrArray::MemoryAddress(r_result)], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::MemoryAddress(r_input)], + input_value_types: vec![HeapValueType::Simple], }, ]; @@ -975,19 +1152,20 @@ mod tests { brillig_execute(&mut vm); // Check that VM finished once resumed - assert_eq!(vm.status, VMStatus::Finished); + assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); - // Check result register - let result_value = vm.registers.get(r_result); + // Check result address + let result_value = vm.memory.read(r_result); assert_eq!(result_value, Value::from(10u128)); // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); } + #[test] fn foreign_call_opcode_memory_result() { - let r_input = RegisterIndex::from(0); - let r_output = RegisterIndex::from(1); + let r_input = MemoryAddress::from(0); + let r_output = MemoryAddress::from(1); // Define a simple 2x2 matrix in memory let initial_matrix = @@ -998,21 +1176,34 @@ mod tests { vec![Value::from(1u128), Value::from(3u128), Value::from(2u128), Value::from(4u128)]; let invert_program = vec![ + Opcode::CalldataCopy { + destination_address: MemoryAddress::from(2), + size: initial_matrix.len(), + offset: 0, + }, // input = 0 - Opcode::Const { destination: r_input, value: Value::from(0u128) }, + Opcode::Const { destination: r_input, value: 2_usize.into(), bit_size: 32 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(0u128) }, + Opcode::Const { destination: r_output, value: 2_usize.into(), bit_size: 32 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), - destinations: vec![RegisterOrMemory::HeapArray(HeapArray { + destinations: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_output, size: initial_matrix.len(), })], - inputs: vec![RegisterOrMemory::HeapArray(HeapArray { + destination_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], + inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), })], + input_value_types: vec![HeapValueType::Array { + value_types: vec![HeapValueType::Simple], + size: initial_matrix.len(), + }], }, ]; @@ -1034,10 +1225,10 @@ mod tests { brillig_execute(&mut vm); // Check that VM finished once resumed - assert_eq!(vm.status, VMStatus::Finished); + assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check result in memory - let result_values = vm.memory.read_slice(0, 4).to_vec(); + let result_values = vm.memory.read_slice(MemoryAddress(2), 4).to_vec(); assert_eq!(result_values, expected_result); // Ensure the foreign call counter has been incremented @@ -1047,11 +1238,11 @@ mod tests { /// Calling a simple foreign call function that takes any string input, concatenates it with itself, and reverses the concatenation #[test] fn foreign_call_opcode_vector_input_and_output() { - let r_input_pointer = RegisterIndex::from(0); - let r_input_size = RegisterIndex::from(1); + let r_input_pointer = MemoryAddress::from(0); + let r_input_size = MemoryAddress::from(1); // We need to pass a location of appropriate size - let r_output_pointer = RegisterIndex::from(2); - let r_output_size = RegisterIndex::from(3); + let r_output_pointer = MemoryAddress::from(2); + let r_output_size = MemoryAddress::from(3); // Our first string to use the identity function with let input_string = @@ -1064,28 +1255,48 @@ mod tests { // First call: let string_double_program = vec![ - // input_pointer = 0 - Opcode::Const { destination: r_input_pointer, value: Value::from(0u128) }, + Opcode::CalldataCopy { + destination_address: MemoryAddress(4), + size: input_string.len(), + offset: 0, + }, + // input_pointer = 4 + Opcode::Const { destination: r_input_pointer, value: Value::from(4u128), bit_size: 32 }, // input_size = input_string.len() (constant here) - Opcode::Const { destination: r_input_size, value: Value::from(input_string.len()) }, - // output_pointer = 0 + input_size = input_size - Opcode::Const { destination: r_output_pointer, value: Value::from(input_string.len()) }, + Opcode::Const { + destination: r_input_size, + value: Value::from(input_string.len()), + bit_size: 32, + }, + // output_pointer = 4 + input_size + Opcode::Const { + destination: r_output_pointer, + value: Value::from(4 + input_string.len()), + bit_size: 32, + }, // output_size = input_size * 2 Opcode::Const { destination: r_output_size, value: Value::from(input_string.len() * 2), + bit_size: 32, }, // output_pointer[0..output_size] = string_double(input_pointer[0...input_size]) Opcode::ForeignCall { function: "string_double".into(), - destinations: vec![RegisterOrMemory::HeapVector(HeapVector { + destinations: vec![ValueOrArray::HeapVector(HeapVector { pointer: r_output_pointer, size: r_output_size, })], - inputs: vec![RegisterOrMemory::HeapVector(HeapVector { + destination_value_types: vec![HeapValueType::Vector { + value_types: vec![HeapValueType::Simple], + }], + inputs: vec![ValueOrArray::HeapVector(HeapVector { pointer: r_input_pointer, size: r_input_size, })], + input_value_types: vec![HeapValueType::Vector { + value_types: vec![HeapValueType::Simple], + }], }, ]; @@ -1109,10 +1320,13 @@ mod tests { brillig_execute(&mut vm); // Check that VM finished once resumed - assert_eq!(vm.status, VMStatus::Finished); + assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check result in memory - let result_values = vm.memory.read_slice(input_string.len(), output_string.len()).to_vec(); + let result_values = vm + .memory + .read_slice(MemoryAddress(4 + input_string.len()), output_string.len()) + .to_vec(); assert_eq!(result_values, output_string); // Ensure the foreign call counter has been incremented @@ -1121,8 +1335,8 @@ mod tests { #[test] fn foreign_call_opcode_memory_alloc_result() { - let r_input = RegisterIndex::from(0); - let r_output = RegisterIndex::from(1); + let r_input = MemoryAddress::from(0); + let r_output = MemoryAddress::from(1); // Define a simple 2x2 matrix in memory let initial_matrix = @@ -1133,21 +1347,34 @@ mod tests { vec![Value::from(1u128), Value::from(3u128), Value::from(2u128), Value::from(4u128)]; let invert_program = vec![ + Opcode::CalldataCopy { + destination_address: MemoryAddress::from(2), + size: initial_matrix.len(), + offset: 0, + }, // input = 0 - Opcode::Const { destination: r_input, value: Value::from(0u128) }, + Opcode::Const { destination: r_input, value: Value::from(2u128), bit_size: 32 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(4u128) }, + Opcode::Const { destination: r_output, value: Value::from(6u128), bit_size: 32 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), - destinations: vec![RegisterOrMemory::HeapArray(HeapArray { + destinations: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_output, size: initial_matrix.len(), })], - inputs: vec![RegisterOrMemory::HeapArray(HeapArray { + destination_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], + inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), })], + input_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], }, ]; @@ -1169,14 +1396,14 @@ mod tests { brillig_execute(&mut vm); // Check that VM finished once resumed - assert_eq!(vm.status, VMStatus::Finished); + assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check initial memory still in place - let initial_values = vm.memory.read_slice(0, 4).to_vec(); + let initial_values = vm.memory.read_slice(MemoryAddress(2), 4).to_vec(); assert_eq!(initial_values, initial_matrix); // Check result in memory - let result_values = vm.memory.read_slice(4, 4).to_vec(); + let result_values = vm.memory.read_slice(MemoryAddress(6), 4).to_vec(); assert_eq!(result_values, expected_result); // Ensure the foreign call counter has been incremented @@ -1185,9 +1412,9 @@ mod tests { #[test] fn foreign_call_opcode_multiple_array_inputs_result() { - let r_input_a = RegisterIndex::from(0); - let r_input_b = RegisterIndex::from(1); - let r_output = RegisterIndex::from(2); + let r_input_a = MemoryAddress::from(0); + let r_input_b = MemoryAddress::from(1); + let r_output = MemoryAddress::from(2); // Define a simple 2x2 matrix in memory let matrix_a = @@ -1209,28 +1436,41 @@ mod tests { ]; let matrix_mul_program = vec![ - // input = 0 - Opcode::Const { destination: r_input_a, value: Value::from(0u128) }, - // input = 0 - Opcode::Const { destination: r_input_b, value: Value::from(4u128) }, + Opcode::CalldataCopy { + destination_address: MemoryAddress::from(3), + size: matrix_a.len() + matrix_b.len(), + offset: 0, + }, + // input = 3 + Opcode::Const { destination: r_input_a, value: Value::from(3u128), bit_size: 32 }, + // input = 7 + Opcode::Const { destination: r_input_b, value: Value::from(7u128), bit_size: 32 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(0u128) }, + Opcode::Const { destination: r_output, value: Value::from(0u128), bit_size: 32 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), - destinations: vec![RegisterOrMemory::HeapArray(HeapArray { + destinations: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_output, size: matrix_a.len(), })], + destination_value_types: vec![HeapValueType::Array { + size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ - RegisterOrMemory::HeapArray(HeapArray { - pointer: r_input_a, + ValueOrArray::HeapArray(HeapArray { pointer: r_input_a, size: matrix_a.len() }), + ValueOrArray::HeapArray(HeapArray { pointer: r_input_b, size: matrix_b.len() }), + ], + input_value_types: vec![ + HeapValueType::Array { size: matrix_a.len(), - }), - RegisterOrMemory::HeapArray(HeapArray { - pointer: r_input_b, + value_types: vec![HeapValueType::Simple], + }, + HeapValueType::Array { size: matrix_b.len(), - }), + value_types: vec![HeapValueType::Simple], + }, ], }, ]; @@ -1254,13 +1494,130 @@ mod tests { brillig_execute(&mut vm); // Check that VM finished once resumed - assert_eq!(vm.status, VMStatus::Finished); + assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check result in memory - let result_values = vm.memory.read_slice(0, 4).to_vec(); + let result_values = vm.memory.read_slice(MemoryAddress(0), 4).to_vec(); assert_eq!(result_values, expected_result); // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); } + + #[test] + fn foreign_call_opcode_nested_arrays_and_slices_input() { + // [(1, <2,3>, [4]), (5, <6,7,8>, [9])] + + let v2 = vec![Value::from(2u128), Value::from(3u128)]; + let a4 = vec![Value::from(4u128)]; + let v6 = vec![Value::from(6u128), Value::from(7u128), Value::from(8u128)]; + let a9 = vec![Value::from(9u128)]; + + // construct memory by declaring all inner arrays/vectors first + let v2_ptr = 0u128; + let mut memory = v2.clone(); + let v2_start = memory.len(); + memory.extend(vec![Value::from(v2_ptr), Value::from(v2.len()), Value::from(1u128)]); + let a4_ptr = memory.len(); + memory.extend(a4.clone()); + let a4_start = memory.len(); + memory.extend(vec![Value::from(a4_ptr), Value::from(1u128)]); + let v6_ptr = memory.len(); + memory.extend(v6.clone()); + let v6_start = memory.len(); + memory.extend(vec![Value::from(v6_ptr), Value::from(v6.len()), Value::from(1u128)]); + let a9_ptr = memory.len(); + memory.extend(a9.clone()); + let a9_start = memory.len(); + memory.extend(vec![Value::from(a9_ptr), Value::from(1u128)]); + // finally we add the contents of the outer array + let outer_ptr = memory.len(); + let outer_array = vec![ + Value::from(1u128), + Value::from(v2.len()), + Value::from(v2_start), + Value::from(a4_start), + Value::from(5u128), + Value::from(v6.len()), + Value::from(v6_start), + Value::from(a9_start), + ]; + memory.extend(outer_array.clone()); + + let input_array_value_types = vec![ + HeapValueType::Simple, + HeapValueType::Simple, // size of following vector + HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }, + HeapValueType::Array { value_types: vec![HeapValueType::Simple], size: 1 }, + ]; + + // memory address of the end of the above data structures + let r_ptr = memory.len(); + + let r_input = MemoryAddress::from(r_ptr); + let r_output = MemoryAddress::from(r_ptr + 1); + + let program = vec![ + Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: memory.len(), + offset: 0, + }, + // input = 0 + Opcode::Const { destination: r_input, value: Value::from(outer_ptr), bit_size: 32 }, + // some_function(input) + Opcode::ForeignCall { + function: "flat_sum".into(), + destinations: vec![ValueOrArray::MemoryAddress(r_output)], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::HeapArray(HeapArray { + pointer: r_input, + size: outer_array.len(), + })], + input_value_types: vec![HeapValueType::Array { + value_types: input_array_value_types, + size: outer_array.len(), + }], + }, + ]; + + let mut vm = brillig_execute_and_get_vm(memory, &program); + + // Check that VM is waiting + assert_eq!( + vm.status, + VMStatus::ForeignCallWait { + function: "flat_sum".into(), + inputs: vec![ForeignCallParam::Array(vec![ + Value::from(1u128), + Value::from(2u128), // size of following vector + Value::from(2u128), + Value::from(3u128), + Value::from(4u128), + Value::from(5u128), + Value::from(3u128), // size of following vector + Value::from(6u128), + Value::from(7u128), + Value::from(8u128), + Value::from(9u128), + ])], + } + ); + + // Push result we're waiting for + vm.resolve_foreign_call(Value::from(45u128).into()); + + // Resume VM + brillig_execute(&mut vm); + + // Check that VM finished once resumed + assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); + + // Check result + let result_value = vm.memory.read(r_output); + assert_eq!(result_value, Value::from(45u128)); + + // Ensure the foreign call counter has been incremented + assert_eq!(vm.foreign_call_counter, 1); + } } diff --git a/acvm-repo/brillig_vm/src/memory.rs b/acvm-repo/brillig_vm/src/memory.rs index 8a6993f1353..d1c81447170 100644 --- a/acvm-repo/brillig_vm/src/memory.rs +++ b/acvm-repo/brillig_vm/src/memory.rs @@ -1,41 +1,45 @@ +use acir::{brillig::MemoryAddress, FieldElement}; + use crate::Value; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct Memory { // Memory is a vector of values. // We grow the memory when values past the end are set, extending with 0s. inner: Vec, } -impl From> for Memory { - fn from(values: Vec) -> Self { - Memory { inner: values } - } -} - impl Memory { /// Gets the value at pointer - pub fn read(&self, ptr: usize) -> Value { - self.inner[ptr] + pub fn read(&self, ptr: MemoryAddress) -> Value { + self.inner.get(ptr.to_usize()).copied().unwrap_or(0_u128.into()) } - pub fn read_slice(&self, ptr: usize, len: usize) -> &[Value] { - &self.inner[ptr..ptr + len] + pub fn read_ref(&self, ptr: MemoryAddress) -> MemoryAddress { + MemoryAddress(self.read(ptr).to_usize()) + } + + pub fn read_slice(&self, addr: MemoryAddress, len: usize) -> &[Value] { + &self.inner[addr.to_usize()..(addr.to_usize() + len)] } /// Sets the value at pointer `ptr` to `value` - pub fn write(&mut self, ptr: usize, value: Value) { - self.write_slice(ptr, &[value]); + pub fn write(&mut self, ptr: MemoryAddress, value: Value) { + self.resize_to_fit(ptr.to_usize() + 1); + self.inner[ptr.to_usize()] = value; } - /// Sets the values after pointer `ptr` to `values` - pub fn write_slice(&mut self, ptr: usize, values: &[Value]) { + fn resize_to_fit(&mut self, size: usize) { // Calculate new memory size - let new_size = std::cmp::max(self.inner.len(), ptr + values.len()); + let new_size = std::cmp::max(self.inner.len(), size); // Expand memory to new size with default values if needed - self.inner.resize(new_size, Value::from(0_usize)); + self.inner.resize(new_size, Value::from(FieldElement::zero())); + } - self.inner[ptr..ptr + values.len()].copy_from_slice(values); + /// Sets the values after pointer `ptr` to `values` + pub fn write_slice(&mut self, ptr: MemoryAddress, values: &[Value]) { + self.resize_to_fit(ptr.to_usize() + values.len()); + self.inner[ptr.to_usize()..(ptr.to_usize() + values.len())].copy_from_slice(values); } /// Returns the values of the memory diff --git a/acvm-repo/brillig_vm/src/registers.rs b/acvm-repo/brillig_vm/src/registers.rs deleted file mode 100644 index fcc596dd6c9..00000000000 --- a/acvm-repo/brillig_vm/src/registers.rs +++ /dev/null @@ -1,43 +0,0 @@ -use acir::brillig::{RegisterIndex, Value}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Registers { - // Registers are a vector of values. - // We grow the register as registers past the end are set, extending with 0s. - pub inner: Vec, -} - -/// Aims to match a reasonable max register count for a SNARK prover. -/// As well, catches obvious erroneous use of registers. -/// This can be revisited if it proves not enough. -const MAX_REGISTERS: usize = 2_usize.pow(16); - -/// Registers will store field element values during the -/// duration of the execution of the bytecode. -impl Registers { - /// Create a Registers object initialized with definite values - pub fn load(values: Vec) -> Registers { - let inner = values.into_iter().collect(); - Self { inner } - } - - /// Gets the values at register with address `index` - pub fn get(&self, register_index: RegisterIndex) -> Value { - let index = register_index.to_usize(); - assert!(index < MAX_REGISTERS, "Reading register past maximum!"); - let value = self.inner.get(index); - match value { - Some(value) => *value, - None => 0u128.into(), - } - } - - /// Sets the value at register with address `index` to `value` - pub fn set(&mut self, RegisterIndex(index): RegisterIndex, value: Value) { - assert!(index < MAX_REGISTERS, "Writing register past maximum!"); - // if size isn't at least index + 1, resize - let new_register_size = std::cmp::max(index + 1, self.inner.len()); - self.inner.resize(new_register_size, 0u128.into()); - self.inner[index] = value; - } -} diff --git a/aztec_macros/Cargo.toml b/aztec_macros/Cargo.toml index 04f74d3b022..5e908b2e672 100644 --- a/aztec_macros/Cargo.toml +++ b/aztec_macros/Cargo.toml @@ -12,3 +12,4 @@ repository.workspace = true [dependencies] noirc_frontend.workspace = true iter-extended.workspace = true +convert_case = "0.6.0" diff --git a/aztec_macros/src/lib.rs b/aztec_macros/src/lib.rs index baabd9aa1dc..7ca4b79eed8 100644 --- a/aztec_macros/src/lib.rs +++ b/aztec_macros/src/lib.rs @@ -1,5 +1,8 @@ -use iter_extended::vecmap; +use std::borrow::{Borrow, BorrowMut}; +use std::vec; +use convert_case::{Case, Casing}; +use iter_extended::vecmap; use noirc_frontend::macros_api::FieldElement; use noirc_frontend::macros_api::{ BlockExpression, CallExpression, CastExpression, Distinctness, Expression, ExpressionKind, @@ -13,6 +16,8 @@ use noirc_frontend::macros_api::{ use noirc_frontend::macros_api::{CrateId, FileId}; use noirc_frontend::macros_api::{MacroError, MacroProcessor}; use noirc_frontend::macros_api::{ModuleDefId, NodeInterner, SortedModule, StructId}; +use noirc_frontend::node_interner::{TraitId, TraitImplKind}; +use noirc_frontend::Lambda; pub struct AztecMacro; @@ -45,6 +50,8 @@ pub enum AztecMacroError { ContractHasTooManyFunctions { span: Span }, ContractConstructorMissing { span: Span }, UnsupportedFunctionArgumentType { span: Span, typ: UnresolvedTypeData }, + UnsupportedStorageType { span: Option, typ: UnresolvedTypeData }, + CouldNotAssignStorageSlots { secondary_message: Option }, EventError { span: Span, message: String }, } @@ -52,12 +59,12 @@ impl From for MacroError { fn from(err: AztecMacroError) -> Self { match err { AztecMacroError::AztecDepNotFound {} => MacroError { - primary_message: "Aztec dependency not found. Please add aztec as a dependency in your Cargo.toml. For more information go to https://docs.aztec.network/dev_docs/debugging/aztecnr-errors#aztec-dependency-not-found-please-add-aztec-as-a-dependency-in-your-nargotoml".to_owned(), + primary_message: "Aztec dependency not found. Please add aztec as a dependency in your Cargo.toml. For more information go to https://docs.aztec.network/developers/debugging/aztecnr-errors#aztec-dependency-not-found-please-add-aztec-as-a-dependency-in-your-nargotoml".to_owned(), secondary_message: None, span: None, }, AztecMacroError::ComputeNoteHashAndNullifierNotFound { span } => MacroError { - primary_message: "compute_note_hash_and_nullifier function not found. Define it in your contract. For more information go to https://docs.aztec.network/dev_docs/debugging/aztecnr-errors#compute_note_hash_and_nullifier-function-not-found-define-it-in-your-contract".to_owned(), + primary_message: "compute_note_hash_and_nullifier function not found. Define it in your contract. For more information go to https://docs.aztec.network/developers/debugging/aztecnr-errors#compute_note_hash_and_nullifier-function-not-found-define-it-in-your-contract".to_owned(), secondary_message: None, span: Some(span), }, @@ -76,6 +83,16 @@ impl From for MacroError { secondary_message: None, span: Some(span), }, + AztecMacroError::UnsupportedStorageType { span, typ } => MacroError { + primary_message: format!("Provided storage type `{typ:?}` is not directly supported in Aztec. Please provide a custom storage implementation"), + secondary_message: None, + span, + }, + AztecMacroError::CouldNotAssignStorageSlots { secondary_message } => MacroError { + primary_message: "Could not assign storage slots, please provide a custom storage implementation".to_string(), + secondary_message, + span: None, + }, AztecMacroError::EventError { span, message } => MacroError { primary_message: message, secondary_message: None, @@ -133,7 +150,7 @@ fn pattern(name: &str) -> Pattern { } fn mutable(name: &str) -> Pattern { - Pattern::Mutable(Box::new(pattern(name)), Span::default()) + Pattern::Mutable(Box::new(pattern(name)), Span::default(), true) } fn mutable_assignment(name: &str, assigned_to: Expression) -> Statement { @@ -166,7 +183,28 @@ fn member_access(lhs: &str, rhs: &str) -> Expression { }))) } +fn return_type(path: Path) -> FunctionReturnType { + let ty = make_type(UnresolvedTypeData::Named(path, vec![], true)); + FunctionReturnType::Ty(ty) +} + +fn lambda(parameters: Vec<(Pattern, UnresolvedType)>, body: Expression) -> Expression { + expression(ExpressionKind::Lambda(Box::new(Lambda { + parameters, + return_type: UnresolvedType { + typ: UnresolvedTypeData::Unspecified, + span: Some(Span::default()), + }, + body, + }))) +} + macro_rules! chained_path { + ( $base:expr ) => { + { + ident_path($base) + } + }; ( $base:expr $(, $tail:expr)* ) => { { let mut base_path = ident_path($base); @@ -196,7 +234,7 @@ fn cast(lhs: Expression, ty: UnresolvedTypeData) -> Expression { } fn make_type(typ: UnresolvedTypeData) -> UnresolvedType { - UnresolvedType { typ, span: None } + UnresolvedType { typ, span: Some(Span::default()) } } fn index_array(array: Ident, index: &str) -> Expression { @@ -251,7 +289,8 @@ fn transform_hir( crate_id: &CrateId, context: &mut HirContext, ) -> Result<(), (AztecMacroError, FileId)> { - transform_events(crate_id, context) + transform_events(crate_id, context)?; + assign_storage_slots(crate_id, context) } /// Includes an import to the aztec library if it has not been included yet @@ -288,13 +327,23 @@ fn check_for_storage_definition(module: &SortedModule) -> bool { module.types.iter().any(|r#struct| r#struct.name.0.contents == "Storage") } +// Check to see if the user has defined a storage struct +fn check_for_storage_implementation(module: &SortedModule) -> bool { + module.impls.iter().any(|r#impl| match &r#impl.object_type.typ { + UnresolvedTypeData::Named(path, _, _) => { + path.segments.last().is_some_and(|segment| segment.0.contents == "Storage") + } + _ => false, + }) +} + // Check if "compute_note_hash_and_nullifier(AztecAddress,Field,Field,[Field; N]) -> [Field; 4]" is defined fn check_for_compute_note_hash_and_nullifier_definition(module: &SortedModule) -> bool { module.functions.iter().any(|func| { func.def.name.0.contents == "compute_note_hash_and_nullifier" && func.def.parameters.len() == 4 && match &func.def.parameters[0].typ.typ { - UnresolvedTypeData::Named(path, _) => path.segments.last().unwrap().0.contents == "AztecAddress", + UnresolvedTypeData::Named(path, _, _) => path.segments.last().unwrap().0.contents == "AztecAddress", _ => false, } && func.def.parameters[1].typ.typ == UnresolvedTypeData::FieldElement @@ -343,9 +392,15 @@ fn transform_module( // Check for a user defined storage struct let storage_defined = check_for_storage_definition(module); + let storage_implemented = check_for_storage_implementation(module); + + let crate_graph = &context.crate_graph[crate_id]; + + if storage_defined && !storage_implemented { + generate_storage_implementation(module).map_err(|err| (err, crate_graph.root_file_id))?; + } if storage_defined && !check_for_compute_note_hash_and_nullifier_definition(module) { - let crate_graph = &context.crate_graph[crate_id]; return Err(( AztecMacroError::ComputeNoteHashAndNullifierNotFound { span: Span::default() }, crate_graph.root_file_id, @@ -370,6 +425,10 @@ fn transform_module( transform_function("Public", func, storage_defined) .map_err(|err| (err, crate_graph.root_file_id))?; has_transformed_module = true; + } else if is_custom_attribute(&secondary_attribute, "aztec(public-vm)") { + transform_vm_function(func, storage_defined) + .map_err(|err| (err, crate_graph.root_file_id))?; + has_transformed_module = true; } } // Add the storage struct to the beginning of the function if it is unconstrained in an aztec contract @@ -403,6 +462,136 @@ fn transform_module( Ok(has_transformed_module) } +/// Auxiliary function to generate the storage constructor for a given field, using +/// the Storage definition as a reference. Supports nesting. +fn generate_storage_field_constructor( + (type_ident, unresolved_type): &(Ident, UnresolvedType), + slot: Expression, +) -> Result { + let typ = &unresolved_type.typ; + match typ { + UnresolvedTypeData::Named(path, generics, _) => { + let mut new_path = path.clone().to_owned(); + new_path.segments.push(ident("new")); + match path.segments.last().unwrap().0.contents.as_str() { + "Map" => Ok(call( + variable_path(new_path), + vec![ + variable("context"), + slot, + lambda( + vec![ + ( + pattern("context"), + make_type(UnresolvedTypeData::Named( + chained_path!("aztec", "context", "Context"), + vec![], + true, + )), + ), + ( + Pattern::Identifier(ident("slot")), + make_type(UnresolvedTypeData::FieldElement), + ), + ], + generate_storage_field_constructor( + &(type_ident.clone(), generics.iter().last().unwrap().clone()), + variable("slot"), + )?, + ), + ], + )), + _ => Ok(call(variable_path(new_path), vec![variable("context"), slot])), + } + } + _ => Err(AztecMacroError::UnsupportedStorageType { + typ: typ.clone(), + span: Some(type_ident.span()), + }), + } +} + +// Generates the Storage implementation block from the Storage struct definition if it does not exist +/// From: +/// +/// struct Storage { +/// a_map: Map>, +/// a_nested_map: Map>>, +/// a_field: SomeStoragePrimitive, +/// } +/// +/// To: +/// +/// impl Storage { +/// fn init(context: Context) -> Self { +/// Storage { +/// a_map: Map::new(context, 0, |context, slot| { +/// SomeStoragePrimitive::new(context, slot) +/// }), +/// a_nested_map: Map::new(context, 0, |context, slot| { +/// Map::new(context, slot, |context, slot| { +/// SomeStoragePrimitive::new(context, slot) +/// }) +/// }), +/// a_field: SomeStoragePrimitive::new(context, 0), +/// } +/// } +/// } +/// +/// Storage slots are generated as 0 and will be populated using the information from the HIR +/// at a later stage. +fn generate_storage_implementation(module: &mut SortedModule) -> Result<(), AztecMacroError> { + let definition = + module.types.iter().find(|r#struct| r#struct.name.0.contents == "Storage").unwrap(); + + let slot_zero = expression(ExpressionKind::Literal(Literal::Integer( + FieldElement::from(i128::from(0)), + false, + ))); + + let field_constructors = definition + .fields + .iter() + .flat_map(|field| { + generate_storage_field_constructor(field, slot_zero.clone()) + .map(|expression| (field.0.clone(), expression)) + }) + .collect(); + + let storage_constructor_statement = make_statement(StatementKind::Expression(expression( + ExpressionKind::constructor((chained_path!("Storage"), field_constructors)), + ))); + + let init = NoirFunction::normal(FunctionDefinition::normal( + &ident("init"), + &vec![], + &[( + ident("context"), + make_type(UnresolvedTypeData::Named( + chained_path!("aztec", "context", "Context"), + vec![], + true, + )), + )], + &BlockExpression(vec![storage_constructor_statement]), + &[], + &return_type(chained_path!("Self")), + )); + + let storage_impl = TypeImpl { + object_type: UnresolvedType { + typ: UnresolvedTypeData::Named(chained_path!("Storage"), vec![], true), + span: Some(Span::default()), + }, + type_span: Span::default(), + generics: vec![], + methods: vec![(init, Span::default())], + }; + module.impls.push(storage_impl); + + Ok(()) +} + /// If it does, it will insert the following things: /// - A new Input that is provided for a kernel app circuit, named: {Public/Private}ContextInputs /// - Hashes all of the function input variables @@ -454,6 +643,24 @@ fn transform_function( Ok(()) } +/// Transform a function to work with AVM bytecode +fn transform_vm_function( + func: &mut NoirFunction, + _storage_defined: bool, +) -> Result<(), AztecMacroError> { + // Push Avm context creation to the beginning of the function + let create_context = create_avm_context()?; + func.def.body.0.insert(0, create_context); + + // We want the function to be seen as a public function + func.def.is_open = true; + + // NOTE: the line below is a temporary hack to trigger external transpilation tools + // It will be removed once the transpiler is integrated into the Noir compiler + func.def.name.0.contents = format!("avm_{}", func.def.name.0.contents); + Ok(()) +} + /// Transform Unconstrained /// /// Inserts the following code at the beginning of an unconstrained function @@ -484,6 +691,23 @@ fn collect_crate_structs(crate_id: &CrateId, context: &HirContext) -> Vec Vec { + let crates = context.crates(); + crates + .flat_map(|crate_id| context.def_map(&crate_id).map(|def_map| def_map.modules())) + .flatten() + .flat_map(|(_, module)| { + module.type_definitions().filter_map(|typ| { + if let ModuleDefId::TraitId(struct_id) = typ { + Some(struct_id) + } else { + None + } + }) + }) + .collect() +} + /// Substitutes the signature literal that was introduced in the selector method previously with the actual signature. fn transform_event( struct_id: StructId, @@ -576,6 +800,185 @@ fn transform_events( Ok(()) } +/// Obtains the serialized length of a type that implements the Serialize trait. +fn get_serialized_length( + traits: &[TraitId], + typ: &Type, + interner: &NodeInterner, +) -> Result { + let (struct_name, maybe_stored_in_state) = match typ { + Type::Struct(struct_type, generics) => { + Ok((struct_type.borrow().name.0.contents.clone(), generics.get(0))) + } + _ => Err(AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some("State storage variable must be a struct".to_string()), + }), + }?; + let stored_in_state = + maybe_stored_in_state.ok_or(AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some("State storage variable must be generic".to_string()), + })?; + + let is_note = traits.iter().any(|&trait_id| { + let r#trait = interner.get_trait(trait_id); + r#trait.name.0.contents == "NoteInterface" + && !interner.lookup_all_trait_implementations(stored_in_state, trait_id).is_empty() + }); + + // Maps and (private) Notes always occupy a single slot. Someone could store a Note in PublicState for whatever reason though. + if struct_name == "Map" || (is_note && struct_name != "PublicState") { + return Ok(1); + } + + let serialized_trait_impl_kind = traits + .iter() + .filter_map(|&trait_id| { + let r#trait = interner.get_trait(trait_id); + if r#trait.borrow().name.0.contents == "Serialize" + && r#trait.borrow().generics.len() == 1 + { + interner + .lookup_all_trait_implementations(stored_in_state, trait_id) + .into_iter() + .next() + } else { + None + } + }) + .next() + .ok_or(AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some("Stored data must implement Serialize trait".to_string()), + })?; + + let serialized_trait_impl_id = match serialized_trait_impl_kind { + TraitImplKind::Normal(trait_impl_id) => Ok(trait_impl_id), + _ => Err(AztecMacroError::CouldNotAssignStorageSlots { secondary_message: None }), + }?; + + let serialized_trait_impl_shared = interner.get_trait_implementation(*serialized_trait_impl_id); + let serialized_trait_impl = serialized_trait_impl_shared.borrow(); + + match serialized_trait_impl.trait_generics.get(0).unwrap() { + Type::Constant(value) => Ok(*value), + _ => Err(AztecMacroError::CouldNotAssignStorageSlots { secondary_message: None }), + } +} + +/// Assigns storage slots to the storage struct fields based on the serialized length of the types. This automatic assignment +/// will only trigger if the assigned storage slot is invalid (0 as generated by generate_storage_implementation) +fn assign_storage_slots( + crate_id: &CrateId, + context: &mut HirContext, +) -> Result<(), (AztecMacroError, FileId)> { + let traits: Vec<_> = collect_traits(context); + for struct_id in collect_crate_structs(crate_id, context) { + let interner: &mut NodeInterner = context.def_interner.borrow_mut(); + let r#struct = interner.get_struct(struct_id); + let file_id = r#struct.borrow().location.file; + if r#struct.borrow().name.0.contents == "Storage" && r#struct.borrow().id.krate().is_root() + { + let init_id = interner + .lookup_method( + &Type::Struct(interner.get_struct(struct_id), vec![]), + struct_id, + "init", + false, + ) + .ok_or(( + AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some( + "Storage struct must have an init function".to_string(), + ), + }, + file_id, + ))?; + let init_function = interner.function(&init_id).block(interner); + let init_function_statement_id = init_function.statements().first().ok_or(( + AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some("Init storage statement not found".to_string()), + }, + file_id, + ))?; + let storage_constructor_statement = interner.statement(init_function_statement_id); + + let storage_constructor_expression = match storage_constructor_statement { + HirStatement::Expression(expression_id) => { + match interner.expression(&expression_id) { + HirExpression::Constructor(hir_constructor_expression) => { + Ok(hir_constructor_expression) + } + _ => Err((AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some( + "Storage constructor statement must be a constructor expression" + .to_string(), + ), + }, file_id)) + } + } + _ => Err(( + AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some( + "Storage constructor statement must be an expression".to_string(), + ), + }, + file_id, + )), + }?; + + let mut storage_slot: u64 = 1; + for (index, (_, expr_id)) in storage_constructor_expression.fields.iter().enumerate() { + let fields = r#struct.borrow().get_fields(&[]); + let (_, field_type) = fields.get(index).unwrap(); + let new_call_expression = match interner.expression(expr_id) { + HirExpression::Call(hir_call_expression) => Ok(hir_call_expression), + _ => Err(( + AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some( + "Storage field initialization expression is not a call expression" + .to_string(), + ), + }, + file_id, + )), + }?; + + let slot_arg_expression = interner.expression(&new_call_expression.arguments[1]); + + let current_storage_slot = match slot_arg_expression { + HirExpression::Literal(HirLiteral::Integer(slot, _)) => { + Ok(slot.borrow().to_u128()) + } + _ => Err(( + AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some( + "Storage slot argument expression must be a literal integer" + .to_string(), + ), + }, + file_id, + )), + }?; + + if current_storage_slot != 0 { + continue; + } + + let type_serialized_len = get_serialized_length(&traits, field_type, interner) + .map_err(|err| (err, file_id))?; + interner.update_expression(new_call_expression.arguments[1], |expr| { + *expr = HirExpression::Literal(HirLiteral::Integer( + FieldElement::from(u128::from(storage_slot)), + false, + )); + }); + + storage_slot += type_serialized_len; + } + } + } + Ok(()) +} + const SIGNATURE_PLACEHOLDER: &str = "SIGNATURE_PLACEHOLDER"; /// Generates the impl for an event selector @@ -593,7 +996,8 @@ const SIGNATURE_PLACEHOLDER: &str = "SIGNATURE_PLACEHOLDER"; /// The signature cannot be known at this point since types are not resolved yet, so we use a signature placeholder. /// It'll get resolved after by transforming the HIR. fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { - let struct_type = make_type(UnresolvedTypeData::Named(path(structure.name.clone()), vec![])); + let struct_type = + make_type(UnresolvedTypeData::Named(path(structure.name.clone()), vec![], true)); let selector_path = chained_path!("aztec", "protocol_types", "abis", "function_selector", "FunctionSelector"); @@ -607,7 +1011,7 @@ fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { // Define `FunctionSelector` return type let return_type = - FunctionReturnType::Ty(make_type(UnresolvedTypeData::Named(selector_path, vec![]))); + FunctionReturnType::Ty(make_type(UnresolvedTypeData::Named(selector_path, vec![], true))); let mut selector_fn_def = FunctionDefinition::normal( &ident("selector"), @@ -627,7 +1031,7 @@ fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { object_type: struct_type, type_span: structure.span, generics: vec![], - methods: vec![NoirFunction::normal(selector_fn_def)], + methods: vec![(NoirFunction::normal(selector_fn_def), Span::default())], } } @@ -649,8 +1053,11 @@ fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { fn create_inputs(ty: &str) -> Param { let context_ident = ident("inputs"); let context_pattern = Pattern::Identifier(context_ident); - let type_path = chained_path!("aztec", "abi", ty); - let context_type = make_type(UnresolvedTypeData::Named(type_path, vec![])); + + let path_snippet = ty.to_case(Case::Snake); // e.g. private_context_inputs + let type_path = chained_path!("aztec", "context", "inputs", &path_snippet, ty); + + let context_type = make_type(UnresolvedTypeData::Named(type_path, vec![], true)); let visibility = Visibility::Private; Param { pattern: context_pattern, typ: context_type, visibility, span: Span::default() } @@ -688,8 +1095,8 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac let let_hasher = mutable_assignment( "hasher", // Assigned to call( - variable_path(chained_path!("aztec", "abi", "Hasher", "new")), // Path - vec![], // args + variable_path(chained_path!("aztec", "hasher", "Hasher", "new")), // Path + vec![], // args ), ); @@ -748,12 +1155,14 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac vec![], // args ); + let path_snippet = ty.to_case(Case::Snake); // e.g. private_context + // let mut context = {ty}::new(inputs, hash); let let_context = mutable_assignment( "context", // Assigned to call( - variable_path(chained_path!("aztec", "context", ty, "new")), // Path - vec![inputs_expression, hash_call], // args + variable_path(chained_path!("aztec", "context", &path_snippet, ty, "new")), // Path + vec![inputs_expression, hash_call], // args ), ); injected_expressions.push(let_context); @@ -762,6 +1171,35 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac Ok(injected_expressions) } +/// Creates an mutable avm context +/// +/// ```noir +/// /// Before +/// #[aztec(public-vm)] +/// fn foo() -> Field { +/// let mut context = aztec::context::AVMContext::new(); +/// let timestamp = context.timestamp(); +/// // ... +/// } +/// +/// /// After +/// #[aztec(private)] +/// fn foo() -> Field { +/// let mut timestamp = context.timestamp(); +/// // ... +/// } +fn create_avm_context() -> Result { + let let_context = mutable_assignment( + "context", // Assigned to + call( + variable_path(chained_path!("aztec", "context", "AVMContext", "new")), // Path + vec![], // args + ), + ); + + Ok(let_context) +} + /// Abstract Return Type /// /// This function intercepts the function's current return type and replaces it with pushes @@ -771,7 +1209,7 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac /// ```noir /// /// Before /// #[aztec(private)] -/// fn foo() -> abi::PrivateCircuitPublicInputs { +/// fn foo() -> protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { /// // ... /// let my_return_value: Field = 10; /// context.return_values.push(my_return_value); @@ -890,11 +1328,11 @@ fn make_return_push(push_value: Expression) -> Statement { /// Make Return push array /// /// Translates to: -/// `context.return_values.push_array({push_value})` -fn make_return_push_array(push_value: Expression) -> Statement { +/// `context.return_values.extend_from_array({push_value})` +fn make_return_extend_from_array(push_value: Expression) -> Statement { make_statement(StatementKind::Semi(method_call( context_return_values(), - "push_array", + "extend_from_array", vec![push_value], ))) } @@ -903,14 +1341,14 @@ fn make_return_push_array(push_value: Expression) -> Statement { /// /// Translates to: /// ```noir -/// `context.return_values.push_array({push_value}.serialize())` +/// `context.return_values.extend_from_array({push_value}.serialize())` fn make_struct_return_type(expression: Expression) -> Statement { let serialized_call = method_call( expression, // variable "serialize", // method name vec![], // args ); - make_return_push_array(serialized_call) + make_return_extend_from_array(serialized_call) } /// Make array return type @@ -947,8 +1385,8 @@ fn make_castable_return_type(expression: Expression) -> Statement { /// Create Return Type /// -/// Public functions return abi::PublicCircuitPublicInputs while -/// private functions return abi::PrivateCircuitPublicInputs +/// Public functions return protocol_types::abis::public_circuit_public_inputs::PublicCircuitPublicInputs while +/// private functions return protocol_types::abis::private_circuit_public_inputs::::PrivateCircuitPublicInputs /// /// This call constructs an ast token referencing the above types /// The name is set in the function above `transform`, hence the @@ -958,7 +1396,7 @@ fn make_castable_return_type(expression: Expression) -> Statement { /// ```noir /// /// /// Before -/// fn foo() -> abi::PrivateCircuitPublicInputs { +/// fn foo() -> protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { /// // ... /// } /// @@ -968,10 +1406,9 @@ fn make_castable_return_type(expression: Expression) -> Statement { /// // ... /// } fn create_return_type(ty: &str) -> FunctionReturnType { - let return_path = chained_path!("aztec", "abi", ty); - - let ty = make_type(UnresolvedTypeData::Named(return_path, vec![])); - FunctionReturnType::Ty(ty) + let path_snippet = ty.to_case(Case::Snake); // e.g. private_circuit_public_inputs or public_circuit_public_inputs + let return_path = chained_path!("aztec", "protocol_types", "abis", &path_snippet, ty); + return_type(return_path) } /// Create Context Finish @@ -982,7 +1419,7 @@ fn create_return_type(ty: &str) -> FunctionReturnType { /// The replaced code: /// ```noir /// /// Before -/// fn foo() -> abi::PrivateCircuitPublicInputs { +/// fn foo() -> protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { /// // ... /// context.finish() /// } diff --git a/compiler/integration-tests/package.json b/compiler/integration-tests/package.json index c4e424df480..a89e37dc64f 100644 --- a/compiler/integration-tests/package.json +++ b/compiler/integration-tests/package.json @@ -5,8 +5,8 @@ "private": true, "scripts": { "build": "echo Integration Test build step", - "test": "bash ./scripts/codegen-verifiers.sh && yarn test:browser && yarn test:node", - "test:node": "hardhat test test/node/**/*", + "test": "yarn test:browser && yarn test:node", + "test:node": "bash ./scripts/codegen-verifiers.sh && hardhat test test/node/**/*", "test:browser": "web-test-runner", "test:integration:browser": "web-test-runner test/browser/**/*.test.ts", "test:integration:browser:watch": "web-test-runner test/browser/**/*.test.ts --watch", diff --git a/compiler/integration-tests/test/browser/compile_prove_verify.test.ts b/compiler/integration-tests/test/browser/compile_prove_verify.test.ts index 0a829def09e..dba51895bb8 100644 --- a/compiler/integration-tests/test/browser/compile_prove_verify.test.ts +++ b/compiler/integration-tests/test/browser/compile_prove_verify.test.ts @@ -59,11 +59,11 @@ test_cases.forEach((testInfo) => { // JS Proving - const proofWithPublicInputs = await program.generateFinalProof(inputs); + const proofWithPublicInputs = await program.generateProof(inputs); // JS verification - const verified = await program.verifyFinalProof(proofWithPublicInputs); + const verified = await program.verifyProof(proofWithPublicInputs); expect(verified, 'Proof fails verification in JS').to.be.true; }); diff --git a/compiler/integration-tests/test/browser/recursion.test.ts b/compiler/integration-tests/test/browser/recursion.test.ts index 80199de5701..a8927aa6a75 100644 --- a/compiler/integration-tests/test/browser/recursion.test.ts +++ b/compiler/integration-tests/test/browser/recursion.test.ts @@ -19,7 +19,7 @@ await newABICoder(); await initACVM(); const base_relative_path = '../../../../..'; -const circuit_main = 'test_programs/execution_success/assert_statement'; +const circuit_main = 'test_programs/execution_success/assert_statement_recursive'; const circuit_recursion = 'compiler/integration-tests/circuits/recursion'; async function getCircuit(projectPath: string) { @@ -48,15 +48,15 @@ describe('It compiles noir program code, receiving circuit bytes and abi object. const { witness: main_witnessUint8Array } = await new Noir(main_program).execute(main_inputs); - const main_proof = await main_backend.generateIntermediateProof(main_witnessUint8Array); - const main_verification = await main_backend.verifyIntermediateProof(main_proof); + const main_proof = await main_backend.generateProof(main_witnessUint8Array); + const main_verification = await main_backend.verifyProof(main_proof); logger.debug('main_verification', main_verification); expect(main_verification).to.be.true; const numPublicInputs = 1; - const { proofAsFields, vkAsFields, vkHash } = await main_backend.generateIntermediateProofArtifacts( + const { proofAsFields, vkAsFields, vkHash } = await main_backend.generateRecursiveProofArtifacts( main_proof, numPublicInputs, ); @@ -76,20 +76,20 @@ describe('It compiles noir program code, receiving circuit bytes and abi object. const { witness: recursion_witnessUint8Array } = await new Noir(recursion_program).execute(recursion_inputs); - const recursion_proof = await recursion_backend.generateFinalProof(recursion_witnessUint8Array); + const recursion_proof = await recursion_backend.generateProof(recursion_witnessUint8Array); // Causes an "unreachable" error. // Due to the fact that it's a non-recursive proof? // // const recursion_numPublicInputs = 1; - // const { proofAsFields: recursion_proofAsFields } = await recursion_backend.generateIntermediateProofArtifacts( + // const { proofAsFields: recursion_proofAsFields } = await recursion_backend.generateRecursiveProofArtifacts( // recursion_proof, // recursion_numPublicInputs, // ); // // logger.debug('recursion_proofAsFields', recursion_proofAsFields); - const recursion_verification = await recursion_backend.verifyFinalProof(recursion_proof); + const recursion_verification = await recursion_backend.verifyProof(recursion_proof); logger.debug('recursion_verification', recursion_verification); diff --git a/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts b/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts index 9cdd80edc15..6147f770f16 100644 --- a/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts +++ b/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts @@ -16,7 +16,7 @@ it(`smart contract can verify a recursive proof`, async () => { const fm = createFileManager(basePath); const innerCompilationResult = await compile( fm, - join(basePath, './test_programs/execution_success/assert_statement'), + join(basePath, './test_programs/execution_success/assert_statement_recursive'), ); if (!('program' in innerCompilationResult)) { throw new Error('Compilation failed'); @@ -38,17 +38,17 @@ it(`smart contract can verify a recursive proof`, async () => { const inner = new Noir(innerProgram); const inner_prover_toml = readFileSync( - join(basePath, `./test_programs/execution_success/assert_statement/Prover.toml`), + join(basePath, `./test_programs/execution_success/assert_statement_recursive/Prover.toml`), ).toString(); const inner_inputs = toml.parse(inner_prover_toml); const { witness: main_witness } = await inner.execute(inner_inputs); - const intermediate_proof = await inner_backend.generateIntermediateProof(main_witness); + const intermediate_proof = await inner_backend.generateProof(main_witness); - expect(await inner_backend.verifyIntermediateProof(intermediate_proof)).to.be.true; + expect(await inner_backend.verifyProof(intermediate_proof)).to.be.true; - const { proofAsFields, vkAsFields, vkHash } = await inner_backend.generateIntermediateProofArtifacts( + const { proofAsFields, vkAsFields, vkHash } = await inner_backend.generateRecursiveProofArtifacts( intermediate_proof, 1, // 1 public input ); @@ -65,8 +65,8 @@ it(`smart contract can verify a recursive proof`, async () => { key_hash: vkHash, }; - const recursion_proof = await recursion.generateFinalProof(recursion_inputs); - expect(await recursion.verifyFinalProof(recursion_proof)).to.be.true; + const recursion_proof = await recursion.generateProof(recursion_inputs); + expect(await recursion.verifyProof(recursion_proof)).to.be.true; // Smart contract verification diff --git a/compiler/integration-tests/test/node/smart_contract_verifier.test.ts b/compiler/integration-tests/test/node/smart_contract_verifier.test.ts index d870956ea7a..79a0520da32 100644 --- a/compiler/integration-tests/test/node/smart_contract_verifier.test.ts +++ b/compiler/integration-tests/test/node/smart_contract_verifier.test.ts @@ -46,11 +46,11 @@ test_cases.forEach((testInfo) => { const prover_toml = readFileSync(resolve(`${base_relative_path}/${test_case}/Prover.toml`)).toString(); const inputs = toml.parse(prover_toml); - const proofData = await program.generateFinalProof(inputs); + const proofData = await program.generateProof(inputs); // JS verification - const verified = await program.verifyFinalProof(proofData); + const verified = await program.verifyProof(proofData); expect(verified, 'Proof fails verification in JS').to.be.true; // Smart contract verification diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index d782330a677..8b0fc5dc97a 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -3,7 +3,7 @@ #![warn(unreachable_pub)] #![warn(clippy::semicolon_if_nothing_returned)] -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use clap::Args; use fm::{FileId, FileManager}; use iter_extended::vecmap; @@ -97,12 +97,14 @@ pub struct CompileOptions { fn parse_expression_width(input: &str) -> Result { use std::io::{Error, ErrorKind}; - let width = input .parse::() .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?; - Ok(ExpressionWidth::from(width)) + match width { + 0 => Ok(ExpressionWidth::Unbounded), + _ => Ok(ExpressionWidth::Bounded { width }), + } } /// Helper type used to signify where only warnings are expected in file diagnostics diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 96d80cb8131..dfe23b45034 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -244,13 +244,13 @@ pub(crate) fn convert_black_box_call( ) } } - BlackBoxFunc::BigIntNeg => { + BlackBoxFunc::BigIntSub => { if let ( [BrilligVariable::Simple(lhs), BrilligVariable::Simple(rhs)], [BrilligVariable::Simple(output)], ) = (function_arguments, function_results) { - brillig_context.black_box_op_instruction(BlackBoxOp::BigIntNeg { + brillig_context.black_box_op_instruction(BlackBoxOp::BigIntSub { lhs: *lhs, rhs: *rhs, output: *output, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index e236d43556d..d095e4efd5f 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,4 +1,6 @@ -use crate::brillig::brillig_ir::brillig_variable::{BrilligArray, BrilligVariable, BrilligVector}; +use crate::brillig::brillig_ir::brillig_variable::{ + type_to_heap_value_type, BrilligArray, BrilligVariable, BrilligVector, +}; use crate::brillig::brillig_ir::{ BrilligBinaryOp, BrilligContext, BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, }; @@ -14,7 +16,7 @@ use crate::ssa::ir::{ types::{NumericType, Type}, value::{Value, ValueId}, }; -use acvm::acir::brillig::{BinaryFieldOp, BinaryIntOp, RegisterIndex, RegisterOrMemory}; +use acvm::acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, ValueOrArray}; use acvm::brillig_vm::brillig::HeapVector; use acvm::FieldElement; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; @@ -86,10 +88,10 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_terminator(terminator_instruction, dfg); } - fn get_bit_size_from_ssa_type(typ: Type) -> u32 { + fn get_bit_size_from_ssa_type(typ: &Type) -> u32 { match typ { Type::Numeric(num_type) => match num_type { - NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => bit_size, + NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => *bit_size, NumericType::NativeField => FieldElement::max_num_bits(), }, _ => unreachable!("ICE bitwise not on a non numeric type"), @@ -346,7 +348,7 @@ impl<'block> BrilligBlock<'block> { dfg.instruction_results(instruction_id)[0], dfg, ); - let bit_size = Self::get_bit_size_from_ssa_type(dfg.type_of_value(*value)); + let bit_size = Self::get_bit_size_from_ssa_type(&dfg.type_of_value(*value)); self.brillig_context.not_instruction(condition_register, bit_size, result_register); } Instruction::Call { func, arguments } => match &dfg[*func] { @@ -356,26 +358,33 @@ impl<'block> BrilligBlock<'block> { let input_registers = vecmap(arguments, |value_id| { self.convert_ssa_value(*value_id, dfg).to_register_or_memory() }); + let input_value_types = vecmap(arguments, |value_id| { + let value_type = dfg.type_of_value(*value_id); + type_to_heap_value_type(&value_type) + }); let output_registers = vecmap(result_ids, |value_id| { self.allocate_external_call_result(*value_id, dfg).to_register_or_memory() }); + let output_value_types = vecmap(result_ids, |value_id| { + let value_type = dfg.type_of_value(*value_id); + type_to_heap_value_type(&value_type) + }); self.brillig_context.foreign_call_instruction( func_name.to_owned(), &input_registers, + &input_value_types, &output_registers, + &output_value_types, ); for (i, output_register) in output_registers.iter().enumerate() { - if let RegisterOrMemory::HeapVector(HeapVector { size, .. }) = - output_register - { + if let ValueOrArray::HeapVector(HeapVector { size, .. }) = output_register { // Update the stack pointer so that we do not overwrite // dynamic memory returned from other external calls self.brillig_context.update_stack_pointer(*size); // Update the dynamic slice length maintained in SSA - if let RegisterOrMemory::RegisterIndex(len_index) = - output_registers[i - 1] + if let ValueOrArray::MemoryAddress(len_index) = output_registers[i - 1] { let element_size = dfg[result_ids[i]].get_type().element_size(); self.brillig_context.mov_instruction(len_index, *size); @@ -527,7 +536,9 @@ impl<'block> BrilligBlock<'block> { BrilligVariable::Simple(..) => unreachable!("ICE: ToBits on non-array"), }; - let radix = self.brillig_context.make_constant(2_usize.into()); + let radix = self + .brillig_context + .make_constant(2_usize.into(), FieldElement::max_num_bits()); // Update the user-facing slice length self.brillig_context.mov_instruction(target_len, limb_count); @@ -624,6 +635,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.const_instruction( right, FieldElement::from_be_bytes_reduce(&max.to_bytes_be()).into(), + FieldElement::max_num_bits(), ); let brillig_binary_op = BrilligBinaryOp::Integer { @@ -666,7 +678,7 @@ impl<'block> BrilligBlock<'block> { result_ids: &[ValueId], ) { // Convert the arguments to registers casting those to the types of the receiving function - let argument_registers: Vec = arguments + let argument_registers: Vec = arguments .iter() .flat_map(|argument_id| self.convert_ssa_value(*argument_id, dfg).extract_registers()) .collect(); @@ -700,7 +712,7 @@ impl<'block> BrilligBlock<'block> { }); // Collect the registers that should have been returned - let returned_registers: Vec = variables_assigned_to + let returned_registers: Vec = variables_assigned_to .iter() .flat_map(|returned_variable| returned_variable.extract_registers()) .collect(); @@ -718,11 +730,11 @@ impl<'block> BrilligBlock<'block> { fn validate_array_index( &mut self, array_variable: BrilligVariable, - index_register: RegisterIndex, + index_register: MemoryAddress, ) { let (size_as_register, should_deallocate_size) = match array_variable { BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { - (self.brillig_context.make_constant(size.into()), true) + (self.brillig_context.make_usize_constant(size.into()), true) } BrilligVariable::BrilligVector(BrilligVector { size, .. }) => (size, false), _ => unreachable!("ICE: validate array index on non-array"), @@ -748,8 +760,8 @@ impl<'block> BrilligBlock<'block> { pub(crate) fn retrieve_variable_from_array( &mut self, - array_pointer: RegisterIndex, - index_register: RegisterIndex, + array_pointer: MemoryAddress, + index_register: MemoryAddress, destination_variable: BrilligVariable, ) { match destination_variable { @@ -771,7 +783,7 @@ impl<'block> BrilligBlock<'block> { &mut self, source_variable: BrilligVariable, destination_variable: BrilligVariable, - index_register: RegisterIndex, + index_register: MemoryAddress, value_variable: BrilligVariable, ) { let destination_pointer = match destination_variable { @@ -789,7 +801,7 @@ impl<'block> BrilligBlock<'block> { let (source_pointer, source_size_as_register) = match source_variable { BrilligVariable::BrilligArray(BrilligArray { size, pointer, rc: _ }) => { let source_size_register = self.brillig_context.allocate_register(); - self.brillig_context.const_instruction(source_size_register, size.into()); + self.brillig_context.usize_const(source_size_register, size.into()); (pointer, source_size_register) } BrilligVariable::BrilligVector(BrilligVector { size, pointer, rc: _ }) => { @@ -800,7 +812,7 @@ impl<'block> BrilligBlock<'block> { _ => unreachable!("ICE: array set on non-array"), }; - let one = self.brillig_context.make_constant(1_usize.into()); + let one = self.brillig_context.make_usize_constant(1_usize.into()); let condition = self.brillig_context.allocate_register(); self.brillig_context.binary_instruction( @@ -828,7 +840,7 @@ impl<'block> BrilligBlock<'block> { match destination_variable { BrilligVariable::BrilligArray(BrilligArray { rc: target_rc, .. }) => { - self.brillig_context.const_instruction(target_rc, 1_usize.into()); + self.brillig_context.usize_const(target_rc, 1_usize.into()); } BrilligVariable::BrilligVector(BrilligVector { size: target_size, @@ -836,7 +848,7 @@ impl<'block> BrilligBlock<'block> { .. }) => { self.brillig_context.mov_instruction(target_size, source_size_as_register); - self.brillig_context.const_instruction(target_rc, 1_usize.into()); + self.brillig_context.usize_const(target_rc, 1_usize.into()); } _ => unreachable!("ICE: array set on non-array"), } @@ -851,8 +863,8 @@ impl<'block> BrilligBlock<'block> { pub(crate) fn store_variable_in_array_with_ctx( ctx: &mut BrilligContext, - destination_pointer: RegisterIndex, - index_register: RegisterIndex, + destination_pointer: MemoryAddress, + index_register: MemoryAddress, value_variable: BrilligVariable, ) { match value_variable { @@ -860,7 +872,7 @@ impl<'block> BrilligBlock<'block> { ctx.array_set(destination_pointer, index_register, value_register); } BrilligVariable::BrilligArray(_) => { - let reference: RegisterIndex = ctx.allocate_register(); + let reference: MemoryAddress = ctx.allocate_register(); ctx.allocate_array_reference_instruction(reference); ctx.store_variable_instruction(reference, value_variable); ctx.array_set(destination_pointer, index_register, reference); @@ -878,8 +890,8 @@ impl<'block> BrilligBlock<'block> { pub(crate) fn store_variable_in_array( &mut self, - destination_pointer: RegisterIndex, - index_register: RegisterIndex, + destination_pointer: MemoryAddress, + index_register: MemoryAddress, value_variable: BrilligVariable, ) { Self::store_variable_in_array_with_ctx( @@ -1048,7 +1060,7 @@ impl<'block> BrilligBlock<'block> { // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 let user_index = self.convert_ssa_register_value(arguments[2], dfg); - let converted_index = self.brillig_context.make_constant(element_size.into()); + let converted_index = self.brillig_context.make_usize_constant(element_size.into()); self.brillig_context.memory_op( converted_index, @@ -1091,7 +1103,7 @@ impl<'block> BrilligBlock<'block> { // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 let user_index = self.convert_ssa_register_value(arguments[2], dfg); - let converted_index = self.brillig_context.make_constant(element_size.into()); + let converted_index = self.brillig_context.make_usize_constant(element_size.into()); self.brillig_context.memory_op( converted_index, user_index, @@ -1134,7 +1146,7 @@ impl<'block> BrilligBlock<'block> { /// of fields in the vector. fn update_slice_length( &mut self, - target_len: RegisterIndex, + target_len: MemoryAddress, source_value: ValueId, dfg: &DataFlowGraph, binary_op: BinaryIntOp, @@ -1147,7 +1159,7 @@ impl<'block> BrilligBlock<'block> { /// Converts an SSA cast to a sequence of Brillig opcodes. /// Casting is only necessary when shrinking the bit size of a numeric value. - fn convert_cast(&mut self, destination: RegisterIndex, source: RegisterIndex) { + fn convert_cast(&mut self, destination: MemoryAddress, source: MemoryAddress) { // We assume that `source` is a valid `target_type` as it's expected that a truncate instruction was emitted // to ensure this is the case. @@ -1159,7 +1171,7 @@ impl<'block> BrilligBlock<'block> { &mut self, binary: &Binary, dfg: &DataFlowGraph, - result_register: RegisterIndex, + result_register: MemoryAddress, ) { let binary_type = type_of_binary_operation(dfg[binary.lhs].get_type(), dfg[binary.rhs].get_type()); @@ -1184,7 +1196,7 @@ impl<'block> BrilligBlock<'block> { // converted to registers so we fetch from the cache. self.variables.get_allocation(self.function_context, value_id, dfg) } - Value::NumericConstant { constant, .. } => { + Value::NumericConstant { constant, typ } => { // Constants might have been converted previously or not, so we get or create and // (re)initialize the value inside. if let Some(variable) = self.variables.get_constant(value_id, dfg) { @@ -1194,7 +1206,11 @@ impl<'block> BrilligBlock<'block> { self.variables.allocate_constant(self.brillig_context, value_id, dfg); let register_index = new_variable.extract_register(); - self.brillig_context.const_instruction(register_index, (*constant).into()); + self.brillig_context.const_instruction( + register_index, + (*constant).into(), + Self::get_bit_size_from_ssa_type(typ), + ); new_variable } } @@ -1210,16 +1226,15 @@ impl<'block> BrilligBlock<'block> { BrilligVariable::BrilligArray(brillig_array) => { self.brillig_context .allocate_fixed_length_array(brillig_array.pointer, array.len()); - self.brillig_context - .const_instruction(brillig_array.rc, 1_usize.into()); + self.brillig_context.usize_const(brillig_array.rc, 1_usize.into()); brillig_array.pointer } BrilligVariable::BrilligVector(vector) => { - self.brillig_context.const_instruction(vector.size, array.len().into()); + self.brillig_context.usize_const(vector.size, array.len().into()); self.brillig_context .allocate_array_instruction(vector.pointer, vector.size); - self.brillig_context.const_instruction(vector.rc, 1_usize.into()); + self.brillig_context.usize_const(vector.rc, 1_usize.into()); vector.pointer } @@ -1231,7 +1246,8 @@ impl<'block> BrilligBlock<'block> { // Write the items // Allocate a register for the iterator - let iterator_register = self.brillig_context.make_constant(0_usize.into()); + let iterator_register = + self.brillig_context.make_usize_constant(0_usize.into()); for element_id in array.iter() { let element_variable = self.convert_ssa_value(*element_id, dfg); @@ -1259,7 +1275,11 @@ impl<'block> BrilligBlock<'block> { self.variables.allocate_constant(self.brillig_context, value_id, dfg); let register_index = new_variable.extract_register(); - self.brillig_context.const_instruction(register_index, value_id.to_usize().into()); + self.brillig_context.const_instruction( + register_index, + value_id.to_usize().into(), + 32, + ); new_variable } Value::Intrinsic(_) | Value::ForeignFunction(_) => { @@ -1268,12 +1288,12 @@ impl<'block> BrilligBlock<'block> { } } - /// Converts an SSA `ValueId` into a `RegisterIndex`. Initializes if necessary. + /// Converts an SSA `ValueId` into a `MemoryAddress`. Initializes if necessary. fn convert_ssa_register_value( &mut self, value_id: ValueId, dfg: &DataFlowGraph, - ) -> RegisterIndex { + ) -> MemoryAddress { let variable = self.convert_ssa_value(value_id, dfg); variable.extract_register() } @@ -1301,7 +1321,7 @@ impl<'block> BrilligBlock<'block> { ); let array = variable.extract_array(); self.brillig_context.allocate_fixed_length_array(array.pointer, array.size); - self.brillig_context.const_instruction(array.rc, 1_usize.into()); + self.brillig_context.usize_const(array.rc, 1_usize.into()); variable } @@ -1318,7 +1338,7 @@ impl<'block> BrilligBlock<'block> { // The stack pointer will then be updated by the caller of this method // once the external call is resolved and the array size is known self.brillig_context.set_array_pointer(vector.pointer); - self.brillig_context.const_instruction(vector.rc, 1_usize.into()); + self.brillig_context.usize_const(vector.rc, 1_usize.into()); variable } @@ -1334,7 +1354,7 @@ impl<'block> BrilligBlock<'block> { fn convert_ssa_array_len( &mut self, array_id: ValueId, - result_register: RegisterIndex, + result_register: MemoryAddress, dfg: &DataFlowGraph, ) { let array_variable = self.convert_ssa_value(array_id, dfg); @@ -1342,8 +1362,7 @@ impl<'block> BrilligBlock<'block> { match array_variable { BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { - self.brillig_context - .const_instruction(result_register, (size / element_size).into()); + self.brillig_context.usize_const(result_register, (size / element_size).into()); } BrilligVariable::BrilligVector(BrilligVector { size, .. }) => { self.brillig_context.usize_op( @@ -1449,6 +1468,8 @@ pub(crate) fn convert_ssa_binary_op_to_brillig_binary_op( BinaryOp::And => BinaryIntOp::And, BinaryOp::Or => BinaryIntOp::Or, BinaryOp::Xor => BinaryIntOp::Xor, + BinaryOp::Shl => BinaryIntOp::Shl, + BinaryOp::Shr => BinaryIntOp::Shr, }; BrilligBinaryOp::Integer { op: operation, bit_size } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs index 64e8bb1acf4..cbb3049a904 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs @@ -1,4 +1,4 @@ -use acvm::brillig_vm::brillig::RegisterIndex; +use acvm::brillig_vm::brillig::MemoryAddress; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use crate::{ @@ -75,7 +75,7 @@ impl BlockVariables { brillig_context: &mut BrilligContext, value: ValueId, dfg: &DataFlowGraph, - ) -> RegisterIndex { + ) -> MemoryAddress { let variable = self.define_variable(function_context, brillig_context, value, dfg); variable.extract_register() } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index a07865073ff..93c4b1a5042 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -1,5 +1,6 @@ -use acvm::acir::brillig::{ - BinaryFieldOp, BinaryIntOp, Opcode as BrilligOpcode, RegisterIndex, Value, +use acvm::{ + acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode, Value}, + FieldElement, }; use crate::brillig::brillig_ir::artifact::GeneratedBrillig; @@ -13,17 +14,22 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { // The input argument, ie the value that will be inverted. // We store the result in this register too. - let input = RegisterIndex::from(0); - let one_const = RegisterIndex::from(1); + let input = MemoryAddress::from(0); + let one_const = MemoryAddress::from(1); // Location of the stop opcode let stop_location = 3; GeneratedBrillig { byte_code: vec![ + BrilligOpcode::CalldataCopy { destination_address: input, size: 1, offset: 0 }, // If the input is zero, then we jump to the stop opcode BrilligOpcode::JumpIfNot { condition: input, location: stop_location }, // Put value one in register (1) - BrilligOpcode::Const { destination: one_const, value: Value::from(1_usize) }, + BrilligOpcode::Const { + destination: one_const, + value: Value::from(1_usize), + bit_size: FieldElement::max_num_bits(), + }, // Divide 1 by the input, and set the result of the division into register (0) BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Div, @@ -31,7 +37,7 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { rhs: input, destination: input, }, - BrilligOpcode::Stop, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 1 }, ], assert_messages: Default::default(), locations: Default::default(), @@ -52,36 +58,41 @@ pub(crate) fn directive_quotient(bit_size: u32) -> GeneratedBrillig { // `b` is (1) GeneratedBrillig { byte_code: vec![ + BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: 2, + offset: 0, + }, //q = a/b is set into register (2) BrilligOpcode::BinaryIntOp { op: BinaryIntOp::UnsignedDiv, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(2), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(2), bit_size, }, //(1)= q*b BrilligOpcode::BinaryIntOp { op: BinaryIntOp::Mul, - lhs: RegisterIndex::from(2), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(1), + lhs: MemoryAddress::from(2), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(1), bit_size, }, //(1) = a-q*b BrilligOpcode::BinaryIntOp { op: BinaryIntOp::Sub, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(1), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(1), bit_size, }, //(0) = q BrilligOpcode::Mov { - destination: RegisterIndex::from(0), - source: RegisterIndex::from(2), + destination: MemoryAddress::from(0), + source: MemoryAddress::from(2), }, - BrilligOpcode::Stop, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 2 }, ], assert_messages: Default::default(), locations: Default::default(), diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 6402e6f9d97..3fed8ee91d9 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -1,4 +1,4 @@ -use acvm::brillig_vm::brillig::{BinaryIntOp, RegisterIndex}; +use acvm::brillig_vm::brillig::{BinaryIntOp, MemoryAddress}; use crate::brillig::brillig_ir::brillig_variable::{BrilligVariable, BrilligVector}; @@ -20,7 +20,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we copy the source vector into the target vector self.brillig_context.copy_array_instruction( @@ -30,7 +30,7 @@ impl<'block> BrilligBlock<'block> { ); for (index, variable) in variables_to_insert.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.brillig_context.memory_op( target_index, source_vector.size, @@ -57,7 +57,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we offset the target pointer by variables_to_insert.len() let destination_copy_pointer = self.brillig_context.allocate_register(); @@ -77,7 +77,7 @@ impl<'block> BrilligBlock<'block> { // Then we write the items to insert at the start for (index, variable) in variables_to_insert.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.store_variable_in_array(target_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); } @@ -100,7 +100,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we offset the source pointer by removed_items.len() let source_copy_pointer = self.brillig_context.allocate_register(); @@ -119,7 +119,7 @@ impl<'block> BrilligBlock<'block> { ); for (index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); } @@ -142,7 +142,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we copy all elements except the last items into the target vector self.brillig_context.copy_array_instruction( @@ -152,7 +152,7 @@ impl<'block> BrilligBlock<'block> { ); for (index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.brillig_context.memory_op( target_index, target_vector.size, @@ -168,7 +168,7 @@ impl<'block> BrilligBlock<'block> { &mut self, target_vector: BrilligVector, source_vector: BrilligVector, - index: RegisterIndex, + index: MemoryAddress, items: &[BrilligVariable], ) { // First we need to allocate the target vector incrementing the size by items.len() @@ -180,7 +180,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Copy the elements to the left of the index self.brillig_context.copy_array_instruction( @@ -225,7 +225,7 @@ impl<'block> BrilligBlock<'block> { // Write the items to insert starting at the index for (subitem_index, variable) in items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(subitem_index.into()); + let target_index = self.brillig_context.make_usize_constant(subitem_index.into()); self.brillig_context.memory_op(target_index, index, target_index, BinaryIntOp::Add); self.store_variable_in_array(target_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); @@ -240,7 +240,7 @@ impl<'block> BrilligBlock<'block> { &mut self, target_vector: BrilligVector, source_vector: BrilligVector, - index: RegisterIndex, + index: MemoryAddress, removed_items: &[BrilligVariable], ) { // First we need to allocate the target vector decrementing the size by removed_items.len() @@ -252,7 +252,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Copy the elements to the left of the index self.brillig_context.copy_array_instruction( @@ -298,7 +298,7 @@ impl<'block> BrilligBlock<'block> { // Get the removed items for (subitem_index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(subitem_index.into()); + let target_index = self.brillig_context.make_usize_constant(subitem_index.into()); self.brillig_context.memory_op(target_index, index, target_index, BinaryIntOp::Add); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); @@ -328,7 +328,6 @@ mod tests { use std::vec; use acvm::acir::brillig::Value; - use acvm::brillig_vm::brillig::RegisterIndex; use crate::brillig::brillig_gen::brillig_block::BrilligBlock; use crate::brillig::brillig_gen::brillig_block_variables::BlockVariables; @@ -375,17 +374,15 @@ mod tests { fn test_case_push( push_back: bool, array: Vec, - expected_mem: Vec, item_to_push: Value, + expected_return: Vec, ) { let arguments = vec![ BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), BrilligParameter::Simple, ]; - let returns = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() + 1), - BrilligParameter::Simple, - ]; + let returns = + vec![BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() + 1)]; let (_, mut function_context, mut context) = create_test_environment(); @@ -423,55 +420,42 @@ mod tests { ); } - context.return_instruction(&[ - target_vector.pointer, - target_vector.rc, - target_vector.size, - ]); + context.return_instruction(&[target_vector.pointer, target_vector.rc]); let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; - let vm = create_and_run_vm( - array.clone(), - vec![Value::from(0_usize), item_to_push], - &bytecode, + let (vm, return_data_offset, return_data_size) = + create_and_run_vm(array.into_iter().chain(vec![item_to_push]).collect(), &bytecode); + assert_eq!(return_data_size, expected_return.len()); + assert_eq!( + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + expected_return ); - - assert_eq!(vm.get_memory(), &expected_mem); - - assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); - assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() + 1)); } test_case_push( true, vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], + Value::from(27_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), Value::from(1_usize), Value::from(2_usize), Value::from(3_usize), Value::from(27_usize), ], - Value::from(27_usize), ); - test_case_push(true, vec![], vec![Value::from(27_usize)], Value::from(27_usize)); + test_case_push(true, vec![], Value::from(27_usize), vec![Value::from(27_usize)]); test_case_push( false, vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], + Value::from(27_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), Value::from(27_usize), Value::from(1_usize), Value::from(2_usize), Value::from(3_usize), ], - Value::from(27_usize), ); - test_case_push(false, vec![], vec![Value::from(27_usize)], Value::from(27_usize)); + test_case_push(false, vec![], Value::from(27_usize), vec![Value::from(27_usize)]); } #[test] @@ -479,15 +463,14 @@ mod tests { fn test_case_pop( pop_back: bool, array: Vec, - expected_mem: Vec, - expected_removed_item: Value, + expected_return_array: Vec, + expected_return_item: Value, ) { let arguments = vec![BrilligParameter::Array(vec![BrilligParameter::Simple], array.len())]; let returns = vec![ BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() - 1), BrilligParameter::Simple, - BrilligParameter::Simple, ]; let (_, mut function_context, mut context) = create_test_environment(); @@ -526,51 +509,32 @@ mod tests { ); } - context.return_instruction(&[ - target_vector.pointer, - target_vector.rc, - target_vector.size, - removed_item, - ]); + context.return_instruction(&[target_vector.pointer, target_vector.rc, removed_item]); let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; - let vm = create_and_run_vm(array.clone(), vec![Value::from(0_usize)], &bytecode); - - assert_eq!(vm.get_memory(), &expected_mem); - - assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); - assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() - 1)); - assert_eq!(vm.get_registers().get(RegisterIndex(2)), expected_removed_item); + let expected_return: Vec<_> = + expected_return_array.into_iter().chain(vec![expected_return_item]).collect(); + let (vm, return_data_offset, return_data_size) = + create_and_run_vm(array.clone(), &bytecode); + assert_eq!(return_data_size, expected_return.len()); + + assert_eq!( + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + expected_return + ); } test_case_pop( true, vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(1_usize), - Value::from(2_usize), - ], + vec![Value::from(1_usize), Value::from(2_usize)], Value::from(3_usize), ); - test_case_pop( - true, - vec![Value::from(1_usize)], - vec![Value::from(1_usize)], - Value::from(1_usize), - ); + test_case_pop(true, vec![Value::from(1_usize)], vec![], Value::from(1_usize)); test_case_pop( false, vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(2_usize), - Value::from(3_usize), - ], + vec![Value::from(2_usize), Value::from(3_usize)], Value::from(1_usize), ); } @@ -579,19 +543,17 @@ mod tests { fn test_slice_insert_operation() { fn test_case_insert( array: Vec, - expected_mem: Vec, item: Value, index: Value, + expected_return: Vec, ) { let arguments = vec![ BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), BrilligParameter::Simple, BrilligParameter::Simple, ]; - let returns = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() + 1), - BrilligParameter::Simple, - ]; + let returns = + vec![BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() + 1)]; let (_, mut function_context, mut context) = create_test_environment(); @@ -623,87 +585,69 @@ mod tests { &[BrilligVariable::Simple(item_to_insert)], ); - context.return_instruction(&[ - target_vector.pointer, - target_vector.rc, - target_vector.size, - ]); + context.return_instruction(&[target_vector.pointer, target_vector.rc]); + let calldata = array.into_iter().chain(vec![item]).chain(vec![index]).collect(); let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; - let vm = create_and_run_vm( - array.clone(), - vec![Value::from(0_usize), item, index], - &bytecode, - ); + let (vm, return_data_offset, return_data_size) = create_and_run_vm(calldata, &bytecode); + assert_eq!(return_data_size, expected_return.len()); - assert_eq!(vm.get_memory(), &expected_mem); - - assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); - assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() + 1)); + assert_eq!( + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + expected_return + ); } test_case_insert( vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], + Value::from(27_usize), + Value::from(1_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), Value::from(1_usize), Value::from(27_usize), Value::from(2_usize), Value::from(3_usize), ], - Value::from(27_usize), - Value::from(1_usize), ); test_case_insert( vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], + Value::from(27_usize), + Value::from(0_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), Value::from(27_usize), Value::from(1_usize), Value::from(2_usize), Value::from(3_usize), ], - Value::from(27_usize), - Value::from(0_usize), ); test_case_insert( vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], + Value::from(27_usize), + Value::from(2_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), Value::from(1_usize), Value::from(2_usize), Value::from(27_usize), Value::from(3_usize), ], - Value::from(27_usize), - Value::from(2_usize), ); test_case_insert( vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], + Value::from(27_usize), + Value::from(3_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), Value::from(1_usize), Value::from(2_usize), Value::from(3_usize), Value::from(27_usize), ], - Value::from(27_usize), - Value::from(3_usize), ); test_case_insert( vec![], - vec![Value::from(27_usize)], Value::from(27_usize), Value::from(0_usize), + vec![Value::from(27_usize)], ); } @@ -711,8 +655,8 @@ mod tests { fn test_slice_remove_operation() { fn test_case_remove( array: Vec, - expected_mem: Vec, index: Value, + expected_array: Vec, expected_removed_item: Value, ) { let arguments = vec![ @@ -722,7 +666,6 @@ mod tests { let returns = vec![ BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() - 1), BrilligParameter::Simple, - BrilligParameter::Simple, ]; let (_, mut function_context, mut context) = create_test_environment(); @@ -755,65 +698,47 @@ mod tests { &[BrilligVariable::Simple(removed_item)], ); - context.return_instruction(&[ - target_vector.pointer, - target_vector.rc, - target_vector.size, - removed_item, - ]); + context.return_instruction(&[target_vector.pointer, target_vector.size, removed_item]); + + let calldata: Vec<_> = array.into_iter().chain(vec![index]).collect(); let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; - let vm = create_and_run_vm(array.clone(), vec![Value::from(0_usize), index], &bytecode); + let (vm, return_data_offset, return_data_size) = create_and_run_vm(calldata, &bytecode); - assert_eq!(vm.get_memory(), &expected_mem); + let expected_return: Vec<_> = + expected_array.into_iter().chain(vec![expected_removed_item]).collect(); + assert_eq!(return_data_size, expected_return.len()); - assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); - assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() - 1)); - assert_eq!(vm.get_registers().get(RegisterIndex(2)), expected_removed_item); + assert_eq!( + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + expected_return + ); } test_case_remove( vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(2_usize), - Value::from(3_usize), - ], Value::from(0_usize), + vec![Value::from(2_usize), Value::from(3_usize)], Value::from(1_usize), ); test_case_remove( vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(1_usize), - Value::from(3_usize), - ], Value::from(1_usize), + vec![Value::from(1_usize), Value::from(3_usize)], Value::from(2_usize), ); test_case_remove( vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(1_usize), - Value::from(2_usize), - ], Value::from(2_usize), + vec![Value::from(1_usize), Value::from(2_usize)], Value::from(3_usize), ); test_case_remove( - vec![Value::from(1_usize)], vec![Value::from(1_usize)], Value::from(0_usize), + vec![], Value::from(1_usize), ); } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 3e6c3d4d7de..94656ed6f46 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -20,9 +20,10 @@ use self::{ }; use acvm::{ acir::brillig::{ - BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode, RegisterIndex, - RegisterOrMemory, Value, + BinaryFieldOp, BinaryIntOp, BlackBoxOp, MemoryAddress, Opcode as BrilligOpcode, Value, + ValueOrArray, }, + brillig_vm::brillig::HeapValueType, FieldElement, }; use debug_show::DebugShow; @@ -41,7 +42,7 @@ pub(crate) const BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE: u32 = 127; /// The Brillig VM does not apply a limit to the memory address space, /// As a convention, we take use 64 bits. This means that we assume that /// memory has 2^64 memory slots. -pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 64; +pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 32; // Registers reserved in runtime for special purposes. pub(crate) enum ReservedRegisters { @@ -64,18 +65,18 @@ impl ReservedRegisters { } /// Returns the stack pointer register. This will get used to allocate memory in runtime. - pub(crate) fn stack_pointer() -> RegisterIndex { - RegisterIndex::from(ReservedRegisters::StackPointer as usize) + pub(crate) fn stack_pointer() -> MemoryAddress { + MemoryAddress::from(ReservedRegisters::StackPointer as usize) } /// Returns the previous stack pointer register. This will be used to restore the registers after a fn call. - pub(crate) fn previous_stack_pointer() -> RegisterIndex { - RegisterIndex::from(ReservedRegisters::PreviousStackPointer as usize) + pub(crate) fn previous_stack_pointer() -> MemoryAddress { + MemoryAddress::from(ReservedRegisters::PreviousStackPointer as usize) } /// Returns a user defined (non-reserved) register index. - fn user_register_index(index: usize) -> RegisterIndex { - RegisterIndex::from(index + ReservedRegisters::len()) + fn user_register_index(index: usize) -> MemoryAddress { + MemoryAddress::from(index + ReservedRegisters::len()) } } @@ -109,7 +110,7 @@ impl BrilligContext { } } - pub(crate) fn set_allocated_registers(&mut self, allocated_registers: Vec) { + pub(crate) fn set_allocated_registers(&mut self, allocated_registers: Vec) { self.registers = BrilligRegistersContext::from_preallocated_registers(allocated_registers); } @@ -127,27 +128,28 @@ impl BrilligContext { /// in `pointer_register` pub(crate) fn allocate_fixed_length_array( &mut self, - pointer_register: RegisterIndex, + pointer_register: MemoryAddress, size: usize, ) { // debug_show handled by allocate_array_instruction - let size_register = self.make_constant(size.into()); + let size_register = self.make_usize_constant(size.into()); self.allocate_array_instruction(pointer_register, size_register); + self.deallocate_register(size_register); } /// Allocates an array of size contained in size_register and stores the /// pointer to the array in `pointer_register` pub(crate) fn allocate_array_instruction( &mut self, - pointer_register: RegisterIndex, - size_register: RegisterIndex, + pointer_register: MemoryAddress, + size_register: MemoryAddress, ) { self.debug_show.allocate_array_instruction(pointer_register, size_register); self.set_array_pointer(pointer_register); self.update_stack_pointer(size_register); } - pub(crate) fn set_array_pointer(&mut self, pointer_register: RegisterIndex) { + pub(crate) fn set_array_pointer(&mut self, pointer_register: MemoryAddress) { self.debug_show.mov_instruction(pointer_register, ReservedRegisters::stack_pointer()); self.push_opcode(BrilligOpcode::Mov { destination: pointer_register, @@ -155,7 +157,7 @@ impl BrilligContext { }); } - pub(crate) fn update_stack_pointer(&mut self, size_register: RegisterIndex) { + pub(crate) fn update_stack_pointer(&mut self, size_register: MemoryAddress) { self.memory_op( ReservedRegisters::stack_pointer(), size_register, @@ -168,12 +170,12 @@ impl BrilligContext { /// pointer to the array in `pointer_register` fn allocate_variable_reference_instruction( &mut self, - pointer_register: RegisterIndex, + pointer_register: MemoryAddress, size: usize, ) { self.debug_show.allocate_instruction(pointer_register); // A variable can be stored in up to three values, so we reserve three values for that. - let size_register = self.make_constant(size.into()); + let size_register = self.make_usize_constant(size.into()); self.push_opcode(BrilligOpcode::Mov { destination: pointer_register, source: ReservedRegisters::stack_pointer(), @@ -184,16 +186,17 @@ impl BrilligContext { ReservedRegisters::stack_pointer(), BinaryIntOp::Add, ); + self.deallocate_register(size_register); } pub(crate) fn allocate_simple_reference_instruction( &mut self, - pointer_register: RegisterIndex, + pointer_register: MemoryAddress, ) { self.allocate_variable_reference_instruction(pointer_register, 1); } - pub(crate) fn allocate_array_reference_instruction(&mut self, pointer_register: RegisterIndex) { + pub(crate) fn allocate_array_reference_instruction(&mut self, pointer_register: MemoryAddress) { self.allocate_variable_reference_instruction( pointer_register, BrilligArray::registers_count(), @@ -202,7 +205,7 @@ impl BrilligContext { pub(crate) fn allocate_vector_reference_instruction( &mut self, - pointer_register: RegisterIndex, + pointer_register: MemoryAddress, ) { self.allocate_variable_reference_instruction( pointer_register, @@ -213,9 +216,9 @@ impl BrilligContext { /// Gets the value in the array at index `index` and stores it in `result` pub(crate) fn array_get( &mut self, - array_ptr: RegisterIndex, - index: RegisterIndex, - result: RegisterIndex, + array_ptr: MemoryAddress, + index: MemoryAddress, + result: MemoryAddress, ) { self.debug_show.array_get(array_ptr, index, result); // Computes array_ptr + index, ie array[index] @@ -235,9 +238,9 @@ impl BrilligContext { /// Sets the item in the array at index `index` to `value` pub(crate) fn array_set( &mut self, - array_ptr: RegisterIndex, - index: RegisterIndex, - value: RegisterIndex, + array_ptr: MemoryAddress, + index: MemoryAddress, + value: MemoryAddress, ) { self.debug_show.array_set(array_ptr, index, value); // Computes array_ptr + index, ie array[index] @@ -258,9 +261,9 @@ impl BrilligContext { /// Into the array pointed by destination pub(crate) fn copy_array_instruction( &mut self, - source_pointer: RegisterIndex, - destination_pointer: RegisterIndex, - num_elements_register: RegisterIndex, + source_pointer: MemoryAddress, + destination_pointer: MemoryAddress, + num_elements_register: MemoryAddress, ) { self.debug_show.copy_array_instruction( source_pointer, @@ -280,11 +283,11 @@ impl BrilligContext { /// This instruction will issue a loop that will iterate iteration_count times /// The body of the loop should be issued by the caller in the on_iteration closure. - pub(crate) fn loop_instruction(&mut self, iteration_count: RegisterIndex, on_iteration: F) + pub(crate) fn loop_instruction(&mut self, iteration_count: MemoryAddress, on_iteration: F) where - F: FnOnce(&mut BrilligContext, RegisterIndex), + F: FnOnce(&mut BrilligContext, MemoryAddress), { - let iterator_register = self.make_constant(0_u128.into()); + let iterator_register = self.make_usize_constant(0_u128.into()); let (loop_section, loop_label) = self.reserve_next_section_label(); self.enter_section(loop_section); @@ -327,7 +330,7 @@ impl BrilligContext { /// functions to allow the given function to mutably alias its environment. pub(crate) fn branch_instruction( &mut self, - condition: RegisterIndex, + condition: MemoryAddress, mut f: impl FnMut(&mut BrilligContext, bool), ) { // Reserve 3 sections @@ -394,7 +397,7 @@ impl BrilligContext { /// Adds a unresolved `JumpIf` instruction to the bytecode. pub(crate) fn jump_if_instruction( &mut self, - condition: RegisterIndex, + condition: MemoryAddress, target_label: T, ) { self.debug_show.jump_if_instruction(condition, target_label.to_string()); @@ -414,14 +417,14 @@ impl BrilligContext { } /// Allocates an unused register. - pub(crate) fn allocate_register(&mut self) -> RegisterIndex { + pub(crate) fn allocate_register(&mut self) -> MemoryAddress { self.registers.allocate_register() } /// Push a register to the deallocation list, ready for reuse. /// TODO(AD): currently, register deallocation is only done with immediate values. /// TODO(AD): See https://github.com/noir-lang/noir/issues/1720 - pub(crate) fn deallocate_register(&mut self, register_index: RegisterIndex) { + pub(crate) fn deallocate_register(&mut self, register_index: MemoryAddress) { self.registers.deallocate_register(register_index); } } @@ -431,7 +434,7 @@ impl BrilligContext { /// is false. pub(crate) fn constrain_instruction( &mut self, - condition: RegisterIndex, + condition: MemoryAddress, assert_message: Option, ) { self.debug_show.constrain_instruction(condition); @@ -453,7 +456,7 @@ impl BrilligContext { /// Brillig does not have an explicit return instruction, so this /// method will move all register values to the first `N` values in /// the VM. - pub(crate) fn return_instruction(&mut self, return_registers: &[RegisterIndex]) { + pub(crate) fn return_instruction(&mut self, return_registers: &[MemoryAddress]) { self.debug_show.return_instruction(return_registers); let mut sources = Vec::with_capacity(return_registers.len()); let mut destinations = Vec::with_capacity(return_registers.len()); @@ -473,8 +476,8 @@ impl BrilligContext { /// It first moves all sources to new allocated registers to avoid overwriting. pub(crate) fn mov_registers_to_registers_instruction( &mut self, - sources: Vec, - destinations: Vec, + sources: Vec, + destinations: Vec, ) { let new_sources: Vec<_> = sources .iter() @@ -493,7 +496,7 @@ impl BrilligContext { /// Emits a `mov` instruction. /// /// Copies the value at `source` into `destination` - pub(crate) fn mov_instruction(&mut self, destination: RegisterIndex, source: RegisterIndex) { + pub(crate) fn mov_instruction(&mut self, destination: MemoryAddress, source: MemoryAddress) { self.debug_show.mov_instruction(destination, source); self.push_opcode(BrilligOpcode::Mov { destination, source }); } @@ -504,9 +507,9 @@ impl BrilligContext { /// and store the result in the `result` register. pub(crate) fn binary_instruction( &mut self, - lhs: RegisterIndex, - rhs: RegisterIndex, - result: RegisterIndex, + lhs: MemoryAddress, + rhs: MemoryAddress, + result: MemoryAddress, operation: BrilligBinaryOp, ) { self.debug_show.binary_instruction(lhs, rhs, result, operation.clone()); @@ -527,9 +530,18 @@ impl BrilligContext { } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&mut self, result: RegisterIndex, constant: Value) { + pub(crate) fn const_instruction( + &mut self, + result: MemoryAddress, + constant: Value, + bit_size: u32, + ) { self.debug_show.const_instruction(result, constant); - self.push_opcode(BrilligOpcode::Const { destination: result, value: constant }); + self.push_opcode(BrilligOpcode::Const { destination: result, value: constant, bit_size }); + } + + pub(crate) fn usize_const(&mut self, result: MemoryAddress, constant: Value) { + self.const_instruction(result, constant, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); } /// Processes a not instruction. @@ -538,15 +550,15 @@ impl BrilligContext { /// in Brillig. pub(crate) fn not_instruction( &mut self, - input: RegisterIndex, + input: MemoryAddress, bit_size: u32, - result: RegisterIndex, + result: MemoryAddress, ) { self.debug_show.not_instruction(input, bit_size, result); // Compile !x as ((-1) - x) let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(bit_size as i128)) - FieldElement::one(); - let max = self.make_constant(Value::from(u_max)); + let max = self.make_constant(Value::from(u_max), bit_size); let opcode = BrilligOpcode::BinaryIntOp { destination: result, op: BinaryIntOp::Sub, @@ -565,14 +577,20 @@ impl BrilligContext { pub(crate) fn foreign_call_instruction( &mut self, func_name: String, - inputs: &[RegisterOrMemory], - outputs: &[RegisterOrMemory], + inputs: &[ValueOrArray], + input_value_types: &[HeapValueType], + outputs: &[ValueOrArray], + output_value_types: &[HeapValueType], ) { + assert!(inputs.len() == input_value_types.len()); + assert!(outputs.len() == output_value_types.len()); self.debug_show.foreign_call_instruction(func_name.clone(), inputs, outputs); let opcode = BrilligOpcode::ForeignCall { function: func_name, destinations: outputs.to_vec(), + destination_value_types: output_value_types.to_vec(), inputs: inputs.to_vec(), + input_value_types: input_value_types.to_vec(), }; self.push_opcode(opcode); } @@ -580,8 +598,8 @@ impl BrilligContext { /// Emits a load instruction pub(crate) fn load_instruction( &mut self, - destination: RegisterIndex, - source_pointer: RegisterIndex, + destination: MemoryAddress, + source_pointer: MemoryAddress, ) { self.debug_show.load_instruction(destination, source_pointer); self.push_opcode(BrilligOpcode::Load { destination, source_pointer }); @@ -591,7 +609,7 @@ impl BrilligContext { pub(crate) fn load_variable_instruction( &mut self, destination: BrilligVariable, - variable_pointer: RegisterIndex, + variable_pointer: MemoryAddress, ) { match destination { BrilligVariable::Simple(register_index) => { @@ -630,8 +648,8 @@ impl BrilligContext { /// Emits a store instruction pub(crate) fn store_instruction( &mut self, - destination_pointer: RegisterIndex, - source: RegisterIndex, + destination_pointer: MemoryAddress, + source: MemoryAddress, ) { self.debug_show.store_instruction(destination_pointer, source); self.push_opcode(BrilligOpcode::Store { destination_pointer, source }); @@ -640,7 +658,7 @@ impl BrilligContext { /// Stores a variable by saving its registers to memory pub(crate) fn store_variable_instruction( &mut self, - variable_pointer: RegisterIndex, + variable_pointer: MemoryAddress, source: BrilligVariable, ) { match source { @@ -650,7 +668,7 @@ impl BrilligContext { BrilligVariable::BrilligArray(BrilligArray { pointer, size: _, rc }) => { self.store_instruction(variable_pointer, pointer); - let rc_pointer: RegisterIndex = self.allocate_register(); + let rc_pointer: MemoryAddress = self.allocate_register(); self.mov_instruction(rc_pointer, variable_pointer); self.usize_op_in_place(rc_pointer, BinaryIntOp::Add, 1_usize); self.store_instruction(rc_pointer, rc); @@ -664,7 +682,7 @@ impl BrilligContext { self.usize_op_in_place(size_pointer, BinaryIntOp::Add, 1_usize); self.store_instruction(size_pointer, size); - let rc_pointer: RegisterIndex = self.allocate_register(); + let rc_pointer: MemoryAddress = self.allocate_register(); self.mov_instruction(rc_pointer, variable_pointer); self.usize_op_in_place(rc_pointer, BinaryIntOp::Add, 2_usize); self.store_instruction(rc_pointer, rc); @@ -685,8 +703,8 @@ impl BrilligContext { /// For Brillig, all integer operations will overflow as its cheap. pub(crate) fn truncate_instruction( &mut self, - destination_of_truncated_value: RegisterIndex, - value_to_truncate: RegisterIndex, + destination_of_truncated_value: MemoryAddress, + value_to_truncate: MemoryAddress, bit_size: u32, ) { self.debug_show.truncate_instruction( @@ -702,7 +720,7 @@ impl BrilligContext { // The brillig VM performs all arithmetic operations modulo 2**bit_size // So to truncate any value to a target bit size we can just issue a no-op arithmetic operation // With bit size equal to target_bit_size - let zero_register = self.make_constant(Value::from(FieldElement::zero())); + let zero_register = self.make_constant(Value::from(FieldElement::zero()), bit_size); self.binary_instruction( value_to_truncate, zero_register, @@ -715,13 +733,20 @@ impl BrilligContext { /// Emits a stop instruction pub(crate) fn stop_instruction(&mut self) { self.debug_show.stop_instruction(); - self.push_opcode(BrilligOpcode::Stop); + self.push_opcode(BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }); } /// Returns a register which holds the value of a constant - pub(crate) fn make_constant(&mut self, constant: Value) -> RegisterIndex { + pub(crate) fn make_constant(&mut self, constant: Value, bit_size: u32) -> MemoryAddress { let register = self.allocate_register(); - self.const_instruction(register, constant); + self.const_instruction(register, constant, bit_size); + register + } + + /// Returns a register which holds the value of an usize constant + pub(crate) fn make_usize_constant(&mut self, constant: Value) -> MemoryAddress { + let register = self.allocate_register(); + self.usize_const(register, constant); register } @@ -736,9 +761,9 @@ impl BrilligContext { /// to other binary instructions. pub(crate) fn modulo_instruction( &mut self, - result_register: RegisterIndex, - left: RegisterIndex, - right: RegisterIndex, + result_register: MemoryAddress, + left: MemoryAddress, + right: MemoryAddress, bit_size: u32, signed: bool, ) { @@ -791,12 +816,12 @@ impl BrilligContext { } /// Returns the i'th register after the reserved ones - pub(crate) fn register(&self, i: usize) -> RegisterIndex { - RegisterIndex::from(ReservedRegisters::NUM_RESERVED_REGISTERS + i) + pub(crate) fn register(&self, i: usize) -> MemoryAddress { + MemoryAddress::from(ReservedRegisters::NUM_RESERVED_REGISTERS + i) } /// Saves all of the registers that have been used up until this point. - fn save_registers_of_vars(&mut self, vars: &[BrilligVariable]) -> Vec { + fn save_registers_of_vars(&mut self, vars: &[BrilligVariable]) -> Vec { // Save all of the used registers at this point in memory // because the function call will/may overwrite them. // @@ -822,7 +847,7 @@ impl BrilligContext { } /// Loads all of the registers that have been save by save_all_used_registers. - fn load_all_saved_registers(&mut self, used_registers: &[RegisterIndex]) { + fn load_all_saved_registers(&mut self, used_registers: &[MemoryAddress]) { // Load all of the used registers that we saved. // We do all the reverse operations of save_all_used_registers. // Iterate our registers in reverse @@ -839,7 +864,7 @@ impl BrilligContext { /// Utility method to perform a binary instruction with a constant value in place pub(crate) fn usize_op_in_place( &mut self, - destination: RegisterIndex, + destination: MemoryAddress, op: BinaryIntOp, constant: usize, ) { @@ -849,12 +874,12 @@ impl BrilligContext { /// Utility method to perform a binary instruction with a constant value pub(crate) fn usize_op( &mut self, - operand: RegisterIndex, - destination: RegisterIndex, + operand: MemoryAddress, + destination: MemoryAddress, op: BinaryIntOp, constant: usize, ) { - let const_register = self.make_constant(Value::from(constant)); + let const_register = self.make_usize_constant(Value::from(constant)); self.memory_op(operand, const_register, destination, op); // Mark as no longer used for this purpose, frees for reuse self.deallocate_register(const_register); @@ -863,9 +888,9 @@ impl BrilligContext { /// Utility method to perform a binary instruction with a memory address pub(crate) fn memory_op( &mut self, - lhs: RegisterIndex, - rhs: RegisterIndex, - destination: RegisterIndex, + lhs: MemoryAddress, + rhs: MemoryAddress, + destination: MemoryAddress, op: BinaryIntOp, ) { self.binary_instruction( @@ -881,9 +906,9 @@ impl BrilligContext { // Move argument values to the front of the register indices. pub(crate) fn pre_call_save_registers_prep_args( &mut self, - arguments: &[RegisterIndex], + arguments: &[MemoryAddress], variables_to_save: &[BrilligVariable], - ) -> Vec { + ) -> Vec { // Save all the registers we have used to the stack. let saved_registers = self.save_registers_of_vars(variables_to_save); @@ -891,8 +916,11 @@ impl BrilligContext { // // This means that the arguments will be in the first `n` registers after // the number of reserved registers. - let (sources, destinations) = + let (sources, destinations): (Vec<_>, Vec<_>) = arguments.iter().enumerate().map(|(i, argument)| (*argument, self.register(i))).unzip(); + destinations + .iter() + .for_each(|destination| self.registers.ensure_register_is_allocated(*destination)); self.mov_registers_to_registers_instruction(sources, destinations); saved_registers } @@ -902,8 +930,8 @@ impl BrilligContext { // Load all the registers we have previous saved in save_registers_prep_args. pub(crate) fn post_call_prep_returns_load_registers( &mut self, - result_registers: &[RegisterIndex], - saved_registers: &[RegisterIndex], + result_registers: &[MemoryAddress], + saved_registers: &[MemoryAddress], ) { // Allocate our result registers and write into them // We assume the return values of our call are held in 0..num results register indices @@ -924,13 +952,13 @@ impl BrilligContext { /// Utility method to transform a HeapArray to a HeapVector by making a runtime constant with the size. pub(crate) fn array_to_vector(&mut self, array: &BrilligArray) -> BrilligVector { - let size_register = self.make_constant(array.size.into()); + let size_register = self.make_usize_constant(array.size.into()); BrilligVector { size: size_register, pointer: array.pointer, rc: array.rc } } /// Issues a blackbox operation. pub(crate) fn black_box_op_instruction(&mut self, op: BlackBoxOp) { - self.debug_show.black_box_op_instruction(op); + self.debug_show.black_box_op_instruction(&op); self.push_opcode(BrilligOpcode::BlackBox(op)); } @@ -938,20 +966,20 @@ impl BrilligContext { /// And the radix register limb_count times to the target vector. pub(crate) fn radix_instruction( &mut self, - source: RegisterIndex, + source: MemoryAddress, target_vector: BrilligVector, - radix: RegisterIndex, - limb_count: RegisterIndex, + radix: MemoryAddress, + limb_count: MemoryAddress, big_endian: bool, ) { self.mov_instruction(target_vector.size, limb_count); - self.const_instruction(target_vector.rc, 1_usize.into()); + self.usize_const(target_vector.rc, 1_usize.into()); self.allocate_array_instruction(target_vector.pointer, target_vector.size); let shifted_register = self.allocate_register(); self.mov_instruction(shifted_register, source); - let modulus_register: RegisterIndex = self.allocate_register(); + let modulus_register: MemoryAddress = self.allocate_register(); self.loop_instruction(target_vector.size, |ctx, iterator_register| { // Compute the modulus @@ -1042,10 +1070,11 @@ pub(crate) mod tests { use std::vec; use acvm::acir::brillig::{ - BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapVector, RegisterIndex, - RegisterOrMemory, Value, + BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapVector, MemoryAddress, Value, + ValueOrArray, }; - use acvm::brillig_vm::{Registers, VMStatus, VM}; + use acvm::brillig_vm::brillig::HeapValueType; + use acvm::brillig_vm::{VMStatus, VM}; use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; use crate::brillig::brillig_ir::BrilligContext; @@ -1117,21 +1146,17 @@ pub(crate) mod tests { } pub(crate) fn create_and_run_vm( - memory: Vec, - param_registers: Vec, + calldata: Vec, bytecode: &[BrilligOpcode], - ) -> VM<'_, DummyBlackBoxSolver> { - let mut vm = VM::new( - Registers { inner: param_registers }, - memory, - bytecode, - vec![], - &DummyBlackBoxSolver, - ); + ) -> (VM<'_, DummyBlackBoxSolver>, usize, usize) { + let mut vm = VM::new(calldata, bytecode, vec![], &DummyBlackBoxSolver); let status = vm.process_opcodes(); - assert_eq!(status, VMStatus::Finished); - vm + if let VMStatus::Finished { return_data_offset, return_data_size } = status { + (vm, return_data_offset, return_data_size) + } else { + panic!("VM did not finish") + } } /// Test a Brillig foreign call returning a vector @@ -1150,18 +1175,20 @@ pub(crate) mod tests { let mut context = BrilligContext::new(true); let r_stack = ReservedRegisters::stack_pointer(); // Start stack pointer at 0 - context.const_instruction(r_stack, Value::from(0_usize)); - let r_input_size = RegisterIndex::from(ReservedRegisters::len()); - let r_array_ptr = RegisterIndex::from(ReservedRegisters::len() + 1); - let r_output_size = RegisterIndex::from(ReservedRegisters::len() + 2); - let r_equality = RegisterIndex::from(ReservedRegisters::len() + 3); - context.const_instruction(r_input_size, Value::from(12_usize)); + context.usize_const(r_stack, Value::from(ReservedRegisters::len() + 3)); + let r_input_size = MemoryAddress::from(ReservedRegisters::len()); + let r_array_ptr = MemoryAddress::from(ReservedRegisters::len() + 1); + let r_output_size = MemoryAddress::from(ReservedRegisters::len() + 2); + let r_equality = MemoryAddress::from(ReservedRegisters::len() + 3); + context.usize_const(r_input_size, Value::from(12_usize)); // copy our stack frame to r_array_ptr context.mov_instruction(r_array_ptr, r_stack); context.foreign_call_instruction( "make_number_sequence".into(), - &[RegisterOrMemory::RegisterIndex(r_input_size)], - &[RegisterOrMemory::HeapVector(HeapVector { pointer: r_stack, size: r_output_size })], + &[ValueOrArray::MemoryAddress(r_input_size)], + &[HeapValueType::Simple], + &[ValueOrArray::HeapVector(HeapVector { pointer: r_stack, size: r_output_size })], + &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }], ); // push stack frame by r_returned_size context.memory_op(r_stack, r_output_size, r_stack, BinaryIntOp::Add); @@ -1178,13 +1205,12 @@ pub(crate) mod tests { let bytecode = context.artifact().finish().byte_code; let number_sequence: Vec = (0_usize..12_usize).map(Value::from).collect(); let mut vm = VM::new( - Registers { inner: vec![] }, vec![], &bytecode, vec![ForeignCallResult { values: vec![ForeignCallParam::Array(number_sequence)] }], &DummyBlackBoxSolver, ); let status = vm.process_opcodes(); - assert_eq!(status, VMStatus::Finished); + assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs index 9b8c3913123..437774da157 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs @@ -97,7 +97,7 @@ impl BrilligArtifact { // Replace STOP with RETURN because this is not the end of the program now. let stop_position = byte_code .iter() - .position(|opcode| matches!(opcode, BrilligOpcode::Stop)) + .position(|opcode| matches!(opcode, BrilligOpcode::Stop { .. })) .expect("Trying to link with a function that does not have a stop opcode"); byte_code[stop_position] = BrilligOpcode::Return; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index 46c54d55ecb..856fb709fa9 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -1,12 +1,16 @@ -use acvm::brillig_vm::brillig::{HeapArray, HeapVector, RegisterIndex, RegisterOrMemory}; +use acvm::brillig_vm::brillig::{ + HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray, +}; use serde::{Deserialize, Serialize}; +use crate::ssa::ir::types::Type; + /// The representation of a noir array in the Brillig IR #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) struct BrilligArray { - pub(crate) pointer: RegisterIndex, + pub(crate) pointer: MemoryAddress, pub(crate) size: usize, - pub(crate) rc: RegisterIndex, + pub(crate) rc: MemoryAddress, } impl BrilligArray { @@ -18,7 +22,7 @@ impl BrilligArray { 2 } - pub(crate) fn extract_registers(self) -> Vec { + pub(crate) fn extract_registers(self) -> Vec { vec![self.pointer, self.rc] } } @@ -26,9 +30,9 @@ impl BrilligArray { /// The representation of a noir slice in the Brillig IR #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) struct BrilligVector { - pub(crate) pointer: RegisterIndex, - pub(crate) size: RegisterIndex, - pub(crate) rc: RegisterIndex, + pub(crate) pointer: MemoryAddress, + pub(crate) size: MemoryAddress, + pub(crate) rc: MemoryAddress, } impl BrilligVector { @@ -40,7 +44,7 @@ impl BrilligVector { 3 } - pub(crate) fn extract_registers(self) -> Vec { + pub(crate) fn extract_registers(self) -> Vec { vec![self.pointer, self.size, self.rc] } } @@ -48,13 +52,13 @@ impl BrilligVector { /// The representation of a noir value in the Brillig IR #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) enum BrilligVariable { - Simple(RegisterIndex), + Simple(MemoryAddress), BrilligArray(BrilligArray), BrilligVector(BrilligVector), } impl BrilligVariable { - pub(crate) fn extract_register(self) -> RegisterIndex { + pub(crate) fn extract_register(self) -> MemoryAddress { match self { BrilligVariable::Simple(register_index) => register_index, _ => unreachable!("ICE: Expected register, got {self:?}"), @@ -75,7 +79,7 @@ impl BrilligVariable { } } - pub(crate) fn extract_registers(self) -> Vec { + pub(crate) fn extract_registers(self) -> Vec { match self { BrilligVariable::Simple(register_index) => vec![register_index], BrilligVariable::BrilligArray(array) => array.extract_registers(), @@ -83,17 +87,26 @@ impl BrilligVariable { } } - pub(crate) fn to_register_or_memory(self) -> RegisterOrMemory { + pub(crate) fn to_register_or_memory(self) -> ValueOrArray { match self { - BrilligVariable::Simple(register_index) => { - RegisterOrMemory::RegisterIndex(register_index) - } - BrilligVariable::BrilligArray(array) => { - RegisterOrMemory::HeapArray(array.to_heap_array()) - } + BrilligVariable::Simple(register_index) => ValueOrArray::MemoryAddress(register_index), + BrilligVariable::BrilligArray(array) => ValueOrArray::HeapArray(array.to_heap_array()), BrilligVariable::BrilligVector(vector) => { - RegisterOrMemory::HeapVector(vector.to_heap_vector()) + ValueOrArray::HeapVector(vector.to_heap_vector()) } } } } + +pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType { + match typ { + Type::Numeric(_) | Type::Reference(_) | Type::Function => HeapValueType::Simple, + Type::Array(elem_type, size) => HeapValueType::Array { + value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), + size: typ.element_size() * size, + }, + Type::Slice(elem_type) => HeapValueType::Vector { + value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), + }, + } +} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index a8563dc9efe..616c5c5027a 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -3,8 +3,8 @@ use super::BrilligBinaryOp; use crate::brillig::brillig_ir::{ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE}; use acvm::acir::brillig::{ - BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapArray, HeapVector, RegisterIndex, RegisterOrMemory, - Value, + BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapArray, HeapVector, MemoryAddress, Value, + ValueOrArray, }; /// Trait for converting values into debug-friendly strings. @@ -24,7 +24,7 @@ macro_rules! default_to_string_impl { default_to_string_impl! { str usize u32 } -impl DebugToString for RegisterIndex { +impl DebugToString for MemoryAddress { fn debug_to_string(&self) -> String { if *self == ReservedRegisters::stack_pointer() { "Stack".into() @@ -74,9 +74,8 @@ impl DebugToString for BinaryIntOp { BinaryIntOp::And => "&&".into(), BinaryIntOp::Or => "||".into(), BinaryIntOp::Xor => "^".into(), - BinaryIntOp::Shl | BinaryIntOp::Shr => { - unreachable!("bit shift should have been replaced") - } + BinaryIntOp::Shl => "<<".into(), + BinaryIntOp::Shr => ">>".into(), } } } @@ -112,12 +111,12 @@ impl DebugToString for Value { } } -impl DebugToString for RegisterOrMemory { +impl DebugToString for ValueOrArray { fn debug_to_string(&self) -> String { match self { - RegisterOrMemory::RegisterIndex(index) => index.debug_to_string(), - RegisterOrMemory::HeapArray(heap_array) => heap_array.debug_to_string(), - RegisterOrMemory::HeapVector(vector) => vector.debug_to_string(), + ValueOrArray::MemoryAddress(index) => index.debug_to_string(), + ValueOrArray::HeapArray(heap_array) => heap_array.debug_to_string(), + ValueOrArray::HeapVector(vector) => vector.debug_to_string(), } } } @@ -152,15 +151,15 @@ impl DebugShow { /// Emits brillig bytecode to jump to a trap condition if `condition` /// is false. - pub(crate) fn constrain_instruction(&self, condition: RegisterIndex) { + pub(crate) fn constrain_instruction(&self, condition: MemoryAddress) { debug_println!(self.enable_debug_trace, " ASSERT {} != 0", condition); } /// Processes a return instruction. - pub(crate) fn return_instruction(&self, return_registers: &[RegisterIndex]) { + pub(crate) fn return_instruction(&self, return_registers: &[MemoryAddress]) { let registers_string = return_registers .iter() - .map(RegisterIndex::debug_to_string) + .map(MemoryAddress::debug_to_string) .collect::>() .join(", "); @@ -168,32 +167,32 @@ impl DebugShow { } /// Emits a `mov` instruction. - pub(crate) fn mov_instruction(&self, destination: RegisterIndex, source: RegisterIndex) { + pub(crate) fn mov_instruction(&self, destination: MemoryAddress, source: MemoryAddress) { debug_println!(self.enable_debug_trace, " MOV {}, {}", destination, source); } /// Processes a binary instruction according `operation`. pub(crate) fn binary_instruction( &self, - lhs: RegisterIndex, - rhs: RegisterIndex, - result: RegisterIndex, + lhs: MemoryAddress, + rhs: MemoryAddress, + result: MemoryAddress, operation: BrilligBinaryOp, ) { debug_println!(self.enable_debug_trace, " {} = {} {} {}", result, lhs, operation, rhs); } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&self, result: RegisterIndex, constant: Value) { + pub(crate) fn const_instruction(&self, result: MemoryAddress, constant: Value) { debug_println!(self.enable_debug_trace, " CONST {} = {}", result, constant); } /// Processes a not instruction. Append with "_" as this is a high-level instruction. pub(crate) fn not_instruction( &self, - condition: RegisterIndex, + condition: MemoryAddress, bit_size: u32, - result: RegisterIndex, + result: MemoryAddress, ) { debug_println!(self.enable_debug_trace, " i{}_NOT {} = !{}", bit_size, result, condition); } @@ -202,8 +201,8 @@ impl DebugShow { pub(crate) fn foreign_call_instruction( &self, func_name: String, - inputs: &[RegisterOrMemory], - outputs: &[RegisterOrMemory], + inputs: &[ValueOrArray], + outputs: &[ValueOrArray], ) { debug_println!( self.enable_debug_trace, @@ -217,8 +216,8 @@ impl DebugShow { /// Emits a load instruction pub(crate) fn load_instruction( &self, - destination: RegisterIndex, - source_pointer: RegisterIndex, + destination: MemoryAddress, + source_pointer: MemoryAddress, ) { debug_println!(self.enable_debug_trace, " LOAD {} = *{}", destination, source_pointer); } @@ -226,8 +225,8 @@ impl DebugShow { /// Emits a store instruction pub(crate) fn store_instruction( &self, - destination_pointer: RegisterIndex, - source: RegisterIndex, + destination_pointer: MemoryAddress, + source: MemoryAddress, ) { debug_println!(self.enable_debug_trace, " STORE *{} = {}", destination_pointer, source); } @@ -240,8 +239,8 @@ impl DebugShow { /// Debug function for allocate_array_instruction pub(crate) fn allocate_array_instruction( &self, - pointer_register: RegisterIndex, - size_register: RegisterIndex, + pointer_register: MemoryAddress, + size_register: MemoryAddress, ) { debug_println!( self.enable_debug_trace, @@ -252,16 +251,16 @@ impl DebugShow { } /// Debug function for allocate_instruction - pub(crate) fn allocate_instruction(&self, pointer_register: RegisterIndex) { + pub(crate) fn allocate_instruction(&self, pointer_register: MemoryAddress) { debug_println!(self.enable_debug_trace, " ALLOCATE {} ", pointer_register); } /// Debug function for array_get pub(crate) fn array_get( &self, - array_ptr: RegisterIndex, - index: RegisterIndex, - result: RegisterIndex, + array_ptr: MemoryAddress, + index: MemoryAddress, + result: MemoryAddress, ) { debug_println!( self.enable_debug_trace, @@ -275,9 +274,9 @@ impl DebugShow { /// Debug function for array_set pub(crate) fn array_set( &self, - array_ptr: RegisterIndex, - index: RegisterIndex, - value: RegisterIndex, + array_ptr: MemoryAddress, + index: MemoryAddress, + value: MemoryAddress, ) { debug_println!(self.enable_debug_trace, " ARRAY_SET {}[{}] = {}", array_ptr, index, value); } @@ -285,9 +284,9 @@ impl DebugShow { /// Debug function for copy_array_instruction pub(crate) fn copy_array_instruction( &self, - source: RegisterIndex, - destination: RegisterIndex, - num_elements_register: RegisterIndex, + source: MemoryAddress, + destination: MemoryAddress, + num_elements_register: MemoryAddress, ) { debug_println!( self.enable_debug_trace, @@ -314,7 +313,7 @@ impl DebugShow { /// Debug function for jump_if_instruction pub(crate) fn jump_if_instruction( &self, - condition: RegisterIndex, + condition: MemoryAddress, target_label: T, ) { debug_println!( @@ -328,8 +327,8 @@ impl DebugShow { /// Debug function for cast_instruction pub(crate) fn truncate_instruction( &self, - destination: RegisterIndex, - source: RegisterIndex, + destination: MemoryAddress, + source: MemoryAddress, target_bit_size: u32, ) { debug_println!( @@ -342,7 +341,7 @@ impl DebugShow { } /// Debug function for black_box_op - pub(crate) fn black_box_op_instruction(&self, op: BlackBoxOp) { + pub(crate) fn black_box_op_instruction(&self, op: &BlackBoxOp) { match op { BlackBoxOp::Sha256 { message, output } => { debug_println!(self.enable_debug_trace, " SHA256 {} -> {}", message, output); @@ -457,7 +456,7 @@ impl DebugShow { output ); } - BlackBoxOp::BigIntNeg { lhs, rhs, output } => { + BlackBoxOp::BigIntSub { lhs, rhs, output } => { debug_println!( self.enable_debug_trace, " BIGINT_NEG {} {} -> {}", diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 36ca414f38e..fc4ac36d7fd 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -1,13 +1,13 @@ -use crate::brillig::brillig_ir::ReservedRegisters; - use super::{ artifact::{BrilligArtifact, BrilligParameter}, brillig_variable::{BrilligArray, BrilligVariable}, debug_show::DebugShow, registers::BrilligRegistersContext, - BrilligContext, + BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; -use acvm::acir::brillig::{Opcode as BrilligOpcode, RegisterIndex}; +use acvm::acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}; + +pub(crate) const MAX_STACK_SIZE: usize = 1024; impl BrilligContext { /// Creates an entry point artifact that will jump to the function label provided. @@ -25,87 +25,86 @@ impl BrilligContext { debug_show: DebugShow::new(false), }; - context.entry_point_instruction(arguments); + context.entry_point_instruction(&arguments, &return_parameters); context.add_external_call_instruction(target_function); - context.exit_point_instruction(return_parameters); + context.exit_point_instruction(&arguments, &return_parameters); context.artifact() } /// Adds the instructions needed to handle entry point parameters - /// The runtime will leave the parameters in the first `n` registers. - /// Arrays will be passed as pointers to the first element, with all the nested arrays flattened. - /// First, reserve the registers that contain the parameters. - /// This function also sets the starting value of the reserved registers - fn entry_point_instruction(&mut self, arguments: Vec) { - let preallocated_registers: Vec<_> = - arguments.iter().enumerate().map(|(i, _)| RegisterIndex::from(i)).collect(); - self.set_allocated_registers(preallocated_registers.clone()); - - // Then allocate and initialize the variables that will hold the parameters - let argument_variables: Vec<_> = arguments + /// The runtime will leave the parameters in calldata. + /// Arrays will be passed flattened. + fn entry_point_instruction( + &mut self, + arguments: &[BrilligParameter], + return_parameters: &[BrilligParameter], + ) { + let calldata_size = BrilligContext::flattened_tuple_size(arguments); + let return_data_size = BrilligContext::flattened_tuple_size(return_parameters); + + // Set initial value of stack pointer: MAX_STACK_SIZE + calldata_size + return_data_size + self.push_opcode(BrilligOpcode::Const { + destination: ReservedRegisters::stack_pointer(), + value: (MAX_STACK_SIZE + calldata_size + return_data_size).into(), + bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + }); + + // Copy calldata + self.push_opcode(BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress(MAX_STACK_SIZE), + size: calldata_size, + offset: 0, + }); + + // Allocate the variables for every argument: + let mut current_calldata_pointer = MAX_STACK_SIZE; + + let mut argument_variables: Vec<_> = arguments .iter() - .zip(preallocated_registers) - .map(|(argument, param_register)| match argument { + .map(|argument| match argument { BrilligParameter::Simple => { - let variable_register = self.allocate_register(); - self.mov_instruction(variable_register, param_register); - BrilligVariable::Simple(variable_register) + let simple_address = self.allocate_register(); + let var = BrilligVariable::Simple(simple_address); + self.mov_instruction(simple_address, MemoryAddress(current_calldata_pointer)); + current_calldata_pointer += 1; + var } - BrilligParameter::Array(item_types, item_count) => { - let pointer_register = self.allocate_register(); - let rc_register = self.allocate_register(); - self.mov_instruction(pointer_register, param_register); - self.const_instruction(rc_register, 1_usize.into()); - BrilligVariable::BrilligArray(BrilligArray { - pointer: pointer_register, - size: item_types.len() * item_count, + BrilligParameter::Array(_, _) => { + let pointer_to_the_array_in_calldata = + self.make_usize_constant(current_calldata_pointer.into()); + let rc_register = self.make_usize_constant(1_usize.into()); + let flattened_size = BrilligContext::flattened_size(argument); + let var = BrilligVariable::BrilligArray(BrilligArray { + pointer: pointer_to_the_array_in_calldata, + size: flattened_size, rc: rc_register, - }) + }); + + current_calldata_pointer += flattened_size; + var } BrilligParameter::Slice(_) => unimplemented!("Unsupported slices as parameter"), }) .collect(); - // Calculate the initial value for the stack pointer register - let size_arguments_memory: usize = arguments - .iter() - .map(|arg| match arg { - BrilligParameter::Simple => 0, - _ => BrilligContext::flattened_size(arg), - }) - .sum(); - - // Set the initial value of the stack pointer register - self.push_opcode(BrilligOpcode::Const { - destination: ReservedRegisters::stack_pointer(), - value: size_arguments_memory.into(), - }); - // Set the initial value of the previous stack pointer register - self.push_opcode(BrilligOpcode::Const { - destination: ReservedRegisters::previous_stack_pointer(), - value: 0_usize.into(), - }); - - // Deflatten the arrays - for (parameter, assigned_variable) in arguments.iter().zip(&argument_variables) { - if let BrilligParameter::Array(item_type, item_count) = parameter { - if item_type.iter().any(|param| !matches!(param, BrilligParameter::Simple)) { - let pointer_register = assigned_variable.extract_array().pointer; - let deflattened_register = - self.deflatten_array(item_type, *item_count, pointer_register); - self.mov_instruction(pointer_register, deflattened_register); + // Deflatten arrays + for (argument_variable, argument) in argument_variables.iter_mut().zip(arguments) { + if let ( + BrilligVariable::BrilligArray(array), + BrilligParameter::Array(item_type, item_count), + ) = (argument_variable, argument) + { + if BrilligContext::has_nested_arrays(item_type) { + let deflattened_address = + self.deflatten_array(item_type, array.size, array.pointer); + self.mov_instruction(array.pointer, deflattened_address); + array.size = item_type.len() * item_count; + self.deallocate_register(deflattened_address); } } } - - // Move the parameters to the first user defined registers, to follow function call convention. - for (i, register) in - argument_variables.into_iter().flat_map(|arg| arg.extract_registers()).enumerate() - { - self.mov_instruction(ReservedRegisters::user_register_index(i), register); - } } /// Computes the size of a parameter if it was flattened @@ -122,95 +121,130 @@ impl BrilligContext { } } + /// Computes the size of a parameter if it was flattened + fn flattened_tuple_size(tuple: &[BrilligParameter]) -> usize { + tuple.iter().map(BrilligContext::flattened_size).sum() + } + + /// Computes the size of a parameter if it was flattened + fn has_nested_arrays(tuple: &[BrilligParameter]) -> bool { + tuple.iter().any(|param| !matches!(param, BrilligParameter::Simple)) + } + /// Deflatten an array by recursively allocating nested arrays and copying the plain values. /// Returns the pointer to the deflattened items. fn deflatten_array( &mut self, item_type: &[BrilligParameter], item_count: usize, - flattened_array_pointer: RegisterIndex, - ) -> RegisterIndex { - let movement_register = self.allocate_register(); - let deflattened_array_pointer = self.allocate_register(); - - let target_item_size = item_type.len(); - let source_item_size: usize = item_type.iter().map(BrilligContext::flattened_size).sum(); - - self.allocate_fixed_length_array(deflattened_array_pointer, item_count * target_item_size); - - for item_index in 0..item_count { - let source_item_base_index = item_index * source_item_size; - let target_item_base_index = item_index * target_item_size; - - let mut source_offset = 0; - - for (subitem_index, subitem) in item_type.iter().enumerate() { - let source_index = - self.make_constant((source_item_base_index + source_offset).into()); - - let target_index = - self.make_constant((target_item_base_index + subitem_index).into()); - - match subitem { - BrilligParameter::Simple => { - self.array_get(flattened_array_pointer, source_index, movement_register); - self.array_set(deflattened_array_pointer, target_index, movement_register); - source_offset += 1; - } - BrilligParameter::Array(nested_array_item_type, nested_array_item_count) => { - let nested_array_pointer = self.allocate_register(); - self.mov_instruction(nested_array_pointer, flattened_array_pointer); - self.memory_op( - nested_array_pointer, - source_index, - nested_array_pointer, - acvm::brillig_vm::brillig::BinaryIntOp::Add, - ); - let deflattened_nested_array_pointer = self.deflatten_array( + flattened_array_pointer: MemoryAddress, + ) -> MemoryAddress { + if BrilligContext::has_nested_arrays(item_type) { + let movement_register = self.allocate_register(); + let deflattened_array_pointer = self.allocate_register(); + + let target_item_size = item_type.len(); + let source_item_size = BrilligContext::flattened_tuple_size(item_type); + + self.allocate_fixed_length_array( + deflattened_array_pointer, + item_count * target_item_size, + ); + + for item_index in 0..item_count { + let source_item_base_index = item_index * source_item_size; + let target_item_base_index = item_index * target_item_size; + + let mut source_offset = 0; + + for (subitem_index, subitem) in item_type.iter().enumerate() { + let source_index = + self.make_usize_constant((source_item_base_index + source_offset).into()); + + let target_index = + self.make_usize_constant((target_item_base_index + subitem_index).into()); + + match subitem { + BrilligParameter::Simple => { + self.array_get( + flattened_array_pointer, + source_index, + movement_register, + ); + self.array_set( + deflattened_array_pointer, + target_index, + movement_register, + ); + source_offset += 1; + } + BrilligParameter::Array( nested_array_item_type, - *nested_array_item_count, - nested_array_pointer, - ); - let reference = self.allocate_register(); - let rc = self.allocate_register(); - self.const_instruction(rc, 1_usize.into()); - - self.allocate_array_reference_instruction(reference); - self.store_variable_instruction( - reference, - BrilligVariable::BrilligArray(BrilligArray { + nested_array_item_count, + ) => { + let nested_array_pointer = self.allocate_register(); + self.mov_instruction(nested_array_pointer, flattened_array_pointer); + self.memory_op( + nested_array_pointer, + source_index, + nested_array_pointer, + acvm::brillig_vm::brillig::BinaryIntOp::Add, + ); + let deflattened_nested_array_pointer = self.deflatten_array( + nested_array_item_type, + *nested_array_item_count, + nested_array_pointer, + ); + let reference = self.allocate_register(); + let rc = self.allocate_register(); + self.usize_const(rc, 1_usize.into()); + + self.allocate_array_reference_instruction(reference); + let array_variable = BrilligVariable::BrilligArray(BrilligArray { pointer: deflattened_nested_array_pointer, size: nested_array_item_type.len() * nested_array_item_count, rc, - }), - ); + }); + self.store_variable_instruction(reference, array_variable); - self.array_set(deflattened_array_pointer, target_index, reference); + self.array_set(deflattened_array_pointer, target_index, reference); - self.deallocate_register(nested_array_pointer); - self.deallocate_register(reference); - self.deallocate_register(rc); + self.deallocate_register(nested_array_pointer); + self.deallocate_register(reference); + array_variable + .extract_registers() + .into_iter() + .for_each(|register| self.deallocate_register(register)); - source_offset += BrilligContext::flattened_size(subitem); + source_offset += BrilligContext::flattened_size(subitem); + } + BrilligParameter::Slice(..) => unreachable!("ICE: Cannot deflatten slices"), } - BrilligParameter::Slice(..) => unreachable!("ICE: Cannot deflatten slices"), - } - self.deallocate_register(source_index); - self.deallocate_register(target_index); + self.deallocate_register(source_index); + self.deallocate_register(target_index); + } } - } - self.deallocate_register(movement_register); + self.deallocate_register(movement_register); - deflattened_array_pointer + deflattened_array_pointer + } else { + let deflattened_array_pointer = self.allocate_register(); + self.mov_instruction(deflattened_array_pointer, flattened_array_pointer); + deflattened_array_pointer + } } /// Adds the instructions needed to handle return parameters - /// The runtime expects the results in the first `n` registers. - /// Arrays are expected to be returned as pointers to the first element with all the nested arrays flattened. + /// The runtime expects the results in a contiguous memory region. + /// Arrays are expected to be returned with all the nested arrays flattened. /// However, the function called returns variables (that have extra data) and the returned arrays are deflattened. - fn exit_point_instruction(&mut self, return_parameters: Vec) { + fn exit_point_instruction( + &mut self, + arguments: &[BrilligParameter], + return_parameters: &[BrilligParameter], + ) { // First, we allocate the registers that hold the returned variables from the function call. self.set_allocated_registers(vec![]); let returned_variables: Vec<_> = return_parameters @@ -227,43 +261,45 @@ impl BrilligContext { BrilligParameter::Slice(..) => unreachable!("ICE: Cannot return slices"), }) .collect(); - // Now, we deflatten the returned arrays - for (return_param, returned_variable) in return_parameters.iter().zip(&returned_variables) { - if let BrilligParameter::Array(item_type, item_count) = return_param { - if item_type.iter().any(|item| !matches!(item, BrilligParameter::Simple)) { - let returned_pointer = returned_variable.extract_array().pointer; - let flattened_array_pointer = self.allocate_register(); - self.allocate_fixed_length_array( - flattened_array_pointer, - BrilligContext::flattened_size(return_param), + // Now, we deflatten the return data + let calldata_size = BrilligContext::flattened_tuple_size(arguments); + let return_data_size = BrilligContext::flattened_tuple_size(return_parameters); + + // Return data has a reserved space after calldata + let return_data_offset = MAX_STACK_SIZE + calldata_size; + let mut return_data_index = return_data_offset; + + for (return_param, returned_variable) in return_parameters.iter().zip(&returned_variables) { + match return_param { + BrilligParameter::Simple => { + self.mov_instruction( + MemoryAddress(return_data_index), + returned_variable.extract_register(), ); + return_data_index += 1; + } + BrilligParameter::Array(item_type, item_count) => { + let returned_pointer = returned_variable.extract_array().pointer; + let pointer_to_return_data = self.make_usize_constant(return_data_index.into()); self.flatten_array( item_type, *item_count, - flattened_array_pointer, + pointer_to_return_data, returned_pointer, ); - self.mov_instruction(returned_pointer, flattened_array_pointer); + self.deallocate_register(pointer_to_return_data); + return_data_index += BrilligContext::flattened_size(return_param); + } + BrilligParameter::Slice(..) => { + unreachable!("ICE: Cannot return slices from brillig entrypoints") } } } - // The VM expects us to follow the calling convention of returning - // their results in the first `n` registers. So we to move the return values - // to the first `n` registers once completed. - - // Move the results to registers 0..n - for (i, returned_variable) in returned_variables.into_iter().enumerate() { - let register = match returned_variable { - BrilligVariable::Simple(register) => register, - BrilligVariable::BrilligArray(array) => array.pointer, - BrilligVariable::BrilligVector(vector) => vector.pointer, - }; - self.push_opcode(BrilligOpcode::Mov { destination: i.into(), source: register }); - } - self.push_opcode(BrilligOpcode::Stop); + + self.push_opcode(BrilligOpcode::Stop { return_data_offset, return_data_size }); } // Flattens an array by recursively copying nested arrays and regular items. @@ -271,96 +307,119 @@ impl BrilligContext { &mut self, item_type: &[BrilligParameter], item_count: usize, - flattened_array_pointer: RegisterIndex, - deflattened_array_pointer: RegisterIndex, + flattened_array_pointer: MemoryAddress, + deflattened_array_pointer: MemoryAddress, ) { - let movement_register = self.allocate_register(); - - let source_item_size = item_type.len(); - let target_item_size: usize = item_type.iter().map(BrilligContext::flattened_size).sum(); - - for item_index in 0..item_count { - let source_item_base_index = item_index * source_item_size; - let target_item_base_index = item_index * target_item_size; - - let mut target_offset = 0; - - for (subitem_index, subitem) in item_type.iter().enumerate() { - let source_index = - self.make_constant((source_item_base_index + subitem_index).into()); - let target_index = - self.make_constant((target_item_base_index + target_offset).into()); - - match subitem { - BrilligParameter::Simple => { - self.array_get(deflattened_array_pointer, source_index, movement_register); - self.array_set(flattened_array_pointer, target_index, movement_register); - target_offset += 1; - } - BrilligParameter::Array(nested_array_item_type, nested_array_item_count) => { - let nested_array_reference = self.allocate_register(); - self.array_get( - deflattened_array_pointer, - source_index, - nested_array_reference, - ); - - let nested_array_variable = BrilligVariable::BrilligArray(BrilligArray { - pointer: self.allocate_register(), - size: nested_array_item_type.len() * nested_array_item_count, - rc: self.allocate_register(), - }); - - self.load_variable_instruction( - nested_array_variable, - nested_array_reference, - ); - - let flattened_nested_array_pointer = self.allocate_register(); - - self.mov_instruction( - flattened_nested_array_pointer, - flattened_array_pointer, - ); - - self.memory_op( - flattened_nested_array_pointer, - target_index, - flattened_nested_array_pointer, - acvm::brillig_vm::brillig::BinaryIntOp::Add, - ); - - self.flatten_array( + if BrilligContext::has_nested_arrays(item_type) { + let movement_register = self.allocate_register(); + + let source_item_size = item_type.len(); + let target_item_size: usize = + item_type.iter().map(BrilligContext::flattened_size).sum(); + + for item_index in 0..item_count { + let source_item_base_index = item_index * source_item_size; + let target_item_base_index = item_index * target_item_size; + + let mut target_offset = 0; + + for (subitem_index, subitem) in item_type.iter().enumerate() { + let source_index = + self.make_usize_constant((source_item_base_index + subitem_index).into()); + let target_index = + self.make_usize_constant((target_item_base_index + target_offset).into()); + + match subitem { + BrilligParameter::Simple => { + self.array_get( + deflattened_array_pointer, + source_index, + movement_register, + ); + self.array_set( + flattened_array_pointer, + target_index, + movement_register, + ); + target_offset += 1; + } + BrilligParameter::Array( nested_array_item_type, - *nested_array_item_count, - flattened_nested_array_pointer, - nested_array_variable.extract_array().pointer, - ); - - self.deallocate_register(nested_array_reference); - self.deallocate_register(flattened_nested_array_pointer); - nested_array_variable - .extract_registers() - .into_iter() - .for_each(|register| self.deallocate_register(register)); - - target_offset += BrilligContext::flattened_size(subitem); + nested_array_item_count, + ) => { + let nested_array_reference = self.allocate_register(); + self.array_get( + deflattened_array_pointer, + source_index, + nested_array_reference, + ); + + let nested_array_variable = + BrilligVariable::BrilligArray(BrilligArray { + pointer: self.allocate_register(), + size: nested_array_item_type.len() * nested_array_item_count, + rc: self.allocate_register(), + }); + + self.load_variable_instruction( + nested_array_variable, + nested_array_reference, + ); + + let flattened_nested_array_pointer = self.allocate_register(); + + self.mov_instruction( + flattened_nested_array_pointer, + flattened_array_pointer, + ); + + self.memory_op( + flattened_nested_array_pointer, + target_index, + flattened_nested_array_pointer, + acvm::brillig_vm::brillig::BinaryIntOp::Add, + ); + + self.flatten_array( + nested_array_item_type, + *nested_array_item_count, + flattened_nested_array_pointer, + nested_array_variable.extract_array().pointer, + ); + + self.deallocate_register(nested_array_reference); + self.deallocate_register(flattened_nested_array_pointer); + nested_array_variable + .extract_registers() + .into_iter() + .for_each(|register| self.deallocate_register(register)); + + target_offset += BrilligContext::flattened_size(subitem); + } + BrilligParameter::Slice(..) => unreachable!("ICE: Cannot flatten slices"), } - BrilligParameter::Slice(..) => unreachable!("ICE: Cannot flatten slices"), - } - self.deallocate_register(source_index); - self.deallocate_register(target_index); + self.deallocate_register(source_index); + self.deallocate_register(target_index); + } } - } - self.deallocate_register(movement_register); + self.deallocate_register(movement_register); + } else { + let item_count = self.make_usize_constant((item_count * item_type.len()).into()); + self.copy_array_instruction( + deflattened_array_pointer, + flattened_array_pointer, + item_count, + ); + self.deallocate_register(item_count); + } } } #[cfg(test)] mod tests { - use acvm::brillig_vm::brillig::{RegisterIndex, Value}; + use acvm::brillig_vm::brillig::Value; use crate::brillig::brillig_ir::{ artifact::BrilligParameter, @@ -370,7 +429,7 @@ mod tests { #[test] fn entry_point_with_nested_array_parameter() { - let flattened_array = vec![ + let calldata = vec![ Value::from(1_usize), Value::from(2_usize), Value::from(3_usize), @@ -391,44 +450,19 @@ mod tests { // Allocate the parameter let array_pointer = context.allocate_register(); + let array_value = context.allocate_register(); - context.return_instruction(&[array_pointer]); + context.load_instruction(array_pointer, array_pointer); + context.load_instruction(array_pointer, array_pointer); + context.load_instruction(array_value, array_pointer); - let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; - let vm = create_and_run_vm(flattened_array.clone(), vec![Value::from(0_usize)], &bytecode); - let memory = vm.get_memory(); + context.return_instruction(&[array_value]); - assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(flattened_array.len())); - assert_eq!( - memory, - &vec![ - // The original flattened values - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(4_usize), - Value::from(5_usize), - Value::from(6_usize), - // The pointer to the nested reference of the first item - Value::from(12_usize), - Value::from(3_usize), - // The pointer to the nested reference of the second item - Value::from(16_usize), - Value::from(6_usize), - // The nested array of the first item - Value::from(1_usize), - Value::from(2_usize), - // The nested reference of the first item - Value::from(10_usize), - Value::from(1_usize), - // The nested array of the second item - Value::from(4_usize), - Value::from(5_usize), - // The nested reference of the second item - Value::from(14_usize), - Value::from(1_usize), - ] - ); + let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; + let (vm, return_data_offset, return_data_size) = + create_and_run_vm(calldata.clone(), &bytecode); + assert_eq!(return_data_size, 1, "Return data size is incorrect"); + assert_eq!(vm.get_memory()[return_data_offset], Value::from(1_usize)); } #[test] @@ -463,46 +497,14 @@ mod tests { context.return_instruction(&brillig_array.extract_registers()); let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; - let vm = create_and_run_vm(flattened_array.clone(), vec![Value::from(0_usize)], &bytecode); + let (vm, return_data_pointer, return_data_size) = + create_and_run_vm(flattened_array.clone(), &bytecode); let memory = vm.get_memory(); assert_eq!( - memory, - &vec![ - // The original flattened values - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(4_usize), - Value::from(5_usize), - Value::from(6_usize), - // The pointer to the nested reference of the first item - Value::from(12_usize), - Value::from(3_usize), - // The pointer to the nested reference of the second item - Value::from(16_usize), - Value::from(6_usize), - // The nested array of the first item - Value::from(1_usize), - Value::from(2_usize), - // The nested reference of the first item - Value::from(10_usize), - Value::from(1_usize), - // The nested array of the second item - Value::from(4_usize), - Value::from(5_usize), - // The nested reference of the second item - Value::from(14_usize), - Value::from(1_usize), - // The original flattened again - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(4_usize), - Value::from(5_usize), - Value::from(6_usize), - ] + memory[return_data_pointer..(return_data_pointer + flattened_array.len())], + flattened_array ); - assert_eq!(vm.get_registers().get(RegisterIndex(0)), 18_usize.into()); + assert_eq!(return_data_size, flattened_array.len()); } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs index e7ab1492acb..8c0e36215a9 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs @@ -1,4 +1,6 @@ -use acvm::acir::brillig::RegisterIndex; +use acvm::acir::brillig::MemoryAddress; + +use crate::brillig::brillig_ir::entry_point::MAX_STACK_SIZE; use super::ReservedRegisters; @@ -8,7 +10,7 @@ use super::ReservedRegisters; /// Each has a stack base pointer from which all stack allocations can be offset. pub(crate) struct BrilligRegistersContext { /// A free-list of registers that have been deallocated and can be used again. - deallocated_registers: Vec, + deallocated_registers: Vec, /// A usize indicating the next un-used register. next_free_register_index: usize, } @@ -23,7 +25,7 @@ impl BrilligRegistersContext { } /// Creates a new register context from a set of registers allocated previously. - pub(crate) fn from_preallocated_registers(preallocated_registers: Vec) -> Self { + pub(crate) fn from_preallocated_registers(preallocated_registers: Vec) -> Self { let next_free_register_index = preallocated_registers.iter().fold( ReservedRegisters::len(), |free_register_index, preallocated_register| { @@ -36,8 +38,8 @@ impl BrilligRegistersContext { ); let mut deallocated_registers = Vec::new(); for i in ReservedRegisters::len()..next_free_register_index { - if !preallocated_registers.contains(&RegisterIndex::from(i)) { - deallocated_registers.push(RegisterIndex::from(i)); + if !preallocated_registers.contains(&MemoryAddress::from(i)) { + deallocated_registers.push(MemoryAddress::from(i)); } } @@ -45,7 +47,7 @@ impl BrilligRegistersContext { } /// Ensures a register is allocated. - pub(crate) fn ensure_register_is_allocated(&mut self, register: RegisterIndex) { + pub(crate) fn ensure_register_is_allocated(&mut self, register: MemoryAddress) { let index = register.to_usize(); if index < self.next_free_register_index { // If it could be allocated, check if it's in the deallocated list and remove it from there @@ -53,26 +55,28 @@ impl BrilligRegistersContext { } else { // If it couldn't yet be, expand the register space. self.next_free_register_index = index + 1; + assert!(self.next_free_register_index < MAX_STACK_SIZE, "Stack too deep"); } } /// Creates a new register. - pub(crate) fn allocate_register(&mut self) -> RegisterIndex { + pub(crate) fn allocate_register(&mut self) -> MemoryAddress { // If we have a register in our free list of deallocated registers, // consume it first. This prioritizes reuse. if let Some(register) = self.deallocated_registers.pop() { return register; } // Otherwise, move to our latest register. - let register = RegisterIndex::from(self.next_free_register_index); + let register = MemoryAddress::from(self.next_free_register_index); self.next_free_register_index += 1; + assert!(self.next_free_register_index < MAX_STACK_SIZE, "Stack too deep"); register } /// Push a register to the deallocation list, ready for reuse. /// TODO(AD): currently, register deallocation is only done with immediate values. /// TODO(AD): See https://github.com/noir-lang/noir/issues/1720 - pub(crate) fn deallocate_register(&mut self, register_index: RegisterIndex) { + pub(crate) fn deallocate_register(&mut self, register_index: MemoryAddress) { assert!(!self.deallocated_registers.contains(®ister_index)); self.deallocated_registers.push(register_index); } diff --git a/compiler/noirc_evaluator/src/errors.rs b/compiler/noirc_evaluator/src/errors.rs index 9aabe3bc749..ed94adac28e 100644 --- a/compiler/noirc_evaluator/src/errors.rs +++ b/compiler/noirc_evaluator/src/errors.rs @@ -177,7 +177,7 @@ impl RuntimeError { _ => { let message = self.to_string(); let location = - self.call_stack().back().expect("Expected RuntimeError to have a location"); + self.call_stack().back().unwrap_or_else(|| panic!("Expected RuntimeError to have a location. Error message: {message}")); Diagnostic::simple_error(message, String::new(), location.span) } diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index 2ddee1765b0..d19c4467235 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -14,7 +14,7 @@ use crate::{ errors::{RuntimeError, SsaReport}, }; use acvm::acir::{ - circuit::{Circuit, PublicInputs}, + circuit::{Circuit, ExpressionWidth, PublicInputs}, native_types::Witness, }; @@ -60,6 +60,7 @@ pub(crate) fn optimize_into_acir( // and this pass is missed, slice merging will fail inside of flattening. .run_pass(Ssa::mem2reg, "After Mem2Reg:") .run_pass(Ssa::flatten_cfg, "After Flattening:") + .run_pass(Ssa::remove_bit_shifts, "After Removing Bit Shifts:") // Run mem2reg once more with the flattened CFG to catch any remaining loads/stores .run_pass(Ssa::mem2reg, "After Mem2Reg:") .run_pass(Ssa::fold_constants, "After Constant Folding:") @@ -93,6 +94,7 @@ pub fn create_circuit( let debug_variables = program.debug_variables.clone(); let debug_types = program.debug_types.clone(); let func_sig = program.main_function_signature.clone(); + let recursive = program.recursive; let mut generated_acir = optimize_into_acir( program, enable_ssa_logging, @@ -118,11 +120,13 @@ pub fn create_circuit( let circuit = Circuit { current_witness_index, + expression_width: ExpressionWidth::Unbounded, opcodes, private_parameters, public_parameters, return_values, assert_messages: assert_messages.into_iter().collect(), + recursive, }; // This converts each im::Vector in the BTreeMap to a Vec 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 aef6f0a2e96..912447721cd 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 @@ -11,7 +11,7 @@ use acvm::acir::circuit::brillig::{BrilligInputs, BrilligOutputs}; use acvm::acir::circuit::opcodes::{BlockId, MemOp}; use acvm::acir::circuit::Opcode; use acvm::blackbox_solver; -use acvm::brillig_vm::{brillig::Value, Registers, VMStatus, VM}; +use acvm::brillig_vm::{brillig::Value, VMStatus, VM}; use acvm::{ acir::{ brillig::Opcode as BrilligOpcode, @@ -1198,7 +1198,7 @@ impl AcirContext { (vec![state_len], Vec::new()) } BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv => { assert_eq!(inputs.len(), 4, "ICE - bigint operation requires 4 inputs"); @@ -1244,7 +1244,8 @@ impl AcirContext { for i in const_inputs { field_inputs.push(i?); } - let modulus = self.big_int_ctx.modulus(field_inputs[0]); + let bigint = self.big_int_ctx.get(field_inputs[0]); + let modulus = self.big_int_ctx.modulus(bigint.modulus_id()); let bytes_len = ((modulus - BigUint::from(1_u32)).bits() - 1) / 8 + 1; output_count = bytes_len as usize; (field_inputs, vec![FieldElement::from(bytes_len as u128)]) @@ -1452,10 +1453,8 @@ impl AcirContext { } Ok(BrilligInputs::Array(var_expressions)) } - AcirValue::DynamicArray(_) => { - let mut var_expressions = Vec::new(); - self.brillig_array_input(&mut var_expressions, i)?; - Ok(BrilligInputs::Array(var_expressions)) + AcirValue::DynamicArray(AcirDynamicArray { block_id, .. }) => { + Ok(BrilligInputs::MemoryArray(block_id)) } } })?; @@ -1590,23 +1589,17 @@ impl AcirContext { inputs: &[BrilligInputs], outputs_types: &[AcirType], ) -> Option> { - let (registers, memory) = execute_brillig(code, inputs)?; - - let outputs_var = vecmap(outputs_types.iter().enumerate(), |(index, output)| { - let register_value = registers.get(index.into()); - match output { - AcirType::NumericType(_) => { - let var = self.add_data(AcirVarData::Const(register_value.to_field())); - AcirValue::Var(var, output.clone()) - } - AcirType::Array(element_types, size) => { - let mem_ptr = register_value.to_usize(); - self.brillig_constant_array_output( - element_types, - *size, - &mut memory.iter().skip(mem_ptr), - ) - } + let mut memory = (execute_brillig(code, inputs)?).into_iter(); + + let outputs_var = vecmap(outputs_types.iter(), |output| match output { + AcirType::NumericType(_) => { + let var = self.add_data(AcirVarData::Const( + memory.next().expect("Missing return data").to_field(), + )); + AcirValue::Var(var, output.clone()) + } + AcirType::Array(element_types, size) => { + self.brillig_constant_array_output(element_types, *size, &mut memory) } }); @@ -1614,11 +1607,11 @@ impl AcirContext { } /// Recursively create [`AcirValue`]s for returned arrays. This is necessary because a brillig returned array can have nested arrays as elements. - fn brillig_constant_array_output<'a>( + fn brillig_constant_array_output( &mut self, element_types: &[AcirType], size: usize, - memory_iter: &mut impl Iterator, + memory_iter: &mut impl Iterator, ) -> AcirValue { let mut array_values = im::Vector::new(); for _ in 0..size { @@ -1817,42 +1810,31 @@ pub(crate) struct AcirVar(usize); /// Returns the finished state of the Brillig VM if execution can complete. /// /// Returns `None` if complete execution of the Brillig bytecode is not possible. -fn execute_brillig( - code: &[BrilligOpcode], - inputs: &[BrilligInputs], -) -> Option<(Registers, Vec)> { +fn execute_brillig(code: &[BrilligOpcode], inputs: &[BrilligInputs]) -> Option> { // Set input values - let mut input_register_values: Vec = Vec::with_capacity(inputs.len()); - let mut input_memory: Vec = Vec::new(); + let mut calldata: Vec = Vec::new(); + // Each input represents a constant or array of constants. // Iterate over each input and push it into registers and/or memory. for input in inputs { match input { BrilligInputs::Single(expr) => { - input_register_values.push(expr.to_const()?.into()); + calldata.push(expr.to_const()?.into()); } BrilligInputs::Array(expr_arr) => { // Attempt to fetch all array input values - let memory_pointer = input_memory.len(); for expr in expr_arr.iter() { - input_memory.push(expr.to_const()?.into()); + calldata.push(expr.to_const()?.into()); } - - // Push value of the array pointer as a register - input_register_values.push(Value::from(memory_pointer)); + } + BrilligInputs::MemoryArray(_) => { + return None; } } } // Instantiate a Brillig VM given the solved input registers and memory, along with the Brillig bytecode. - let input_registers = Registers::load(input_register_values); - let mut vm = VM::new( - input_registers, - input_memory, - code, - Vec::new(), - &blackbox_solver::StubbedBlackBoxSolver, - ); + let mut vm = VM::new(calldata, code, Vec::new(), &blackbox_solver::StubbedBlackBoxSolver); // Run the Brillig VM on these inputs, bytecode, etc! let vm_status = vm.process_opcodes(); @@ -1861,7 +1843,9 @@ fn execute_brillig( // It may be finished, in-progress, failed, or may be waiting for results of a foreign call. // If it's finished then we can omit the opcode and just write in the return values. match vm_status { - VMStatus::Finished => Some((vm.get_registers().clone(), vm.get_memory().to_vec())), + VMStatus::Finished { return_data_offset, return_data_size } => Some( + vm.get_memory()[return_data_offset..(return_data_offset + return_data_size)].to_vec(), + ), VMStatus::InProgress => unreachable!("Brillig VM has not completed execution"), VMStatus::Failure { .. } => { // TODO: Return an error stating that the brillig function failed. diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index e241c0d8ea8..1d05e998b13 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -256,7 +256,7 @@ impl GeneratedAcir { rhs: constant_inputs[1].to_u128() as u32, output: constant_outputs[0].to_u128() as u32, }, - BlackBoxFunc::BigIntNeg => BlackBoxFuncCall::BigIntNeg { + BlackBoxFunc::BigIntSub => BlackBoxFuncCall::BigIntSub { lhs: constant_inputs[0].to_u128() as u32, rhs: constant_inputs[1].to_u128() as u32, output: constant_outputs[0].to_u128() as u32, @@ -616,7 +616,7 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { // Big integer operations take in 0 inputs. They use constants for their inputs. BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv | BlackBoxFunc::BigIntToLeBytes => Some(0), @@ -666,7 +666,7 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { // Big integer operations return a big integer BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv | BlackBoxFunc::BigIntFromLeBytes => Some(0), diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 2c151ed1e68..9603377a107 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -679,11 +679,11 @@ impl Context { instruction: InstructionId, dfg: &DataFlowGraph, index: ValueId, - array: ValueId, + array_id: ValueId, store_value: Option, ) -> Result { let index_const = dfg.get_numeric_constant(index); - let value_type = dfg.type_of_value(array); + let value_type = dfg.type_of_value(array_id); // Compiler sanity checks assert!( !value_type.is_nested_slice(), @@ -693,7 +693,7 @@ impl Context { unreachable!("ICE: expected array or slice type"); }; - match self.convert_value(array, dfg) { + match self.convert_value(array_id, dfg) { AcirValue::Var(acir_var, _) => { return Err(RuntimeError::InternalError(InternalError::Unexpected { expected: "an array value".to_string(), @@ -1483,6 +1483,9 @@ impl Context { bit_count, self.current_side_effects_enabled_var, ), + BinaryOp::Shl | BinaryOp::Shr => unreachable!( + "ICE - bit shift operators do not exist in ACIR and should have been replaced" + ), } } diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index 989249d04ef..7ad9a4b4031 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -18,8 +18,7 @@ use super::{ basic_block::BasicBlock, dfg::{CallStack, InsertInstructionResult}, function::RuntimeType, - instruction::{ConstrainError, Endian, InstructionId, Intrinsic}, - types::NumericType, + instruction::{ConstrainError, InstructionId, Intrinsic}, }, ssa_gen::Ssa, }; @@ -279,108 +278,6 @@ impl FunctionBuilder { self.insert_instruction(Instruction::Call { func, arguments }, Some(result_types)).results() } - /// Insert ssa instructions which computes lhs << rhs by doing lhs*2^rhs - /// and truncate the result to bit_size - pub(crate) fn insert_wrapping_shift_left( - &mut self, - lhs: ValueId, - rhs: ValueId, - bit_size: u32, - ) -> ValueId { - let base = self.field_constant(FieldElement::from(2_u128)); - let typ = self.current_function.dfg.type_of_value(lhs); - let (max_bit, pow) = - if let Some(rhs_constant) = self.current_function.dfg.get_numeric_constant(rhs) { - // Happy case is that we know precisely by how many bits the the integer will - // increase: lhs_bit_size + rhs - let bit_shift_size = rhs_constant.to_u128() as u32; - - let (rhs_bit_size_pow_2, overflows) = 2_u128.overflowing_pow(bit_shift_size); - if overflows { - assert!(bit_size < 128, "ICE - shift left with big integers are not supported"); - if bit_size < 128 { - let zero = self.numeric_constant(FieldElement::zero(), typ); - return InsertInstructionResult::SimplifiedTo(zero).first(); - } - } - let pow = self.numeric_constant(FieldElement::from(rhs_bit_size_pow_2), typ); - - let max_lhs_bits = self.current_function.dfg.get_value_max_num_bits(lhs); - - (max_lhs_bits + bit_shift_size, pow) - } else { - // we use a predicate to nullify the result in case of overflow - let bit_size_var = - self.numeric_constant(FieldElement::from(bit_size as u128), typ.clone()); - let overflow = self.insert_binary(rhs, BinaryOp::Lt, bit_size_var); - let predicate = self.insert_cast(overflow, typ.clone()); - // we can safely cast to unsigned because overflow_checks prevent bit-shift with a negative value - let rhs_unsigned = self.insert_cast(rhs, Type::unsigned(bit_size)); - let pow = self.pow(base, rhs_unsigned); - let pow = self.insert_cast(pow, typ); - (FieldElement::max_num_bits(), self.insert_binary(predicate, BinaryOp::Mul, pow)) - }; - - if max_bit <= bit_size { - self.insert_binary(lhs, BinaryOp::Mul, pow) - } else { - let result = self.insert_binary(lhs, BinaryOp::Mul, pow); - self.insert_truncate(result, bit_size, max_bit) - } - } - - /// Insert ssa instructions which computes lhs >> rhs by doing lhs/2^rhs - pub(crate) fn insert_shift_right( - &mut self, - lhs: ValueId, - rhs: ValueId, - bit_size: u32, - ) -> ValueId { - let base = self.field_constant(FieldElement::from(2_u128)); - // we can safely cast to unsigned because overflow_checks prevent bit-shift with a negative value - let rhs_unsigned = self.insert_cast(rhs, Type::unsigned(bit_size)); - let pow = self.pow(base, rhs_unsigned); - self.insert_binary(lhs, BinaryOp::Div, pow) - } - - /// Computes lhs^rhs via square&multiply, using the bits decomposition of rhs - /// Pseudo-code of the computation: - /// let mut r = 1; - /// let rhs_bits = to_bits(rhs); - /// for i in 1 .. bit_size + 1 { - /// let r_squared = r * r; - /// let b = rhs_bits[bit_size - i]; - /// r = (r_squared * lhs * b) + (1 - b) * r_squared; - /// } - pub(crate) fn pow(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId { - let typ = self.current_function.dfg.type_of_value(rhs); - if let Type::Numeric(NumericType::Unsigned { bit_size }) = typ { - let to_bits = self.import_intrinsic_id(Intrinsic::ToBits(Endian::Little)); - let length = self.field_constant(FieldElement::from(bit_size as i128)); - let result_types = - vec![Type::field(), Type::Array(Rc::new(vec![Type::bool()]), bit_size as usize)]; - let rhs_bits = self.insert_call(to_bits, vec![rhs, length], result_types); - let rhs_bits = rhs_bits[1]; - let one = self.field_constant(FieldElement::one()); - let mut r = one; - for i in 1..bit_size + 1 { - let r_squared = self.insert_binary(r, BinaryOp::Mul, r); - let a = self.insert_binary(r_squared, BinaryOp::Mul, lhs); - let idx = self.field_constant(FieldElement::from((bit_size - i) as i128)); - let b = self.insert_array_get(rhs_bits, idx, Type::bool()); - let not_b = self.insert_not(b); - let b = self.insert_cast(b, Type::field()); - let not_b = self.insert_cast(not_b, Type::field()); - let r1 = self.insert_binary(a, BinaryOp::Mul, b); - let r2 = self.insert_binary(r_squared, BinaryOp::Mul, not_b); - r = self.insert_binary(r1, BinaryOp::Add, r2); - } - r - } else { - unreachable!("Value must be unsigned in power operation"); - } - } - /// Insert an instruction to extract an element from an array pub(crate) fn insert_array_get( &mut self, diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs index 1cb32d94148..552be9420d9 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs @@ -38,6 +38,10 @@ pub(crate) enum BinaryOp { Or, /// Bitwise xor (^) Xor, + /// Bitshift left (<<) + Shl, + /// Bitshift right (>>) + Shr, } impl std::fmt::Display for BinaryOp { @@ -53,6 +57,8 @@ impl std::fmt::Display for BinaryOp { BinaryOp::And => write!(f, "and"), BinaryOp::Or => write!(f, "or"), BinaryOp::Xor => write!(f, "xor"), + BinaryOp::Shl => write!(f, "shl"), + BinaryOp::Shr => write!(f, "shr"), } } } @@ -215,7 +221,27 @@ impl Binary { return SimplifyResult::SimplifiedTo(zero); } } - } + BinaryOp::Shl => return SimplifyResult::None, + BinaryOp::Shr => { + // Bit shifts by constants can be treated as divisions. + if let Some(rhs_const) = rhs { + if rhs_const >= FieldElement::from(operand_type.bit_size() as u128) { + // Shifting by the full width of the operand type, any `lhs` goes to zero. + let zero = dfg.make_constant(FieldElement::zero(), operand_type); + return SimplifyResult::SimplifiedTo(zero); + } + + // `two_pow_rhs` is limited to be at most `2 ^ {operand_bitsize - 1}` so it fits in `operand_type`. + let two_pow_rhs = FieldElement::from(2u128).pow(&rhs_const); + let two_pow_rhs = dfg.make_constant(two_pow_rhs, operand_type); + return SimplifyResult::SimplifiedToInstruction(Instruction::binary( + BinaryOp::Div, + self.lhs, + two_pow_rhs, + )); + } + } + }; SimplifyResult::None } } @@ -314,6 +340,8 @@ impl BinaryOp { BinaryOp::And => None, BinaryOp::Or => None, BinaryOp::Xor => None, + BinaryOp::Shl => None, + BinaryOp::Shr => None, } } @@ -329,6 +357,8 @@ impl BinaryOp { BinaryOp::Xor => |x, y| Some(x ^ y), BinaryOp::Eq => |x, y| Some((x == y) as u128), BinaryOp::Lt => |x, y| Some((x < y) as u128), + BinaryOp::Shl => |x, y| Some(x << y), + BinaryOp::Shr => |x, y| Some(x >> y), } } @@ -344,6 +374,8 @@ impl BinaryOp { BinaryOp::Xor => |x, y| Some(x ^ y), BinaryOp::Eq => |x, y| Some((x == y) as i128), BinaryOp::Lt => |x, y| Some((x < y) as i128), + BinaryOp::Shl => |x, y| Some(x << y), + BinaryOp::Shr => |x, y| Some(x >> y), } } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 6ff1ccd29db..4217a3d4710 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -1,3 +1,4 @@ +use fxhash::FxHashMap as HashMap; use std::{collections::VecDeque, rc::Rc}; use acvm::{acir::BlackBoxFunc, BlackBoxResolutionError, FieldElement}; @@ -318,6 +319,8 @@ fn simplify_slice_push_back( for elem in &arguments[2..] { slice.push_back(*elem); } + let slice_size = slice.len(); + let element_size = element_type.element_size(); let new_slice = dfg.make_array(slice, element_type); let set_last_slice_value_instr = @@ -326,7 +329,11 @@ fn simplify_slice_push_back( .insert_instruction_and_results(set_last_slice_value_instr, block, None, call_stack) .first(); - let mut value_merger = ValueMerger::new(dfg, block, None, None); + let mut slice_sizes = HashMap::default(); + slice_sizes.insert(set_last_slice_value, slice_size / element_size); + slice_sizes.insert(new_slice, slice_size / element_size); + + let mut value_merger = ValueMerger::new(dfg, block, &mut slice_sizes); let new_slice = value_merger.merge_values( len_not_equals_capacity, len_equals_capacity, @@ -433,7 +440,7 @@ fn simplify_black_box_func( SimplifyResult::None } BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv | BlackBoxFunc::RecursiveAggregation diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs index 0ae0f8f2892..b4198e2cfec 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs @@ -120,6 +120,23 @@ pub(super) fn decompose_constrain( } } + ( + Value::Instruction { instruction: instruction_lhs, .. }, + Value::Instruction { instruction: instruction_rhs, .. }, + ) => { + match (&dfg[*instruction_lhs], &dfg[*instruction_rhs]) { + // Casting two values just to enforce an equality on them. + // + // This is equivalent to enforcing equality on the original values. + (Instruction::Cast(original_lhs, _), Instruction::Cast(original_rhs, _)) + if dfg.type_of_value(*original_lhs) == dfg.type_of_value(*original_rhs) => + { + vec![Instruction::Constrain(*original_lhs, *original_rhs, msg.clone())] + } + + _ => vec![Instruction::Constrain(lhs, rhs, msg.clone())], + } + } _ => vec![Instruction::Constrain(lhs, rhs, msg.clone())], } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/types.rs b/compiler/noirc_evaluator/src/ssa/ir/types.rs index f412def1e76..8dc9e67db79 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/types.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/types.rs @@ -120,7 +120,7 @@ impl Type { } Type::Slice(_) => true, Type::Numeric(_) => false, - Type::Reference(_) => false, + Type::Reference(element) => element.contains_slice_element(), Type::Function => false, } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index 1059994b9be..943a57c1bc0 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -152,8 +152,10 @@ use crate::ssa::{ }; mod branch_analysis; +mod capacity_tracker; pub(crate) mod value_merger; +use capacity_tracker::SliceCapacityTracker; use value_merger::ValueMerger; impl Ssa { @@ -184,17 +186,6 @@ struct Context<'f> { /// between inlining of branches. store_values: HashMap, - /// Maps an address to the old and new value of the element at that address - /// The difference between this map and store_values is that this stores - /// the old and new value of an element from the outer block whose jmpif - /// terminator is being flattened. - /// - /// This map persists throughout the flattening process, where addresses - /// are overwritten as new stores are found. This overwriting is the desired behavior, - /// as we want the most update to date value to be stored at a given address as - /// we walk through blocks to flatten. - outer_block_stores: HashMap, - /// Stores all allocations local to the current branch. /// Since these branches are local to the current branch (ie. only defined within one branch of /// an if expression), they should not be merged with their previous value or stored value in @@ -209,6 +200,10 @@ struct Context<'f> { /// condition. If we are under multiple conditions (a nested if), the topmost condition is /// the most recent condition combined with all previous conditions via `And` instructions. conditions: Vec<(BasicBlockId, ValueId)>, + + /// Maps SSA array values with a slice type to their size. + /// This is maintained by appropriate calls to the `SliceCapacityTracker` and is used by the `ValueMerger`. + slice_sizes: HashMap, } pub(crate) struct Store { @@ -239,7 +234,7 @@ fn flatten_function_cfg(function: &mut Function) { local_allocations: HashSet::new(), branch_ends, conditions: Vec::new(), - outer_block_stores: HashMap::default(), + slice_sizes: HashMap::default(), }; context.flatten(); } @@ -262,21 +257,18 @@ impl<'f> Context<'f> { /// Returns the last block to be inlined. This is either the return block of the function or, /// if self.conditions is not empty, the end block of the most recent condition. fn handle_terminator(&mut self, block: BasicBlockId) -> BasicBlockId { - if let TerminatorInstruction::JmpIf { .. } = - self.inserter.function.dfg[block].unwrap_terminator() - { - // Find stores in the outer block and insert into the `outer_block_stores` map. - // Not using this map can lead to issues when attempting to merge slices. - // When inlining a branch end, only the then branch and the else branch are checked for stores. - // However, there are cases where we want to load a value that comes from the outer block - // that we are handling the terminator for here. - let instructions = self.inserter.function.dfg[block].instructions().to_vec(); - for instruction in instructions { - let (instruction, _) = self.inserter.map_instruction(instruction); - if let Instruction::Store { address, value } = instruction { - self.outer_block_stores.insert(address, value); - } - } + // As we recursively flatten inner blocks, we need to track the slice information + // for the outer block before we start recursively inlining + let outer_block_instructions = self.inserter.function.dfg[block].instructions(); + let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + for instruction in outer_block_instructions { + let results = self.inserter.function.dfg.instruction_results(*instruction); + let instruction = &self.inserter.function.dfg[*instruction]; + capacity_tracker.collect_slice_information( + instruction, + &mut self.slice_sizes, + results.to_vec(), + ); } match self.inserter.function.dfg[block].unwrap_terminator() { @@ -494,12 +486,16 @@ impl<'f> Context<'f> { }); let block = self.inserter.function.entry_block(); - let mut value_merger = ValueMerger::new( - &mut self.inserter.function.dfg, - block, - Some(&self.store_values), - Some(&self.outer_block_stores), - ); + + // Make sure we have tracked the slice capacities of any block arguments + let capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + for (then_arg, else_arg) in args.iter() { + capacity_tracker.compute_slice_capacity(*then_arg, &mut self.slice_sizes); + capacity_tracker.compute_slice_capacity(*else_arg, &mut self.slice_sizes); + } + + let mut value_merger = + ValueMerger::new(&mut self.inserter.function.dfg, block, &mut self.slice_sizes); // Cannot include this in the previous vecmap since it requires exclusive access to self let args = vecmap(args, |(then_arg, else_arg)| { @@ -538,18 +534,22 @@ impl<'f> Context<'f> { } } + // Most slice information is collected when instructions are inlined. + // We need to collect information on slice values here as we may possibly merge stores + // before any inlining occurs. + let capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + for (then_case, else_case, _) in new_map.values() { + capacity_tracker.compute_slice_capacity(*then_case, &mut self.slice_sizes); + capacity_tracker.compute_slice_capacity(*else_case, &mut self.slice_sizes); + } + let then_condition = then_branch.condition; let else_condition = else_branch.condition; let block = self.inserter.function.entry_block(); - let mut value_merger = ValueMerger::new( - &mut self.inserter.function.dfg, - block, - Some(&self.store_values), - Some(&self.outer_block_stores), - ); - + let mut value_merger = + ValueMerger::new(&mut self.inserter.function.dfg, block, &mut self.slice_sizes); // Merging must occur in a separate loop as we cannot borrow `self` as mutable while `value_merger` does let mut new_values = HashMap::default(); for (address, (then_case, else_case, _)) in &new_map { @@ -571,6 +571,16 @@ impl<'f> Context<'f> { .insert(address, Store { old_value: *old_value, new_value: value }); } } + + // Collect any potential slice information on the stores we are merging + for (address, (_, _, _)) in &new_map { + let value = new_values[address]; + let address = *address; + let instruction = Instruction::Store { address, value }; + + let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + capacity_tracker.collect_slice_information(&instruction, &mut self.slice_sizes, vec![]); + } } fn remember_store(&mut self, address: ValueId, new_value: ValueId) { @@ -579,8 +589,18 @@ impl<'f> Context<'f> { store_value.new_value = new_value; } else { let load = Instruction::Load { address }; + let load_type = Some(vec![self.inserter.function.dfg.type_of_value(new_value)]); - let old_value = self.insert_instruction_with_typevars(load, load_type).first(); + let old_value = + self.insert_instruction_with_typevars(load.clone(), load_type).first(); + + // Need this or else we will be missing a the previous value of a slice that we wish to merge + let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + capacity_tracker.collect_slice_information( + &load, + &mut self.slice_sizes, + vec![old_value], + ); self.store_values.insert(address, Store { old_value, new_value }); } @@ -602,8 +622,15 @@ impl<'f> Context<'f> { // unnecessary, when removing it actually causes an aliasing/mutability error. let instructions = self.inserter.function.dfg[destination].instructions().to_vec(); - for instruction in instructions { - self.push_instruction(instruction); + for instruction in instructions.iter() { + let results = self.push_instruction(*instruction); + let (instruction, _) = self.inserter.map_instruction(*instruction); + let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + capacity_tracker.collect_slice_information( + &instruction, + &mut self.slice_sizes, + results, + ); } self.handle_terminator(destination) @@ -615,7 +642,7 @@ impl<'f> Context<'f> { /// As a result, the instruction that will be pushed will actually be a new instruction /// with a different InstructionId from the original. The results of the given instruction /// will also be mapped to the results of the new instruction. - fn push_instruction(&mut self, id: InstructionId) { + fn push_instruction(&mut self, id: InstructionId) -> Vec { let (instruction, call_stack) = self.inserter.map_instruction(id); let instruction = self.handle_instruction_side_effects(instruction, call_stack.clone()); let is_allocate = matches!(instruction, Instruction::Allocate); @@ -628,6 +655,8 @@ impl<'f> Context<'f> { if is_allocate { self.local_allocations.insert(results.first()); } + + results.results().into_owned() } /// If we are currently in a branch, we need to modify constrain instructions diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs new file mode 100644 index 00000000000..7cd0fe3084e --- /dev/null +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs @@ -0,0 +1,150 @@ +use crate::ssa::ir::{ + dfg::DataFlowGraph, + instruction::{Instruction, Intrinsic}, + types::Type, + value::{Value, ValueId}, +}; + +use fxhash::FxHashMap as HashMap; + +pub(crate) struct SliceCapacityTracker<'a> { + dfg: &'a DataFlowGraph, +} + +impl<'a> SliceCapacityTracker<'a> { + pub(crate) fn new(dfg: &'a DataFlowGraph) -> Self { + SliceCapacityTracker { dfg } + } + + /// Determine how the slice sizes map needs to be updated according to the provided instruction. + pub(crate) fn collect_slice_information( + &mut self, + instruction: &Instruction, + slice_sizes: &mut HashMap, + results: Vec, + ) { + match instruction { + Instruction::ArrayGet { array, .. } => { + let array_typ = self.dfg.type_of_value(*array); + let array_value = &self.dfg[*array]; + if matches!(array_value, Value::Array { .. }) && array_typ.contains_slice_element() + { + // Initial insertion into the slice sizes map + // Any other insertions should only occur if the value is already + // a part of the map. + self.compute_slice_capacity(*array, slice_sizes); + } + } + Instruction::ArraySet { array, value, .. } => { + let array_typ = self.dfg.type_of_value(*array); + let array_value = &self.dfg[*array]; + if matches!(array_value, Value::Array { .. }) && array_typ.contains_slice_element() + { + // Initial insertion into the slice sizes map + // Any other insertions should only occur if the value is already + // a part of the map. + self.compute_slice_capacity(*array, slice_sizes); + } + + let value_typ = self.dfg.type_of_value(*value); + // Compiler sanity check + assert!(!value_typ.contains_slice_element(), "ICE: Nested slices are not allowed and should not have reached the flattening pass of SSA"); + + if let Some(capacity) = slice_sizes.get(array) { + slice_sizes.insert(results[0], *capacity); + } + } + Instruction::Call { func, arguments } => { + let func = &self.dfg[*func]; + if let Value::Intrinsic(intrinsic) = func { + let (argument_index, result_index) = match intrinsic { + Intrinsic::SlicePushBack + | Intrinsic::SlicePushFront + | Intrinsic::SlicePopBack + | Intrinsic::SliceInsert + | Intrinsic::SliceRemove => (1, 1), + // `pop_front` returns the popped element, and then the respective slice. + // This means in the case of a slice with structs, the result index of the popped slice + // will change depending on the number of elements in the struct. + // For example, a slice with four elements will look as such in SSA: + // v3, v4, v5, v6, v7, v8 = call slice_pop_front(v1, v2) + // where v7 is the slice length and v8 is the popped slice itself. + Intrinsic::SlicePopFront => (1, results.len() - 1), + _ => return, + }; + let slice_contents = arguments[argument_index]; + match intrinsic { + Intrinsic::SlicePushBack + | Intrinsic::SlicePushFront + | Intrinsic::SliceInsert => { + for arg in &arguments[(argument_index + 1)..] { + let element_typ = self.dfg.type_of_value(*arg); + if element_typ.contains_slice_element() { + self.compute_slice_capacity(*arg, slice_sizes); + } + } + if let Some(contents_capacity) = slice_sizes.get(&slice_contents) { + let new_capacity = *contents_capacity + 1; + slice_sizes.insert(results[result_index], new_capacity); + } + } + Intrinsic::SlicePopBack + | Intrinsic::SliceRemove + | Intrinsic::SlicePopFront => { + // We do not decrement the size on intrinsics that could remove values from a slice. + // This is because we could potentially go back to the smaller slice and not fill in dummies. + // This pass should be tracking the potential max that a slice ***could be*** + if let Some(contents_capacity) = slice_sizes.get(&slice_contents) { + let new_capacity = *contents_capacity - 1; + slice_sizes.insert(results[result_index], new_capacity); + } + } + _ => {} + } + } + } + Instruction::Store { address, value } => { + let value_typ = self.dfg.type_of_value(*value); + if value_typ.contains_slice_element() { + self.compute_slice_capacity(*value, slice_sizes); + + let value_capacity = slice_sizes.get(value).unwrap_or_else(|| { + panic!("ICE: should have slice capacity set for value {value} being stored at {address}") + }); + + slice_sizes.insert(*address, *value_capacity); + } + } + Instruction::Load { address } => { + let load_typ = self.dfg.type_of_value(*address); + if load_typ.contains_slice_element() { + let result = results[0]; + + let address_capacity = slice_sizes.get(address).unwrap_or_else(|| { + panic!("ICE: should have slice capacity set at address {address} being loaded into {result}") + }); + + slice_sizes.insert(result, *address_capacity); + } + } + _ => {} + } + } + + /// Computes the starting capacity of a slice which is still a `Value::Array` + pub(crate) fn compute_slice_capacity( + &self, + array_id: ValueId, + slice_sizes: &mut HashMap, + ) { + if let Value::Array { array, typ } = &self.dfg[array_id] { + // Compiler sanity check + assert!(!typ.is_nested_slice(), "ICE: Nested slices are not allowed and should not have reached the flattening pass of SSA"); + if let Type::Slice(_) = typ { + let element_size = typ.element_size(); + let len = array.len() / element_size; + slice_sizes.insert(array_id, len); + } + } + } +} diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 446560f45f1..6b923a2e42d 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -4,35 +4,26 @@ use fxhash::FxHashMap as HashMap; use crate::ssa::ir::{ basic_block::BasicBlockId, dfg::{CallStack, DataFlowGraph}, - instruction::{BinaryOp, Instruction, Intrinsic}, + instruction::{BinaryOp, Instruction}, types::Type, - value::{Value, ValueId}, + value::ValueId, }; -use crate::ssa::opt::flatten_cfg::Store; - pub(crate) struct ValueMerger<'a> { dfg: &'a mut DataFlowGraph, block: BasicBlockId, - store_values: Option<&'a HashMap>, - outer_block_stores: Option<&'a HashMap>, - slice_sizes: HashMap, + // Maps SSA array values with a slice type to their size. + // This must be computed before merging values. + slice_sizes: &'a mut HashMap, } impl<'a> ValueMerger<'a> { pub(crate) fn new( dfg: &'a mut DataFlowGraph, block: BasicBlockId, - store_values: Option<&'a HashMap>, - outer_block_stores: Option<&'a HashMap>, + slice_sizes: &'a mut HashMap, ) -> Self { - ValueMerger { - dfg, - block, - store_values, - outer_block_stores, - slice_sizes: HashMap::default(), - } + ValueMerger { dfg, block, slice_sizes } } /// Merge two values a and b from separate basic blocks to a single value. @@ -184,11 +175,13 @@ impl<'a> ValueMerger<'a> { _ => panic!("Expected slice type"), }; - let then_len = self.get_slice_length(then_value_id); - self.slice_sizes.insert(then_value_id, then_len); + let then_len = *self.slice_sizes.get(&then_value_id).unwrap_or_else(|| { + panic!("ICE: Merging values during flattening encountered slice {then_value_id} without a preset size"); + }); - let else_len = self.get_slice_length(else_value_id); - self.slice_sizes.insert(else_value_id, else_len); + let else_len = *self.slice_sizes.get(&else_value_id).unwrap_or_else(|| { + panic!("ICE: Merging values during flattening encountered slice {else_value_id} without a preset size"); + }); let len = then_len.max(else_len); @@ -218,8 +211,10 @@ impl<'a> ValueMerger<'a> { } }; - let then_element = get_element(then_value_id, typevars.clone(), then_len); - let else_element = get_element(else_value_id, typevars, else_len); + let then_element = + get_element(then_value_id, typevars.clone(), then_len * element_types.len()); + let else_element = + get_element(else_value_id, typevars, else_len * element_types.len()); merged.push_back(self.merge_values( then_condition, @@ -233,82 +228,6 @@ impl<'a> ValueMerger<'a> { self.dfg.make_array(merged, typ) } - fn get_slice_length(&mut self, value_id: ValueId) -> usize { - let value = &self.dfg[value_id]; - match value { - Value::Array { array, .. } => array.len(), - Value::Instruction { instruction: instruction_id, .. } => { - let instruction = &self.dfg[*instruction_id]; - match instruction { - // TODO(#3188): A slice can be the result of an ArrayGet when it is the - // fetched from a slice of slices or as a struct field. - // However, we need to incorporate nested slice support in flattening - // in order for this to be valid - // Instruction::ArrayGet { array, .. } => {} - Instruction::ArraySet { array, .. } => { - let array = *array; - let len = self.get_slice_length(array); - self.slice_sizes.insert(array, len); - len - } - Instruction::Load { address } => { - let outer_block_stores = self.outer_block_stores.expect("ICE: A map of previous stores is required in order to resolve a slice load"); - let store_values = self.store_values.expect("ICE: A map of previous stores is required in order to resolve a slice load"); - let store_value = outer_block_stores - .get(address) - .expect("ICE: load in merger should have store from outer block"); - - if let Some(len) = self.slice_sizes.get(store_value) { - return *len; - } - - let store_value = if let Some(store) = store_values.get(address) { - if let Some(len) = self.slice_sizes.get(&store.new_value) { - return *len; - } - - store.new_value - } else { - *store_value - }; - - self.get_slice_length(store_value) - } - Instruction::Call { func, arguments } => { - let slice_contents = arguments[1]; - let func = &self.dfg[*func]; - match func { - Value::Intrinsic(intrinsic) => match intrinsic { - Intrinsic::SlicePushBack - | Intrinsic::SlicePushFront - | Intrinsic::SliceInsert => { - // `get_slice_length` needs to be called here as it is borrows self as mutable - let initial_len = self.get_slice_length(slice_contents); - self.slice_sizes.insert(slice_contents, initial_len); - initial_len + 1 - } - Intrinsic::SlicePopBack - | Intrinsic::SlicePopFront - | Intrinsic::SliceRemove => { - // `get_slice_length` needs to be called here as it is borrows self as mutable - let initial_len = self.get_slice_length(slice_contents); - self.slice_sizes.insert(slice_contents, initial_len); - initial_len - 1 - } - _ => { - unreachable!("ICE: Intrinsic not supported, got {intrinsic:?}") - } - }, - _ => unreachable!("ICE: Expected intrinsic value but got {func:?}"), - } - } - _ => unreachable!("ICE: Got unexpected instruction: {instruction:?}"), - } - } - _ => unreachable!("ICE: Got unexpected value when resolving slice length {value:?}"), - } - } - /// Construct a dummy value to be attached to the smaller of two slices being merged. /// We need to make sure we follow the internal element type structure of the slice type /// even for dummy data to ensure that we do not have errors later in the compiler, diff --git a/compiler/noirc_evaluator/src/ssa/opt/mod.rs b/compiler/noirc_evaluator/src/ssa/opt/mod.rs index 71725422a7a..a315695f7db 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mod.rs @@ -12,5 +12,6 @@ mod die; pub(crate) mod flatten_cfg; mod inlining; mod mem2reg; +mod remove_bit_shifts; mod simplify_cfg; mod unrolling; diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs new file mode 100644 index 00000000000..a71a42d5757 --- /dev/null +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs @@ -0,0 +1,285 @@ +use std::{borrow::Cow, rc::Rc}; + +use acvm::FieldElement; + +use crate::ssa::{ + ir::{ + basic_block::BasicBlockId, + dfg::{CallStack, InsertInstructionResult}, + function::{Function, RuntimeType}, + instruction::{Binary, BinaryOp, Endian, Instruction, InstructionId, Intrinsic}, + types::{NumericType, Type}, + value::ValueId, + }, + ssa_gen::Ssa, +}; + +impl Ssa { + /// Performs constant folding on each instruction. + /// + /// See [`constant_folding`][self] module for more information. + #[tracing::instrument(level = "trace", skip(self))] + pub(crate) fn remove_bit_shifts(mut self) -> Ssa { + remove_bit_shifts(self.main_mut()); + self + } +} + +/// The structure of this pass is simple: +/// Go through each block and re-insert all instructions. +fn remove_bit_shifts(function: &mut Function) { + if let RuntimeType::Brillig = function.runtime() { + return; + } + + let block = function.entry_block(); + let mut context = + Context { function, new_instructions: Vec::new(), block, call_stack: CallStack::default() }; + + context.remove_bit_shifts(); +} + +struct Context<'f> { + function: &'f mut Function, + new_instructions: Vec, + + block: BasicBlockId, + call_stack: CallStack, +} + +impl Context<'_> { + fn remove_bit_shifts(&mut self) { + let instructions = self.function.dfg[self.block].take_instructions(); + + for instruction_id in instructions { + match self.function.dfg[instruction_id] { + Instruction::Binary(Binary { lhs, rhs, operator }) + if matches!(operator, BinaryOp::Shl | BinaryOp::Shr) => + { + self.call_stack = self.function.dfg.get_call_stack(instruction_id).clone(); + let old_result = + *self.function.dfg.instruction_results(instruction_id).first().unwrap(); + + let bit_size = match self.function.dfg.type_of_value(lhs) { + Type::Numeric(NumericType::Signed { bit_size }) + | Type::Numeric(NumericType::Unsigned { bit_size }) => bit_size, + _ => unreachable!("ICE: right-shift attempted on non-integer"), + }; + let new_result = if operator == BinaryOp::Shl { + self.insert_wrapping_shift_left(lhs, rhs, bit_size) + } else { + self.insert_shift_right(lhs, rhs, bit_size) + }; + + self.function.dfg.set_value_from_id(old_result, new_result); + } + _ => { + self.new_instructions.push(instruction_id); + } + }; + } + + *self.function.dfg[self.block].instructions_mut() = + std::mem::take(&mut self.new_instructions); + } + + /// Insert ssa instructions which computes lhs << rhs by doing lhs*2^rhs + /// and truncate the result to bit_size + pub(crate) fn insert_wrapping_shift_left( + &mut self, + lhs: ValueId, + rhs: ValueId, + bit_size: u32, + ) -> ValueId { + let base = self.field_constant(FieldElement::from(2_u128)); + let typ = self.function.dfg.type_of_value(lhs); + let (max_bit, pow) = if let Some(rhs_constant) = self.function.dfg.get_numeric_constant(rhs) + { + // Happy case is that we know precisely by how many bits the the integer will + // increase: lhs_bit_size + rhs + let bit_shift_size = rhs_constant.to_u128() as u32; + + let (rhs_bit_size_pow_2, overflows) = 2_u128.overflowing_pow(bit_shift_size); + if overflows { + assert!(bit_size < 128, "ICE - shift left with big integers are not supported"); + if bit_size < 128 { + let zero = self.numeric_constant(FieldElement::zero(), typ); + return InsertInstructionResult::SimplifiedTo(zero).first(); + } + } + let pow = self.numeric_constant(FieldElement::from(rhs_bit_size_pow_2), typ); + + let max_lhs_bits = self.function.dfg.get_value_max_num_bits(lhs); + + (max_lhs_bits + bit_shift_size, pow) + } else { + // we use a predicate to nullify the result in case of overflow + let bit_size_var = + self.numeric_constant(FieldElement::from(bit_size as u128), typ.clone()); + let overflow = self.insert_binary(rhs, BinaryOp::Lt, bit_size_var); + let predicate = self.insert_cast(overflow, typ.clone()); + // we can safely cast to unsigned because overflow_checks prevent bit-shift with a negative value + let rhs_unsigned = self.insert_cast(rhs, Type::unsigned(bit_size)); + let pow = self.pow(base, rhs_unsigned); + let pow = self.insert_cast(pow, typ); + (FieldElement::max_num_bits(), self.insert_binary(predicate, BinaryOp::Mul, pow)) + }; + + if max_bit <= bit_size { + self.insert_binary(lhs, BinaryOp::Mul, pow) + } else { + let result = self.insert_binary(lhs, BinaryOp::Mul, pow); + self.insert_truncate(result, bit_size, max_bit) + } + } + + /// Insert ssa instructions which computes lhs >> rhs by doing lhs/2^rhs + pub(crate) fn insert_shift_right( + &mut self, + lhs: ValueId, + rhs: ValueId, + bit_size: u32, + ) -> ValueId { + let lhs_typ = self.function.dfg.type_of_value(lhs); + let base = self.field_constant(FieldElement::from(2_u128)); + // we can safely cast to unsigned because overflow_checks prevent bit-shift with a negative value + let rhs_unsigned = self.insert_cast(rhs, Type::unsigned(bit_size)); + let pow = self.pow(base, rhs_unsigned); + // We need at least one more bit for the case where rhs == bit_size + let div_type = Type::unsigned(bit_size + 1); + let casted_lhs = self.insert_cast(lhs, div_type.clone()); + let casted_pow = self.insert_cast(pow, div_type); + let div_result = self.insert_binary(casted_lhs, BinaryOp::Div, casted_pow); + // We have to cast back to the original type + self.insert_cast(div_result, lhs_typ) + } + + /// Computes lhs^rhs via square&multiply, using the bits decomposition of rhs + /// Pseudo-code of the computation: + /// let mut r = 1; + /// let rhs_bits = to_bits(rhs); + /// for i in 1 .. bit_size + 1 { + /// let r_squared = r * r; + /// let b = rhs_bits[bit_size - i]; + /// r = (r_squared * lhs * b) + (1 - b) * r_squared; + /// } + fn pow(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId { + let typ = self.function.dfg.type_of_value(rhs); + if let Type::Numeric(NumericType::Unsigned { bit_size }) = typ { + let to_bits = self.function.dfg.import_intrinsic(Intrinsic::ToBits(Endian::Little)); + let length = self.field_constant(FieldElement::from(bit_size as i128)); + let result_types = + vec![Type::field(), Type::Array(Rc::new(vec![Type::bool()]), bit_size as usize)]; + let rhs_bits = self.insert_call(to_bits, vec![rhs, length], result_types); + + let rhs_bits = rhs_bits[1]; + let one = self.field_constant(FieldElement::one()); + let mut r = one; + for i in 1..bit_size + 1 { + let r_squared = self.insert_binary(r, BinaryOp::Mul, r); + let a = self.insert_binary(r_squared, BinaryOp::Mul, lhs); + let idx = self.field_constant(FieldElement::from((bit_size - i) as i128)); + let b = self.insert_array_get(rhs_bits, idx, Type::bool()); + let not_b = self.insert_not(b); + let b = self.insert_cast(b, Type::field()); + let not_b = self.insert_cast(not_b, Type::field()); + let r1 = self.insert_binary(a, BinaryOp::Mul, b); + let r2 = self.insert_binary(r_squared, BinaryOp::Mul, not_b); + r = self.insert_binary(r1, BinaryOp::Add, r2); + } + r + } else { + unreachable!("Value must be unsigned in power operation"); + } + } + + pub(crate) fn field_constant(&mut self, constant: FieldElement) -> ValueId { + self.function.dfg.make_constant(constant, Type::field()) + } + + /// Insert a numeric constant into the current function + pub(crate) fn numeric_constant( + &mut self, + value: impl Into, + typ: Type, + ) -> ValueId { + self.function.dfg.make_constant(value.into(), typ) + } + + /// Insert a binary instruction at the end of the current block. + /// Returns the result of the binary instruction. + pub(crate) fn insert_binary( + &mut self, + lhs: ValueId, + operator: BinaryOp, + rhs: ValueId, + ) -> ValueId { + let instruction = Instruction::Binary(Binary { lhs, rhs, operator }); + self.insert_instruction(instruction, None).first() + } + + /// Insert a not instruction at the end of the current block. + /// Returns the result of the instruction. + pub(crate) fn insert_not(&mut self, rhs: ValueId) -> ValueId { + self.insert_instruction(Instruction::Not(rhs), None).first() + } + + /// Insert a truncate instruction at the end of the current block. + /// Returns the result of the truncate instruction. + pub(crate) fn insert_truncate( + &mut self, + value: ValueId, + bit_size: u32, + max_bit_size: u32, + ) -> ValueId { + self.insert_instruction(Instruction::Truncate { value, bit_size, max_bit_size }, None) + .first() + } + + /// Insert a cast instruction at the end of the current block. + /// Returns the result of the cast instruction. + pub(crate) fn insert_cast(&mut self, value: ValueId, typ: Type) -> ValueId { + self.insert_instruction(Instruction::Cast(value, typ), None).first() + } + + /// Insert a call instruction at the end of the current block and return + /// the results of the call. + pub(crate) fn insert_call( + &mut self, + func: ValueId, + arguments: Vec, + result_types: Vec, + ) -> Cow<[ValueId]> { + self.insert_instruction(Instruction::Call { func, arguments }, Some(result_types)).results() + } + + /// Insert an instruction to extract an element from an array + pub(crate) fn insert_array_get( + &mut self, + array: ValueId, + index: ValueId, + element_type: Type, + ) -> ValueId { + let element_type = Some(vec![element_type]); + self.insert_instruction(Instruction::ArrayGet { array, index }, element_type).first() + } + + pub(crate) fn insert_instruction( + &mut self, + instruction: Instruction, + ctrl_typevars: Option>, + ) -> InsertInstructionResult { + let result = self.function.dfg.insert_instruction_and_results( + instruction, + self.block, + ctrl_typevars, + self.call_stack.clone(), + ); + + if let InsertInstructionResult::Results(instruction_id, _) = result { + self.new_instructions.push(instruction_id); + } + + result + } +} diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs index 284bc9f41f5..2219d0264ab 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -552,22 +552,6 @@ impl<'a> FunctionContext<'a> { ) -> Values { let result_type = self.builder.type_of_value(lhs); let mut result = match operator { - BinaryOpKind::ShiftLeft => { - let bit_size = match result_type { - Type::Numeric(NumericType::Signed { bit_size }) - | Type::Numeric(NumericType::Unsigned { bit_size }) => bit_size, - _ => unreachable!("ICE: left-shift attempted on non-integer"), - }; - self.builder.insert_wrapping_shift_left(lhs, rhs, bit_size) - } - BinaryOpKind::ShiftRight => { - let bit_size = match result_type { - Type::Numeric(NumericType::Signed { bit_size }) - | Type::Numeric(NumericType::Unsigned { bit_size }) => bit_size, - _ => unreachable!("ICE: right-shift attempted on non-integer"), - }; - self.builder.insert_shift_right(lhs, rhs, bit_size) - } BinaryOpKind::Equal | BinaryOpKind::NotEqual if matches!(result_type, Type::Array(..)) => { @@ -1142,9 +1126,8 @@ fn convert_operator(op: noirc_frontend::BinaryOpKind) -> BinaryOp { BinaryOpKind::And => BinaryOp::And, BinaryOpKind::Or => BinaryOp::Or, BinaryOpKind::Xor => BinaryOp::Xor, - BinaryOpKind::ShiftRight | BinaryOpKind::ShiftLeft => unreachable!( - "ICE - bit shift operators do not exist in SSA and should have been replaced" - ), + BinaryOpKind::ShiftLeft => BinaryOp::Shl, + BinaryOpKind::ShiftRight => BinaryOp::Shr, } } diff --git a/compiler/noirc_frontend/src/ast/function.rs b/compiler/noirc_frontend/src/ast/function.rs index f20fc54b101..46f0ac0fa0f 100644 --- a/compiler/noirc_frontend/src/ast/function.rs +++ b/compiler/noirc_frontend/src/ast/function.rs @@ -29,6 +29,7 @@ pub enum FunctionKind { Builtin, Normal, Oracle, + Recursive, } impl NoirFunction { @@ -106,6 +107,7 @@ impl From for NoirFunction { Some(FunctionAttribute::Foreign(_)) => FunctionKind::LowLevel, Some(FunctionAttribute::Test { .. }) => FunctionKind::Normal, Some(FunctionAttribute::Oracle(_)) => FunctionKind::Oracle, + Some(FunctionAttribute::Recursive) => FunctionKind::Recursive, None => FunctionKind::Normal, }; diff --git a/compiler/noirc_frontend/src/ast/mod.rs b/compiler/noirc_frontend/src/ast/mod.rs index d9af5893024..1223f822af3 100644 --- a/compiler/noirc_frontend/src/ast/mod.rs +++ b/compiler/noirc_frontend/src/ast/mod.rs @@ -45,7 +45,7 @@ pub enum UnresolvedTypeData { Parenthesized(Box), /// A Named UnresolvedType can be a struct type or a type variable - Named(Path, Vec), + Named(Path, Vec, /*is_synthesized*/ bool), /// A Trait as return type or parameter of function, including its generics TraitAsType(Path, Vec), @@ -110,7 +110,7 @@ impl std::fmt::Display for UnresolvedTypeData { Signedness::Signed => write!(f, "i{num_bits}"), Signedness::Unsigned => write!(f, "u{num_bits}"), }, - Named(s, args) => { + Named(s, args, _) => { let args = vecmap(args, |arg| ToString::to_string(&arg.typ)); if args.is_empty() { write!(f, "{s}") @@ -179,6 +179,14 @@ impl std::fmt::Display for UnresolvedTypeExpression { } impl UnresolvedType { + pub fn is_synthesized(&self) -> bool { + match &self.typ { + UnresolvedTypeData::MutableReference(ty) => ty.is_synthesized(), + UnresolvedTypeData::Named(_, _, synthesized) => *synthesized, + _ => false, + } + } + pub fn without_span(typ: UnresolvedTypeData) -> UnresolvedType { UnresolvedType { typ, span: None } } diff --git a/compiler/noirc_frontend/src/ast/statement.rs b/compiler/noirc_frontend/src/ast/statement.rs index a2c29a8c52e..f39b71405d3 100644 --- a/compiler/noirc_frontend/src/ast/statement.rs +++ b/compiler/noirc_frontend/src/ast/statement.rs @@ -428,18 +428,22 @@ pub enum ConstrainKind { #[derive(Debug, PartialEq, Eq, Clone)] pub enum Pattern { Identifier(Ident), - Mutable(Box, Span), + Mutable(Box, Span, /*is_synthesized*/ bool), Tuple(Vec, Span), Struct(Path, Vec<(Ident, Pattern)>, Span), } impl Pattern { + pub fn is_synthesized(&self) -> bool { + matches!(self, Pattern::Mutable(_, _, true)) + } + pub fn span(&self) -> Span { match self { Pattern::Identifier(ident) => ident.span(), - Pattern::Mutable(_, span) | Pattern::Tuple(_, span) | Pattern::Struct(_, _, span) => { - *span - } + Pattern::Mutable(_, span, _) + | Pattern::Tuple(_, span) + | Pattern::Struct(_, _, span) => *span, } } pub fn name_ident(&self) -> &Ident { @@ -452,7 +456,7 @@ impl Pattern { pub(crate) fn into_ident(self) -> Ident { match self { Pattern::Identifier(ident) => ident, - Pattern::Mutable(pattern, _) => pattern.into_ident(), + Pattern::Mutable(pattern, _, _) => pattern.into_ident(), other => panic!("Pattern::into_ident called on {other} pattern with no identifier"), } } @@ -688,7 +692,7 @@ impl Display for Pattern { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Pattern::Identifier(name) => name.fmt(f), - Pattern::Mutable(name, _) => write!(f, "mut {name}"), + Pattern::Mutable(name, _, _) => write!(f, "mut {name}"), Pattern::Tuple(fields, _) => { let fields = vecmap(fields, ToString::to_string); write!(f, "({})", fields.join(", ")) diff --git a/compiler/noirc_frontend/src/ast/traits.rs b/compiler/noirc_frontend/src/ast/traits.rs index feb627df60b..775f0a5f2b4 100644 --- a/compiler/noirc_frontend/src/ast/traits.rs +++ b/compiler/noirc_frontend/src/ast/traits.rs @@ -48,7 +48,7 @@ pub struct TypeImpl { pub object_type: UnresolvedType, pub type_span: Span, pub generics: UnresolvedGenerics, - pub methods: Vec, + pub methods: Vec<(NoirFunction, Span)>, } /// Ast node for an implementation of a trait for a particular type @@ -101,7 +101,7 @@ impl Display for TypeImpl { writeln!(f, "impl{} {} {{", generics, self.object_type)?; - for method in self.methods.iter() { + for (method, _) in self.methods.iter() { let method = method.to_string(); for line in method.lines() { writeln!(f, " {line}")?; diff --git a/compiler/noirc_frontend/src/debug/mod.rs b/compiler/noirc_frontend/src/debug/mod.rs index 9f182d2baa2..8335867c819 100644 --- a/compiler/noirc_frontend/src/debug/mod.rs +++ b/compiler/noirc_frontend/src/debug/mod.rs @@ -181,7 +181,11 @@ impl DebugInstrumenter { .iter() .map(|(id, is_mut)| { if *is_mut { - ast::Pattern::Mutable(Box::new(ast::Pattern::Identifier(id.clone())), id.span()) + ast::Pattern::Mutable( + Box::new(ast::Pattern::Identifier(id.clone())), + id.span(), + true, + ) } else { ast::Pattern::Identifier(id.clone()) } @@ -562,7 +566,7 @@ fn pattern_vars(pattern: &ast::Pattern) -> Vec<(ast::Ident, bool)> { ast::Pattern::Identifier(id) => { vars.push((id.clone(), is_mut)); } - ast::Pattern::Mutable(pattern, _) => { + ast::Pattern::Mutable(pattern, _, _) => { stack.push_back((pattern, true)); } ast::Pattern::Tuple(patterns, _) => { diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index debf6863f71..55643389383 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -16,7 +16,7 @@ use crate::hir::Context; use crate::macros_api::{MacroError, MacroProcessor}; use crate::node_interner::{ - DependencyId, FuncId, NodeInterner, StmtId, StructId, TraitId, TypeAliasId, + DependencyId, FuncId, GlobalId, NodeInterner, StructId, TraitId, TypeAliasId, }; use crate::parser::{ParserError, SortedModule}; @@ -112,7 +112,7 @@ pub struct UnresolvedTypeAlias { pub struct UnresolvedGlobal { pub file_id: FileId, pub module_id: LocalModuleId, - pub stmt_id: StmtId, + pub global_id: GlobalId, pub stmt_def: LetStatement, } @@ -324,7 +324,7 @@ impl DefCollector { // Must resolve structs before we resolve globals. errors.extend(resolve_structs(context, def_collector.collected_types, crate_id)); - // We must wait to resolve non-integer globals until after we resolve structs since structs + // We must wait to resolve non-integer globals until after we resolve structs since struct // globals will need to reference the struct type they're initialized to to ensure they are valid. resolved_globals.extend(resolve_globals(context, other_globals, crate_id)); errors.extend(resolved_globals.errors); @@ -464,15 +464,15 @@ fn filter_literal_globals( fn type_check_globals( interner: &mut NodeInterner, - global_ids: Vec<(FileId, StmtId)>, + global_ids: Vec<(FileId, GlobalId)>, ) -> Vec<(CompilationError, fm::FileId)> { global_ids - .iter() - .flat_map(|(file_id, stmt_id)| { - TypeChecker::check_global(stmt_id, interner) + .into_iter() + .flat_map(|(file_id, global_id)| { + TypeChecker::check_global(global_id, interner) .iter() .cloned() - .map(|e| (e.into(), *file_id)) + .map(|e| (e.into(), file_id)) .collect::>() }) .collect() @@ -483,12 +483,12 @@ fn type_check_functions( file_func_ids: Vec<(FileId, FuncId)>, ) -> Vec<(CompilationError, fm::FileId)> { file_func_ids - .iter() + .into_iter() .flat_map(|(file, func)| { - type_check_func(interner, *func) + type_check_func(interner, func) .iter() .cloned() - .map(|e| (e.into(), *file)) + .map(|e| (e.into(), file)) .collect::>() }) .collect() diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 3cd60c33b8b..77224cc311c 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -89,13 +89,12 @@ impl<'a> ModCollector<'a> { for global in globals { let name = global.pattern.name_ident().clone(); - // First create dummy function in the DefInterner - // So that we can get a StmtId - let stmt_id = context.def_interner.push_empty_global(); + let global_id = + context.def_interner.push_empty_global(name.clone(), self.module_id, self.file_id); // Add the statement to the scope so its path can be looked up later - let result = - self.def_collector.def_map.modules[self.module_id.0].declare_global(name, stmt_id); + let result = self.def_collector.def_map.modules[self.module_id.0] + .declare_global(name, global_id); if let Err((first_def, second_def)) = result { let err = DefCollectorErrorKind::Duplicate { @@ -109,7 +108,7 @@ impl<'a> ModCollector<'a> { self.def_collector.collected_globals.push(UnresolvedGlobal { file_id: self.file_id, module_id: self.module_id, - stmt_id, + global_id, stmt_def: global, }); } @@ -126,7 +125,7 @@ impl<'a> ModCollector<'a> { trait_id: None, }; - for method in r#impl.methods { + for (method, _) in r#impl.methods { let func_id = context.def_interner.push_empty_fn(); let location = Location::new(method.span(), self.file_id); context.def_interner.push_function(func_id, &method.def, module_id, location); @@ -440,11 +439,15 @@ impl<'a> ModCollector<'a> { } } TraitItem::Constant { name, .. } => { - let stmt_id = context.def_interner.push_empty_global(); + let global_id = context.def_interner.push_empty_global( + name.clone(), + trait_id.0.local_id, + self.file_id, + ); if let Err((first_def, second_def)) = self.def_collector.def_map.modules [trait_id.0.local_id.0] - .declare_global(name.clone(), stmt_id) + .declare_global(name.clone(), global_id) { let error = DefCollectorErrorKind::Duplicate { typ: DuplicateType::TraitAssociatedConst, diff --git a/compiler/noirc_frontend/src/hir/def_map/module_data.rs b/compiler/noirc_frontend/src/hir/def_map/module_data.rs index fbb5e5cf741..309618dd011 100644 --- a/compiler/noirc_frontend/src/hir/def_map/module_data.rs +++ b/compiler/noirc_frontend/src/hir/def_map/module_data.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use noirc_errors::Location; use crate::{ - node_interner::{FuncId, StmtId, StructId, TraitId, TypeAliasId}, + node_interner::{FuncId, GlobalId, StructId, TraitId, TypeAliasId}, Ident, }; @@ -76,7 +76,7 @@ impl ModuleData { self.definitions.remove_definition(name); } - pub fn declare_global(&mut self, name: Ident, id: StmtId) -> Result<(), (Ident, Ident)> { + pub fn declare_global(&mut self, name: Ident, id: GlobalId) -> Result<(), (Ident, Ident)> { self.declare(name, id.into(), None) } diff --git a/compiler/noirc_frontend/src/hir/def_map/module_def.rs b/compiler/noirc_frontend/src/hir/def_map/module_def.rs index 3e5629639fa..54d092f9515 100644 --- a/compiler/noirc_frontend/src/hir/def_map/module_def.rs +++ b/compiler/noirc_frontend/src/hir/def_map/module_def.rs @@ -1,4 +1,4 @@ -use crate::node_interner::{FuncId, StmtId, StructId, TraitId, TypeAliasId}; +use crate::node_interner::{FuncId, GlobalId, StructId, TraitId, TypeAliasId}; use super::ModuleId; @@ -10,7 +10,7 @@ pub enum ModuleDefId { TypeId(StructId), TypeAliasId(TypeAliasId), TraitId(TraitId), - GlobalId(StmtId), + GlobalId(GlobalId), } impl ModuleDefId { @@ -42,9 +42,9 @@ impl ModuleDefId { } } - pub fn as_global(&self) -> Option { + pub fn as_global(&self) -> Option { match self { - ModuleDefId::GlobalId(stmt_id) => Some(*stmt_id), + ModuleDefId::GlobalId(global_id) => Some(*global_id), _ => None, } } @@ -88,9 +88,9 @@ impl From for ModuleDefId { } } -impl From for ModuleDefId { - fn from(stmt_id: StmtId) -> Self { - ModuleDefId::GlobalId(stmt_id) +impl From for ModuleDefId { + fn from(global_id: GlobalId) -> Self { + ModuleDefId::GlobalId(global_id) } } @@ -162,13 +162,13 @@ impl TryFromModuleDefId for TraitId { } } -impl TryFromModuleDefId for StmtId { +impl TryFromModuleDefId for GlobalId { fn try_from(id: ModuleDefId) -> Option { id.as_global() } fn dummy_id() -> Self { - StmtId::dummy_id() + GlobalId::dummy_id() } fn description() -> String { diff --git a/compiler/noirc_frontend/src/hir/resolution/errors.rs b/compiler/noirc_frontend/src/hir/resolution/errors.rs index d15196b10c0..d2fe67da38c 100644 --- a/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -84,6 +84,8 @@ pub enum ResolverError { InvalidTypeForEntryPoint { span: Span }, #[error("Nested slices are not supported")] NestedSlices { span: Span }, + #[error("#[recursive] attribute is only allowed on entry points to a program")] + MisplacedRecursiveAttribute { ident: Ident }, #[error("Usage of the `#[foreign]` or `#[builtin]` function attributes are not allowed outside of the Noir standard library")] LowLevelFunctionOutsideOfStdlib { ident: Ident }, #[error("Dependency cycle found, '{item}' recursively depends on itself: {cycle} ")] @@ -142,33 +144,33 @@ impl From for Diagnostic { field.span(), ), ResolverError::NoSuchField { field, struct_definition } => { - let mut error = Diagnostic::simple_error( + Diagnostic::simple_error( format!("no such field {field} defined in struct {struct_definition}"), String::new(), field.span(), - ); - - error.add_secondary( - format!("{struct_definition} defined here with no {field} field"), - struct_definition.span(), - ); - error + ) } - ResolverError::MissingFields { span, missing_fields, struct_definition } => { + ResolverError::MissingFields { span, mut missing_fields, struct_definition } => { let plural = if missing_fields.len() != 1 { "s" } else { "" }; - let missing_fields = missing_fields.join(", "); + let remaining_fields_names = match &missing_fields[..] { + [field1] => field1.clone(), + [field1, field2] => format!("{field1} and {field2}"), + [field1, field2, field3] => format!("{field1}, {field2} and {field3}"), + _ => { + let len = missing_fields.len() - 3; + let len_plural = if len != 1 {"s"} else {""}; - let mut error = Diagnostic::simple_error( - format!("missing field{plural}: {missing_fields}"), + let truncated_fields = format!(" and {len} other field{len_plural}"); + missing_fields.truncate(3); + format!("{}{truncated_fields}", missing_fields.join(", ")) + } + }; + + Diagnostic::simple_error( + format!("missing field{plural} {remaining_fields_names} in struct {struct_definition}"), String::new(), span, - ); - - error.add_secondary( - format!("{struct_definition} defined here"), - struct_definition.span(), - ); - error + ) } ResolverError::UnnecessaryMut { first_mut, second_mut } => { let mut error = Diagnostic::simple_error( @@ -315,6 +317,18 @@ impl From for Diagnostic { "Try to use a constant sized array instead".into(), span, ), + ResolverError::MisplacedRecursiveAttribute { ident } => { + let name = &ident.0.contents; + + let mut diag = Diagnostic::simple_error( + format!("misplaced #[recursive] attribute on function {name} rather than the main function"), + "misplaced #[recursive] attribute".to_string(), + ident.0.span(), + ); + + diag.add_note("The `#[recursive]` attribute specifies to the backend whether it should use a prover which generates proofs that are friendly for recursive verification in another circuit".to_owned()); + diag + } ResolverError::LowLevelFunctionOutsideOfStdlib { ident } => Diagnostic::simple_error( "Definition of low-level function outside of standard library".into(), "Usage of the `#[foreign]` or `#[builtin]` function attributes are not allowed outside of the Noir standard library".into(), diff --git a/compiler/noirc_frontend/src/hir/resolution/globals.rs b/compiler/noirc_frontend/src/hir/resolution/globals.rs index b5aec212dbf..9fb31271727 100644 --- a/compiler/noirc_frontend/src/hir/resolution/globals.rs +++ b/compiler/noirc_frontend/src/hir/resolution/globals.rs @@ -6,13 +6,13 @@ use crate::{ def_map::ModuleId, Context, }, - node_interner::StmtId, + node_interner::GlobalId, }; use fm::FileId; use iter_extended::vecmap; pub(crate) struct ResolvedGlobals { - pub(crate) globals: Vec<(FileId, StmtId)>, + pub(crate) globals: Vec<(FileId, GlobalId)>, pub(crate) errors: Vec<(CompilationError, FileId)>, } @@ -40,16 +40,13 @@ pub(crate) fn resolve_globals( global.file_id, ); - let name = global.stmt_def.pattern.name_ident().clone(); - - let hir_stmt = resolver.resolve_global_let(global.stmt_def); + let hir_stmt = resolver.resolve_global_let(global.stmt_def, global.global_id); errors.extend(take_errors(global.file_id, resolver)); - context.def_interner.update_global(global.stmt_id, hir_stmt); - - context.def_interner.push_global(global.stmt_id, name, global.module_id); + let statement_id = context.def_interner.get_global(global.global_id).let_statement; + context.def_interner.replace_statement(statement_id, hir_stmt); - (global.file_id, global.stmt_id) + (global.file_id, global.global_id) }); ResolvedGlobals { globals, errors } } diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index d33ba9ba253..1d75e16e5d1 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -28,8 +28,8 @@ use crate::graph::CrateId; use crate::hir::def_map::{LocalModuleId, ModuleDefId, TryFromModuleDefId, MAIN_FUNCTION}; use crate::hir_def::stmt::{HirAssignStatement, HirForStatement, HirLValue, HirPattern}; use crate::node_interner::{ - DefinitionId, DefinitionKind, DependencyId, ExprId, FuncId, NodeInterner, StmtId, StructId, - TraitId, TraitImplId, TraitMethodId, + DefinitionId, DefinitionKind, DependencyId, ExprId, FuncId, GlobalId, NodeInterner, StmtId, + StructId, TraitId, TraitImplId, TraitMethodId, }; use crate::{ hir::{def_map::CrateDefMap, resolution::path_resolver::PathResolver}, @@ -93,8 +93,9 @@ pub struct Resolver<'a> { /// to the corresponding trait impl ID. current_trait_impl: Option, - /// If we're currently resolving fields in a struct type, this is set to that type. - current_struct_type: Option, + /// The current dependency item we're resolving. + /// Used to link items to their dependencies in the dependency graph + current_item: Option, /// True if the current module is a contract. /// This is usually determined by self.path_resolver.module_id(), but it can @@ -151,7 +152,7 @@ impl<'a> Resolver<'a> { errors: Vec::new(), lambda_stack: Vec::new(), current_trait_impl: None, - current_struct_type: None, + current_item: None, file, in_contract, } @@ -188,6 +189,7 @@ impl<'a> Resolver<'a> { func_id: FuncId, ) -> (HirFunction, FuncMeta, Vec) { self.scopes.start_function(); + self.current_item = Some(DependencyId::Function(func_id)); // Check whether the function has globals in the local module and add them to the scope self.resolve_local_globals(); @@ -342,21 +344,22 @@ impl<'a> Resolver<'a> { // This check is necessary to maintain the same definition ids in the interner. Currently, each function uses a new resolver that has its own ScopeForest and thus global scope. // We must first check whether an existing definition ID has been inserted as otherwise there will be multiple definitions for the same global statement. // This leads to an error in evaluation where the wrong definition ID is selected when evaluating a statement using the global. The check below prevents this error. - let mut stmt_id = None; + let mut global_id = None; let global = self.interner.get_all_globals(); - for (global_stmt_id, global_info) in global { + for global_info in global { if global_info.ident == name && global_info.local_id == self.path_resolver.local_module_id() { - stmt_id = Some(global_stmt_id); + global_id = Some(global_info.id); } } - let (ident, resolver_meta) = if let Some(id) = stmt_id { - let hir_let_stmt = self.interner.let_statement(&id); - let ident = hir_let_stmt.ident(); + let (ident, resolver_meta) = if let Some(id) = global_id { + let global = self.interner.get_global(id); + let hir_ident = HirIdent::non_trait_method(global.definition_id, global.location); + let ident = hir_ident.clone(); let resolver_meta = ResolverMeta { num_times_used: 0, ident, warn_if_unused: true }; - (hir_let_stmt.ident(), resolver_meta) + (hir_ident, resolver_meta) } else { let location = Location::new(name.span(), self.file); let id = @@ -418,7 +421,7 @@ impl<'a> Resolver<'a> { FunctionKind::Builtin | FunctionKind::LowLevel | FunctionKind::Oracle => { HirFunction::empty() } - FunctionKind::Normal => { + FunctionKind::Normal | FunctionKind::Recursive => { let expr_id = self.intern_block(func.def.body); self.interner.push_expr_location(expr_id, func.def.span, self.file); HirFunction::unchecked_from_expr(expr_id) @@ -487,7 +490,7 @@ impl<'a> Resolver<'a> { Unit => Type::Unit, Unspecified => Type::Error, Error => Type::Error, - Named(path, args) => self.resolve_named_type(path, args, new_variables), + Named(path, args, _) => self.resolve_named_type(path, args, new_variables), TraitAsType(path, args) => self.resolve_trait_as_type(path, args, new_variables), Tuple(fields) => { @@ -603,9 +606,9 @@ impl<'a> Resolver<'a> { struct_type.borrow().to_string() }); - if let Some(current_struct) = self.current_struct_type { + if let Some(current_item) = self.current_item { let dependency_id = struct_type.borrow().id; - self.interner.add_type_dependency(current_struct, dependency_id); + self.interner.add_type_dependency(current_item, dependency_id); } Type::Struct(struct_type, args) @@ -660,10 +663,10 @@ impl<'a> Resolver<'a> { // If we cannot find a local generic of the same name, try to look up a global match self.path_resolver.resolve(self.def_maps, path.clone()) { Ok(ModuleDefId::GlobalId(id)) => { - if let Some(current_struct) = self.current_struct_type { - self.interner.add_type_global_dependency(current_struct, id); + if let Some(current_item) = self.current_item { + self.interner.add_global_dependency(current_item, id); } - Some(Type::Constant(self.eval_global_as_array_length(id))) + Some(Type::Constant(self.eval_global_as_array_length(id, path))) } _ => None, } @@ -849,18 +852,20 @@ impl<'a> Resolver<'a> { // Check whether the struct definition has globals in the local module and add them to the scope self.resolve_local_globals(); - self.current_struct_type = Some(struct_id); + self.current_item = Some(DependencyId::Struct(struct_id)); let fields = vecmap(unresolved.fields, |(ident, typ)| (ident, self.resolve_type(typ))); (generics, fields, self.errors) } fn resolve_local_globals(&mut self) { - for (stmt_id, global_info) in self.interner.get_all_globals() { - if global_info.local_id == self.path_resolver.local_module_id() { - let global_stmt = self.interner.let_statement(&stmt_id); - let definition = DefinitionKind::Global(global_stmt.expression); - self.add_global_variable_decl(global_info.ident, definition); + let globals = vecmap(self.interner.get_all_globals(), |global| { + (global.id, global.local_id, global.ident.clone()) + }); + for (id, local_module_id, name) in globals { + if local_module_id == self.path_resolver.local_module_id() { + let definition = DefinitionKind::Global(id); + self.add_global_variable_decl(name, definition); } } } @@ -937,6 +942,12 @@ impl<'a> Resolver<'a> { { self.push_err(ResolverError::NecessaryPub { ident: func.name_ident().clone() }); } + // '#[recursive]' attribute is only allowed for entry point functions + if !self.is_entry_point_function(func) && func.kind == FunctionKind::Recursive { + self.push_err(ResolverError::MisplacedRecursiveAttribute { + ident: func.name_ident().clone(), + }); + } if !self.distinct_allowed(func) && func.def.return_distinctness != Distinctness::DuplicationAllowed @@ -1124,9 +1135,15 @@ impl<'a> Resolver<'a> { } } - pub fn resolve_global_let(&mut self, let_stmt: crate::LetStatement) -> HirStatement { - let expression = self.resolve_expression(let_stmt.clone().expression); - let definition = DefinitionKind::Global(expression); + pub fn resolve_global_let( + &mut self, + let_stmt: crate::LetStatement, + global_id: GlobalId, + ) -> HirStatement { + self.current_item = Some(DependencyId::Global(global_id)); + let expression = self.resolve_expression(let_stmt.expression); + let global_id = self.interner.next_global_id(); + let definition = DefinitionKind::Global(global_id); HirStatement::Let(HirLetStatement { pattern: self.resolve_pattern(let_stmt.pattern, definition), @@ -1407,6 +1424,10 @@ impl<'a> Resolver<'a> { if hir_ident.id != DefinitionId::dummy_id() { match self.interner.definition(hir_ident.id).kind { DefinitionKind::Function(id) => { + if let Some(current_item) = self.current_item { + self.interner.add_function_dependency(current_item, id); + } + if self.interner.function_visibility(id) != FunctionVisibility::Public { @@ -1425,7 +1446,11 @@ impl<'a> Resolver<'a> { ); } } - DefinitionKind::Global(_) => {} + DefinitionKind::Global(global_id) => { + if let Some(current_item) = self.current_item { + self.interner.add_global_dependency(current_item, global_id); + } + } DefinitionKind::GenericType(_) => { // Initialize numeric generics to a polymorphic integer type in case // they're used in expressions. We must do this here since the type @@ -1597,7 +1622,7 @@ impl<'a> Resolver<'a> { let id = self.add_variable_decl(name, mutable.is_some(), true, definition); HirPattern::Identifier(id) } - Pattern::Mutable(pattern, span) => { + Pattern::Mutable(pattern, span, _) => { if let Some(first_mut) = mutable { self.push_err(ResolverError::UnnecessaryMut { first_mut, second_mut: span }); } @@ -1721,8 +1746,8 @@ impl<'a> Resolver<'a> { } if let Some(global) = TryFromModuleDefId::try_from(id) { - let let_stmt = self.interner.let_statement(&global); - return Ok(let_stmt.ident().id); + let global = self.interner.get_global(global); + return Ok(global.definition_id); } let expected = "global variable".into(); @@ -1846,7 +1871,7 @@ impl<'a> Resolver<'a> { } for UnresolvedTraitConstraint { typ, trait_bound } in self.trait_bounds.clone() { - if let UnresolvedTypeData::Named(constraint_path, _) = &typ.typ { + if let UnresolvedTypeData::Named(constraint_path, _, _) = &typ.typ { // if `path` is `T::method_name`, we're looking for constraint of the form `T: SomeTrait` if constraint_path.segments.len() == 1 && path.segments[0] != constraint_path.last_segment() @@ -1904,10 +1929,11 @@ impl<'a> Resolver<'a> { self.interner.push_expr(hir_block) } - fn eval_global_as_array_length(&mut self, global: StmtId) -> u64 { - let stmt = match self.interner.statement(&global) { - HirStatement::Let(let_expr) => let_expr, - _ => return 0, + fn eval_global_as_array_length(&mut self, global: GlobalId, path: &Path) -> u64 { + let Some(stmt) = self.interner.get_global_let_statement(global) else { + let path = path.clone(); + self.push_err(ResolverError::NoSuchNumericTypeVariable { path }); + return 0; }; let length = stmt.expression; @@ -2007,7 +2033,7 @@ impl<'a> Resolver<'a> { self.push_err(ResolverError::InvalidTypeForEntryPoint { span }); } } - UnresolvedTypeData::Named(path, generics) => { + UnresolvedTypeData::Named(path, generics, _) => { // Since the type is named, we need to resolve it to see what it actually refers to // in order to check whether it is valid. Since resolving it may lead to a // resolution error, we have to truncate our error count to the previous count just diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index 998abeedcec..b3180e0dd20 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -153,11 +153,10 @@ impl<'interner> TypeChecker<'interner> { HirExpression::Call(call_expr) => { // Need to setup these flags here as `self` is borrowed mutably to type check the rest of the call expression // These flags are later used to type check calls to unconstrained functions from constrained functions - let current_func = self - .current_function - .expect("Can only have call expression inside of a function body"); - let func_mod = self.interner.function_modifiers(¤t_func); - let is_current_func_constrained = !func_mod.is_unconstrained; + let current_func = self.current_function; + let func_mod = current_func.map(|func| self.interner.function_modifiers(&func)); + let is_current_func_constrained = + func_mod.map_or(true, |func_mod| !func_mod.is_unconstrained); let is_unconstrained_call = self.is_unconstrained_call(&call_expr.func); self.check_if_deprecated(&call_expr.func); @@ -170,15 +169,14 @@ impl<'interner> TypeChecker<'interner> { }); // Check that we are not passing a mutable reference from a constrained runtime to an unconstrained runtime - for (typ, _, _) in args.iter() { - if is_current_func_constrained - && is_unconstrained_call - && matches!(&typ, Type::MutableReference(_)) - { - self.errors.push(TypeCheckError::ConstrainedReferenceToUnconstrained { - span: self.interner.expr_span(expr_id), - }); - return Type::Error; + if is_current_func_constrained && is_unconstrained_call { + for (typ, _, _) in args.iter() { + if matches!(&typ.follow_bindings(), Type::MutableReference(_)) { + self.errors.push(TypeCheckError::ConstrainedReferenceToUnconstrained { + span: self.interner.expr_span(expr_id), + }); + return Type::Error; + } } } diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index 3c2a970ee84..8952ba83586 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -15,7 +15,7 @@ pub use errors::TypeCheckError; use crate::{ hir_def::{expr::HirExpression, stmt::HirStatement, traits::TraitConstraint}, - node_interner::{ExprId, FuncId, NodeInterner, StmtId}, + node_interner::{ExprId, FuncId, GlobalId, NodeInterner}, Type, }; @@ -193,7 +193,10 @@ impl<'interner> TypeChecker<'interner> { (body_type, std::mem::take(&mut self.delayed_type_checks)) } - pub fn check_global(id: &StmtId, interner: &'interner mut NodeInterner) -> Vec { + pub fn check_global( + id: GlobalId, + interner: &'interner mut NodeInterner, + ) -> Vec { let mut this = Self { delayed_type_checks: Vec::new(), interner, @@ -201,7 +204,8 @@ impl<'interner> TypeChecker<'interner> { trait_constraints: Vec::new(), current_function: None, }; - this.check_statement(id); + let statement = this.interner.get_global(id).let_statement; + this.check_statement(&statement); this.errors } diff --git a/compiler/noirc_frontend/src/hir_def/function.rs b/compiler/noirc_frontend/src/hir_def/function.rs index 0ea352a3d04..d3ab2a9393b 100644 --- a/compiler/noirc_frontend/src/hir_def/function.rs +++ b/compiler/noirc_frontend/src/hir_def/function.rs @@ -122,7 +122,7 @@ impl FuncMeta { pub fn can_ignore_return_type(&self) -> bool { match self.kind { FunctionKind::LowLevel | FunctionKind::Builtin | FunctionKind::Oracle => true, - FunctionKind::Normal => false, + FunctionKind::Normal | FunctionKind::Recursive => false, } } diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index 835a0baae3f..5d08ab03ad3 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -491,6 +491,7 @@ impl Attribute { Attribute::Function(FunctionAttribute::Oracle(name.to_string())) } ["test"] => Attribute::Function(FunctionAttribute::Test(TestScope::None)), + ["recursive"] => Attribute::Function(FunctionAttribute::Recursive), ["test", name] => { validate(name)?; let malformed_scope = @@ -541,6 +542,7 @@ pub enum FunctionAttribute { Builtin(String), Oracle(String), Test(TestScope), + Recursive, } impl FunctionAttribute { @@ -578,6 +580,7 @@ impl fmt::Display for FunctionAttribute { FunctionAttribute::Foreign(ref k) => write!(f, "#[foreign({k})]"), FunctionAttribute::Builtin(ref k) => write!(f, "#[builtin({k})]"), FunctionAttribute::Oracle(ref k) => write!(f, "#[oracle({k})]"), + FunctionAttribute::Recursive => write!(f, "#[recursive]"), } } } @@ -621,6 +624,7 @@ impl AsRef for FunctionAttribute { FunctionAttribute::Builtin(string) => string, FunctionAttribute::Oracle(string) => string, FunctionAttribute::Test { .. } => "", + FunctionAttribute::Recursive => "", } } } diff --git a/compiler/noirc_frontend/src/monomorphization/ast.rs b/compiler/noirc_frontend/src/monomorphization/ast.rs index ccfce12aff0..73e7ef372ab 100644 --- a/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -249,17 +249,21 @@ pub struct Program { pub return_distinctness: Distinctness, pub return_location: Option, pub return_visibility: Visibility, + /// Indicates to a backend whether a SNARK-friendly prover should be used. + pub recursive: bool, pub debug_variables: DebugVariables, pub debug_types: DebugTypes, } impl Program { + #[allow(clippy::too_many_arguments)] pub fn new( functions: Vec, main_function_signature: FunctionSignature, return_distinctness: Distinctness, return_location: Option, return_visibility: Visibility, + recursive: bool, debug_variables: DebugVariables, debug_types: DebugTypes, ) -> Program { @@ -269,6 +273,7 @@ impl Program { return_distinctness, return_location, return_visibility, + recursive, debug_variables, debug_types, } diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index 3323f1e24c4..21c095eb877 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -124,7 +124,7 @@ pub fn monomorphize_debug( } let functions = vecmap(monomorphizer.finished_functions, |(_, f)| f); - let FuncMeta { return_distinctness, return_visibility, .. } = + let FuncMeta { return_distinctness, return_visibility, kind, .. } = monomorphizer.interner.function_meta(&main); let (debug_variables, debug_types) = monomorphizer.debug_type_tracker.extract_vars_and_types(); @@ -134,6 +134,7 @@ pub fn monomorphize_debug( *return_distinctness, monomorphizer.return_location, *return_visibility, + *kind == FunctionKind::Recursive, debug_variables, debug_types, ) @@ -215,6 +216,9 @@ impl<'interner> Monomorphizer<'interner> { _ => unreachable!("Oracle function must have an oracle attribute"), } } + FunctionKind::Recursive => { + unreachable!("Only main can be specified as recursive, which should already be checked"); + } } } } @@ -726,7 +730,12 @@ impl<'interner> Monomorphizer<'interner> { ident_expression } } - DefinitionKind::Global(expr_id) => self.expr(*expr_id), + DefinitionKind::Global(global_id) => { + let Some(let_) = self.interner.get_global_let_statement(*global_id) else { + unreachable!("Globals should have a corresponding let statement by monomorphization") + }; + self.expr(let_.expression) + } DefinitionKind::Local(_) => self.lookup_captured_expr(ident.id).unwrap_or_else(|| { let ident = self.local_ident(&ident).unwrap(); ast::Expression::Ident(ident) diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 914b353c216..bd2b63738d3 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::collections::HashMap; +use std::ops::Deref; use arena::{Arena, Index}; use fm::FileId; @@ -141,7 +142,9 @@ pub struct NodeInterner { /// checking. field_indices: HashMap, - globals: HashMap, // NOTE: currently only used for checking repeat globals and restricting their scope to a module + // Maps GlobalId -> GlobalInfo + // NOTE: currently only used for checking repeat globals and restricting their scope to a module + globals: Vec, next_type_variable_id: std::cell::Cell, @@ -187,9 +190,9 @@ pub struct NodeInterner { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum DependencyId { Struct(StructId), - Global(StmtId), GlobalDefinition(DefinitionId), GlobalReference, + Global(GlobalId), Function(FuncId), Alias(TypeAliasId), FunctionCall, @@ -290,6 +293,17 @@ impl From for Index { } } +/// An ID for a global value +#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] +pub struct GlobalId(usize); + +impl GlobalId { + // Dummy id for error reporting + pub fn dummy_id() -> Self { + GlobalId(std::usize::MAX) + } +} + #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] pub struct StmtId(Index); @@ -440,7 +454,7 @@ impl DefinitionInfo { pub enum DefinitionKind { Function(FuncId), - Global(ExprId), + Global(GlobalId), /// Locals may be defined in let statements or parameters, /// in which case they will not have an associated ExprId @@ -461,7 +475,7 @@ impl DefinitionKind { pub fn get_rhs(&self) -> Option { match self { DefinitionKind::Function(_) => None, - DefinitionKind::Global(id) => Some(*id), + DefinitionKind::Global(_) => None, DefinitionKind::Local(id) => *id, DefinitionKind::GenericType(_) => None, } @@ -470,8 +484,12 @@ impl DefinitionKind { #[derive(Debug, Clone)] pub struct GlobalInfo { + pub id: GlobalId, + pub definition_id: DefinitionId, pub ident: Ident, pub local_id: LocalModuleId, + pub location: Location, + pub let_statement: StmtId, } impl Default for NodeInterner { @@ -500,7 +518,7 @@ impl Default for NodeInterner { instantiation_bindings: HashMap::new(), field_indices: HashMap::new(), next_type_variable_id: std::cell::Cell::new(0), - globals: HashMap::new(), + globals: Vec::new(), struct_methods: HashMap::new(), primitive_methods: HashMap::new(), type_alias_ref: Vec::new(), @@ -665,26 +683,41 @@ impl NodeInterner { self.type_ref_locations.push((typ, location)); } - pub fn push_global(&mut self, stmt_id: StmtId, ident: Ident, local_id: LocalModuleId) { - self.globals.insert(stmt_id, GlobalInfo { ident, local_id }); + fn push_global( + &mut self, + ident: Ident, + local_id: LocalModuleId, + let_statement: StmtId, + file: FileId, + ) -> GlobalId { + let id = GlobalId(self.globals.len()); + let location = Location::new(ident.span(), file); + let name = ident.to_string(); + let definition_id = self.push_definition(name, false, DefinitionKind::Global(id), location); + self.globals.push(GlobalInfo { + id, + definition_id, + ident, + local_id, + let_statement, + location, + }); + id } - /// Intern an empty global stmt. Used for collecting globals - pub fn push_empty_global(&mut self) -> StmtId { - self.push_stmt(HirStatement::Error) + pub fn next_global_id(&mut self) -> GlobalId { + GlobalId(self.globals.len()) } - pub fn update_global(&mut self, stmt_id: StmtId, hir_stmt: HirStatement) { - let def = - self.nodes.get_mut(stmt_id.0).expect("ice: all function ids should have definitions"); - - let stmt = match def { - Node::Statement(stmt) => stmt, - _ => { - panic!("ice: all global ids should correspond to a statement in the interner") - } - }; - *stmt = hir_stmt; + /// Intern an empty global. Used for collecting globals before they're defined + pub fn push_empty_global( + &mut self, + name: Ident, + local_id: LocalModuleId, + file: FileId, + ) -> GlobalId { + let statement = self.push_stmt(HirStatement::Error); + self.push_global(name, local_id, statement, file) } /// Intern an empty function. @@ -868,19 +901,19 @@ impl NodeInterner { } } - /// Returns the interned let statement corresponding to `stmt_id` - pub fn let_statement(&self, stmt_id: &StmtId) -> HirLetStatement { - let def = - self.nodes.get(stmt_id.0).expect("ice: all statement ids should have definitions"); + /// Try to get the `HirLetStatement` which defines a given global value + pub fn get_global_let_statement(&self, global: GlobalId) -> Option { + let global = self.get_global(global); + let def = self.nodes.get(global.let_statement.0)?; match def { - Node::Statement(hir_stmt) => { - match hir_stmt { - HirStatement::Let(let_stmt) => let_stmt.clone(), - _ => panic!("ice: all let statement ids should correspond to a let statement in the interner"), + Node::Statement(hir_stmt) => match hir_stmt { + HirStatement::Let(let_stmt) => Some(let_stmt.clone()), + _ => { + panic!("ice: all globals should correspond to a let statement in the interner") } }, - _ => panic!("ice: all statement ids should correspond to a statement in the interner"), + _ => panic!("ice: all globals should correspond to a statement in the interner"), } } @@ -946,12 +979,17 @@ impl NodeInterner { &self.type_aliases[id.0] } - pub fn get_global(&self, stmt_id: &StmtId) -> Option { - self.globals.get(stmt_id).cloned() + pub fn get_global(&self, global_id: GlobalId) -> &GlobalInfo { + &self.globals[global_id.0] + } + + pub fn get_global_definition(&self, global_id: GlobalId) -> &DefinitionInfo { + let global = self.get_global(global_id); + self.definition(global.definition_id) } - pub fn get_all_globals(&self) -> HashMap { - self.globals.clone() + pub fn get_all_globals(&self) -> &[GlobalInfo] { + &self.globals } /// Returns the type of an item stored in the Interner or Error if it was not found. @@ -987,6 +1025,12 @@ impl NodeInterner { *old = Node::Expression(new); } + /// Replaces the HirStatement at the given StmtId with a new HirStatement + pub fn replace_statement(&mut self, stmt_id: StmtId, hir_stmt: HirStatement) { + let old = self.nodes.get_mut(stmt_id.0).unwrap(); + *old = Node::Statement(hir_stmt); + } + pub fn next_type_variable_id(&self) -> TypeVariableId { let id = self.next_type_variable_id.get(); self.next_type_variable_id.set(id + 1); @@ -1095,6 +1139,34 @@ impl NodeInterner { Ok(impl_kind) } + /// Given a `ObjectType: TraitId` pair, find all implementations without taking constraints into account or + /// applying any type bindings. Useful to look for a specific trait in a type that is used in a macro. + pub fn lookup_all_trait_implementations( + &self, + object_type: &Type, + trait_id: TraitId, + ) -> Vec<&TraitImplKind> { + let trait_impl = self.trait_implementation_map.get(&trait_id); + + trait_impl + .map(|trait_impl| { + trait_impl + .iter() + .filter_map(|(typ, impl_kind)| match &typ { + Type::Forall(_, typ) => { + if typ.deref() == object_type { + Some(impl_kind) + } else { + None + } + } + _ => None, + }) + .collect() + }) + .unwrap_or(vec![]) + } + /// Similar to `lookup_trait_implementation` but does not apply any type bindings on success. pub fn try_lookup_trait_implementation( &self, @@ -1316,7 +1388,6 @@ impl NodeInterner { force_type_check: bool, ) -> Option { let methods = self.struct_methods.get(&(id, method_name.to_owned())); - // If there is only one method, just return it immediately. // It will still be typechecked later. if !force_type_check { @@ -1474,12 +1545,16 @@ impl NodeInterner { /// Register that `dependent` depends on `dependency`. /// This is usually because `dependent` refers to `dependency` in one of its struct fields. - pub fn add_type_dependency(&mut self, dependent: StructId, dependency: StructId) { - self.add_dependency(DependencyId::Struct(dependent), DependencyId::Struct(dependency)); + pub fn add_type_dependency(&mut self, dependent: DependencyId, dependency: StructId) { + self.add_dependency(dependent, DependencyId::Struct(dependency)); + } + + pub fn add_global_dependency(&mut self, dependent: DependencyId, dependency: GlobalId) { + self.add_dependency(dependent, DependencyId::Global(dependency)); } - pub fn add_type_global_dependency(&mut self, dependent: StructId, dependency: StmtId) { - self.add_dependency(DependencyId::Struct(dependent), DependencyId::Global(dependency)); + pub fn add_function_dependency(&mut self, dependent: DependencyId, dependency: FuncId) { + self.add_dependency(dependent, DependencyId::Function(dependency)); } pub(crate) fn add_dependency(&mut self, dependent: DependencyId, dependency: DependencyId) { @@ -1521,20 +1596,15 @@ impl NodeInterner { break; } DependencyId::Global(global_id) => { - let let_stmt = match self.statement(&global_id) { - HirStatement::Let(let_stmt) => let_stmt, - other => unreachable!( - "Expected global to be a `let` statement, found {other:?}" - ), - }; - - let (name, location) = - self.pattern_name_and_location(&let_stmt.pattern); - push_error(name, &scc, i, location); + let global = self.get_global(global_id); + let name = global.ident.to_string(); + push_error(name, &scc, i, global.location); + break; } DependencyId::Alias(alias_id) => { let alias = self.get_type_alias(alias_id); push_error(alias.name.to_string(), &scc, i, alias.location); + break; } // Mutually recursive functions are allowed DependencyId::Function(_) => (), @@ -1558,58 +1628,21 @@ impl NodeInterner { Cow::Borrowed(self.get_type_alias(id).name.0.contents.as_ref()) } DependencyId::Global(id) => { - let let_stmt = match self.statement(&id) { - HirStatement::Let(let_stmt) => let_stmt, - other => { - unreachable!("Expected global to be a `let` statement, found {other:?}") - } - }; - Cow::Owned(self.pattern_name_and_location(&let_stmt.pattern).0) + Cow::Borrowed(self.get_global(id).ident.0.contents.as_ref()) } _ => Cow::Borrowed(""), }; let mut cycle = index_to_string(scc[start_index]).to_string(); - for i in 0..scc.len() { + // Reversing the dependencies here matches the order users would expect for the error message + for i in (0..scc.len()).rev() { cycle += " -> "; - cycle += &index_to_string(scc[(start_index + i + 1) % scc.len()]); + cycle += &index_to_string(scc[(start_index + i) % scc.len()]); } cycle } - - /// Returns the name and location of this pattern. - /// If this pattern is a tuple or struct the 'name' will be a string representation of the - /// entire pattern. Similarly, the location will be the merged location of all fields. - fn pattern_name_and_location( - &self, - pattern: &crate::hir_def::stmt::HirPattern, - ) -> (String, Location) { - match pattern { - crate::hir_def::stmt::HirPattern::Identifier(ident) => { - let definition = self.definition(ident.id); - (definition.name.clone(), definition.location) - } - crate::hir_def::stmt::HirPattern::Mutable(pattern, _) => { - self.pattern_name_and_location(pattern) - } - crate::hir_def::stmt::HirPattern::Tuple(fields, location) => { - let fields = vecmap(fields, |field| self.pattern_name_and_location(field).0); - - let fields = fields.join(", "); - (format!("({fields})"), *location) - } - crate::hir_def::stmt::HirPattern::Struct(typ, fields, location) => { - let fields = vecmap(fields, |(field_name, field)| { - let field = self.pattern_name_and_location(field).0; - format!("{field_name}: {field}") - }); - let fields = fields.join(", "); - (format!("{typ} {{ {fields} }}"), *location) - } - } - } } impl Methods { diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index 1f41a29dd4f..b1ec18f5ec5 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -133,7 +133,7 @@ fn global_declaration() -> impl NoirParser { ); let p = then_commit(p, optional_type_annotation()); let p = then_commit_ignore(p, just(Token::Assign)); - let p = then_commit(p, literal_or_collection(expression()).map_with_span(Expression::new)); + let p = then_commit(p, expression()); p.map(LetStatement::new_let).map(TopLevelStatement::Global) } @@ -381,24 +381,24 @@ fn self_parameter() -> impl NoirParser { Token::Ident(ref word) if word == "self" => Ok(span), _ => Err(ParserError::expected_label(ParsingRuleLabel::Parameter, found, span)), })) - .map(|(pattern_keyword, span)| { - let ident = Ident::new("self".to_string(), span); - let path = Path::from_single("Self".to_owned(), span); - let mut self_type = UnresolvedTypeData::Named(path, vec![]).with_span(span); + .map(|(pattern_keyword, ident_span)| { + let ident = Ident::new("self".to_string(), ident_span); + let path = Path::from_single("Self".to_owned(), ident_span); + let mut self_type = UnresolvedTypeData::Named(path, vec![], true).with_span(ident_span); let mut pattern = Pattern::Identifier(ident); match pattern_keyword { Some((Token::Ampersand, _)) => { - self_type = - UnresolvedTypeData::MutableReference(Box::new(self_type)).with_span(span); + self_type = UnresolvedTypeData::MutableReference(Box::new(self_type)) + .with_span(ident_span); } Some((Token::Keyword(_), span)) => { - pattern = Pattern::Mutable(Box::new(pattern), span); + pattern = Pattern::Mutable(Box::new(pattern), span.merge(ident_span), true); } _ => (), } - Param { pattern, typ: self_type, visibility: Visibility::Private, span } + Param { span: pattern.span(), pattern, typ: self_type, visibility: Visibility::Private } }) } @@ -558,7 +558,7 @@ fn implementation() -> impl NoirParser { .ignore_then(generics()) .then(parse_type().map_with_span(|typ, span| (typ, span))) .then_ignore(just(Token::LeftBrace)) - .then(function_definition(true).repeated()) + .then(spanned(function_definition(true)).repeated()) .then_ignore(just(Token::RightBrace)) .map(|((generics, (object_type, type_span)), methods)| { TopLevelStatement::Impl(TypeImpl { generics, object_type, type_span, methods }) @@ -894,7 +894,7 @@ fn pattern() -> impl NoirParser { let mut_pattern = keyword(Keyword::Mut) .ignore_then(pattern.clone()) - .map_with_span(|inner, span| Pattern::Mutable(Box::new(inner), span)); + .map_with_span(|inner, span| Pattern::Mutable(Box::new(inner), span, false)); let short_field = ident().map(|name| (name.clone(), Pattern::Identifier(name))); let long_field = ident().then_ignore(just(Token::Colon)).then(pattern.clone()); @@ -1109,9 +1109,9 @@ fn int_type() -> impl NoirParser { } fn named_type(type_parser: impl NoirParser) -> impl NoirParser { - path() - .then(generic_type_args(type_parser)) - .map_with_span(|(path, args), span| UnresolvedTypeData::Named(path, args).with_span(span)) + path().then(generic_type_args(type_parser)).map_with_span(|(path, args), span| { + UnresolvedTypeData::Named(path, args, false).with_span(span) + }) } fn named_trait(type_parser: impl NoirParser) -> impl NoirParser { @@ -1676,24 +1676,6 @@ fn literal() -> impl NoirParser { }) } -fn literal_with_sign() -> impl NoirParser { - choice(( - literal(), - just(Token::Minus).then(literal()).map(|(_, exp)| match exp { - ExpressionKind::Literal(Literal::Integer(value, sign)) => { - ExpressionKind::Literal(Literal::Integer(value, !sign)) - } - _ => unreachable!(), - }), - )) -} - -fn literal_or_collection<'a>( - expr_parser: impl ExprParser + 'a, -) -> impl NoirParser + 'a { - choice((literal_with_sign(), constructor(expr_parser.clone()), array_expr(expr_parser))) -} - #[cfg(test)] mod test { use noirc_errors::CustomDiagnostic; diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 5aae579ecb4..1deff446d7e 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -1174,4 +1174,14 @@ fn lambda$f1(mut env$l1: (Field)) -> Field { "#; assert_eq!(get_program_errors(src).len(), 1); } + + #[test] + fn deny_cyclic_globals() { + let src = r#" + global A = B; + global B = A; + fn main() {} + "#; + assert_eq!(get_program_errors(src).len(), 1); + } } diff --git a/compiler/wasm/README.md b/compiler/wasm/README.md index 0b2d92b0815..52f7e83e19e 100644 --- a/compiler/wasm/README.md +++ b/compiler/wasm/README.md @@ -1,9 +1,32 @@ # Noir Lang WASM JavaScript Package -This JavaScript package enables users to compile a Noir program, i.e. generating its artifacts. +This JavaScript package enables users to compile a Noir program, i.e. generating its artifacts, both in Node.JS environments and the browser. The package also handles dependency management like how Nargo (Noir's CLI tool) operates, but the package is used just for compilation, not proving, verifying and simulating functions. +## Usage + +```typescript +// Node.js + +import { compile, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager(myProjectPath); +const myCompiledCode = await compile(fm); +``` + +```typescript +// Browser + +import { compile, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager('/'); +for (const path of files) { + await fm.writeFile(path, await getFileAsStream(path)); +} +const myCompiledCode = await compile(fm); +``` + ## Building from source Outside of the [noir repo](https://github.com/noir-lang/noir), this package can be built using the command below: diff --git a/compiler/wasm/package.json b/compiler/wasm/package.json index 2aaf4a494df..74dfd27de3e 100644 --- a/compiler/wasm/package.json +++ b/compiler/wasm/package.json @@ -80,6 +80,7 @@ "webpack-cli": "^4.7.2" }, "dependencies": { + "@noir-lang/types": "workspace:*", "pako": "^2.1.0" } } diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index b39a27a7931..c8b1680bc00 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -177,7 +177,7 @@ pub fn compile( let compile_options = CompileOptions::default(); // For now we default to a bounded width of 3, though we can add it as a parameter - let expression_width = acvm::ExpressionWidth::Bounded { width: 3 }; + let expression_width = acvm::acir::circuit::ExpressionWidth::Bounded { width: 3 }; if contracts.unwrap_or_default() { let compiled_contract = compile_contract(&mut context, crate_id, &compile_options) diff --git a/compiler/wasm/src/compile_new.rs b/compiler/wasm/src/compile_new.rs index 4616004ae2b..f8fbed4f470 100644 --- a/compiler/wasm/src/compile_new.rs +++ b/compiler/wasm/src/compile_new.rs @@ -94,7 +94,7 @@ impl CompilerContext { program_width: usize, ) -> Result { let compile_options = CompileOptions::default(); - let np_language = acvm::ExpressionWidth::Bounded { width: program_width }; + let np_language = acvm::acir::circuit::ExpressionWidth::Bounded { width: program_width }; let root_crate_id = *self.context.root_crate_id(); @@ -120,7 +120,7 @@ impl CompilerContext { program_width: usize, ) -> Result { let compile_options = CompileOptions::default(); - let np_language = acvm::ExpressionWidth::Bounded { width: program_width }; + let np_language = acvm::acir::circuit::ExpressionWidth::Bounded { width: program_width }; let root_crate_id = *self.context.root_crate_id(); let compiled_contract = diff --git a/compiler/wasm/src/index.cts b/compiler/wasm/src/index.cts index 14687e615df..7c707e662d8 100644 --- a/compiler/wasm/src/index.cts +++ b/compiler/wasm/src/index.cts @@ -5,6 +5,36 @@ import { LogData, LogFn } from './utils'; import { CompilationResult } from './types/noir_artifact'; import { inflateDebugSymbols } from './noir/debug'; +/** + * Compiles a Noir project + * + * @param fileManager - The file manager to use + * @param projectPath - The path to the project inside the file manager. Defaults to the root of the file manager + * @param logFn - A logging function. If not provided, console.log will be used + * @param debugLogFn - A debug logging function. If not provided, logFn will be used + * + * @example + * ```typescript + * // Node.js + * + * import { compile, createFileManager } from '@noir-lang/noir_wasm'; + * + * const fm = createFileManager(myProjectPath); + * const myCompiledCode = await compile(fm); + * ``` + * + * ```typescript + * // Browser + * + * import { compile, createFileManager } from '@noir-lang/noir_wasm'; + * + * const fm = createFileManager('/'); + * for (const path of files) { + * await fm.writeFile(path, await getFileAsStream(path)); + * } + * const myCompiledCode = await compile(fm); + * ``` + */ async function compile( fileManager: FileManager, projectPath?: string, diff --git a/compiler/wasm/src/index.mts b/compiler/wasm/src/index.mts index 8774a7857ef..d4ed0beccfc 100644 --- a/compiler/wasm/src/index.mts +++ b/compiler/wasm/src/index.mts @@ -5,6 +5,36 @@ import { LogData, LogFn } from './utils'; import { CompilationResult } from './types/noir_artifact'; import { inflateDebugSymbols } from './noir/debug'; +/** + * Compiles a Noir project + * + * @param fileManager - The file manager to use + * @param projectPath - The path to the project inside the file manager. Defaults to the root of the file manager + * @param logFn - A logging function. If not provided, console.log will be used + * @param debugLogFn - A debug logging function. If not provided, logFn will be used + * + * @example + * ```typescript + * // Node.js + * + * import { compile, createFileManager } from '@noir-lang/noir_wasm'; + * + * const fm = createFileManager(myProjectPath); + * const myCompiledCode = await compile(fm); + * ``` + * + * ```typescript + * // Browser + * + * import { compile, createFileManager } from '@noir-lang/noir_wasm'; + * + * const fm = createFileManager('/'); + * for (const path of files) { + * await fm.writeFile(path, await getFileAsStream(path)); + * } + * const myCompiledCode = await compile(fm); + * ``` + */ async function compile( fileManager: FileManager, projectPath?: string, diff --git a/compiler/wasm/src/noir/debug.ts b/compiler/wasm/src/noir/debug.ts index 7a65f4b68c2..1a4ccfe95ec 100644 --- a/compiler/wasm/src/noir/debug.ts +++ b/compiler/wasm/src/noir/debug.ts @@ -1,6 +1,9 @@ import { inflate } from 'pako'; -/** Decompresses and decodes the debug symbols */ +/** + * Decompresses and decodes the debug symbols + * @param debugSymbols - The base64 encoded debug symbols + */ export function inflateDebugSymbols(debugSymbols: string) { return JSON.parse(inflate(Buffer.from(debugSymbols, 'base64'), { to: 'string', raw: true })); } diff --git a/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts b/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts index 1a8250f49cc..195eea8a70d 100644 --- a/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts +++ b/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts @@ -18,8 +18,9 @@ export async function readdirRecursive(dir: string): Promise { } /** - * Creates a new FileManager instance based on nodejs fs - * @param dataDir - where to store files + * Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) + * + * @param dataDir - root of the file system */ export function createNodejsFileManager(dataDir: string): FileManager { return new FileManager( diff --git a/compiler/wasm/src/types/noir_artifact.ts b/compiler/wasm/src/types/noir_artifact.ts index 715877e335f..350a4053a9a 100644 --- a/compiler/wasm/src/types/noir_artifact.ts +++ b/compiler/wasm/src/types/noir_artifact.ts @@ -1,4 +1,4 @@ -import { Abi, AbiType } from '@noir-lang/noirc_abi'; +import { Abi, AbiType } from '@noir-lang/types'; /** * A named type. diff --git a/docs/docs/index.mdx b/docs/docs/index.mdx index 2cec2397051..75086ddcdde 100644 --- a/docs/docs/index.mdx +++ b/docs/docs/index.mdx @@ -34,7 +34,7 @@ Noir works differently from most ZK languages by taking a two-pronged path. Firs :::info -Noir is backend agnostic, which means it makes no assumptions on which proving backend powers the ZK proof. Being the language that powers [Aztec Contracts](https://docs.aztec.network/dev_docs/contracts/main), it defaults to Aztec's Barretenberg proving backend. +Noir is backend agnostic, which means it makes no assumptions on which proving backend powers the ZK proof. Being the language that powers [Aztec Contracts](https://docs.aztec.network/developers/contracts/main), it defaults to Aztec's Barretenberg proving backend. However, the ACIR output can be transformed to be compatible with other PLONK-based backends, or into a [rank-1 constraint system](https://www.rareskills.io/post/rank-1-constraint-system) suitable for backends such as Arkwork's Marlin. @@ -48,7 +48,7 @@ Noir can be used both in complex cloud-based backends and in user's smartphones, Noir Logo - Aztec Contracts leverage Noir to allow for the storage and execution of private information. Writing an Aztec Contract is as easy as writing Noir, and Aztec developers can easily interact with the network storage and execution through the [Aztec.nr](https://docs.aztec.network/dev_docs/contracts/main) library. + Aztec Contracts leverage Noir to allow for the storage and execution of private information. Writing an Aztec Contract is as easy as writing Noir, and Aztec developers can easily interact with the network storage and execution through the [Aztec.nr](https://docs.aztec.network/developers/contracts/main) library. Soliditry Verifier Example diff --git a/docs/docs/noir/concepts/data_types/fields.md b/docs/docs/noir/concepts/data_types/fields.md index 7870c98c858..99b4aa63549 100644 --- a/docs/docs/noir/concepts/data_types/fields.md +++ b/docs/docs/noir/concepts/data_types/fields.md @@ -181,3 +181,12 @@ Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} ```rust fn sgn0(self) -> u1 ``` + + +### lt + +Returns true if the field is less than the other field + +```rust +pub fn lt(self, another: Field) -> bool +``` diff --git a/docs/docs/noir/concepts/globals.md b/docs/docs/noir/concepts/globals.md new file mode 100644 index 00000000000..063a3d89248 --- /dev/null +++ b/docs/docs/noir/concepts/globals.md @@ -0,0 +1,72 @@ +--- +title: Global Variables +description: + Learn about global variables in Noir. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, globals, global variables, constants] +sidebar_position: 8 +--- + +## Globals + + +Noir supports global variables. The global's type can be inferred by the compiler entirely: + +```rust +global N = 5; // Same as `global N: Field = 5` + +global TUPLE = (3, 2); + +fn main() { + assert(N == 5); + assert(N == TUPLE.0 + TUPLE.1); +} +``` + +:::info + +Globals can be defined as any expression, so long as they don't depend on themselves - otherwise there would be a dependency cycle! For example: + +```rust +global T = foo(T); // dependency error +``` + +::: + + +If they are initialized to a literal integer, globals can be used to specify an array's length: + +```rust +global N: Field = 2; + +fn main(y : [Field; N]) { + assert(y[0] == y[1]) +} +``` + +A global from another module can be imported or referenced externally like any other name: + +```rust +global N = 20; + +fn main() { + assert(my_submodule::N != N); +} + +mod my_submodule { + global N: Field = 10; +} +``` + +When a global is used, Noir replaces the name with its definition on each occurrence. +This means globals defined using function calls will repeat the call each time they're used: + +```rust +global RESULT = foo(); + +fn foo() -> [Field; 100] { ... } +``` + +This is usually fine since Noir will generally optimize any function call that does not +refer to a program input into a constant. It should be kept in mind however, if the called +function performs side-effects like `println`, as these will still occur on each use. diff --git a/docs/docs/noir/standard_library/black_box_fns.md b/docs/docs/noir/standard_library/black_box_fns.md index 6b22d0e7466..eae8744abf0 100644 --- a/docs/docs/noir/standard_library/black_box_fns.md +++ b/docs/docs/noir/standard_library/black_box_fns.md @@ -15,7 +15,7 @@ Here is a list of the current black box functions: - [SHA256](./cryptographic_primitives/hashes#sha256) - [Schnorr signature verification](./cryptographic_primitives/schnorr) - [Blake2s](./cryptographic_primitives/hashes#blake2s) -- [Blake3](./cryptographic_primitives/hashes#blake2s) +- [Blake3](./cryptographic_primitives/hashes#blake3) - [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) - [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) - [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) diff --git a/docs/docs/noir/standard_library/bn254.md b/docs/docs/noir/standard_library/bn254.md new file mode 100644 index 00000000000..3294f005dbb --- /dev/null +++ b/docs/docs/noir/standard_library/bn254.md @@ -0,0 +1,46 @@ +--- +title: Bn254 Field Library +--- + +Noir provides a module in standard library with some optimized functions for bn254 Fr in `std::field::bn254`. + +## decompose + +```rust +fn decompose(x: Field) -> (Field, Field) {} +``` + +Decomposes a single field into two fields, low and high. The low field contains the lower 16 bytes of the input field and the high field contains the upper 16 bytes of the input field. Both field results are range checked to 128 bits. + + +## assert_gt + +```rust +fn assert_gt(a: Field, b: Field) {} +``` + +Asserts that a > b. This will generate less constraints than using `assert(gt(a, b))`. + +## assert_lt + +```rust +fn assert_lt(a: Field, b: Field) {} +``` + +Asserts that a < b. This will generate less constraints than using `assert(lt(a, b))`. + +## gt + +```rust +fn gt(a: Field, b: Field) -> bool {} +``` + +Returns true if a > b. + +## lt + +```rust +fn lt(a: Field, b: Field) -> bool {} +``` + +Returns true if a < b. \ No newline at end of file diff --git a/docs/docs/tutorials/noirjs_app.md b/docs/docs/tutorials/noirjs_app.md index 23534795dde..ad76dd255cc 100644 --- a/docs/docs/tutorials/noirjs_app.md +++ b/docs/docs/tutorials/noirjs_app.md @@ -101,7 +101,7 @@ At this point in the tutorial, your folder structure should look like this: `npx create vite` is amazing but it creates a bunch of files we don't really need for our simple example. Actually, let's just delete everything except for `index.html`, `main.js` and `package.json`. I feel lighter already. -![my heart is ready for you, noir.js](../../static/img/memes/titanic.jpeg) +![my heart is ready for you, noir.js](@site/static/img/memes/titanic.jpeg) ## HTML @@ -270,7 +270,7 @@ if (verification) display('logs', 'Verifying proof... ✅'); You have successfully generated a client-side Noir web app! -![coded app without math knowledge](../../static/img/memes/flextape.jpeg) +![coded app without math knowledge](@site/static/img/memes/flextape.jpeg) ## Further Reading diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index d1d344ba635..e041d0a32a4 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -26,7 +26,7 @@ export default { '@docusaurus/preset-classic', { docs: { - path: "processed-docs", + path: 'processed-docs', sidebarPath: './sidebars.js', routeBasePath: '/docs', remarkPlugins: [math], @@ -210,6 +210,37 @@ export default { membersWithOwnFile: ['Interface', 'Class', 'TypeAlias'], }, ], + [ + 'docusaurus-plugin-typedoc', + { + id: 'noir_wasm', + entryPoints: ['../compiler/wasm/src/index.cts'], + tsconfig: '../compiler/wasm/tsconfig.json', + entryPointStrategy: 'resolve', + out: 'processed-docs/reference/NoirJS/noir_wasm', + plugin: ['typedoc-plugin-markdown'], + name: 'noir_wasm', + disableSources: true, + excludePrivate: true, + skipErrorChecking: true, + sidebar: { + filteredIds: ['reference/noir_wasm/index'], + }, + readme: 'none', + hidePageHeader: true, + hideBreadcrumbs: true, + hideInPageTOC: true, + useCodeBlocks: true, + typeDeclarationFormat: 'table', + propertiesFormat: 'table', + parametersFormat: 'table', + enumMembersFormat: 'table', + indexFormat: 'table', + outputFileStrategy: 'members', + memberPageTitle: '{name}', + membersWithOwnFile: ['Function', 'TypeAlias'], + }, + ], ], markdown: { format: 'detect', diff --git a/docs/package.json b/docs/package.json index c2a36357b05..146c2a9800c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -18,7 +18,6 @@ "@noir-lang/noir_js": "workspace:*", "@noir-lang/noirc_abi": "workspace:*", "@noir-lang/types": "workspace:*", - "@signorecello/noir_playground": "^0.7.0", "axios": "^1.4.0", "clsx": "^1.2.1", "hast-util-is-element": "^1.1.0", diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index 5a526ec5bfd..b08766fbc3b 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -209,3 +209,8 @@ html[data-theme='dark'] { border-width: 0; border-style: solid; } + +input#docsearch-input { + background-color: transparent; +} + diff --git a/docs/src/pages/index.jsx b/docs/src/pages/index.jsx index 6b52628a5ff..b372871e7b4 100644 --- a/docs/src/pages/index.jsx +++ b/docs/src/pages/index.jsx @@ -5,19 +5,7 @@ import Link from '@docusaurus/Link'; import headerPic from '@site/static/img/homepage_header_pic.png'; import { BeatLoader } from 'react-spinners'; -const NoirEditor = lazy(() => import('@signorecello/noir_playground')); - -const Spinner = () => { - return ( -
- -
- ); -}; - export default function Landing() { - const [tryIt, setTryIt] = React.useState(false); - return (
@@ -41,65 +29,46 @@ export default function Landing() { compatible proving system. Its design choices are influenced heavily by Rust and focuses on a simple, familiar syntax.

- {!tryIt && ( -
-
- - - - - - -
-
- )} - {tryIt && ( - }> + +
+
- - - )} +
+
- {!tryIt && ( -
-
-

Learn

- - - - - - -
-
-

Coming from...

- - - - - - -
-
-

New to Everything

- - - - - - -
+
+
+

Learn

+ + + + + + +
+
+

Coming from...

+ + + + + + +
+
+

New to Everything

+ + + + + +
- )} +
diff --git a/docs/versioned_docs/version-v0.23.0/index.mdx b/docs/versioned_docs/version-v0.23.0/index.mdx index 2cec2397051..75086ddcdde 100644 --- a/docs/versioned_docs/version-v0.23.0/index.mdx +++ b/docs/versioned_docs/version-v0.23.0/index.mdx @@ -34,7 +34,7 @@ Noir works differently from most ZK languages by taking a two-pronged path. Firs :::info -Noir is backend agnostic, which means it makes no assumptions on which proving backend powers the ZK proof. Being the language that powers [Aztec Contracts](https://docs.aztec.network/dev_docs/contracts/main), it defaults to Aztec's Barretenberg proving backend. +Noir is backend agnostic, which means it makes no assumptions on which proving backend powers the ZK proof. Being the language that powers [Aztec Contracts](https://docs.aztec.network/developers/contracts/main), it defaults to Aztec's Barretenberg proving backend. However, the ACIR output can be transformed to be compatible with other PLONK-based backends, or into a [rank-1 constraint system](https://www.rareskills.io/post/rank-1-constraint-system) suitable for backends such as Arkwork's Marlin. @@ -48,7 +48,7 @@ Noir can be used both in complex cloud-based backends and in user's smartphones, Noir Logo - Aztec Contracts leverage Noir to allow for the storage and execution of private information. Writing an Aztec Contract is as easy as writing Noir, and Aztec developers can easily interact with the network storage and execution through the [Aztec.nr](https://docs.aztec.network/dev_docs/contracts/main) library. + Aztec Contracts leverage Noir to allow for the storage and execution of private information. Writing an Aztec Contract is as easy as writing Noir, and Aztec developers can easily interact with the network storage and execution through the [Aztec.nr](https://docs.aztec.network/developers/contracts/main) library. Soliditry Verifier Example diff --git a/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md b/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md index a1c67945d66..99b4aa63549 100644 --- a/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md +++ b/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md @@ -157,6 +157,23 @@ fn main() { } ``` +### assert_max_bit_size + +Adds a constraint to specify that the field can be represented with `bit_size` number of bits + +```rust +fn assert_max_bit_size(self, bit_size: u32) +``` + +example: + +```rust +fn main() { + let field = 2 + field.assert_max_bit_size(32); +} +``` + ### sgn0 Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. @@ -164,3 +181,12 @@ Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} ```rust fn sgn0(self) -> u1 ``` + + +### lt + +Returns true if the field is less than the other field + +```rust +pub fn lt(self, another: Field) -> bool +``` diff --git a/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md b/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md index 7d1e83cf4e9..30135d76e4a 100644 --- a/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md +++ b/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md @@ -51,6 +51,55 @@ If you are using the default proving backend with Noir, both even (e.g. _u2_, _i ::: + +## 128 bits Unsigned Integers + +The built-in structure `U128` allows you to use 128-bit unsigned integers almost like a native integer type. However, there are some differences to keep in mind: +- You cannot cast between a native integer and `U128` +- There is a higher performance cost when using `U128`, compared to a native type. + +Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. + +```rust +fn main() { + let x = U128::from_integer(23); + let y = U128::from_hex("0x7"); + let z = x + y; + assert(z.to_integer() == 30); +} +``` + +`U128` is implemented with two 64 bits limbs, representing the low and high bits, which explains the performance cost. You should expect `U128` to be twice more costly for addition and four times more costly for multiplication. +You can construct a U128 from its limbs: +```rust +fn main(x: u64, y: u64) { + let x = U128::from_u64s_be(x,y); + assert(z.hi == x as Field); + assert(z.lo == y as Field); +} +``` + +Note that the limbs are stored as Field elements in order to avoid unnecessary conversions. +Apart from this, most operations will work as usual: + +```rust +fn main(x: U128, y: U128) { + // multiplication + let c = x * y; + // addition and subtraction + let c = c - x + y; + // division + let c = x / y; + // bit operation; + let c = x & y | y; + // bit shift + let c = x << y; + // comparisons; + let c = x < y; + let c = x == y; +} +``` + ## Overflows Computations that exceed the type boundaries will result in overflow errors. This happens with both signed and unsigned integers. For example, attempting to prove: @@ -108,6 +157,6 @@ Example of how it is used: use dep::std; fn main(x: u8, y: u8) -> pub u8 { - std::wrapping_add(x + y) + std::wrapping_add(x, y) } ``` diff --git a/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md b/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md index 4b1efbd17de..eae8744abf0 100644 --- a/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md +++ b/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md @@ -6,40 +6,26 @@ keywords: [noir, black box functions] Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. This makes certain zk-snark unfriendly computations cheaper than if they were implemented in Noir. -:::warning - -It is likely that not all backends will support a particular black box function. - -::: - -Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. - -Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: - -```rust -#[foreign(sha256)] -fn sha256(_input : [u8; N]) -> [u8; 32] {} -``` +The ACVM spec defines a set of blackbox functions which backends will be expected to implement. This allows backends to use optimized implementations of these constraints if they have them, however they may also fallback to less efficient naive implementations if not. ## Function list -Here is a list of the current black box functions that are supported by UltraPlonk: +Here is a list of the current black box functions: -- AES - [SHA256](./cryptographic_primitives/hashes#sha256) - [Schnorr signature verification](./cryptographic_primitives/schnorr) - [Blake2s](./cryptographic_primitives/hashes#blake2s) +- [Blake3](./cryptographic_primitives/hashes#blake3) - [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) - [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) - [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) - [Fixed base scalar multiplication](./cryptographic_primitives/scalar) -- [Compute merkle root](./merkle_trees#compute_merkle_root) - AND - XOR - RANGE - [Keccak256](./cryptographic_primitives/hashes#keccak256) - [Recursive proof verification](./recursion) -Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. +Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/noir/blob/master/acvm-repo/acir/src/circuit/black_box_functions.rs). diff --git a/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md b/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md new file mode 100644 index 00000000000..3294f005dbb --- /dev/null +++ b/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md @@ -0,0 +1,46 @@ +--- +title: Bn254 Field Library +--- + +Noir provides a module in standard library with some optimized functions for bn254 Fr in `std::field::bn254`. + +## decompose + +```rust +fn decompose(x: Field) -> (Field, Field) {} +``` + +Decomposes a single field into two fields, low and high. The low field contains the lower 16 bytes of the input field and the high field contains the upper 16 bytes of the input field. Both field results are range checked to 128 bits. + + +## assert_gt + +```rust +fn assert_gt(a: Field, b: Field) {} +``` + +Asserts that a > b. This will generate less constraints than using `assert(gt(a, b))`. + +## assert_lt + +```rust +fn assert_lt(a: Field, b: Field) {} +``` + +Asserts that a < b. This will generate less constraints than using `assert(lt(a, b))`. + +## gt + +```rust +fn gt(a: Field, b: Field) -> bool {} +``` + +Returns true if a > b. + +## lt + +```rust +fn lt(a: Field, b: Field) -> bool {} +``` + +Returns true if a < b. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx b/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx index 1376c51dfde..4bf09cef178 100644 --- a/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx +++ b/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx @@ -13,9 +13,16 @@ Noir supports ECDSA signatures verification over the secp256k1 and secp256r1 cur Verifier for ECDSA Secp256k1 signatures -```rust -fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +```rust title="ecdsa_secp256k1" showLineNumbers +pub fn verify_signature( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8; N] +) -> bool ``` +> Source code: noir_stdlib/src/ecdsa_secp256k1.nr#L2-L9 + example: @@ -30,9 +37,16 @@ fn main(hashed_message : [u8;32], pub_key_x : [u8;32], pub_key_y : [u8;32], sign Verifier for ECDSA Secp256r1 signatures -```rust -fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +```rust title="ecdsa_secp256r1" showLineNumbers +pub fn verify_signature( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8; N] +) -> bool ``` +> Source code: noir_stdlib/src/ecdsa_secp256r1.nr#L2-L9 + example: diff --git a/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx b/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx index 3c5f7f79603..730b6d4117f 100644 --- a/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx +++ b/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -14,9 +14,11 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Given an array of bytes, returns the resulting sha256 hash. -```rust -fn sha256(_input : [u8]) -> [u8; 32] +```rust title="sha256" showLineNumbers +pub fn sha256(input: [u8; N]) -> [u8; 32] ``` +> Source code: noir_stdlib/src/hash.nr#L5-L7 + example: @@ -33,9 +35,11 @@ fn main() { Given an array of bytes, returns an array with the Blake2 hash -```rust -fn blake2s(_input : [u8]) -> [u8; 32] +```rust title="blake2s" showLineNumbers +pub fn blake2s(input: [u8; N]) -> [u8; 32] ``` +> Source code: noir_stdlib/src/hash.nr#L11-L13 + example: @@ -48,43 +52,81 @@ fn main() { -## pedersen_hash +## blake3 -Given an array of Fields, returns the Pedersen hash. +Given an array of bytes, returns an array with the Blake3 hash -```rust -fn pedersen_hash(_input : [Field]) -> Field +```rust title="blake3" showLineNumbers +pub fn blake3(input: [u8; N]) -> [u8; 32] ``` +> Source code: noir_stdlib/src/hash.nr#L17-L19 + example: ```rust fn main() { let x = [163, 117, 178, 149]; // some random bytes - let hash = std::hash::pedersen_hash(x); + let hash = std::hash::blake3(x); } ``` +## pedersen_hash + +Given an array of Fields, returns the Pedersen hash. + +```rust title="pedersen_hash" showLineNumbers +pub fn pedersen_hash(input: [Field; N]) -> Field +``` +> Source code: noir_stdlib/src/hash.nr#L42-L44 + + +example: + +```rust title="pedersen-hash" showLineNumbers +use dep::std; + +fn main(x: Field, y: Field, expected_hash: Field) { + let hash = std::hash::pedersen_hash([x, y]); + assert_eq(hash, expected_hash); +} +``` +> Source code: test_programs/execution_success/pedersen_hash/src/main.nr#L1-L8 + + + ## pedersen_commitment Given an array of Fields, returns the Pedersen commitment. -```rust -fn pedersen_commitment(_input : [Field]) -> [Field; 2] +```rust title="pedersen_commitment" showLineNumbers +struct PedersenPoint { + x : Field, + y : Field, +} + +pub fn pedersen_commitment(input: [Field; N]) -> PedersenPoint ``` +> Source code: noir_stdlib/src/hash.nr#L22-L29 + example: -```rust -fn main() { - let x = [163, 117, 178, 149]; // some random bytes - let commitment = std::hash::pedersen_commitment(x); +```rust title="pedersen-commitment" showLineNumbers +use dep::std; + +fn main(x: Field, y: Field, expected_commitment: std::hash::PedersenPoint) { + let commitment = std::hash::pedersen_commitment([x, y]); + assert_eq(commitment.x, expected_commitment.x); + assert_eq(commitment.y, expected_commitment.y); } ``` +> Source code: test_programs/execution_success/pedersen_commitment/src/main.nr#L1-L9 + @@ -94,19 +136,38 @@ Given an array of bytes (`u8`), returns the resulting keccak hash as an array of (`[u8; 32]`). Specify a message_size to hash only the first `message_size` bytes of the input. -```rust -fn keccak256(_input : [u8; N], _message_size: u32) -> [u8; 32] +```rust title="keccak256" showLineNumbers +pub fn keccak256(input: [u8; N], message_size: u32) -> [u8; 32] ``` +> Source code: noir_stdlib/src/hash.nr#L67-L69 + example: -```rust -fn main() { - let x = [163, 117, 178, 149]; // some random bytes +```rust title="keccak256" showLineNumbers +use dep::std; + +fn main(x: Field, result: [u8; 32]) { + // We use the `as` keyword here to denote the fact that we want to take just the first byte from the x Field + // The padding is taken care of by the program + let digest = std::hash::keccak256([x as u8], 1); + assert(digest == result); + + //#1399: variable message size let message_size = 4; - let hash = std::hash::keccak256(x, message_size); + let hash_a = std::hash::keccak256([1, 2, 3, 4], message_size); + let hash_b = std::hash::keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size); + + assert(hash_a == hash_b); + + let message_size_big = 8; + let hash_c = std::hash::keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size_big); + + assert(hash_a != hash_c); } ``` +> Source code: test_programs/execution_success/keccak256/src/main.nr#L1-L22 + @@ -122,13 +183,19 @@ fn hash_1(input: [Field; 1]) -> Field example: -```rust -fn main() -{ - let hash_2 = std::hash::poseidon::bn254::hash_2([1, 2]); - assert(hash2 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); +```rust title="poseidon" showLineNumbers +use dep::std::hash::poseidon; + +fn main(x1: [Field; 2], y1: pub Field, x2: [Field; 4], y2: pub Field) { + let hash1 = poseidon::bn254::hash_2(x1); + assert(hash1 == y1); + + let hash2 = poseidon::bn254::hash_4(x2); + assert(hash2 == y2); } ``` +> Source code: test_programs/execution_success/poseidon_bn254_hash/src/main.nr#L1-L11 + ## mimc_bn254 and mimc diff --git a/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx b/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx index aa4fb8cbaed..df411ca5443 100644 --- a/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx +++ b/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx @@ -12,9 +12,14 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Performs scalar multiplication over the embedded curve whose coordinates are defined by the configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. -```rust -fn fixed_base_embedded_curve(_input : Field) -> [Field; 2] +```rust title="fixed_base_embedded_curve" showLineNumbers +pub fn fixed_base_embedded_curve( + low: Field, + high: Field +) -> [Field; 2] ``` +> Source code: noir_stdlib/src/scalar_mul.nr#L27-L32 + example diff --git a/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx b/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx index 7a2c9c20226..ae12e6c12dc 100644 --- a/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx +++ b/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx @@ -11,9 +11,16 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). -```rust -fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> bool +```rust title="schnorr_verify" showLineNumbers +pub fn verify_signature( + public_key_x: Field, + public_key_y: Field, + signature: [u8; 64], + message: [u8; N] +) -> bool ``` +> Source code: noir_stdlib/src/schnorr.nr#L2-L9 + where `_signature` can be generated like so using the npm package [@noir-lang/barretenberg](https://www.npmjs.com/package/@noir-lang/barretenberg) diff --git a/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md new file mode 100644 index 00000000000..33eb434c3db --- /dev/null +++ b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md @@ -0,0 +1,51 @@ +# compile() + +```ts +compile( + fileManager, + projectPath?, + logFn?, +debugLogFn?): Promise +``` + +Compiles a Noir project + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `fileManager` | `FileManager` | The file manager to use | +| `projectPath`? | `string` | The path to the project inside the file manager. Defaults to the root of the file manager | +| `logFn`? | `LogFn` | A logging function. If not provided, console.log will be used | +| `debugLogFn`? | `LogFn` | A debug logging function. If not provided, logFn will be used | + +## Returns + +`Promise`\<[`CompilationResult`](../type-aliases/CompilationResult.md)\> + +## Example + +```typescript +// Node.js + +import { compile, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager(myProjectPath); +const myCompiledCode = await compile(fm); +``` + +```typescript +// Browser + +import { compile, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager('/'); +for (const path of files) { + await fm.writeFile(path, await getFileAsStream(path)); +} +const myCompiledCode = await compile(fm); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md new file mode 100644 index 00000000000..7e65c1d69c7 --- /dev/null +++ b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md @@ -0,0 +1,21 @@ +# createFileManager() + +```ts +createFileManager(dataDir): FileManager +``` + +Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `dataDir` | `string` | root of the file system | + +## Returns + +`FileManager` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md new file mode 100644 index 00000000000..fcea9275341 --- /dev/null +++ b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md @@ -0,0 +1,21 @@ +# inflateDebugSymbols() + +```ts +inflateDebugSymbols(debugSymbols): any +``` + +Decompresses and decodes the debug symbols + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `debugSymbols` | `string` | The base64 encoded debug symbols | + +## Returns + +`any` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md new file mode 100644 index 00000000000..939f2481687 --- /dev/null +++ b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md @@ -0,0 +1,21 @@ +# noir_wasm + +## Exports + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [CompilationResult](type-aliases/CompilationResult.md) | output of Noir Wasm compilation, can be for a contract or lib/binary | + +### Functions + +| Function | Description | +| :------ | :------ | +| [compile](functions/compile.md) | Compiles a Noir project | +| [createFileManager](functions/createFileManager.md) | Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) | +| [inflateDebugSymbols](functions/inflateDebugSymbols.md) | Decompresses and decodes the debug symbols | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md new file mode 100644 index 00000000000..23cfbe6025d --- /dev/null +++ b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md @@ -0,0 +1,11 @@ +# CompilationResult + +```ts +type CompilationResult: ContractCompilationArtifacts | ProgramCompilationArtifacts; +``` + +output of Noir Wasm compilation, can be for a contract or lib/binary + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs new file mode 100644 index 00000000000..d7eba0db813 --- /dev/null +++ b/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"doc","id":"reference/NoirJS/noir_wasm/index","label":"API"},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/noir_wasm/type-aliases/CompilationResult","label":"CompilationResult"}]},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/compile","label":"compile"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/createFileManager","label":"createFileManager"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/inflateDebugSymbols","label":"inflateDebugSymbols"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md index 23534795dde..ad76dd255cc 100644 --- a/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md @@ -101,7 +101,7 @@ At this point in the tutorial, your folder structure should look like this: `npx create vite` is amazing but it creates a bunch of files we don't really need for our simple example. Actually, let's just delete everything except for `index.html`, `main.js` and `package.json`. I feel lighter already. -![my heart is ready for you, noir.js](../../static/img/memes/titanic.jpeg) +![my heart is ready for you, noir.js](@site/static/img/memes/titanic.jpeg) ## HTML @@ -270,7 +270,7 @@ if (verification) display('logs', 'Verifying proof... ✅'); You have successfully generated a client-side Noir web app! -![coded app without math knowledge](../../static/img/memes/flextape.jpeg) +![coded app without math knowledge](@site/static/img/memes/flextape.jpeg) ## Further Reading diff --git a/noir_stdlib/src/bigint.nr b/noir_stdlib/src/bigint.nr index 14790f69241..11026651207 100644 --- a/noir_stdlib/src/bigint.nr +++ b/noir_stdlib/src/bigint.nr @@ -1,5 +1,20 @@ use crate::ops::{Add, Sub, Mul, Div, Rem,}; + +global bn254_fq = [0x47, 0xFD, 0x7C, 0xD8, 0x16, 0x8C, 0x20, 0x3C, 0x8d, 0xca, 0x71, 0x68, 0x91, 0x6a, 0x81, 0x97, + 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30]; +global bn254_fr = [0x01, 0x00, 0x00, 0x00, 0x3F, 0x59, 0x1F, 0x43, 0x09, 0x97, 0xB9, 0x79, 0x48, 0xE8, 0x33, 0x28, + 0x5D, 0x58, 0x81, 0x81, 0xB6, 0x45, 0x50, 0xB8, 0x29, 0xA0, 0x31, 0xE1, 0x72, 0x4E, 0x64, 0x30]; +global secpk1_fr = [0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; +global secpk1_fq = [0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; +global secpr1_fq = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF]; +global secpr1_fr = [0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,0xFF, 0xFF, 0xFF, 0xFF]; + + struct BigInt { pointer: u32, modulus: u32, @@ -7,21 +22,34 @@ struct BigInt { impl BigInt { #[builtin(bigint_add)] - pub fn bigint_add(_self: Self, _other: BigInt) -> BigInt { + fn bigint_add(self, other: BigInt) -> BigInt { } - #[builtin(bigint_neg)] - pub fn bigint_neg(_self: Self, _other: BigInt) -> BigInt { + #[builtin(bigint_sub)] + fn bigint_sub(self, other: BigInt) -> BigInt { } #[builtin(bigint_mul)] - pub fn bigint_mul(_self: Self, _other: BigInt) -> BigInt { + fn bigint_mul(self, other: BigInt) -> BigInt { } #[builtin(bigint_div)] - pub fn bigint_div(_self: Self, _other: BigInt) -> BigInt { + fn bigint_div(self, other: BigInt) -> BigInt { } #[builtin(bigint_from_le_bytes)] - pub fn from_le_bytes(_bytes: [u8], _modulus: [u8]) -> BigInt {} + fn from_le_bytes(bytes: [u8], modulus: [u8]) -> BigInt {} #[builtin(bigint_to_le_bytes)] - pub fn to_le_bytes(_self: Self) -> [u8] {} + pub fn to_le_bytes(self) -> [u8] {} + + pub fn bn254_fr_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, bn254_fr) + } + pub fn bn254_fq_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, bn254_fq) + } + pub fn secpk1_fq_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, secpk1_fq) + } + pub fn secpk1_fr_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, secpk1_fr) + } } impl Add for BigInt { @@ -31,7 +59,7 @@ impl Add for BigInt { } impl Sub for BigInt { fn sub(self: Self, other: BigInt) -> BigInt { - self.bigint_neg(other) + self.bigint_sub(other) } } impl Mul for BigInt { @@ -47,7 +75,7 @@ impl Div for BigInt { impl Rem for BigInt { fn rem(self: Self, other: BigInt) -> BigInt { let quotient = self.bigint_div(other); - self.bigint_neg(quotient.bigint_mul(other)) + self.bigint_sub(quotient.bigint_mul(other)) } } diff --git a/noir_stdlib/src/field/bn254.nr b/noir_stdlib/src/field/bn254.nr index f6e23f8db0c..9e1445fd3ba 100644 --- a/noir_stdlib/src/field/bn254.nr +++ b/noir_stdlib/src/field/bn254.nr @@ -1,7 +1,10 @@ +// The low and high decomposition of the field modulus global PLO: Field = 53438638232309528389504892708671455233; global PHI: Field = 64323764613183177041862057485226039389; + global TWO_POW_128: Field = 0x100000000000000000000000000000000; +/// A hint for decomposing a single field into two 16 byte fields. unconstrained fn decompose_unsafe(x: Field) -> (Field, Field) { let x_bytes = x.to_le_bytes(32); @@ -18,14 +21,20 @@ unconstrained fn decompose_unsafe(x: Field) -> (Field, Field) { (low, high) } +/// Decompose a single field into two 16 byte fields. pub fn decompose(x: Field) -> (Field, Field) { + // Take hints of the decomposition let (xlo, xhi) = decompose_unsafe(x); let borrow = lt_unsafe(PLO, xlo, 16); + // Range check the limbs xlo.assert_max_bit_size(128); xhi.assert_max_bit_size(128); + // Check that the decomposition is correct assert_eq(x, xlo + TWO_POW_128 * xhi); + + // Check that (xlo < plo && xhi <= phi) || (xlo >= plo && xhi < phi) let rlo = PLO - xlo + (borrow as Field) * TWO_POW_128; let rhi = PHI - xhi - (borrow as Field); @@ -59,11 +68,13 @@ unconstrained fn lte_unsafe(x: Field, y: Field, num_bytes: u32) -> bool { } pub fn assert_gt(a: Field, b: Field) { + // Decompose a and b let (alo, ahi) = decompose(a); let (blo, bhi) = decompose(b); let borrow = lte_unsafe(alo, blo, 16); + // Assert that (alo > blo && ahi >= bhi) || (alo <= blo && ahi > bhi) let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128; let rhi = ahi - bhi - (borrow as Field); diff --git a/noir_stdlib/src/lib.nr b/noir_stdlib/src/lib.nr index 5165d1ee07b..ebde4b88858 100644 --- a/noir_stdlib/src/lib.nr +++ b/noir_stdlib/src/lib.nr @@ -25,7 +25,7 @@ mod ops; mod default; mod prelude; mod uint128; -// mod bigint; +mod bigint; // Oracle calls are required to be wrapped in an unconstrained function // Thus, the only argument to the `println` oracle is expected to always be an ident diff --git a/test_programs/execution_success/assert_statement_recursive/Nargo.toml b/test_programs/execution_success/assert_statement_recursive/Nargo.toml new file mode 100644 index 00000000000..2a5b02cad00 --- /dev/null +++ b/test_programs/execution_success/assert_statement_recursive/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "assert_statement_recursive" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/assert_statement_recursive/Prover.toml b/test_programs/execution_success/assert_statement_recursive/Prover.toml new file mode 100644 index 00000000000..5d1dc99124f --- /dev/null +++ b/test_programs/execution_success/assert_statement_recursive/Prover.toml @@ -0,0 +1,2 @@ +x = "3" +y = "3" diff --git a/test_programs/execution_success/assert_statement_recursive/src/main.nr b/test_programs/execution_success/assert_statement_recursive/src/main.nr new file mode 100644 index 00000000000..687a0d324ba --- /dev/null +++ b/test_programs/execution_success/assert_statement_recursive/src/main.nr @@ -0,0 +1,11 @@ +// Tests a very simple program. +// +// The features being tested is assertion +// This is the same as the `assert_statement` test except we specify +// that the backend should use a prover which will construct proofs +// friendly to recursive verification in another SNARK. +#[recursive] +fn main(x: Field, y: pub Field) { + assert(x == y, "x and y are not equal"); + assert_eq(x, y, "x and y are not equal"); +} \ No newline at end of file diff --git a/test_programs/execution_success/bigint/Nargo.toml b/test_programs/execution_success/bigint/Nargo.toml new file mode 100644 index 00000000000..eee0920f188 --- /dev/null +++ b/test_programs/execution_success/bigint/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "bigint" +type = "bin" +authors = [""] + +[dependencies] diff --git a/test_programs/execution_success/bigint/Prover.toml b/test_programs/execution_success/bigint/Prover.toml new file mode 100644 index 00000000000..c50874a8613 --- /dev/null +++ b/test_programs/execution_success/bigint/Prover.toml @@ -0,0 +1,2 @@ +x = [34,3,5,8,4] +y = [44,7,1,8,8] \ No newline at end of file diff --git a/test_programs/execution_success/bigint/src/main.nr b/test_programs/execution_success/bigint/src/main.nr new file mode 100644 index 00000000000..74949a5f785 --- /dev/null +++ b/test_programs/execution_success/bigint/src/main.nr @@ -0,0 +1,21 @@ +use dep::std::bigint; + +fn main(mut x: [u8;5], y: [u8;5]) { + let a = bigint::BigInt::secpk1_fq_from_le_bytes([x[0],x[1],x[2],x[3],x[4]]); + let b = bigint::BigInt::secpk1_fq_from_le_bytes([y[0],y[1],y[2],y[3],y[4]]); + + let a_bytes = a.to_le_bytes(); + let b_bytes = b.to_le_bytes(); + for i in 0..5 { + assert(a_bytes[i] == x[i]); + assert(b_bytes[i] == y[i]); + } + + let d = a*b - b; + let d_bytes = d.to_le_bytes(); + let d1 = bigint::BigInt::secpk1_fq_from_le_bytes(597243850900842442924.to_le_bytes(10)); + let d1_bytes = d1.to_le_bytes(); + for i in 0..32 { + assert(d_bytes[i] == d1_bytes[i]); + } +} diff --git a/test_programs/execution_success/bit_shifts_runtime/src/main.nr b/test_programs/execution_success/bit_shifts_runtime/src/main.nr index 33d68765598..28b3ef656c1 100644 --- a/test_programs/execution_success/bit_shifts_runtime/src/main.nr +++ b/test_programs/execution_success/bit_shifts_runtime/src/main.nr @@ -16,4 +16,5 @@ fn main(x: u64, y: u64) { assert(a << 7 == -128); assert(a << -a == -2); + assert(x >> x == 0); } diff --git a/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml b/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml new file mode 100644 index 00000000000..ed8200d8a95 --- /dev/null +++ b/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "brillig_bit_shifts_runtime" +type = "bin" +authors = [""] + +[dependencies] diff --git a/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml b/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml new file mode 100644 index 00000000000..98d8630792e --- /dev/null +++ b/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml @@ -0,0 +1,2 @@ +x = 64 +y = 1 \ No newline at end of file diff --git a/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr b/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr new file mode 100644 index 00000000000..f22166b5993 --- /dev/null +++ b/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr @@ -0,0 +1,20 @@ +unconstrained fn main(x: u64, y: u64) { + // runtime shifts on compile-time known values + assert(64 << y == 128); + assert(64 >> y == 32); + // runtime shifts on runtime values + assert(x << y == 128); + assert(x >> y == 32); + + // Bit-shift with signed integers + let mut a :i8 = y as i8; + let mut b: i8 = x as i8; + assert(b << 1 == -128); + assert(b >> 2 == 16); + assert(b >> a == 32); + a = -a; + assert(a << 7 == -128); + assert(a << -a == -2); + + assert(x >> x == 0); +} diff --git a/test_programs/execution_success/brillig_nested_arrays/src/main.nr b/test_programs/execution_success/brillig_nested_arrays/src/main.nr index d0a60ac0a58..5a5657246a8 100644 --- a/test_programs/execution_success/brillig_nested_arrays/src/main.nr +++ b/test_programs/execution_success/brillig_nested_arrays/src/main.nr @@ -12,11 +12,19 @@ unconstrained fn access_nested(notes: [MyNote; 2], x: Field, y: Field) -> Field notes[x].array[y] + notes[y].array[x] + notes[x].plain + notes[y].header.params[x] } -unconstrained fn create_inside_brillig(x: Field, y: Field) { +unconstrained fn create_inside_brillig() -> [MyNote; 2] { let header = Header { params: [1, 2, 3] }; let note0 = MyNote { array: [1, 2], plain: 3, header }; let note1 = MyNote { array: [4, 5], plain: 6, header }; - assert(access_nested([note0, note1], x, y) == (2 + 4 + 3 + 1)); + [note0, note1] +} + +unconstrained fn assert_inside_brillig(notes: [MyNote; 2], x: Field, y: Field) { + assert(access_nested(notes, x, y) == (2 + 4 + 3 + 1)); +} + +unconstrained fn create_and_assert_inside_brillig(x: Field, y: Field) { + assert_inside_brillig(create_inside_brillig(), x, y); } fn main(x: Field, y: Field) { @@ -24,7 +32,10 @@ fn main(x: Field, y: Field) { let note0 = MyNote { array: [1, 2], plain: 3, header }; let note1 = MyNote { array: [4, 5], plain: 6, header }; - create_inside_brillig(x, y); assert(access_nested([note0, note1], x, y) == (2 + 4 + 3 + 1)); + + let notes = create_inside_brillig(); + assert_inside_brillig(notes, x, y); + create_and_assert_inside_brillig(x, y); } diff --git a/test_programs/execution_success/debug_logs/src/main.nr b/test_programs/execution_success/debug_logs/src/main.nr index b640e4f5f0c..49e0041594a 100644 --- a/test_programs/execution_success/debug_logs/src/main.nr +++ b/test_programs/execution_success/debug_logs/src/main.nr @@ -57,6 +57,12 @@ fn main(x: Field, y: pub Field) { regression_2906(); + let first_array = [1, 2, 3]; + let second_array = [4, 5, 6]; + let arrays_nested = [first_array, second_array]; + std::println(f"first_array: {first_array}, second_array: {second_array}"); + std::println(f"arrays_nested: {arrays_nested}"); + let free_lambda = |x| x + 1; let sentinel: u32 = 8888; std::println(f"free_lambda: {free_lambda}, sentinel: {sentinel}"); diff --git a/test_programs/execution_success/global_consts/src/main.nr b/test_programs/execution_success/global_consts/src/main.nr index 70c7a745a22..25cc0e4dd36 100644 --- a/test_programs/execution_success/global_consts/src/main.nr +++ b/test_programs/execution_success/global_consts/src/main.nr @@ -5,7 +5,10 @@ global M: Field = 32; global L: Field = 10; // Unused globals currently allowed global N: Field = 5; global T_LEN = 2; // Type inference is allowed on globals -//global N: Field = 5; // Uncomment to see duplicate globals error + +// Globals can reference other globals +global DERIVED = M + L; + struct Dummy { x: [Field; N], y: [Field; foo::MAGIC_NUMBER] @@ -17,6 +20,13 @@ struct Test { global VALS: [Test; 1] = [Test { v: 100 }]; global NESTED = [VALS, VALS]; +unconstrained fn calculate_global_value() -> Field { + 42 +} + +// Regression test for https://github.com/noir-lang/noir/issues/4318 +global CALCULATED_GLOBAL: Field = calculate_global_value(); + fn main( a: [Field; M + N - N], b: [Field; 30 + N / 2], @@ -70,6 +80,9 @@ fn main( foo::from_foo(d); baz::from_baz(c); + assert(DERIVED == M + L); + + assert(CALCULATED_GLOBAL == 42); } fn multiplyByM(x: Field) -> Field { diff --git a/test_programs/execution_success/regression_4202/Nargo.toml b/test_programs/execution_success/regression_4202/Nargo.toml new file mode 100644 index 00000000000..acfba12dd4f --- /dev/null +++ b/test_programs/execution_success/regression_4202/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_4202" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/regression_4202/Prover.toml b/test_programs/execution_success/regression_4202/Prover.toml new file mode 100644 index 00000000000..e9319802dfd --- /dev/null +++ b/test_programs/execution_success/regression_4202/Prover.toml @@ -0,0 +1 @@ +input = [1, 2, 3, 4] diff --git a/test_programs/execution_success/regression_4202/src/main.nr b/test_programs/execution_success/regression_4202/src/main.nr new file mode 100644 index 00000000000..37d2ee4578d --- /dev/null +++ b/test_programs/execution_success/regression_4202/src/main.nr @@ -0,0 +1,14 @@ +fn main(input: [u32; 4]) { + let mut slice1: [u32] = [1, 2, 3, 4]; + if slice1[0] == 3 { + slice1[1] = 4; + } + + if slice1[1] == 5 { + slice1[3] = 6; + } + + for i in 0..4 { + assert(slice1[i] == input[i]); + } +} diff --git a/tooling/backend_interface/src/cli/info.rs b/tooling/backend_interface/src/cli/info.rs index 934351dd517..8ca3d4dd0a3 100644 --- a/tooling/backend_interface/src/cli/info.rs +++ b/tooling/backend_interface/src/cli/info.rs @@ -1,4 +1,5 @@ -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; + use serde::Deserialize; use std::path::{Path, PathBuf}; diff --git a/tooling/backend_interface/src/cli/prove.rs b/tooling/backend_interface/src/cli/prove.rs index c12e516db57..c63d8afab54 100644 --- a/tooling/backend_interface/src/cli/prove.rs +++ b/tooling/backend_interface/src/cli/prove.rs @@ -13,7 +13,6 @@ use super::string_from_stderr; /// The proof will be written to the specified output file. pub(crate) struct ProveCommand { pub(crate) crs_path: PathBuf, - pub(crate) is_recursive: bool, pub(crate) bytecode_path: PathBuf, pub(crate) witness_path: PathBuf, } @@ -33,10 +32,6 @@ impl ProveCommand { .arg("-o") .arg("-"); - if self.is_recursive { - command.arg("-r"); - } - let output = command.output()?; if output.status.success() { Ok(output.stdout) @@ -61,7 +56,7 @@ fn prove_command() -> Result<(), BackendError> { std::fs::File::create(&witness_path).expect("file should be created"); let crs_path = backend.backend_directory(); - let prove_command = ProveCommand { crs_path, bytecode_path, witness_path, is_recursive: false }; + let prove_command = ProveCommand { crs_path, bytecode_path, witness_path }; let proof = prove_command.run(backend.binary_path())?; assert_eq!(proof, "proof".as_bytes()); diff --git a/tooling/backend_interface/src/cli/verify.rs b/tooling/backend_interface/src/cli/verify.rs index a31f476d84c..1a4ba50b7de 100644 --- a/tooling/backend_interface/src/cli/verify.rs +++ b/tooling/backend_interface/src/cli/verify.rs @@ -6,7 +6,6 @@ use crate::BackendError; /// to verify a proof pub(crate) struct VerifyCommand { pub(crate) crs_path: PathBuf, - pub(crate) is_recursive: bool, pub(crate) proof_path: PathBuf, pub(crate) vk_path: PathBuf, } @@ -24,10 +23,6 @@ impl VerifyCommand { .arg("-k") .arg(self.vk_path); - if self.is_recursive { - command.arg("-r"); - } - let output = command.output()?; // We currently do not distinguish between an invalid proof and an error inside the backend. @@ -64,18 +59,12 @@ fn verify_command() -> Result<(), BackendError> { write_vk_command.run(backend.binary_path())?; - let prove_command = ProveCommand { - crs_path: crs_path.clone(), - is_recursive: false, - bytecode_path, - witness_path, - }; + let prove_command = ProveCommand { crs_path: crs_path.clone(), bytecode_path, witness_path }; let proof = prove_command.run(backend.binary_path())?; write_to_file(&proof, &proof_path); - let verify_command = - VerifyCommand { crs_path, is_recursive: false, proof_path, vk_path: vk_path_output }; + let verify_command = VerifyCommand { crs_path, proof_path, vk_path: vk_path_output }; let verified = verify_command.run(backend.binary_path())?; assert!(verified); diff --git a/tooling/backend_interface/src/proof_system.rs b/tooling/backend_interface/src/proof_system.rs index 595cd7e2020..485381006df 100644 --- a/tooling/backend_interface/src/proof_system.rs +++ b/tooling/backend_interface/src/proof_system.rs @@ -2,8 +2,10 @@ use std::fs::File; use std::io::Write; use std::path::Path; -use acvm::acir::{circuit::Circuit, native_types::WitnessMap}; -use acvm::ExpressionWidth; +use acvm::acir::{ + circuit::{Circuit, ExpressionWidth}, + native_types::WitnessMap, +}; use acvm::FieldElement; use tempfile::tempdir; use tracing::warn; @@ -55,7 +57,6 @@ impl Backend { &self, circuit: &Circuit, witness_values: WitnessMap, - is_recursive: bool, ) -> Result, BackendError> { let binary_path = self.assert_binary_exists()?; self.assert_correct_version()?; @@ -76,13 +77,9 @@ impl Backend { write_to_file(&serialized_circuit, &bytecode_path); // Create proof and store it in the specified path - let proof_with_public_inputs = ProveCommand { - crs_path: self.crs_directory(), - is_recursive, - bytecode_path, - witness_path, - } - .run(binary_path)?; + let proof_with_public_inputs = + ProveCommand { crs_path: self.crs_directory(), bytecode_path, witness_path } + .run(binary_path)?; let proof = bb_abstraction_leaks::remove_public_inputs( circuit.public_inputs().0.len(), @@ -97,7 +94,6 @@ impl Backend { proof: &[u8], public_inputs: WitnessMap, circuit: &Circuit, - is_recursive: bool, ) -> Result { let binary_path = self.assert_binary_exists()?; self.assert_correct_version()?; @@ -127,8 +123,7 @@ impl Backend { .run(binary_path)?; // Verify the proof - VerifyCommand { crs_path: self.crs_directory(), is_recursive, proof_path, vk_path } - .run(binary_path) + VerifyCommand { crs_path: self.crs_directory(), proof_path, vk_path }.run(binary_path) } pub fn get_intermediate_proof_artifacts( diff --git a/tooling/backend_interface/src/smart_contract.rs b/tooling/backend_interface/src/smart_contract.rs index 2548079f8e3..5af75e48389 100644 --- a/tooling/backend_interface/src/smart_contract.rs +++ b/tooling/backend_interface/src/smart_contract.rs @@ -38,7 +38,7 @@ mod tests { use std::collections::BTreeSet; use acvm::acir::{ - circuit::{Circuit, Opcode, PublicInputs}, + circuit::{Circuit, ExpressionWidth, Opcode, PublicInputs}, native_types::{Expression, Witness}, }; @@ -51,11 +51,13 @@ mod tests { let circuit = Circuit { current_witness_index: 4, + expression_width: ExpressionWidth::Bounded { width: 3 }, opcodes: vec![constraint], private_parameters: BTreeSet::from([Witness(1), Witness(2)]), public_parameters: PublicInputs::default(), return_values: PublicInputs::default(), assert_messages: Default::default(), + recursive: false, }; let contract = get_mock_backend()?.eth_contract(&circuit)?; diff --git a/tooling/bb_abstraction_leaks/build.rs b/tooling/bb_abstraction_leaks/build.rs index 6197f52cb4b..24603186c87 100644 --- a/tooling/bb_abstraction_leaks/build.rs +++ b/tooling/bb_abstraction_leaks/build.rs @@ -10,7 +10,7 @@ use const_format::formatcp; const USERNAME: &str = "AztecProtocol"; const REPO: &str = "aztec-packages"; -const VERSION: &str = "0.21.0"; +const VERSION: &str = "0.23.0"; const TAG: &str = formatcp!("aztec-packages-v{}", VERSION); const API_URL: &str = diff --git a/tooling/debugger/Cargo.toml b/tooling/debugger/Cargo.toml index 785eacf9463..30d11db8cf3 100644 --- a/tooling/debugger/Cargo.toml +++ b/tooling/debugger/Cargo.toml @@ -27,5 +27,4 @@ serde_json.workspace = true [dev-dependencies] assert_cmd = "2.0.12" rexpect = "0.5.0" -test-binary = "3.0.1" tempfile.workspace = true diff --git a/tooling/debugger/ignored-tests.txt b/tooling/debugger/ignored-tests.txt index 1aa886866f2..94bf0f91b57 100644 --- a/tooling/debugger/ignored-tests.txt +++ b/tooling/debugger/ignored-tests.txt @@ -16,3 +16,4 @@ scalar_mul signed_comparison simple_2d_array to_bytes_integration +bigint \ No newline at end of file diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index 618f00b5ce1..5ab2c63c365 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -2,7 +2,7 @@ use crate::foreign_calls::DebugForeignCallExecutor; use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap}; use acvm::brillig_vm::brillig::ForeignCallResult; -use acvm::brillig_vm::{brillig::Value, Registers}; +use acvm::brillig_vm::brillig::Value; use acvm::pwg::{ ACVMStatus, BrilligSolver, BrilligSolverStatus, ForeignCallWaitInfo, StepResult, ACVM, }; @@ -78,6 +78,24 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } + pub(super) fn get_call_stack(&self) -> Vec { + let instruction_pointer = self.acvm.instruction_pointer(); + if instruction_pointer >= self.get_opcodes().len() { + vec![] + } else if let Some(ref solver) = self.brillig_solver { + solver + .get_call_stack() + .iter() + .map(|program_counter| OpcodeLocation::Brillig { + acir_index: instruction_pointer, + brillig_index: *program_counter, + }) + .collect() + } else { + vec![OpcodeLocation::Acir(instruction_pointer)] + } + } + pub(super) fn is_source_location_in_debug_module(&self, location: &Location) -> bool { self.debug_artifact .file_map @@ -123,6 +141,21 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { .unwrap_or(vec![]) } + /// Returns the current call stack with expanded source locations. In + /// general, the matching between opcode location and source location is 1 + /// to 1, but due to the compiler inlining functions a single opcode + /// location may expand to multiple source locations. + pub(super) fn get_source_call_stack(&self) -> Vec<(OpcodeLocation, Location)> { + self.get_call_stack() + .iter() + .flat_map(|opcode_location| { + self.get_source_location_for_opcode_location(opcode_location) + .into_iter() + .map(|source_location| (*opcode_location, source_location)) + }) + .collect() + } + fn get_opcodes_sizes(&self) -> Vec { self.get_opcodes() .iter() @@ -362,7 +395,8 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } - pub(super) fn next(&mut self) -> DebugCommandResult { + /// Steps debugging execution until the next source location + pub(super) fn next_into(&mut self) -> DebugCommandResult { let start_location = self.get_current_source_location(); loop { let result = self.step_into_opcode(); @@ -376,6 +410,38 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } + /// Steps debugging execution until the next source location at the same (or + /// less) call stack depth (eg. don't dive into function calls) + pub(super) fn next_over(&mut self) -> DebugCommandResult { + let start_call_stack = self.get_source_call_stack(); + loop { + let result = self.next_into(); + if !matches!(result, DebugCommandResult::Ok) { + return result; + } + let new_call_stack = self.get_source_call_stack(); + if new_call_stack.len() <= start_call_stack.len() { + return DebugCommandResult::Ok; + } + } + } + + /// Steps debugging execution until the next source location with a smaller + /// call stack depth (eg. returning from the current function) + pub(super) fn next_out(&mut self) -> DebugCommandResult { + let start_call_stack = self.get_source_call_stack(); + loop { + let result = self.next_into(); + if !matches!(result, DebugCommandResult::Ok) { + return result; + } + let new_call_stack = self.get_source_call_stack(); + if new_call_stack.len() < start_call_stack.len() { + return DebugCommandResult::Ok; + } + } + } + pub(super) fn cont(&mut self) -> DebugCommandResult { loop { let result = self.step_into_opcode(); @@ -391,16 +457,6 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { acir_index < opcodes.len() && matches!(opcodes[acir_index], Opcode::Brillig(..)) } - pub(super) fn get_brillig_registers(&self) -> Option<&Registers> { - self.brillig_solver.as_ref().map(|solver| solver.get_registers()) - } - - pub(super) fn set_brillig_register(&mut self, register_index: usize, value: FieldElement) { - if let Some(solver) = self.brillig_solver.as_mut() { - solver.set_register(register_index, value.into()); - } - } - pub(super) fn get_brillig_memory(&self) -> Option<&[Value]> { self.brillig_solver.as_ref().map(|solver| solver.get_memory()) } @@ -486,7 +542,7 @@ mod tests { }, blackbox_solver::StubbedBlackBoxSolver, brillig_vm::brillig::{ - BinaryFieldOp, Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory, + BinaryFieldOp, HeapValueType, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray, }, }; use nargo::artifacts::debug::DebugArtifact; @@ -505,16 +561,24 @@ mod tests { })], outputs: vec![], bytecode: vec![ + BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress(0), + size: 1, + offset: 0, + }, BrilligOpcode::Const { - destination: RegisterIndex::from(1), + destination: MemoryAddress::from(1), value: Value::from(fe_0), + bit_size: 32, }, BrilligOpcode::ForeignCall { function: "clear_mock".into(), destinations: vec![], - inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + destination_value_types: vec![], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, - BrilligOpcode::Stop, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, ], predicate: None, }; @@ -541,7 +605,7 @@ mod tests { assert_eq!(context.get_current_opcode_location(), Some(OpcodeLocation::Acir(0))); - // execute the first Brillig opcode (const) + // Execute the first Brillig opcode (calldata copy) let result = context.step_into_opcode(); assert!(matches!(result, DebugCommandResult::Ok)); assert_eq!( @@ -549,15 +613,15 @@ mod tests { Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 1 }) ); - // try to execute the second Brillig opcode (and resolve the foreign call) + // execute the second Brillig opcode (const) let result = context.step_into_opcode(); assert!(matches!(result, DebugCommandResult::Ok)); assert_eq!( context.get_current_opcode_location(), - Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 1 }) + Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 2 }) ); - // retry the second Brillig opcode (foreign call should be finished) + // try to execute the third Brillig opcode (and resolve the foreign call) let result = context.step_into_opcode(); assert!(matches!(result, DebugCommandResult::Ok)); assert_eq!( @@ -565,6 +629,14 @@ mod tests { Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 2 }) ); + // retry the third Brillig opcode (foreign call should be finished) + let result = context.step_into_opcode(); + assert!(matches!(result, DebugCommandResult::Ok)); + assert_eq!( + context.get_current_opcode_location(), + Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 3 }) + ); + // last Brillig opcode let result = context.step_into_opcode(); assert!(matches!(result, DebugCommandResult::Done)); @@ -593,13 +665,18 @@ mod tests { ], outputs: vec![BrilligOutputs::Simple(w_z)], bytecode: vec![ + BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress(0), + size: 2, + offset: 0, + }, BrilligOpcode::BinaryFieldOp { - destination: RegisterIndex::from(0), + destination: MemoryAddress::from(0), op: BinaryFieldOp::Add, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), }, - BrilligOpcode::Stop, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 1 }, ], predicate: None, }; @@ -659,14 +736,22 @@ mod tests { Opcode::Brillig(Brillig { inputs: vec![], outputs: vec![], - bytecode: vec![BrilligOpcode::Stop, BrilligOpcode::Stop, BrilligOpcode::Stop], + bytecode: vec![ + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, + ], predicate: None, }), Opcode::MemoryInit { block_id: BlockId(0), init: vec![] }, Opcode::Brillig(Brillig { inputs: vec![], outputs: vec![], - bytecode: vec![BrilligOpcode::Stop, BrilligOpcode::Stop, BrilligOpcode::Stop], + bytecode: vec![ + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, + ], predicate: None, }), Opcode::AssertZero(Expression::default()), diff --git a/tooling/debugger/src/dap.rs b/tooling/debugger/src/dap.rs index 3d135abe1cd..dd9a30d50da 100644 --- a/tooling/debugger/src/dap.rs +++ b/tooling/debugger/src/dap.rs @@ -18,12 +18,12 @@ use dap::requests::{Command, Request, SetBreakpointsArguments}; use dap::responses::{ ContinueResponse, DisassembleResponse, ResponseBody, ScopesResponse, SetBreakpointsResponse, SetExceptionBreakpointsResponse, SetInstructionBreakpointsResponse, StackTraceResponse, - ThreadsResponse, + ThreadsResponse, VariablesResponse, }; use dap::server::Server; use dap::types::{ - Breakpoint, DisassembledInstruction, Source, StackFrame, SteppingGranularity, - StoppedEventReason, Thread, + Breakpoint, DisassembledInstruction, Scope, Source, StackFrame, SteppingGranularity, + StoppedEventReason, Thread, Variable, }; use nargo::artifacts::debug::DebugArtifact; @@ -41,6 +41,22 @@ pub struct DapSession<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> { source_breakpoints: BTreeMap>, } +enum ScopeReferences { + Locals = 1, + WitnessMap = 2, + InvalidScope = 0, +} + +impl From for ScopeReferences { + fn from(value: i64) -> Self { + match value { + 1 => Self::Locals, + 2 => Self::WitnessMap, + _ => Self::InvalidScope, + } + } +} + // BTreeMap impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { @@ -132,7 +148,7 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { // source location to show when first starting the debugger, but // maybe the default behavior should be to start executing until the // first breakpoint set. - _ = self.context.next(); + _ = self.context.next_into(); } self.server.send_event(Event::Initialized)?; @@ -176,7 +192,7 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { args.granularity.as_ref().unwrap_or(&SteppingGranularity::Statement); match granularity { SteppingGranularity::Instruction => self.handle_step(req)?, - _ => self.handle_next(req)?, + _ => self.handle_next_into(req)?, } } Command::StepOut(ref args) => { @@ -184,7 +200,7 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { args.granularity.as_ref().unwrap_or(&SteppingGranularity::Statement); match granularity { SteppingGranularity::Instruction => self.handle_step(req)?, - _ => self.handle_next(req)?, + _ => self.handle_next_out(req)?, } } Command::Next(ref args) => { @@ -192,18 +208,17 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { args.granularity.as_ref().unwrap_or(&SteppingGranularity::Statement); match granularity { SteppingGranularity::Instruction => self.handle_step(req)?, - _ => self.handle_next(req)?, + _ => self.handle_next_over(req)?, } } Command::Continue(_) => { self.handle_continue(req)?; } Command::Scopes(_) => { - // FIXME: this needs a proper implementation when we can - // show the parameters and variables - self.server.respond( - req.success(ResponseBody::Scopes(ScopesResponse { scopes: vec![] })), - )?; + self.handle_scopes(req)?; + } + Command::Variables(ref _args) => { + self.handle_variables(req)?; } _ => { eprintln!("ERROR: unhandled command: {:?}", req.command); @@ -213,37 +228,38 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { Ok(()) } + fn build_stack_trace(&self) -> Vec { + self.context + .get_source_call_stack() + .iter() + .enumerate() + .map(|(index, (opcode_location, source_location))| { + let line_number = + self.debug_artifact.location_line_number(*source_location).unwrap(); + let column_number = + self.debug_artifact.location_column_number(*source_location).unwrap(); + StackFrame { + id: index as i64, + name: format!("frame #{index}"), + source: Some(Source { + path: self.debug_artifact.file_map[&source_location.file] + .path + .to_str() + .map(String::from), + ..Source::default() + }), + line: line_number as i64, + column: column_number as i64, + instruction_pointer_reference: Some(opcode_location.to_string()), + ..StackFrame::default() + } + }) + .rev() + .collect() + } + fn handle_stack_trace(&mut self, req: Request) -> Result<(), ServerError> { - let opcode_location = self.context.get_current_opcode_location(); - let source_location = self.context.get_current_source_location(); - let frames = match source_location { - None => vec![], - Some(locations) => locations - .iter() - .enumerate() - .map(|(index, location)| { - let line_number = self.debug_artifact.location_line_number(*location).unwrap(); - let column_number = - self.debug_artifact.location_column_number(*location).unwrap(); - let ip_reference = opcode_location.map(|location| location.to_string()); - StackFrame { - id: index as i64, - name: format!("frame #{index}"), - source: Some(Source { - path: self.debug_artifact.file_map[&location.file] - .path - .to_str() - .map(String::from), - ..Source::default() - }), - line: line_number as i64, - column: column_number as i64, - instruction_pointer_reference: ip_reference, - ..StackFrame::default() - } - }) - .collect(), - }; + let frames = self.build_stack_trace(); let total_frames = Some(frames.len() as i64); self.server.respond(req.success(ResponseBody::StackTrace(StackTraceResponse { stack_frames: frames, @@ -315,9 +331,23 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { self.handle_execution_result(result) } - fn handle_next(&mut self, req: Request) -> Result<(), ServerError> { - let result = self.context.next(); - eprintln!("INFO: stepped by statement with result {result:?}"); + fn handle_next_into(&mut self, req: Request) -> Result<(), ServerError> { + let result = self.context.next_into(); + eprintln!("INFO: stepped into by statement with result {result:?}"); + self.server.respond(req.ack()?)?; + self.handle_execution_result(result) + } + + fn handle_next_out(&mut self, req: Request) -> Result<(), ServerError> { + let result = self.context.next_out(); + eprintln!("INFO: stepped out by statement with result {result:?}"); + self.server.respond(req.ack()?)?; + self.handle_execution_result(result) + } + + fn handle_next_over(&mut self, req: Request) -> Result<(), ServerError> { + let result = self.context.next_over(); + eprintln!("INFO: stepped over by statement with result {result:?}"); self.server.respond(req.ack()?)?; self.handle_execution_result(result) } @@ -548,6 +578,73 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { )?; Ok(()) } + + fn handle_scopes(&mut self, req: Request) -> Result<(), ServerError> { + self.server.respond(req.success(ResponseBody::Scopes(ScopesResponse { + scopes: vec![ + Scope { + name: String::from("Locals"), + variables_reference: ScopeReferences::Locals as i64, + ..Scope::default() + }, + Scope { + name: String::from("Witness Map"), + variables_reference: ScopeReferences::WitnessMap as i64, + ..Scope::default() + }, + ], + })))?; + Ok(()) + } + + fn build_local_variables(&self) -> Vec { + let mut variables: Vec<_> = self + .context + .get_variables() + .iter() + .map(|(name, value, _var_type)| Variable { + name: String::from(*name), + value: format!("{:?}", *value), + ..Variable::default() + }) + .collect(); + variables.sort_by(|a, b| a.name.partial_cmp(&b.name).unwrap()); + variables + } + + fn build_witness_map(&self) -> Vec { + self.context + .get_witness_map() + .clone() + .into_iter() + .map(|(witness, value)| Variable { + name: format!("_{}", witness.witness_index()), + value: format!("{value:?}"), + ..Variable::default() + }) + .collect() + } + + fn handle_variables(&mut self, req: Request) -> Result<(), ServerError> { + let Command::Variables(ref args) = req.command else { + unreachable!("handle_variables called on a different request"); + }; + let scope: ScopeReferences = args.variables_reference.into(); + let variables: Vec<_> = match scope { + ScopeReferences::Locals => self.build_local_variables(), + ScopeReferences::WitnessMap => self.build_witness_map(), + _ => { + eprintln!( + "handle_variables with an unknown variables_reference {}", + args.variables_reference + ); + vec![] + } + }; + self.server + .respond(req.success(ResponseBody::Variables(VariablesResponse { variables })))?; + Ok(()) + } } pub fn run_session( diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index 17be7c1a792..8441dbde9be 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -82,6 +82,41 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { } } + fn show_stack_frame(&self, index: usize, location: &OpcodeLocation) { + let opcodes = self.context.get_opcodes(); + match location { + OpcodeLocation::Acir(instruction_pointer) => { + println!( + "Frame #{index}, opcode {}: {}", + instruction_pointer, opcodes[*instruction_pointer] + ) + } + OpcodeLocation::Brillig { acir_index, brillig_index } => { + let Opcode::Brillig(ref brillig) = opcodes[*acir_index] else { + unreachable!("Brillig location does not contain a Brillig block"); + }; + println!( + "Frame #{index}, opcode {}.{}: {:?}", + acir_index, brillig_index, brillig.bytecode[*brillig_index] + ); + } + } + let locations = self.context.get_source_location_for_opcode_location(location); + print_source_code_location(self.debug_artifact, &locations); + } + + pub fn show_current_call_stack(&self) { + let call_stack = self.context.get_call_stack(); + if call_stack.is_empty() { + println!("Finished execution. Call stack empty."); + return; + } + + for (i, frame_location) in call_stack.iter().enumerate() { + self.show_stack_frame(i, frame_location); + } + } + fn display_opcodes(&self) { let opcodes = self.context.get_opcodes(); let current_opcode_location = self.context.get_current_opcode_location(); @@ -196,9 +231,23 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { } } - fn next(&mut self) { + fn next_into(&mut self) { + if self.validate_in_progress() { + let result = self.context.next_into(); + self.handle_debug_command_result(result); + } + } + + fn next_over(&mut self) { if self.validate_in_progress() { - let result = self.context.next(); + let result = self.context.next_over(); + self.handle_debug_command_result(result); + } + } + + fn next_out(&mut self) { + if self.validate_in_progress() { + let result = self.context.next_out(); self.handle_debug_command_result(result); } } @@ -256,37 +305,6 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { println!("_{} = {value}", index); } - pub fn show_brillig_registers(&self) { - if !self.context.is_executing_brillig() { - println!("Not executing a Brillig block"); - return; - } - - let Some(registers) = self.context.get_brillig_registers() else { - // this can happen when just entering the Brillig block since ACVM - // would have not initialized the Brillig VM yet; in fact, the - // Brillig code may be skipped altogether - println!("Brillig VM registers not available"); - return; - }; - - for (index, value) in registers.inner.iter().enumerate() { - println!("{index} = {}", value.to_field()); - } - } - - pub fn set_brillig_register(&mut self, index: usize, value: String) { - let Some(field_value) = FieldElement::try_from_str(&value) else { - println!("Invalid value: {value}"); - return; - }; - if !self.context.is_executing_brillig() { - println!("Not executing a Brillig block"); - return; - } - self.context.set_brillig_register(index, field_value); - } - pub fn show_brillig_memory(&self) { if !self.context.is_executing_brillig() { println!("Not executing a Brillig block"); @@ -374,11 +392,31 @@ pub fn run( command! { "step until a new source location is reached", () => || { - ref_context.borrow_mut().next(); + ref_context.borrow_mut().next_into(); Ok(CommandStatus::Done) } }, ) + .add( + "over", + command! { + "step until a new source location is reached without diving into function calls", + () => || { + ref_context.borrow_mut().next_over(); + Ok(CommandStatus::Done) + } + } + ) + .add( + "out", + command! { + "step until a new source location is reached and the current stack frame is finished", + () => || { + ref_context.borrow_mut().next_out(); + Ok(CommandStatus::Done) + } + } + ) .add( "continue", command! { @@ -460,41 +498,31 @@ pub fn run( }, ) .add( - "registers", + "memory", command! { - "show Brillig registers (valid when executing a Brillig block)", + "show Brillig memory (valid when executing a Brillig block)", () => || { - ref_context.borrow().show_brillig_registers(); + ref_context.borrow().show_brillig_memory(); Ok(CommandStatus::Done) } }, ) .add( - "regset", + "memset", command! { - "update a Brillig register with the given value", + "update a Brillig memory cell with the given value", (index: usize, value: String) => |index, value| { - ref_context.borrow_mut().set_brillig_register(index, value); + ref_context.borrow_mut().write_brillig_memory(index, value); Ok(CommandStatus::Done) } }, ) .add( - "memory", + "stacktrace", command! { - "show Brillig memory (valid when executing a Brillig block)", + "display the current stack trace", () => || { - ref_context.borrow().show_brillig_memory(); - Ok(CommandStatus::Done) - } - }, - ) - .add( - "memset", - command! { - "update a Brillig memory cell with the given value", - (index: usize, value: String) => |index, value| { - ref_context.borrow_mut().write_brillig_memory(index, value); + ref_context.borrow().show_current_call_stack(); Ok(CommandStatus::Done) } }, diff --git a/tooling/debugger/tests/debug.rs b/tooling/debugger/tests/debug.rs index 82872ce2739..4cb678192b8 100644 --- a/tooling/debugger/tests/debug.rs +++ b/tooling/debugger/tests/debug.rs @@ -5,8 +5,6 @@ mod tests { use rexpect::spawn_bash; - test_binary::build_test_binary_once!(mock_backend, "../backend_interface/test-binaries"); - // include tests generated by `build.rs` include!(concat!(env!("OUT_DIR"), "/debug.rs")); @@ -14,20 +12,20 @@ mod tests { let nargo_bin = cargo_bin("nargo").into_os_string().into_string().expect("Cannot parse nargo path"); - let mock_backend_path = - path_to_mock_backend().into_string().expect("Cannot parse mock_backend path"); - let mut dbg_session = spawn_bash(Some(10000)).expect("Could not start bash session"); + // Set backend to `/dev/null` to force an error if nargo tries to speak to a backend. dbg_session - .send_line(&format!("export NARGO_BACKEND_PATH={}", mock_backend_path)) + .send_line("export NARGO_BACKEND_PATH=/dev/null") .expect("Could not export NARGO_BACKEND_PATH."); dbg_session.wait_for_prompt().expect("Could not export NARGO_BACKEND_PATH."); // Start debugger and test that it loads for the given program. dbg_session .execute( - &format!("{} debug --program-dir {} --force-brillig", nargo_bin, test_program_dir), + &format!( + "{nargo_bin} debug --program-dir {test_program_dir} --force-brillig --expression-width 3" + ), ".*\\Starting debugger.*", ) .expect("Could not start debugger"); diff --git a/tooling/lsp/src/requests/profile_run.rs b/tooling/lsp/src/requests/profile_run.rs index d866be8988b..917c247410d 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::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use async_lsp::{ErrorCode, ResponseError}; use nargo::{artifacts::debug::DebugArtifact, insert_all_files_for_workspace_into_file_manager}; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; diff --git a/tooling/nargo/Cargo.toml b/tooling/nargo/Cargo.toml index cd97980b9e0..efd38a182e0 100644 --- a/tooling/nargo/Cargo.toml +++ b/tooling/nargo/Cargo.toml @@ -36,4 +36,3 @@ jsonrpc-http-server = "18.0" jsonrpc-core-client = "18.0" jsonrpc-derive = "18.0" jsonrpc-core = "18.0" -serial_test = "2.0" diff --git a/tooling/nargo/src/ops/foreign_calls.rs b/tooling/nargo/src/ops/foreign_calls.rs index 0f31be3c7f4..f7f36c65c90 100644 --- a/tooling/nargo/src/ops/foreign_calls.rs +++ b/tooling/nargo/src/ops/foreign_calls.rs @@ -333,7 +333,6 @@ mod tests { use jsonrpc_core::Result as RpcResult; use jsonrpc_derive::rpc; use jsonrpc_http_server::{Server, ServerBuilder}; - use serial_test::serial; use crate::ops::{DefaultForeignCallExecutor, ForeignCallExecutor}; @@ -369,15 +368,15 @@ mod tests { let mut io = jsonrpc_core::IoHandler::new(); io.extend_with(OracleResolverImpl.to_delegate()); + // Choosing port 0 results in a random port being assigned. let server = ServerBuilder::new(io) - .start_http(&"127.0.0.1:5555".parse().expect("Invalid address")) + .start_http(&"127.0.0.1:0".parse().expect("Invalid address")) .expect("Could not start server"); let url = format!("http://{}", server.address()); (server, url) } - #[serial] #[test] fn test_oracle_resolver_echo() { let (server, url) = build_oracle_server(); @@ -395,7 +394,6 @@ mod tests { server.close(); } - #[serial] #[test] fn test_oracle_resolver_sum() { let (server, url) = build_oracle_server(); diff --git a/tooling/nargo/src/ops/transform.rs b/tooling/nargo/src/ops/transform.rs index f3efd82333e..9267ed7e045 100644 --- a/tooling/nargo/src/ops/transform.rs +++ b/tooling/nargo/src/ops/transform.rs @@ -1,4 +1,4 @@ -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use iter_extended::vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; diff --git a/tooling/nargo_cli/src/cli/dap_cmd.rs b/tooling/nargo_cli/src/cli/dap_cmd.rs index d5eb3325ba0..7c7e6056901 100644 --- a/tooling/nargo_cli/src/cli/dap_cmd.rs +++ b/tooling/nargo_cli/src/cli/dap_cmd.rs @@ -1,5 +1,5 @@ +use acvm::acir::circuit::ExpressionWidth; use acvm::acir::native_types::WitnessMap; -use acvm::ExpressionWidth; use backend_interface::Backend; use clap::Args; use nargo::constants::PROVER_INPUT_FILE; @@ -44,7 +44,10 @@ fn parse_expression_width(input: &str) -> Result() .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?; - Ok(ExpressionWidth::from(width)) + match width { + 0 => Ok(ExpressionWidth::Unbounded), + _ => Ok(ExpressionWidth::Bounded { width }), + } } struct LoadError(&'static str); diff --git a/tooling/nargo_cli/src/cli/info_cmd.rs b/tooling/nargo_cli/src/cli/info_cmd.rs index 131fd6ad214..ef0df0bf25b 100644 --- a/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/tooling/nargo_cli/src/cli/info_cmd.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use backend_interface::BackendError; use clap::Args; use iter_extended::vecmap; diff --git a/tooling/nargo_cli/src/cli/prove_cmd.rs b/tooling/nargo_cli/src/cli/prove_cmd.rs index 1d20e97af85..cc39b0535bc 100644 --- a/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -138,12 +138,11 @@ pub(crate) fn prove_package( Format::Toml, )?; - let proof = backend.prove(&compiled_program.circuit, solved_witness, false)?; + let proof = backend.prove(&compiled_program.circuit, solved_witness)?; if check_proof { let public_inputs = public_abi.encode(&public_inputs, return_value)?; - let valid_proof = - backend.verify(&proof, public_inputs, &compiled_program.circuit, false)?; + let valid_proof = backend.verify(&proof, public_inputs, &compiled_program.circuit)?; if !valid_proof { return Err(CliError::InvalidProof("".into())); diff --git a/tooling/nargo_cli/src/cli/verify_cmd.rs b/tooling/nargo_cli/src/cli/verify_cmd.rs index ea4aaa051bb..66b88a22f2a 100644 --- a/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -102,7 +102,7 @@ fn verify_package( let proof = load_hex_data(&proof_path)?; - let valid_proof = backend.verify(&proof, public_inputs, &compiled_program.circuit, false)?; + let valid_proof = backend.verify(&proof, public_inputs, &compiled_program.circuit)?; if valid_proof { Ok(()) diff --git a/tooling/nargo_fmt/src/items.rs b/tooling/nargo_fmt/src/items.rs new file mode 100644 index 00000000000..7f998f45b59 --- /dev/null +++ b/tooling/nargo_fmt/src/items.rs @@ -0,0 +1,117 @@ +use noirc_frontend::macros_api::Span; + +use crate::{ + utils::{comment_len, find_comment_end}, + visitor::{FmtVisitor, Shape}, +}; + +#[derive(Debug)] +pub(crate) struct Item { + pub(crate) leading: String, + pub(crate) value: String, + pub(crate) trailing: String, + pub(crate) different_line: bool, +} + +impl Item { + pub(crate) fn total_width(&self) -> usize { + comment_len(&self.leading) + self.value.chars().count() + comment_len(&self.trailing) + } + + pub(crate) fn is_multiline(&self) -> bool { + self.leading.contains('\n') || self.trailing.contains('\n') + } +} + +pub(crate) struct Items<'me, T> { + visitor: &'me FmtVisitor<'me>, + shape: Shape, + elements: std::iter::Peekable>, + last_position: u32, + end_position: u32, +} + +impl<'me, T: HasItem> Items<'me, T> { + pub(crate) fn new( + visitor: &'me FmtVisitor<'me>, + shape: Shape, + span: Span, + elements: Vec, + ) -> Self { + Self { + visitor, + shape, + last_position: span.start() + 1, + end_position: span.end() - 1, + elements: elements.into_iter().peekable(), + } + } +} + +impl Iterator for Items<'_, T> { + type Item = Item; + + fn next(&mut self) -> Option { + let element = self.elements.next()?; + let element_span = element.span(); + + let start = self.last_position; + let end = element_span.start(); + + let is_last = self.elements.peek().is_none(); + let next_start = self.elements.peek().map_or(self.end_position, |expr| expr.start()); + + let (leading, different_line) = self.leading(start, end); + let expr = element.format(self.visitor, self.shape); + let trailing = self.trailing(element_span.end(), next_start, is_last); + + Item { leading, value: expr, trailing, different_line }.into() + } +} + +impl<'me, T> Items<'me, T> { + pub(crate) fn leading(&mut self, start: u32, end: u32) -> (String, bool) { + let mut different_line = false; + + let leading = self.visitor.slice(start..end); + let leading_trimmed = leading.trim(); + + let starts_with_block_comment = leading_trimmed.starts_with("/*"); + let ends_with_block_comment = leading_trimmed.ends_with("*/"); + let starts_with_single_line_comment = leading_trimmed.starts_with("//"); + + if ends_with_block_comment { + let comment_end = leading_trimmed.rfind(|c| c == '/').unwrap(); + + if leading[comment_end..].contains('\n') { + different_line = true; + } + } else if starts_with_single_line_comment || starts_with_block_comment { + different_line = true; + }; + + (leading_trimmed.to_string(), different_line) + } + + pub(crate) fn trailing(&mut self, start: u32, end: u32, is_last: bool) -> String { + let slice = self.visitor.slice(start..end); + let comment_end = find_comment_end(slice, is_last); + let trailing = slice[..comment_end].trim_matches(',').trim(); + self.last_position = start + (comment_end as u32); + trailing.to_string() + } +} + +pub(crate) trait HasItem { + fn span(&self) -> Span; + + fn format(self, visitor: &FmtVisitor, shape: Shape) -> String; + + fn start(&self) -> u32 { + self.span().start() + } + + fn end(&self) -> u32 { + self.span().end() + } +} diff --git a/tooling/nargo_fmt/src/lib.rs b/tooling/nargo_fmt/src/lib.rs index d731934c3c3..0a7903f0ce1 100644 --- a/tooling/nargo_fmt/src/lib.rs +++ b/tooling/nargo_fmt/src/lib.rs @@ -20,6 +20,7 @@ /// in both placement and content during the formatting process. mod config; pub mod errors; +mod items; mod rewrite; mod utils; mod visitor; diff --git a/tooling/nargo_fmt/src/rewrite.rs b/tooling/nargo_fmt/src/rewrite.rs index 6a95eba8759..61792c7a7fa 100644 --- a/tooling/nargo_fmt/src/rewrite.rs +++ b/tooling/nargo_fmt/src/rewrite.rs @@ -1,11 +1,13 @@ mod array; mod expr; +mod imports; mod infix; mod parenthesized; mod typ; pub(crate) use array::rewrite as array; pub(crate) use expr::{rewrite as expr, rewrite_sub_expr as sub_expr}; +pub(crate) use imports::UseTree; pub(crate) use infix::rewrite as infix; pub(crate) use parenthesized::rewrite as parenthesized; pub(crate) use typ::rewrite as typ; diff --git a/tooling/nargo_fmt/src/rewrite/array.rs b/tooling/nargo_fmt/src/rewrite/array.rs index fc5b240f83e..77e5e756f19 100644 --- a/tooling/nargo_fmt/src/rewrite/array.rs +++ b/tooling/nargo_fmt/src/rewrite/array.rs @@ -1,7 +1,8 @@ use noirc_frontend::{hir::resolution::errors::Span, token::Token, Expression}; use crate::{ - utils::{Expr, FindToken}, + items::Item, + utils::FindToken, visitor::{expr::NewlineMode, FmtVisitor}, }; @@ -39,12 +40,12 @@ pub(crate) fn rewrite(mut visitor: FmtVisitor, array: Vec, array_spa let (leading, _) = visitor.format_comment_in_block(leading); let (trailing, _) = visitor.format_comment_in_block(trailing); - result.push(Expr { leading, value: item, trailing, different_line: false }); + result.push(Item { leading, value: item, trailing, different_line: false }); } let slice = visitor.slice(last_position..end_position); let (comment, _) = visitor.format_comment_in_block(slice); - result.push(Expr { + result.push(Item { leading: "".into(), value: "".into(), trailing: comment, diff --git a/tooling/nargo_fmt/src/rewrite/imports.rs b/tooling/nargo_fmt/src/rewrite/imports.rs new file mode 100644 index 00000000000..2788f778140 --- /dev/null +++ b/tooling/nargo_fmt/src/rewrite/imports.rs @@ -0,0 +1,115 @@ +use noirc_frontend::{PathKind, UseTreeKind}; + +use crate::{ + items::Item, + visitor::{ + expr::{format_exprs, Tactic}, + FmtVisitor, Shape, + }, +}; + +#[derive(Debug)] +pub(crate) enum UseSegment { + Ident(String, Option), + List(Vec), + Dep, + Crate, +} + +impl UseSegment { + fn rewrite(&self, visitor: &FmtVisitor, shape: Shape) -> String { + match self { + UseSegment::Ident(ident, None) => ident.clone(), + UseSegment::Ident(ident, Some(rename)) => format!("{ident} as {rename}"), + UseSegment::List(use_tree_list) => { + let mut nested_shape = shape; + nested_shape.indent.block_indent(visitor.config); + + let items: Vec<_> = use_tree_list + .iter() + .map(|item| Item { + leading: String::new(), + value: item.rewrite(visitor, shape).clone(), + trailing: String::new(), + different_line: false, + }) + .collect(); + + let list_str = + format_exprs(visitor.config, Tactic::Mixed, false, items, nested_shape, true); + + if list_str.contains('\n') { + format!( + "{{\n{}{list_str}\n{}}}", + nested_shape.indent.to_string(), + shape.indent.to_string() + ) + } else { + format!("{{{list_str}}}") + } + } + UseSegment::Dep => "dep".into(), + UseSegment::Crate => "crate".into(), + } + } +} + +#[derive(Debug)] +pub(crate) struct UseTree { + path: Vec, +} + +impl UseTree { + pub(crate) fn from_ast(use_tree: noirc_frontend::UseTree) -> Self { + let mut result = UseTree { path: vec![] }; + + match use_tree.prefix.kind { + PathKind::Crate => result.path.push(UseSegment::Crate), + PathKind::Dep => result.path.push(UseSegment::Dep), + PathKind::Plain => {} + }; + + result.path.extend( + use_tree + .prefix + .segments + .into_iter() + .map(|segment| UseSegment::Ident(segment.to_string(), None)), + ); + + match use_tree.kind { + UseTreeKind::Path(name, alias) => { + result.path.push(UseSegment::Ident( + name.to_string(), + alias.map(|rename| rename.to_string()), + )); + } + UseTreeKind::List(list) => { + let segment = UseSegment::List(list.into_iter().map(UseTree::from_ast).collect()); + result.path.push(segment); + } + } + + result + } + + pub(crate) fn rewrite_top_level(&self, visitor: &FmtVisitor, shape: Shape) -> String { + format!("use {};", self.rewrite(visitor, shape)) + } + + fn rewrite(&self, visitor: &FmtVisitor, shape: Shape) -> String { + let mut result = String::new(); + + let mut iter = self.path.iter().peekable(); + while let Some(segment) = iter.next() { + let segment_str = segment.rewrite(visitor, shape); + result.push_str(&segment_str); + + if iter.peek().is_some() { + result.push_str("::"); + } + } + + result + } +} diff --git a/tooling/nargo_fmt/src/rewrite/typ.rs b/tooling/nargo_fmt/src/rewrite/typ.rs index 4c6411e92b8..aaa77b0bea5 100644 --- a/tooling/nargo_fmt/src/rewrite/typ.rs +++ b/tooling/nargo_fmt/src/rewrite/typ.rs @@ -59,7 +59,7 @@ pub(crate) fn rewrite(visitor: &FmtVisitor, _shape: Shape, typ: UnresolvedType) UnresolvedTypeData::FieldElement | UnresolvedTypeData::Integer(_, _) | UnresolvedTypeData::Bool - | UnresolvedTypeData::Named(_, _) + | UnresolvedTypeData::Named(_, _, _) | UnresolvedTypeData::Unit | UnresolvedTypeData::Expression(_) | UnresolvedTypeData::String(_) diff --git a/tooling/nargo_fmt/src/utils.rs b/tooling/nargo_fmt/src/utils.rs index 1160f01972f..5874ebdebbc 100644 --- a/tooling/nargo_fmt/src/utils.rs +++ b/tooling/nargo_fmt/src/utils.rs @@ -1,3 +1,4 @@ +use crate::items::HasItem; use crate::rewrite; use crate::visitor::{FmtVisitor, Shape}; use noirc_frontend::hir::resolution::errors::Span; @@ -21,103 +22,6 @@ pub(crate) fn comments(source: &str) -> impl Iterator + '_ { }) } -#[derive(Debug)] -pub(crate) struct Expr { - pub(crate) leading: String, - pub(crate) value: String, - pub(crate) trailing: String, - pub(crate) different_line: bool, -} - -impl Expr { - pub(crate) fn total_width(&self) -> usize { - comment_len(&self.leading) + self.value.chars().count() + comment_len(&self.trailing) - } - - pub(crate) fn is_multiline(&self) -> bool { - self.leading.contains('\n') || self.trailing.contains('\n') - } -} - -pub(crate) struct Exprs<'me, T> { - pub(crate) visitor: &'me FmtVisitor<'me>, - shape: Shape, - pub(crate) elements: std::iter::Peekable>, - pub(crate) last_position: u32, - pub(crate) end_position: u32, -} - -impl<'me, T: Item> Exprs<'me, T> { - pub(crate) fn new( - visitor: &'me FmtVisitor<'me>, - shape: Shape, - span: Span, - elements: Vec, - ) -> Self { - Self { - visitor, - shape, - last_position: span.start() + 1, /*(*/ - end_position: span.end() - 1, /*)*/ - elements: elements.into_iter().peekable(), - } - } -} - -impl Iterator for Exprs<'_, T> { - type Item = Expr; - - fn next(&mut self) -> Option { - let element = self.elements.next()?; - let element_span = element.span(); - - let start = self.last_position; - let end = element_span.start(); - - let is_last = self.elements.peek().is_none(); - let next_start = self.elements.peek().map_or(self.end_position, |expr| expr.start()); - - let (leading, different_line) = self.leading(start, end); - let expr = element.format(self.visitor, self.shape); - let trailing = self.trailing(element_span.end(), next_start, is_last); - - Expr { leading, value: expr, trailing, different_line }.into() - } -} - -impl<'me, T> Exprs<'me, T> { - pub(crate) fn leading(&mut self, start: u32, end: u32) -> (String, bool) { - let mut different_line = false; - - let leading = self.visitor.slice(start..end); - let leading_trimmed = leading.trim(); - - let starts_with_block_comment = leading_trimmed.starts_with("/*"); - let ends_with_block_comment = leading_trimmed.ends_with("*/"); - let starts_with_single_line_comment = leading_trimmed.starts_with("//"); - - if ends_with_block_comment { - let comment_end = leading_trimmed.rfind(|c| c == '/').unwrap(); - - if leading[comment_end..].contains('\n') { - different_line = true; - } - } else if starts_with_single_line_comment || starts_with_block_comment { - different_line = true; - }; - - (leading_trimmed.to_string(), different_line) - } - - pub(crate) fn trailing(&mut self, start: u32, end: u32, is_last: bool) -> String { - let slice = self.visitor.slice(start..end); - let comment_end = find_comment_end(slice, is_last); - let trailing = slice[..comment_end].trim_matches(',').trim(); - self.last_position = start + (comment_end as u32); - trailing.to_string() - } -} - pub(crate) trait FindToken { fn find_token(&self, token: Token) -> Option; fn find_token_with(&self, f: impl Fn(&Token) -> bool) -> Option; @@ -183,7 +87,7 @@ pub(crate) fn find_comment_end(slice: &str, is_last: bool) -> usize { } } -fn comment_len(comment: &str) -> usize { +pub(crate) fn comment_len(comment: &str) -> usize { match comment { "" => 0, _ => { @@ -201,21 +105,7 @@ pub(crate) fn count_newlines(slice: &str) -> usize { bytecount::count(slice.as_bytes(), b'\n') } -pub(crate) trait Item { - fn span(&self) -> Span; - - fn format(self, visitor: &FmtVisitor, shape: Shape) -> String; - - fn start(&self) -> u32 { - self.span().start() - } - - fn end(&self) -> u32 { - self.span().end() - } -} - -impl Item for Expression { +impl HasItem for Expression { fn span(&self) -> Span { self.span } @@ -225,7 +115,7 @@ impl Item for Expression { } } -impl Item for (Ident, Expression) { +impl HasItem for (Ident, Expression) { fn span(&self) -> Span { let (name, value) = self; (name.span().start()..value.span.end()).into() @@ -245,25 +135,29 @@ impl Item for (Ident, Expression) { } } -impl Item for Param { +impl HasItem for Param { fn span(&self) -> Span { self.span } fn format(self, visitor: &FmtVisitor, shape: Shape) -> String { + let pattern = visitor.slice(self.pattern.span()); let visibility = match self.visibility { Visibility::Public => "pub ", Visibility::Private => "", Visibility::DataBus => "call_data", }; - let pattern = visitor.slice(self.pattern.span()); - let ty = rewrite::typ(visitor, shape, self.typ); - format!("{pattern}: {visibility}{ty}") + if self.pattern.is_synthesized() || self.typ.is_synthesized() { + pattern.to_string() + } else { + let ty = rewrite::typ(visitor, shape, self.typ); + format!("{pattern}: {visibility}{ty}") + } } } -impl Item for Ident { +impl HasItem for Ident { fn span(&self) -> Span { self.span() } diff --git a/tooling/nargo_fmt/src/visitor.rs b/tooling/nargo_fmt/src/visitor.rs index 85989db79d8..db084e5a49d 100644 --- a/tooling/nargo_fmt/src/visitor.rs +++ b/tooling/nargo_fmt/src/visitor.rs @@ -277,7 +277,7 @@ impl Indent { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub(crate) struct Shape { pub(crate) width: usize, pub(crate) indent: Indent, diff --git a/tooling/nargo_fmt/src/visitor/expr.rs b/tooling/nargo_fmt/src/visitor/expr.rs index 586d9583e32..9b36911b1af 100644 --- a/tooling/nargo_fmt/src/visitor/expr.rs +++ b/tooling/nargo_fmt/src/visitor/expr.rs @@ -5,8 +5,9 @@ use noirc_frontend::{ use super::{ExpressionType, FmtVisitor, Shape}; use crate::{ + items::{HasItem, Item, Items}, rewrite, - utils::{self, first_line_width, Expr, FindToken, Item}, + utils::{first_line_width, FindToken}, Config, }; @@ -81,8 +82,7 @@ impl FmtVisitor<'_> { let nested_indent = visitor.shape(); let exprs: Vec<_> = - utils::Exprs::new(&visitor, nested_indent, fields_span, constructor.fields) - .collect(); + Items::new(&visitor, nested_indent, fields_span, constructor.fields).collect(); let exprs = format_exprs( visitor.config, Tactic::HorizontalVertical, @@ -189,7 +189,7 @@ impl FmtVisitor<'_> { // TODO: fixme #[allow(clippy::too_many_arguments)] -pub(crate) fn format_seq( +pub(crate) fn format_seq( shape: Shape, prefix: &str, suffix: &str, @@ -206,7 +206,7 @@ pub(crate) fn format_seq( nested_indent.indent.block_indent(visitor.config); - let exprs: Vec<_> = utils::Exprs::new(&visitor, nested_indent, span, exprs).collect(); + let exprs: Vec<_> = Items::new(&visitor, nested_indent, span, exprs).collect(); let exprs = format_exprs(visitor.config, tactic, trailing_comma, exprs, nested_indent, reduce); wrap_exprs(prefix, suffix, exprs, nested_indent, shape, mode) @@ -249,11 +249,11 @@ pub(crate) fn format_parens( format_seq(shape, "(", ")", visitor, trailing_comma, exprs, span, tactic, mode, reduce) } -fn format_exprs( +pub(crate) fn format_exprs( config: &Config, tactic: Tactic, trailing_comma: bool, - exprs: Vec, + exprs: Vec, shape: Shape, reduce: bool, ) -> String { @@ -396,7 +396,7 @@ pub(crate) enum Tactic { impl Tactic { fn definitive( self, - exprs: &[Expr], + exprs: &[Item], short_width_threshold: usize, reduce: bool, ) -> DefinitiveTactic { @@ -449,7 +449,7 @@ enum DefinitiveTactic { } impl DefinitiveTactic { - fn reduce(self, exprs: &[Expr], short_array_element_width_threshold: usize) -> Self { + fn reduce(self, exprs: &[Item], short_array_element_width_threshold: usize) -> Self { match self { DefinitiveTactic::Vertical if no_long_exprs(exprs, short_array_element_width_threshold) => @@ -467,7 +467,7 @@ fn has_single_line_comment(slice: &str) -> bool { slice.trim_start().starts_with("//") } -fn no_long_exprs(exprs: &[Expr], max_width: usize) -> bool { +fn no_long_exprs(exprs: &[Item], max_width: usize) -> bool { exprs.iter().all(|expr| expr.value.len() <= max_width) } diff --git a/tooling/nargo_fmt/src/visitor/item.rs b/tooling/nargo_fmt/src/visitor/item.rs index eb2086168ba..1825a6e05b0 100644 --- a/tooling/nargo_fmt/src/visitor/item.rs +++ b/tooling/nargo_fmt/src/visitor/item.rs @@ -6,7 +6,7 @@ use noirc_frontend::{ }; use crate::{ - rewrite, + rewrite::{self, UseTree}, utils::{last_line_contains_single_line_comment, last_line_used_width, FindToken}, visitor::expr::{format_seq, NewlineMode}, }; @@ -146,6 +146,9 @@ impl super::FmtVisitor<'_> { for Item { kind, span } in module.items { match kind { ItemKind::Function(func) => { + self.visit_function(span, func); + } + ItemKind::Submodules(module) => { self.format_missing_indent(span.start(), true); if std::mem::take(&mut self.ignore_next_node) { @@ -154,15 +157,27 @@ impl super::FmtVisitor<'_> { continue; } - let (fn_before_block, force_brace_newline) = - self.format_fn_before_block(func.clone(), span.start()); + let name = module.name; + let after_brace = self.span_after(span, Token::LeftBrace).start(); + self.last_position = after_brace; + + let keyword = if module.is_contract { "contract" } else { "mod" }; + + self.push_str(&format!("{keyword} {name} ")); - self.push_str(&fn_before_block); - self.push_str(if force_brace_newline { "\n" } else { " " }); + if module.contents.items.is_empty() { + self.visit_empty_block((after_brace - 1..span.end()).into()); + continue; + } else { + self.push_str("{"); + self.indent.block_indent(self.config); + self.visit_module(module.contents); + } - self.visit_block(func.def.body, func.def.span); + self.close_block((self.last_position..span.end() - 1).into()); + self.last_position = span.end(); } - ItemKind::Submodules(module) => { + ItemKind::Impl(impl_) => { self.format_missing_indent(span.start(), true); if std::mem::take(&mut self.ignore_next_node) { @@ -171,31 +186,37 @@ impl super::FmtVisitor<'_> { continue; } - let name = module.name; + let slice = + self.slice(self.last_position..impl_.object_type.span.unwrap().end()); let after_brace = self.span_after(span, Token::LeftBrace).start(); self.last_position = after_brace; - let keyword = if module.is_contract { "contract" } else { "mod" }; + self.push_str(&format!("{slice} ")); - self.push_str(&format!("{keyword} {name} ")); - - if module.contents.items.is_empty() { + if impl_.methods.is_empty() { self.visit_empty_block((after_brace - 1..span.end()).into()); continue; } else { self.push_str("{"); self.indent.block_indent(self.config); - self.visit_module(module.contents); - } - self.close_block((self.last_position..span.end() - 1).into()); + for (method, span) in impl_.methods { + self.visit_function(span, method); + } + + self.close_block((self.last_position..span.end() - 1).into()); + self.last_position = span.end(); + } + } + ItemKind::Import(use_tree) => { + let use_tree = + UseTree::from_ast(use_tree).rewrite_top_level(self, self.shape()); + self.push_rewrite(use_tree, span); self.last_position = span.end(); } - ItemKind::Import(_) - | ItemKind::Struct(_) + ItemKind::Struct(_) | ItemKind::Trait(_) | ItemKind::TraitImpl(_) - | ItemKind::Impl(_) | ItemKind::TypeAlias(_) | ItemKind::Global(_) | ItemKind::ModuleDecl(_) => { @@ -205,4 +226,18 @@ impl super::FmtVisitor<'_> { } } } + + fn visit_function(&mut self, span: Span, func: NoirFunction) { + self.format_missing_indent(span.start(), true); + if std::mem::take(&mut self.ignore_next_node) { + self.push_str(self.slice(span)); + self.last_position = span.end(); + return; + } + let (fn_before_block, force_brace_newline) = + self.format_fn_before_block(func.clone(), span.start()); + self.push_str(&fn_before_block); + self.push_str(if force_brace_newline { "\n" } else { " " }); + self.visit_block(func.def.body, func.def.span); + } } diff --git a/tooling/nargo_fmt/src/visitor/stmt.rs b/tooling/nargo_fmt/src/visitor/stmt.rs index b414e5ec5c3..44c5dad6b5d 100644 --- a/tooling/nargo_fmt/src/visitor/stmt.rs +++ b/tooling/nargo_fmt/src/visitor/stmt.rs @@ -38,7 +38,10 @@ impl super::FmtVisitor<'_> { nested_shape.indent.block_indent(self.config); - let message = message.map_or(String::new(), |message| format!(", {message}")); + let message = message.map_or(String::new(), |message| { + let message = rewrite::sub_expr(self, nested_shape, message); + format!(", {message}") + }); let (callee, args) = match kind { ConstrainKind::Assert | ConstrainKind::Constrain => { diff --git a/tooling/nargo_fmt/tests/expected/assert.nr b/tooling/nargo_fmt/tests/expected/assert.nr index 1f38e56b799..805e069c9a7 100644 --- a/tooling/nargo_fmt/tests/expected/assert.nr +++ b/tooling/nargo_fmt/tests/expected/assert.nr @@ -1,4 +1,5 @@ fn main(x: Field) { assert(x == 0, "with a message"); assert_eq(x, 1); + assert(x, message); } diff --git a/tooling/nargo_fmt/tests/expected/contract.nr b/tooling/nargo_fmt/tests/expected/contract.nr index 2e3f4d7c8c4..ed828289d22 100644 --- a/tooling/nargo_fmt/tests/expected/contract.nr +++ b/tooling/nargo_fmt/tests/expected/contract.nr @@ -5,18 +5,14 @@ contract Benchmarking { use dep::aztec::protocol_types::abis::function_selector::FunctionSelector; - use dep::value_note::{ - utils::{increment, decrement}, - value_note::{VALUE_NOTE_LEN, ValueNote, ValueNoteMethods}, - }; + use dep::value_note::{utils::{increment, decrement}, value_note::{VALUE_NOTE_LEN, ValueNote, ValueNoteMethods}}; use dep::aztec::{ context::{Context}, note::{utils as note_utils, note_getter_options::NoteGetterOptions, note_header::NoteHeader}, - log::emit_unencrypted_log, - state_vars::{map::Map, public_state::PublicState, set::Set}, + log::emit_unencrypted_log, state_vars::{map::Map, public_state::PublicState, set::Set}, types::type_serialization::field_serialization::{FieldSerializationMethods, FIELD_SERIALIZED_LEN}, - types::address::{AztecAddress}, + types::address::{AztecAddress} }; struct Storage { @@ -27,8 +23,16 @@ contract Benchmarking { impl Storage { fn init(context: Context) -> pub Self { Storage { - notes: Map::new(context, 1, |context, slot| { Set::new(context, slot, ValueNoteMethods) }), - balances: Map::new(context, 2, |context, slot| { PublicState::new(context, slot, FieldSerializationMethods) }), + notes: Map::new( + context, + 1, + |context, slot| { Set::new(context, slot, ValueNoteMethods) } + ), + balances: Map::new( + context, + 2, + |context, slot| { PublicState::new(context, slot, FieldSerializationMethods) } + ) } } } diff --git a/tooling/nargo_fmt/tests/expected/impl.nr b/tooling/nargo_fmt/tests/expected/impl.nr new file mode 100644 index 00000000000..1c0d4564b5e --- /dev/null +++ b/tooling/nargo_fmt/tests/expected/impl.nr @@ -0,0 +1,21 @@ +impl Type {} + +impl Type {} + +impl Type {} + +impl Type { + fn method(self) {} + + fn method(mut self) {} + + fn method(&mut self) {} +} + +impl Type { + fn method(self) {} +} + +impl Type { + fn method(self) {} +} diff --git a/tooling/nargo_fmt/tests/expected/struct.nr b/tooling/nargo_fmt/tests/expected/struct.nr index cf1795892d2..8fc642f7cd5 100644 --- a/tooling/nargo_fmt/tests/expected/struct.nr +++ b/tooling/nargo_fmt/tests/expected/struct.nr @@ -9,8 +9,8 @@ struct Pair { } impl Foo { - fn default(x: Field,y: Field) -> Self { - Self { bar: 0, array: [x,y] } + fn default(x: Field, y: Field) -> Self { + Self { bar: 0, array: [x, y] } } } diff --git a/tooling/nargo_fmt/tests/expected/vec.nr b/tooling/nargo_fmt/tests/expected/vec.nr index 1c9a791961e..466c9844e74 100644 --- a/tooling/nargo_fmt/tests/expected/vec.nr +++ b/tooling/nargo_fmt/tests/expected/vec.nr @@ -20,12 +20,12 @@ impl Vec { /// points beyond the end of the vector. pub fn get(self, index: Field) -> T { self.slice[index] - } + } /// Push a new element to the end of the vector, returning a /// new vector with a length one greater than the /// original unmodified vector. - pub fn push(&mut self, elem: T) { + pub fn push(&mut self, elem: T) { self.slice = self.slice.push_back(elem); } @@ -33,7 +33,7 @@ impl Vec { /// a new vector with a length of one less than the given vector, /// as well as the popped element. /// Panics if the given vector's length is zero. - pub fn pop(&mut self) -> T { + pub fn pop(&mut self) -> T { let (popped_slice, last_elem) = self.slice.pop_back(); self.slice = popped_slice; last_elem @@ -43,7 +43,7 @@ impl Vec { /// after it to the right pub fn insert(&mut self, index: Field, elem: T) { self.slice = self.slice.insert(index, elem); - } + } /// Remove an element at a specified index, shifting all elements /// after it to the left, returning the removed element diff --git a/tooling/nargo_fmt/tests/input/assert.nr b/tooling/nargo_fmt/tests/input/assert.nr index f41e396c041..d0259da0e24 100644 --- a/tooling/nargo_fmt/tests/input/assert.nr +++ b/tooling/nargo_fmt/tests/input/assert.nr @@ -4,4 +4,5 @@ fn main(x: Field) { x, 1 ); + assert( x, message ); } diff --git a/tooling/nargo_fmt/tests/input/impl.nr b/tooling/nargo_fmt/tests/input/impl.nr new file mode 100644 index 00000000000..1f111371a43 --- /dev/null +++ b/tooling/nargo_fmt/tests/input/impl.nr @@ -0,0 +1,21 @@ +impl Type {} + +impl Type {} + +impl Type {} + +impl Type { + fn method(self) {} + + fn method(mut self) {} + + fn method(&mut self) {} +} + +impl Type { +fn method(self) {} +} + +impl Type { + fn method(self) {} +} \ No newline at end of file diff --git a/tooling/noir_js/src/program.ts b/tooling/noir_js/src/program.ts index 809943727eb..8d80ec3a247 100644 --- a/tooling/noir_js/src/program.ts +++ b/tooling/noir_js/src/program.ts @@ -67,13 +67,13 @@ export class Noir { * * @example * ```typescript - * async generateFinalProof(input) + * async generateProof(input) * ``` * */ - async generateFinalProof(inputs: InputMap, foreignCallHandler?: ForeignCallHandler): Promise { + async generateProof(inputs: InputMap, foreignCallHandler?: ForeignCallHandler): Promise { const { witness } = await this.execute(inputs, foreignCallHandler); - return this.getBackend().generateFinalProof(witness); + return this.getBackend().generateProof(witness); } /** @@ -84,11 +84,11 @@ export class Noir { * * @example * ```typescript - * async verifyFinalProof(proof) + * async verifyProof(proof) * ``` * */ - async verifyFinalProof(proofData: ProofData): Promise { - return this.getBackend().verifyFinalProof(proofData); + async verifyProof(proofData: ProofData): Promise { + return this.getBackend().verifyProof(proofData); } } diff --git a/tooling/noir_js/test/node/e2e.test.ts b/tooling/noir_js/test/node/e2e.test.ts index 33d64377b06..8921314e8ea 100644 --- a/tooling/noir_js/test/node/e2e.test.ts +++ b/tooling/noir_js/test/node/e2e.test.ts @@ -21,10 +21,10 @@ it('end-to-end proof creation and verification (outer)', async () => { // // Proof creation const prover = new Backend(assert_lt_program); - const proof = await prover.generateFinalProof(witness); + const proof = await prover.generateProof(witness); // Proof verification - const isValid = await prover.verifyFinalProof(proof); + const isValid = await prover.verifyProof(proof); expect(isValid).to.be.true; }); @@ -40,13 +40,14 @@ it('end-to-end proof creation and verification (outer) -- Program API', async () // Initialize program const program = new Noir(assert_lt_program, backend); // Generate proof - const proof = await program.generateFinalProof(inputs); + const proof = await program.generateProof(inputs); // Proof verification - const isValid = await program.verifyFinalProof(proof); + const isValid = await program.verifyProof(proof); expect(isValid).to.be.true; }); +// TODO: maybe switch to using assert_statement_recursive here to test both options it('end-to-end proof creation and verification (inner)', async () => { // Noir.Js part const inputs = { @@ -62,10 +63,10 @@ it('end-to-end proof creation and verification (inner)', async () => { // // Proof creation const prover = new Backend(assert_lt_program); - const proof = await prover.generateIntermediateProof(witness); + const proof = await prover.generateProof(witness); // Proof verification - const isValid = await prover.verifyIntermediateProof(proof); + const isValid = await prover.verifyProof(proof); expect(isValid).to.be.true; }); @@ -83,10 +84,10 @@ it('end-to-end proving and verification with different instances', async () => { // bb.js part const prover = new Backend(assert_lt_program); - const proof = await prover.generateFinalProof(witness); + const proof = await prover.generateProof(witness); const verifier = new Backend(assert_lt_program); - const proof_is_valid = await verifier.verifyFinalProof(proof); + const proof_is_valid = await verifier.verifyProof(proof); expect(proof_is_valid).to.be.true; }); @@ -115,14 +116,14 @@ it('[BUG] -- bb.js null function or function signature mismatch (outer-inner) ', const prover = new Backend(assert_lt_program); // Create a proof using both proving systems, the majority of the time // one would only use outer proofs. - const proofOuter = await prover.generateFinalProof(witness); - const _proofInner = await prover.generateIntermediateProof(witness); + const proofOuter = await prover.generateProof(witness); + const _proofInner = await prover.generateProof(witness); // Proof verification // - const isValidOuter = await prover.verifyFinalProof(proofOuter); + const isValidOuter = await prover.verifyProof(proofOuter); expect(isValidOuter).to.be.true; // We can also try verifying an inner proof and it will fail. - const isValidInner = await prover.verifyIntermediateProof(_proofInner); + const isValidInner = await prover.verifyProof(_proofInner); expect(isValidInner).to.be.true; }); diff --git a/tooling/noir_js_backend_barretenberg/package.json b/tooling/noir_js_backend_barretenberg/package.json index a0123883efd..b8ab24a73bd 100644 --- a/tooling/noir_js_backend_barretenberg/package.json +++ b/tooling/noir_js_backend_barretenberg/package.json @@ -42,7 +42,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.21.0", + "@aztec/bb.js": "0.23.0", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/tooling/noir_js_backend_barretenberg/src/index.ts b/tooling/noir_js_backend_barretenberg/src/index.ts index 61094a3451f..d79b487c3cf 100644 --- a/tooling/noir_js_backend_barretenberg/src/index.ts +++ b/tooling/noir_js_backend_barretenberg/src/index.ts @@ -47,47 +47,14 @@ export class BarretenbergBackend implements Backend { } } - /** - * Generate a final proof. This is the proof for the circuit which will verify - * intermediate proofs and or can be seen as the proof created for regular circuits. - */ - async generateFinalProof(decompressedWitness: Uint8Array): Promise { - // The settings for this proof are the same as the settings for a "normal" proof - // i.e. one that is not in the recursive setting. - const makeEasyToVerifyInCircuit = false; - return this.generateProof(decompressedWitness, makeEasyToVerifyInCircuit); - } - - /** - * Generates an intermediate proof. This is the proof that can be verified - * in another circuit. - * - * This is sometimes referred to as a recursive proof. - * We avoid this terminology as the only property of this proof - * that matters is the fact that it is easy to verify in another circuit. - * We _could_ choose to verify this proof outside of a circuit just as easily. - * - * @example - * ```typescript - * const intermediateProof = await backend.generateIntermediateProof(witness); - * ``` - */ - async generateIntermediateProof(witness: Uint8Array): Promise { - // We set `makeEasyToVerifyInCircuit` to true, which will tell the backend to - // generate the proof using components that will make the proof - // easier to verify in a circuit. - const makeEasyToVerifyInCircuit = true; - return this.generateProof(witness, makeEasyToVerifyInCircuit); - } - - /** @ignore */ - async generateProof(compressedWitness: Uint8Array, makeEasyToVerifyInCircuit: boolean): Promise { + /** @description Generates a proof */ + async generateProof(compressedWitness: Uint8Array): Promise { await this.instantiate(); + // TODO: Change once `@aztec/bb.js` version is updated to use methods without isRecursive flag const proofWithPublicInputs = await this.api.acirCreateProof( this.acirComposer, this.acirUncompressedBytecode, gunzip(compressedWitness), - makeEasyToVerifyInCircuit, ); const splitIndex = proofWithPublicInputs.length - numBytesInProofWithoutPublicInputs; @@ -105,17 +72,17 @@ export class BarretenbergBackend implements Backend { * Instead of passing the proof and verification key as a byte array, we pass them * as fields which makes it cheaper to verify in a circuit. * - * The proof that is passed here will have been created using the `generateIntermediateProof` - * method. + * The proof that is passed here will have been created using a circuit + * that has the #[recursive] attribute on its `main` method. * * The number of public inputs denotes how many public inputs are in the inner proof. * * @example * ```typescript - * const artifacts = await backend.generateIntermediateProofArtifacts(proof, numOfPublicInputs); + * const artifacts = await backend.generateRecursiveProofArtifacts(proof, numOfPublicInputs); * ``` */ - async generateIntermediateProofArtifacts( + async generateRecursiveProofArtifacts( proofData: ProofData, numOfPublicInputs = 0, ): Promise<{ @@ -143,31 +110,13 @@ export class BarretenbergBackend implements Backend { }; } - async verifyFinalProof(proofData: ProofData): Promise { + /** @description Verifies a proof */ + async verifyProof(proofData: ProofData): Promise { const proof = reconstructProofWithPublicInputs(proofData); - const makeEasyToVerifyInCircuit = false; - const verified = await this.verifyProof(proof, makeEasyToVerifyInCircuit); - return verified; - } - - /** - * - * @example - * ```typescript - * const isValidIntermediate = await backend.verifyIntermediateProof(proof); - * ``` - */ - async verifyIntermediateProof(proofData: ProofData): Promise { - const proof = reconstructProofWithPublicInputs(proofData); - const makeEasyToVerifyInCircuit = true; - return this.verifyProof(proof, makeEasyToVerifyInCircuit); - } - - /** @ignore */ - async verifyProof(proof: Uint8Array, makeEasyToVerifyInCircuit: boolean): Promise { await this.instantiate(); await this.api.acirInitVerificationKey(this.acirComposer); - return await this.api.acirVerifyProof(this.acirComposer, proof, makeEasyToVerifyInCircuit); + // TODO: Change once `@aztec/bb.js` version is updated to use methods without isRecursive flag + return await this.api.acirVerifyProof(this.acirComposer, proof); } async destroy(): Promise { diff --git a/tooling/noir_js_types/package.json b/tooling/noir_js_types/package.json index ef75f3d2fb3..6ec0e772f67 100644 --- a/tooling/noir_js_types/package.json +++ b/tooling/noir_js_types/package.json @@ -38,9 +38,6 @@ "types": "./lib/esm/types.d.ts" } }, - "dependencies": { - "@noir-lang/noirc_abi": "workspace:*" - }, "devDependencies": { "@types/prettier": "^3", "eslint": "^8.50.0", diff --git a/tooling/noir_js_types/src/types.ts b/tooling/noir_js_types/src/types.ts index ee4921bd606..3a62d79a807 100644 --- a/tooling/noir_js_types/src/types.ts +++ b/tooling/noir_js_types/src/types.ts @@ -1,21 +1,44 @@ -import { Abi } from '@noir-lang/noirc_abi'; +export type Field = string | number | boolean; +export type InputValue = Field | InputMap | (Field | InputMap)[]; +export type InputMap = { [key: string]: InputValue }; -export { Abi, WitnessMap } from '@noir-lang/noirc_abi'; +export type Visibility = 'public' | 'private' | 'databus'; +export type Sign = 'unsigned' | 'signed'; +export type AbiType = + | { kind: 'field' } + | { kind: 'boolean' } + | { kind: 'string'; length: number } + | { kind: 'integer'; sign: Sign; width: number } + | { kind: 'array'; length: number; type: AbiType } + | { kind: 'tuple'; fields: AbiType[] } + | { kind: 'struct'; path: string; fields: { name: string; type: AbiType }[] }; -export interface Backend { - /** - * @description Generates a final proof (not meant to be verified in another circuit) */ - generateFinalProof(decompressedWitness: Uint8Array): Promise; +export type AbiParameter = { + name: string; + type: AbiType; + visibility: Visibility; +}; + +// Map from witness index to hex string value of witness. +export type WitnessMap = Map; +export type Abi = { + parameters: AbiParameter[]; + param_witnesses: Record; + return_type: { abi_type: AbiType; visibility: Visibility } | null; + return_witnesses: number[]; +}; + +export interface Backend { /** - * @description Generates an intermediate proof (meant to be verified in another circuit) */ - generateIntermediateProof(decompressedWitness: Uint8Array): Promise; + * @description Generates a proof */ + generateProof(decompressedWitness: Uint8Array): Promise; /** * * @description Retrieves the artifacts from a proof in the Field format */ - generateIntermediateProofArtifacts( + generateRecursiveProofArtifacts( proofData: ProofData, numOfPublicInputs: number, ): Promise<{ @@ -28,11 +51,8 @@ export interface Backend { }>; /** - * @description Verifies a final proof */ - verifyFinalProof(proofData: ProofData): Promise; - - /** @description Verifies an intermediate proof */ - verifyIntermediateProof(proofData: ProofData): Promise; + * @description Verifies a proof */ + verifyProof(proofData: ProofData): Promise; /** * @description Destroys the backend */ diff --git a/tooling/noirc_abi_wasm/package.json b/tooling/noirc_abi_wasm/package.json index db0f6c29153..f829543b9aa 100644 --- a/tooling/noirc_abi_wasm/package.json +++ b/tooling/noirc_abi_wasm/package.json @@ -37,6 +37,9 @@ "build:nix": "nix build -L .#noirc_abi_wasm", "install:from:nix": "yarn clean && yarn build:nix && cp -rL ./result/noirc_abi_wasm/nodejs ./ && cp -rL ./result/noirc_abi_wasm/web ./" }, + "dependencies": { + "@noir-lang/types": "workspace:*" + }, "devDependencies": { "@esm-bundle/chai": "^4.3.4-fix.0", "@web/dev-server-esbuild": "^0.3.6", diff --git a/tooling/noirc_abi_wasm/src/js_witness_map.rs b/tooling/noirc_abi_wasm/src/js_witness_map.rs index fcc6e75f18c..293c5c089f8 100644 --- a/tooling/noirc_abi_wasm/src/js_witness_map.rs +++ b/tooling/noirc_abi_wasm/src/js_witness_map.rs @@ -7,12 +7,6 @@ use acvm::{ use js_sys::{JsString, Map}; use wasm_bindgen::prelude::{wasm_bindgen, JsValue}; -#[wasm_bindgen(typescript_custom_section)] -const WITNESS_MAP: &'static str = r#" -// Map from witness index to hex string value of witness. -export type WitnessMap = Map; -"#; - // WitnessMap #[wasm_bindgen] extern "C" { diff --git a/tooling/noirc_abi_wasm/src/lib.rs b/tooling/noirc_abi_wasm/src/lib.rs index 5557cc917bf..ce15f6d502e 100644 --- a/tooling/noirc_abi_wasm/src/lib.rs +++ b/tooling/noirc_abi_wasm/src/lib.rs @@ -26,9 +26,8 @@ use js_witness_map::JsWitnessMap; #[wasm_bindgen(typescript_custom_section)] const INPUT_MAP: &'static str = r#" -export type Field = string | number | boolean; -export type InputValue = Field | InputMap | (Field | InputMap)[]; -export type InputMap = { [key: string]: InputValue }; +import { Field, InputValue, InputMap, Visibility, Sign, AbiType, AbiParameter, Abi, WitnessMap } from "@noir-lang/types"; +export { Field, InputValue, InputMap, Visibility, Sign, AbiType, AbiParameter, Abi, WitnessMap } from "@noir-lang/types"; "#; #[wasm_bindgen] @@ -36,44 +35,11 @@ extern "C" { #[wasm_bindgen(extends = js_sys::Object, js_name = "InputMap", typescript_type = "InputMap")] #[derive(Clone, Debug, PartialEq, Eq)] pub type JsInputMap; -} -#[wasm_bindgen] -extern "C" { #[wasm_bindgen(extends = js_sys::Object, js_name = "InputValue", typescript_type = "InputValue")] #[derive(Clone, Debug, PartialEq, Eq)] pub type JsInputValue; -} -#[wasm_bindgen(typescript_custom_section)] -const ABI: &'static str = r#" -export type Visibility = "public" | "private" | "databus"; -export type Sign = "unsigned" | "signed"; -export type AbiType = - { kind: "field" } | - { kind: "boolean" } | - { kind: "string", length: number } | - { kind: "integer", sign: Sign, width: number } | - { kind: "array", length: number, type: AbiType } | - { kind: "tuple", fields: AbiType[] } | - { kind: "struct", path: string, fields: { name: string, type: AbiType }[] }; - -export type AbiParameter = { - name: string, - type: AbiType, - visibility: Visibility, -}; - -export type Abi = { - parameters: AbiParameter[], - param_witnesses: Record, - return_type: {abi_type: AbiType, visibility: Visibility} | null, - return_witnesses: number[], -} -"#; - -#[wasm_bindgen] -extern "C" { #[wasm_bindgen(extends = js_sys::Object, js_name = "Abi", typescript_type = "Abi")] #[derive(Clone, Debug, PartialEq, Eq)] pub type JsAbi; diff --git a/yarn.lock b/yarn.lock index 743068f1907..a83bc234e1d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,23 +221,9 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.16.0": - version: 0.16.0 - resolution: "@aztec/bb.js@npm:0.16.0" - dependencies: - comlink: ^4.4.1 - commander: ^10.0.1 - debug: ^4.3.4 - tslib: ^2.4.0 - bin: - bb.js: dest/node/main.js - checksum: 5f68b4ad16284a3a871e0ad21fea05aed670383bc639c9d07ab3bf9b7a9d15cc8a4e5cda404a9290775ad5023924739543a8aac37d602892dd1fb5087521970b - languageName: node - linkType: hard - -"@aztec/bb.js@npm:0.21.0": - version: 0.21.0 - resolution: "@aztec/bb.js@npm:0.21.0" +"@aztec/bb.js@npm:0.23.0": + version: 0.23.0 + resolution: "@aztec/bb.js@npm:0.23.0" dependencies: comlink: ^4.4.1 commander: ^10.0.1 @@ -245,7 +231,7 @@ __metadata: tslib: ^2.4.0 bin: bb.js: dest/node/main.js - checksum: a0fb97476f52025f3c31b7a5e890966ac375ed47c5cfd3434f5c3e4265af3c7566a162f37d6c56f394f44bfe4ba67e5002b7c5998ecc4f6abe70e04f5b8abe34 + checksum: e7bd32a20575a2834fa8a0500becdfae88a8f4a031c0f1796713d64a8ec90e516e16360f19031efeec59d51ede78c50422982ee08911c062bfa3142819af01fc languageName: node linkType: hard @@ -4175,30 +4161,6 @@ __metadata: languageName: node linkType: hard -"@monaco-editor/loader@npm:^1.4.0": - version: 1.4.0 - resolution: "@monaco-editor/loader@npm:1.4.0" - dependencies: - state-local: ^1.0.6 - peerDependencies: - monaco-editor: ">= 0.21.0 < 1" - checksum: 374ec0ea872ee15b33310e105a43217148161480d3955c5cece87d0f801754cd2c45a3f6c539a75da18a066c1615756fb87eaf1003f1df6a64a0cbce5d2c3749 - languageName: node - linkType: hard - -"@monaco-editor/react@npm:4.6.0": - version: 4.6.0 - resolution: "@monaco-editor/react@npm:4.6.0" - dependencies: - "@monaco-editor/loader": ^1.4.0 - peerDependencies: - monaco-editor: ">= 0.25.0 < 1" - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 9d44e76c5baad6db5f84c90a5540fbd3c9af691b97d76cf2a99b3c8273004d0efe44c2572d80e9d975c9af10022c21e4a66923924950a5201e82017c8b20428c - languageName: node - linkType: hard - "@noble/curves@npm:1.2.0": version: 1.2.0 resolution: "@noble/curves@npm:1.2.0" @@ -4395,13 +4357,6 @@ __metadata: languageName: node linkType: hard -"@noir-lang/acvm_js@npm:0.38.0": - version: 0.38.0 - resolution: "@noir-lang/acvm_js@npm:0.38.0" - checksum: 42a5bba45135d1df0d0eb3f7b65439733e016580bad610e859e140638d42200d6b856ff11c4b30417b74ce011da7c39861aafb1c5b8c7211de2172aea449c635 - languageName: node - linkType: hard - "@noir-lang/acvm_js@workspace:*, @noir-lang/acvm_js@workspace:acvm-repo/acvm_js": version: 0.0.0-use.local resolution: "@noir-lang/acvm_js@workspace:acvm-repo/acvm_js" @@ -4420,22 +4375,11 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/backend_barretenberg@npm:^0.22.0": - version: 0.22.0 - resolution: "@noir-lang/backend_barretenberg@npm:0.22.0" - dependencies: - "@aztec/bb.js": 0.16.0 - "@noir-lang/types": 0.22.0 - fflate: ^0.8.0 - checksum: ead456218ba61d925e0fc5b47d1b94272e980b44a220f1262fb6cdc73cff7cd4232ddc69dd67bb21e50f0b43e7696d4a96fde15e3eadc0bf223ec6d59e014e23 - languageName: node - linkType: hard - "@noir-lang/backend_barretenberg@workspace:*, @noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg": version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": 0.21.0 + "@aztec/bb.js": 0.23.0 "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3 @@ -4475,17 +4419,6 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/noir_js@npm:^0.22.0": - version: 0.22.0 - resolution: "@noir-lang/noir_js@npm:0.22.0" - dependencies: - "@noir-lang/acvm_js": 0.38.0 - "@noir-lang/noirc_abi": 0.22.0 - "@noir-lang/types": 0.22.0 - checksum: 3b0873ad87521415af11208bebe5690191d03fa06dcd515789f0a63f7641146cdcb01d292b208452856ea3967e196c8332cb2618e013f9e7e5ce7d6e09de043d - languageName: node - linkType: hard - "@noir-lang/noir_js@workspace:*, @noir-lang/noir_js@workspace:tooling/noir_js": version: 0.0.0-use.local resolution: "@noir-lang/noir_js@workspace:tooling/noir_js" @@ -4509,13 +4442,6 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/noir_wasm@npm:^0.22.0": - version: 0.22.0 - resolution: "@noir-lang/noir_wasm@npm:0.22.0" - checksum: 7ac0ca170bf312df761d7ccfd32a67a27f88f15ad4eed1807864295d761d3b2176ffb82f4c6931e1bc06b225d6f738519962c79ffbce9a33d5ef8a6a2bdea82c - languageName: node - linkType: hard - "@noir-lang/noir_wasm@workspace:*, @noir-lang/noir_wasm@workspace:compiler/wasm": version: 0.0.0-use.local resolution: "@noir-lang/noir_wasm@workspace:compiler/wasm" @@ -4523,6 +4449,7 @@ __metadata: "@esm-bundle/chai": ^4.3.4-fix.0 "@ltd/j-toml": ^1.38.0 "@noir-lang/noirc_abi": "workspace:*" + "@noir-lang/types": "workspace:*" "@types/adm-zip": ^0.5.0 "@types/chai": ^4 "@types/mocha": ^10.0.6 @@ -4560,18 +4487,12 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/noirc_abi@npm:0.22.0": - version: 0.22.0 - resolution: "@noir-lang/noirc_abi@npm:0.22.0" - checksum: a250c6cc5ca37fcf02663f8d6b027776f0e58920fb8f8a84efcf74f079f235bb11bbad682ba332211d9b9a79b6a3eb7faede7701cd88582b682971a41ca6212d - languageName: node - linkType: hard - "@noir-lang/noirc_abi@workspace:*, @noir-lang/noirc_abi@workspace:tooling/noirc_abi_wasm": version: 0.0.0-use.local resolution: "@noir-lang/noirc_abi@workspace:tooling/noirc_abi_wasm" dependencies: "@esm-bundle/chai": ^4.3.4-fix.0 + "@noir-lang/types": "workspace:*" "@web/dev-server-esbuild": ^0.3.6 "@web/test-runner": ^0.15.3 "@web/test-runner-playwright": ^0.10.0 @@ -4597,20 +4518,10 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/types@npm:0.22.0, @noir-lang/types@npm:^0.22.0": - version: 0.22.0 - resolution: "@noir-lang/types@npm:0.22.0" - dependencies: - "@noir-lang/noirc_abi": 0.22.0 - checksum: 5dd1badf0449c518e755172de1d2f2c1b95bfaf7b7328b7de00b8ce9ba68bd447ca65e827185da7d737e7e88dcaf296b29687ffe2e1f5b4d5cc31ce3e3b4f208 - languageName: node - linkType: hard - "@noir-lang/types@workspace:*, @noir-lang/types@workspace:tooling/noir_js_types": version: 0.0.0-use.local resolution: "@noir-lang/types@workspace:tooling/noir_js_types" dependencies: - "@noir-lang/noirc_abi": "workspace:*" "@types/prettier": ^3 eslint: ^8.50.0 eslint-plugin-prettier: ^5.0.0 @@ -5326,26 +5237,6 @@ __metadata: languageName: node linkType: hard -"@signorecello/noir_playground@npm:^0.7.0": - version: 0.7.0 - resolution: "@signorecello/noir_playground@npm:0.7.0" - dependencies: - "@monaco-editor/react": 4.6.0 - "@noir-lang/backend_barretenberg": ^0.22.0 - "@noir-lang/noir_js": ^0.22.0 - "@noir-lang/noir_wasm": ^0.22.0 - "@noir-lang/types": ^0.22.0 - fflate: ^0.8.1 - js-base64: ^3.7.5 - monaco-editor: ^0.44.0 - monaco-editor-textmate: ^4.0.0 - monaco-textmate: ^3.0.1 - onigasm: ^2.2.5 - react-toastify: ^9.1.3 - checksum: 360bd1dbc8964a6ab8a6e8d0eb0cd11d7446cc23bf63c253083b18b5d6d5ccf2ec6ca847614106cd93490bb815aac651a6e4584ac63ea0fda182cdb1aadf3f45 - languageName: node - linkType: hard - "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -10337,7 +10228,6 @@ __metadata: "@noir-lang/noir_js": "workspace:*" "@noir-lang/noirc_abi": "workspace:*" "@noir-lang/types": "workspace:*" - "@signorecello/noir_playground": ^0.7.0 "@types/prettier": ^3 axios: ^1.4.0 clsx: ^1.2.1 @@ -11499,13 +11389,6 @@ __metadata: languageName: node linkType: hard -"fast-plist@npm:^0.1.2": - version: 0.1.3 - resolution: "fast-plist@npm:0.1.3" - checksum: e879f548db3a1fc89c654c476e9c9846f4335fdcd2283ec99e5f234c897f5616cee2a0a4201bf4b64ab6269e75c09daafc3933bd4a038c85af943fac0f113caa - languageName: node - linkType: hard - "fast-url-parser@npm:1.1.3": version: 1.1.3 resolution: "fast-url-parser@npm:1.1.3" @@ -11567,7 +11450,7 @@ __metadata: languageName: node linkType: hard -"fflate@npm:^0.8.0, fflate@npm:^0.8.1": +"fflate@npm:^0.8.0": version: 0.8.1 resolution: "fflate@npm:0.8.1" checksum: 7207e2d333243724485d2488095256b776184bd4545aa9967b655feaee5dc18e9525ed9b6d75f94cfd71d98fb285336f4902641683472f1d0c19a99137084cec @@ -14077,13 +13960,6 @@ __metadata: languageName: node linkType: hard -"js-base64@npm:^3.7.5": - version: 3.7.5 - resolution: "js-base64@npm:3.7.5" - checksum: 67a78c8b1c47b73f1c6fba1957e9fe6fd9dc78ac93ac46cc2e43472dcb9cf150d126fb0e593192e88e0497354fa634d17d255add7cc6ee3c7b4d29870faa8e18 - languageName: node - linkType: hard - "js-sdsl@npm:^4.1.4": version: 4.4.2 resolution: "js-sdsl@npm:4.4.2" @@ -16249,34 +16125,6 @@ __metadata: languageName: node linkType: hard -"monaco-editor-textmate@npm:^4.0.0": - version: 4.0.0 - resolution: "monaco-editor-textmate@npm:4.0.0" - peerDependencies: - monaco-editor: 0.x.x - monaco-textmate: ^3.0.0 - checksum: 9d3f5f24982f928c5f4b7c5c5170a549cb19eb1471eb157aa07bd97cf15cd75dd941585eeb6924b05c54109a55d48adc45191eda9db5d2793b1d8c462181c100 - languageName: node - linkType: hard - -"monaco-editor@npm:^0.44.0": - version: 0.44.0 - resolution: "monaco-editor@npm:0.44.0" - checksum: 6e561b23e5e9090cbdbb820dae5895a8bf9d537acc09281756a8c428960da0481461c72f387cc9a2e14bff69ab4359186c98df2dd29d6d109f1ab7189b573a35 - languageName: node - linkType: hard - -"monaco-textmate@npm:^3.0.1": - version: 3.0.1 - resolution: "monaco-textmate@npm:3.0.1" - dependencies: - fast-plist: ^0.1.2 - peerDependencies: - onigasm: ^2.0.0 - checksum: 0f2ec07ee3e9a37bb880e2aaef802f82cb666660b40fc3c7c3e35553d740aed34ae94399b06296fddf1f96efdaf27eaf347b39cb14bc08ccfb65162c52771d56 - languageName: node - linkType: hard - "mrmime@npm:^1.0.0": version: 1.0.1 resolution: "mrmime@npm:1.0.1" @@ -16708,15 +16556,6 @@ __metadata: languageName: node linkType: hard -"onigasm@npm:^2.2.5": - version: 2.2.5 - resolution: "onigasm@npm:2.2.5" - dependencies: - lru-cache: ^5.1.1 - checksum: 97aedde610ef561f05853609d6a5b720ec1e123f867bdac1b38b5aeb3bc90ed60209678c75a5f0f9821aa793c720b6d17aabfb956e26ab115ee9b81d6e56bdf7 - languageName: node - linkType: hard - "only@npm:~0.0.2": version: 0.0.2 resolution: "only@npm:0.0.2" @@ -18335,18 +18174,6 @@ __metadata: languageName: node linkType: hard -"react-toastify@npm:^9.1.3": - version: 9.1.3 - resolution: "react-toastify@npm:9.1.3" - dependencies: - clsx: ^1.1.1 - peerDependencies: - react: ">=16" - react-dom: ">=16" - checksum: e8bd92c5cbf831b43a042644ab9bc69abe6ceb3ce91ba71f5cd2d8b6a2c9885ca52770e1f1ba64c5632607f6df962db344a26c7fba57606faf5aa0e7bfc8535f - languageName: node - linkType: hard - "react@npm:^18.2.0": version: 18.2.0 resolution: "react@npm:18.2.0" @@ -19869,13 +19696,6 @@ __metadata: languageName: node linkType: hard -"state-local@npm:^1.0.6": - version: 1.0.7 - resolution: "state-local@npm:1.0.7" - checksum: d1afcf1429e7e6eb08685b3a94be8797db847369316d4776fd51f3962b15b984dacc7f8e401ad20968e5798c9565b4b377afedf4e4c4d60fe7495e1cbe14a251 - languageName: node - linkType: hard - "state-toggle@npm:^1.0.0": version: 1.0.3 resolution: "state-toggle@npm:1.0.3" From 39d7d564d740fc9be3c2a1a3845f2eaf22e54f4d Mon Sep 17 00:00:00 2001 From: Koby Date: Mon, 12 Feb 2024 11:53:40 +0100 Subject: [PATCH 06/36] chore: remove globals for now --- compiler/noirc_frontend/src/locations.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index 43a2e06febc..614f26f506c 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -79,11 +79,9 @@ impl NodeInterner { let reference_node = self.graph_references[node_index]; let found_locations: Vec = match reference_node.0 { DependencyId::Alias(_) | DependencyId::Struct(_) | DependencyId::Global(_) => todo!(), - DependencyId::Function(_) | DependencyId::GlobalDefinition(_) => { - self.get_edit_locations(node_index) - } + DependencyId::Function(_) => self.get_edit_locations(node_index), - DependencyId::GlobalReference | DependencyId::FunctionCall => { + DependencyId::FunctionCall => { let mut edit_locations: Vec = Vec::new(); if let Some(referenced_node_index) = self .graph_references From d77236c875d13c03448989f0a9556f7040076d2a Mon Sep 17 00:00:00 2001 From: Koby Date: Mon, 12 Feb 2024 12:15:55 +0100 Subject: [PATCH 07/36] chore: clippy --- .../src/hir/def_collector/dc_crate.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 55643389383..0ada23f16e6 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -398,15 +398,12 @@ fn add_import_refrence( // We ignore empty spans at 0 lcoation, this must be Stdlib return; } - match ns { - crate::macros_api::ModuleDefId::FunctionId(func_id) => { - interner.add_reference_for( - DependencyId::Function(func_id), - (DependencyId::FunctionCall, Location::new(name.span(), file_id)), - ); - } - _ => (), - }; + if let crate::macros_api::ModuleDefId::FunctionId(func_id) = ns { + interner.add_reference_for( + DependencyId::Function(func_id), + (DependencyId::FunctionCall, Location::new(name.span(), file_id)), + ); + } } fn inject_prelude( From 2d124bdd8574c6deb2fadd9d688fc85d622be210 Mon Sep 17 00:00:00 2001 From: Koby Date: Mon, 12 Feb 2024 12:22:22 +0100 Subject: [PATCH 08/36] chore: clippy - unnecesary ret --- tooling/lsp/src/requests/rename.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 0342f1c78f0..14ca799a93d 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -133,10 +133,8 @@ fn on_rename_inner( span: noirc_errors::Span::single_char(byte_index as u32), }; - let rename_changes = interner - .find_rename_symbols_at(search_for_location) - // .get_definition_location_from(search_for_location, false) - .and_then(|locations| { + let rename_changes = + interner.find_rename_symbols_at(search_for_location).and_then(|locations| { let rs = locations.iter().fold( HashMap::new(), |mut acc: HashMap>, location| { @@ -152,7 +150,7 @@ fn on_rename_inner( acc.entry(lsp_location.uri).or_insert_with(Vec::new).push(edit); - return acc; + acc }, ); Some(rs) From 09e898f8238d7fce0949271a6decec03d1459ce3 Mon Sep 17 00:00:00 2001 From: Koby Date: Mon, 12 Feb 2024 12:24:07 +0100 Subject: [PATCH 09/36] chore: clippy - map instead and_then --- tooling/lsp/src/requests/rename.rs | 33 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 14ca799a93d..2621c215418 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -133,28 +133,27 @@ fn on_rename_inner( span: noirc_errors::Span::single_char(byte_index as u32), }; - let rename_changes = - interner.find_rename_symbols_at(search_for_location).and_then(|locations| { - let rs = locations.iter().fold( - HashMap::new(), - |mut acc: HashMap>, location| { - let file_id = location.file; - let span = location.span; - - let Some(lsp_location) = to_lsp_location(files, file_id, span) else { + let rename_changes = interner.find_rename_symbols_at(search_for_location).map(|locations| { + let rs = locations.iter().fold( + HashMap::new(), + |mut acc: HashMap>, location| { + let file_id = location.file; + let span = location.span; + + let Some(lsp_location) = to_lsp_location(files, file_id, span) else { return acc; }; - let edit = - TextEdit { range: lsp_location.range, new_text: params.new_name.clone() }; + let edit = + TextEdit { range: lsp_location.range, new_text: params.new_name.clone() }; - acc.entry(lsp_location.uri).or_insert_with(Vec::new).push(edit); + acc.entry(lsp_location.uri).or_insert_with(Vec::new).push(edit); - acc - }, - ); - Some(rs) - }); + acc + }, + ); + rs + }); let response = WorkspaceEdit { changes: rename_changes, document_changes: None, change_annotations: None }; From ab455b132d38a58ad7433bca222a5e0b87a6aa76 Mon Sep 17 00:00:00 2001 From: Koby Date: Mon, 12 Feb 2024 18:26:39 +0100 Subject: [PATCH 10/36] chore: review nits --- .../src/hir/def_collector/dc_crate.rs | 12 ++++++------ .../noirc_frontend/src/hir/resolution/resolver.rs | 2 -- compiler/noirc_frontend/src/locations.rs | 13 ++++--------- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 0ada23f16e6..44160f0a1e0 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -283,7 +283,7 @@ impl DefCollector { .import(name.clone(), ns, resolved_import.is_prelude); let file_id = current_def_map.file_id(module_id); - add_import_refrence(ns, &name, &mut context.def_interner, file_id); + add_import_reference(ns, &name, &mut context.def_interner, file_id); if let Err((first_def, second_def)) = result { let err = DefCollectorErrorKind::Duplicate { @@ -388,17 +388,17 @@ impl DefCollector { } } -fn add_import_refrence( - ns: crate::macros_api::ModuleDefId, +fn add_import_reference( + def_id: crate::macros_api::ModuleDefId, name: &Ident, interner: &mut NodeInterner, file_id: FileId, ) { - if name.span().start() == 0 && name.span().end() == 0 { - // We ignore empty spans at 0 lcoation, this must be Stdlib + if name.span() == Span::empty(0) { + // We ignore empty spans at 0 location, this must be Stdlib return; } - if let crate::macros_api::ModuleDefId::FunctionId(func_id) = ns { + if let crate::macros_api::ModuleDefId::FunctionId(func_id) = def_id { interner.add_reference_for( DependencyId::Function(func_id), (DependencyId::FunctionCall, Location::new(name.span(), file_id)), diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 1d75e16e5d1..cfe5792a8de 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1419,8 +1419,6 @@ impl<'a> Resolver<'a> { // If the expression is a singular indent, we search the resolver's current scope as normal. let (hir_ident, var_scope_index) = self.get_ident_from_path(path.clone()); - // tracing::debug!("Resolved variable: {:?}", hir_ident); - if hir_ident.id != DefinitionId::dummy_id() { match self.interner.definition(hir_ident.id).kind { DefinitionKind::Function(id) => { diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index 614f26f506c..40fe5647bc9 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -74,23 +74,18 @@ impl NodeInterner { pub fn find_rename_symbols_at(&self, location: Location) -> Option> { let node_index = self.location_store.get_node_from_location(location)?; - // let mut edit_locations: Vec = Vec::new(); - let reference_node = self.graph_references[node_index]; let found_locations: Vec = match reference_node.0 { DependencyId::Alias(_) | DependencyId::Struct(_) | DependencyId::Global(_) => todo!(), DependencyId::Function(_) => self.get_edit_locations(node_index), DependencyId::FunctionCall => { - let mut edit_locations: Vec = Vec::new(); - if let Some(referenced_node_index) = self + let referenced_node_index = self .graph_references .neighbors_directed(node_index, petgraph::Direction::Incoming) - .next() - { - edit_locations.extend(self.get_edit_locations(referenced_node_index)); - } - edit_locations + .next()?; + + self.get_edit_locations(referenced_node_index) } }; Some(found_locations) From d7cd372f56972a32052401551a92bb0d053a9480 Mon Sep 17 00:00:00 2001 From: Koby Date: Mon, 12 Feb 2024 18:36:16 +0100 Subject: [PATCH 11/36] chore: spells --- compiler/noirc_frontend/src/locations.rs | 2 +- compiler/noirc_frontend/src/node_interner.rs | 4 ++-- cspell.json | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index 40fe5647bc9..f88c9f3d31a 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -48,7 +48,7 @@ impl NodeInterner { self.location_store.add_location(reference.1, reference_index); } - pub(crate) fn add_definiton(&mut self, referenced: (DependencyId, Location)) { + pub(crate) fn add_definition(&mut self, referenced: (DependencyId, Location)) { let referenced_index = self.get_or_insert_reference(referenced); self.location_store.add_location(referenced.1, referenced_index); } diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index e4ac2161792..d76c71bd7d7 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -61,7 +61,7 @@ pub struct NodeInterner { function_modules: HashMap, /// This graph tracks dependencies between different global definitions. - /// This is used to ensure the absense of dependency cycles for globals and types. + /// This is used to ensure the absence of dependency cycles for globals and types. dependency_graph: DiGraph, /// To keep track of where each DependencyId is in `dependency_graph`, we need @@ -800,7 +800,7 @@ impl NodeInterner { contract_function_type: Some(if function.is_open { Open } else { Secret }), is_internal: Some(function.is_internal), }; - self.add_definiton(( + self.add_definition(( DependencyId::Function(id), Location::new(function.name.span(), location.file), )); diff --git a/cspell.json b/cspell.json index 34424647616..40ec49c1c71 100644 --- a/cspell.json +++ b/cspell.json @@ -87,6 +87,7 @@ "indexmap", "injective", "Inlines", + "Instrumenter", "interner", "intrinsics", "jmp", @@ -102,6 +103,7 @@ "lvalue", "Maddiaa", "mathbb", + "memfs", "merkle", "metas", "minreq", @@ -127,6 +129,7 @@ "nouner", "pedersen", "peekable", + "petgraph", "plonkc", "PLONKish", "pprof", @@ -136,6 +139,7 @@ "pseudocode", "pubkey", "quantile", + "rangemap", "repr", "reqwest", "rfind", @@ -157,6 +161,7 @@ "subtyping", "swcurve", "Taiko", + "tarjan", "tecurve", "tempdir", "tempfile", @@ -174,6 +179,7 @@ "urem", "USERPROFILE", "vecmap", + "vitkov", "wasi", "wasmer", "Weierstraß", From 4421a2d403228727a2dda61008331fa1e721599f Mon Sep 17 00:00:00 2001 From: Koby Date: Tue, 13 Feb 2024 09:15:42 +0100 Subject: [PATCH 12/36] chore: name change --- compiler/noirc_frontend/src/locations.rs | 26 ++++++++++---------- compiler/noirc_frontend/src/node_interner.rs | 8 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index f88c9f3d31a..449a09095d0 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -30,8 +30,8 @@ impl NodeInterner { reference: (DependencyId, Location), ) { let referenced_index = self.get_or_insert_reference(referenced); - let reference_index = self.graph_references.add_node((reference.0, reference.1)); - self.graph_references.add_edge(referenced_index, reference_index, ()); + let reference_index = self.references_graph.add_node((reference.0, reference.1)); + self.references_graph.add_edge(referenced_index, reference_index, ()); self.location_store.add_location(referenced.1, referenced_index); self.location_store.add_location(reference.1, reference_index); } @@ -41,10 +41,10 @@ impl NodeInterner { referenced_id: DependencyId, reference: (DependencyId, Location), ) { - let Some(referenced_index) = self.graph_references_indices.get(&referenced_id) else { panic!("Compiler Error: Referenced index not found") }; + let Some(referenced_index) = self.references_graph_indices.get(&referenced_id) else { panic!("Compiler Error: Referenced index not found") }; - let reference_index = self.graph_references.add_node((reference.0, reference.1)); - self.graph_references.add_edge(*referenced_index, reference_index, ()); + let reference_index = self.references_graph.add_node((reference.0, reference.1)); + self.references_graph.add_edge(*referenced_index, reference_index, ()); self.location_store.add_location(reference.1, reference_index); } @@ -58,12 +58,12 @@ impl NodeInterner { &mut self, (id, location): (DependencyId, Location), ) -> PetGraphIndex { - if let Some(index) = self.graph_references_indices.get(&id) { + if let Some(index) = self.references_graph_indices.get(&id) { return *index; } - let index = self.graph_references.add_node((id, location)); - self.graph_references_indices.insert(id, index); + let index = self.references_graph.add_node((id, location)); + self.references_graph_indices.insert(id, index); index } @@ -74,14 +74,14 @@ impl NodeInterner { pub fn find_rename_symbols_at(&self, location: Location) -> Option> { let node_index = self.location_store.get_node_from_location(location)?; - let reference_node = self.graph_references[node_index]; + let reference_node = self.references_graph[node_index]; let found_locations: Vec = match reference_node.0 { DependencyId::Alias(_) | DependencyId::Struct(_) | DependencyId::Global(_) => todo!(), DependencyId::Function(_) => self.get_edit_locations(node_index), DependencyId::FunctionCall => { let referenced_node_index = self - .graph_references + .references_graph .neighbors_directed(node_index, petgraph::Direction::Incoming) .next()?; @@ -93,14 +93,14 @@ impl NodeInterner { fn get_edit_locations(&self, referenced_node_index: PetGraphIndex) -> Vec { let mut edit_locations: Vec = Vec::new(); - let (_referenced_id, referencing_location) = self.graph_references[referenced_node_index]; + let (_referenced_id, referencing_location) = self.references_graph[referenced_node_index]; edit_locations.push(referencing_location); - self.graph_references + self.references_graph .neighbors_directed(referenced_node_index, petgraph::Direction::Outgoing) .for_each(|reference_node_index| { let (_reference_dependency_id, reference_location) = - self.graph_references[reference_node_index]; + self.references_graph[reference_node_index]; edit_locations.push(reference_location); }); edit_locations diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index d76c71bd7d7..14f41aea1ae 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -170,9 +170,9 @@ pub struct NodeInterner { pub(crate) type_ref_locations: Vec<(Type, Location)>, /// Store the location of the references in the graph - pub(crate) graph_references: DiGraph<(DependencyId, Location), ()>, + pub(crate) references_graph: DiGraph<(DependencyId, Location), ()>, /// Tracks the index of the references in the graph - pub(crate) graph_references_indices: HashMap, + pub(crate) references_graph_indices: HashMap, /// Store the location of the references in the graph pub(crate) location_store: LocationStore, } @@ -522,8 +522,8 @@ impl Default for NodeInterner { type_alias_ref: Vec::new(), type_ref_locations: Vec::new(), location_store: LocationStore::default(), - graph_references: petgraph::graph::DiGraph::new(), - graph_references_indices: HashMap::new(), + references_graph: petgraph::graph::DiGraph::new(), + references_graph_indices: HashMap::new(), }; // An empty block expression is used often, we add this into the `node` on startup From d564ac827dbfa4a5eee31a89e62d17223ed45851 Mon Sep 17 00:00:00 2001 From: Koby Date: Tue, 13 Feb 2024 09:18:53 +0100 Subject: [PATCH 13/36] chore: name change --- compiler/noirc_frontend/src/locations.rs | 16 ++++++++-------- compiler/noirc_frontend/src/node_interner.rs | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index 449a09095d0..f3900b64931 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -7,11 +7,11 @@ use crate::{macros_api::NodeInterner, node_interner::DependencyId}; use petgraph::prelude::NodeIndex as PetGraphIndex; #[derive(Debug, Default)] -pub(crate) struct LocationStore { +pub(crate) struct LocationIndices { map_file_to_range: FxHashMap>, } -impl LocationStore { +impl LocationIndices { pub(crate) fn add_location(&mut self, location: Location, node_index: PetGraphIndex) { let range_map = self.map_file_to_range.entry(location.file).or_insert_with(RangeMap::new); range_map.insert(location.span.start()..location.span.end(), node_index); @@ -32,8 +32,8 @@ impl NodeInterner { let referenced_index = self.get_or_insert_reference(referenced); let reference_index = self.references_graph.add_node((reference.0, reference.1)); self.references_graph.add_edge(referenced_index, reference_index, ()); - self.location_store.add_location(referenced.1, referenced_index); - self.location_store.add_location(reference.1, reference_index); + self.location_indices.add_location(referenced.1, referenced_index); + self.location_indices.add_location(reference.1, reference_index); } pub(crate) fn add_reference_for( @@ -45,12 +45,12 @@ impl NodeInterner { let reference_index = self.references_graph.add_node((reference.0, reference.1)); self.references_graph.add_edge(*referenced_index, reference_index, ()); - self.location_store.add_location(reference.1, reference_index); + self.location_indices.add_location(reference.1, reference_index); } pub(crate) fn add_definition(&mut self, referenced: (DependencyId, Location)) { let referenced_index = self.get_or_insert_reference(referenced); - self.location_store.add_location(referenced.1, referenced_index); + self.location_indices.add_location(referenced.1, referenced_index); } #[tracing::instrument(skip(self), ret)] @@ -68,11 +68,11 @@ impl NodeInterner { } pub fn check_rename_possible(&self, location: Location) -> bool { - self.location_store.get_node_from_location(location).is_some() + self.location_indices.get_node_from_location(location).is_some() } pub fn find_rename_symbols_at(&self, location: Location) -> Option> { - let node_index = self.location_store.get_node_from_location(location)?; + let node_index = self.location_indices.get_node_from_location(location)?; let reference_node = self.references_graph[node_index]; let found_locations: Vec = match reference_node.0 { diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 14f41aea1ae..34e950b8c57 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -26,7 +26,7 @@ use crate::hir_def::{ function::{FuncMeta, HirFunction}, stmt::HirStatement, }; -use crate::locations::LocationStore; +use crate::locations::LocationIndices; use crate::token::{Attributes, SecondaryAttribute}; use crate::{ BinaryOpKind, ContractFunctionType, FunctionDefinition, FunctionVisibility, Generics, Shared, @@ -174,7 +174,7 @@ pub struct NodeInterner { /// Tracks the index of the references in the graph pub(crate) references_graph_indices: HashMap, /// Store the location of the references in the graph - pub(crate) location_store: LocationStore, + pub(crate) location_indices: LocationIndices, } /// A dependency in the dependency graph may be a type or a definition. @@ -521,7 +521,7 @@ impl Default for NodeInterner { primitive_methods: HashMap::new(), type_alias_ref: Vec::new(), type_ref_locations: Vec::new(), - location_store: LocationStore::default(), + location_indices: LocationIndices::default(), references_graph: petgraph::graph::DiGraph::new(), references_graph_indices: HashMap::new(), }; From f0b81a20659a61924fcb2aab7f315f7f621899e9 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 13 Feb 2024 15:17:53 -0600 Subject: [PATCH 14/36] Fix bug with renaming imported functions from submodules --- .../src/hir/def_collector/dc_crate.rs | 6 +- .../src/hir/def_collector/dc_mod.rs | 3 +- .../src/hir/resolution/resolver.rs | 13 ++-- compiler/noirc_frontend/src/locations.rs | 75 ++++++++++--------- compiler/noirc_frontend/src/node_interner.rs | 28 ++++--- 5 files changed, 70 insertions(+), 55 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 44160f0a1e0..7ad2be704e7 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -399,10 +399,8 @@ fn add_import_reference( return; } if let crate::macros_api::ModuleDefId::FunctionId(func_id) = def_id { - interner.add_reference_for( - DependencyId::Function(func_id), - (DependencyId::FunctionCall, Location::new(name.span(), file_id)), - ); + let variable = DependencyId::Variable(Location::new(name.span(), file_id)); + interner.add_reference_for(DependencyId::Function(func_id), variable); } } diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 77224cc311c..0a4f720c859 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -392,6 +392,7 @@ impl<'a> ModCollector<'a> { let func_id = context.def_interner.push_empty_fn(); method_ids.insert(name.to_string(), func_id); + let location = Location::new(name.span(), self.file_id); let modifiers = FunctionModifiers { name: name.to_string(), visibility: crate::FunctionVisibility::Public, @@ -400,9 +401,9 @@ impl<'a> ModCollector<'a> { is_unconstrained: false, contract_function_type: None, is_internal: None, + name_location: location, }; - let location = Location::new(name.span(), self.file_id); context .def_interner .push_function_definition(func_id, modifiers, trait_id.0, location); diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index cfe5792a8de..6954d5da58d 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1437,17 +1437,18 @@ impl<'a> Resolver<'a> { ); } - if let Some(func_meta) = self.interner.func_meta.get(&id) { - self.interner.add_reference( - (DependencyId::Function(id), func_meta.location), - (DependencyId::FunctionCall, hir_ident.location), - ); - } + let variable = DependencyId::Variable(hir_ident.location); + let function = DependencyId::Function(id); + self.interner.add_reference(function, variable); } DefinitionKind::Global(global_id) => { if let Some(current_item) = self.current_item { self.interner.add_global_dependency(current_item, global_id); } + + let variable = DependencyId::Variable(hir_ident.location); + let global = DependencyId::Global(global_id); + self.interner.add_reference(global, variable); } DefinitionKind::GenericType(_) => { // Initialize numeric generics to a polymorphic integer type in case diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index f3900b64931..a7c8e640a62 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -24,46 +24,55 @@ impl LocationIndices { } impl NodeInterner { - pub(crate) fn add_reference( - &mut self, - referenced: (DependencyId, Location), - reference: (DependencyId, Location), - ) { + pub fn dependency_location(&self, dependency: DependencyId) -> Location { + match dependency { + DependencyId::Function(id) => self.function_modifiers(&id).name_location, + DependencyId::Struct(id) => self.get_struct(id).borrow().location, + DependencyId::Global(id) => self.get_global(id).location, + DependencyId::Alias(id) => self.get_type_alias(id).location, + DependencyId::Variable(location) => location, + } + } + + pub(crate) fn add_reference(&mut self, referenced: DependencyId, reference: DependencyId) { let referenced_index = self.get_or_insert_reference(referenced); - let reference_index = self.references_graph.add_node((reference.0, reference.1)); - self.references_graph.add_edge(referenced_index, reference_index, ()); - self.location_indices.add_location(referenced.1, referenced_index); - self.location_indices.add_location(reference.1, reference_index); + let reference_index = self.reference_graph.add_node(reference); + + let referenced_location = self.dependency_location(referenced); + let reference_location = self.dependency_location(reference); + + self.reference_graph.add_edge(referenced_index, reference_index, ()); + self.location_indices.add_location(referenced_location, referenced_index); + self.location_indices.add_location(reference_location, reference_index); } pub(crate) fn add_reference_for( &mut self, referenced_id: DependencyId, - reference: (DependencyId, Location), + reference: DependencyId, ) { - let Some(referenced_index) = self.references_graph_indices.get(&referenced_id) else { panic!("Compiler Error: Referenced index not found") }; + let Some(referenced_index) = self.reference_graph_indices.get(&referenced_id) else { panic!("Compiler Error: Referenced index not found") }; - let reference_index = self.references_graph.add_node((reference.0, reference.1)); - self.references_graph.add_edge(*referenced_index, reference_index, ()); - self.location_indices.add_location(reference.1, reference_index); + let reference_location = self.dependency_location(reference); + let reference_index = self.reference_graph.add_node(reference); + self.reference_graph.add_edge(*referenced_index, reference_index, ()); + self.location_indices.add_location(reference_location, reference_index); } - pub(crate) fn add_definition(&mut self, referenced: (DependencyId, Location)) { + pub(crate) fn add_definition_location(&mut self, referenced: DependencyId) { let referenced_index = self.get_or_insert_reference(referenced); - self.location_indices.add_location(referenced.1, referenced_index); + let referenced_location = self.dependency_location(referenced); + self.location_indices.add_location(referenced_location, referenced_index); } #[tracing::instrument(skip(self), ret)] - pub(crate) fn get_or_insert_reference( - &mut self, - (id, location): (DependencyId, Location), - ) -> PetGraphIndex { - if let Some(index) = self.references_graph_indices.get(&id) { + pub(crate) fn get_or_insert_reference(&mut self, id: DependencyId) -> PetGraphIndex { + if let Some(index) = self.reference_graph_indices.get(&id) { return *index; } - let index = self.references_graph.add_node((id, location)); - self.references_graph_indices.insert(id, index); + let index = self.reference_graph.add_node(id); + self.reference_graph_indices.insert(id, index); index } @@ -74,14 +83,14 @@ impl NodeInterner { pub fn find_rename_symbols_at(&self, location: Location) -> Option> { let node_index = self.location_indices.get_node_from_location(location)?; - let reference_node = self.references_graph[node_index]; - let found_locations: Vec = match reference_node.0 { + let reference_node = self.reference_graph[node_index]; + let found_locations: Vec = match reference_node { DependencyId::Alias(_) | DependencyId::Struct(_) | DependencyId::Global(_) => todo!(), DependencyId::Function(_) => self.get_edit_locations(node_index), - DependencyId::FunctionCall => { + DependencyId::Variable(_) => { let referenced_node_index = self - .references_graph + .reference_graph .neighbors_directed(node_index, petgraph::Direction::Incoming) .next()?; @@ -92,16 +101,14 @@ impl NodeInterner { } fn get_edit_locations(&self, referenced_node_index: PetGraphIndex) -> Vec { - let mut edit_locations: Vec = Vec::new(); - let (_referenced_id, referencing_location) = self.references_graph[referenced_node_index]; - edit_locations.push(referencing_location); + let id = self.reference_graph[referenced_node_index]; + let mut edit_locations = vec![self.dependency_location(id)]; - self.references_graph + self.reference_graph .neighbors_directed(referenced_node_index, petgraph::Direction::Outgoing) .for_each(|reference_node_index| { - let (_reference_dependency_id, reference_location) = - self.references_graph[reference_node_index]; - edit_locations.push(reference_location); + let id = self.reference_graph[reference_node_index]; + edit_locations.push(self.dependency_location(id)); }); edit_locations } diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 34e950b8c57..77b5e1df78f 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -170,9 +170,11 @@ pub struct NodeInterner { pub(crate) type_ref_locations: Vec<(Type, Location)>, /// Store the location of the references in the graph - pub(crate) references_graph: DiGraph<(DependencyId, Location), ()>, + pub(crate) reference_graph: DiGraph, + /// Tracks the index of the references in the graph - pub(crate) references_graph_indices: HashMap, + pub(crate) reference_graph_indices: HashMap, + /// Store the location of the references in the graph pub(crate) location_indices: LocationIndices, } @@ -193,7 +195,7 @@ pub enum DependencyId { Global(GlobalId), Function(FuncId), Alias(TypeAliasId), - FunctionCall, + Variable(Location), } /// A trait implementation is either a normal implementation that is present in the source @@ -257,6 +259,9 @@ pub struct FunctionModifiers { /// If this function is internal can only be called by itself. /// Will be None if not in contract. pub is_internal: Option, + + /// The location of the function's name rather than the entire function + pub name_location: Location, } impl FunctionModifiers { @@ -271,6 +276,7 @@ impl FunctionModifiers { is_unconstrained: false, is_internal: None, contract_function_type: None, + name_location: Location::dummy(), } } } @@ -522,8 +528,8 @@ impl Default for NodeInterner { type_alias_ref: Vec::new(), type_ref_locations: Vec::new(), location_indices: LocationIndices::default(), - references_graph: petgraph::graph::DiGraph::new(), - references_graph_indices: HashMap::new(), + reference_graph: petgraph::graph::DiGraph::new(), + reference_graph_indices: HashMap::new(), }; // An empty block expression is used often, we add this into the `node` on startup @@ -799,12 +805,14 @@ impl NodeInterner { is_unconstrained: function.is_unconstrained, contract_function_type: Some(if function.is_open { Open } else { Secret }), is_internal: Some(function.is_internal), + name_location: Location::new(function.name.span(), location.file), }; - self.add_definition(( - DependencyId::Function(id), - Location::new(function.name.span(), location.file), - )); - self.push_function_definition(id, modifiers, module, location) + let definition_id = self.push_function_definition(id, modifiers, module, location); + + // This needs to be done after pushing the definition since it will reference the + // location that was stored + self.add_definition_location(DependencyId::Function(id)); + definition_id } pub fn push_function_definition( From 0b0eca72fda9897a8c07826916e09972f9b40b7f Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 13 Feb 2024 15:30:16 -0600 Subject: [PATCH 15/36] Add unreachable cases --- .../src/hir/resolution/resolver.rs | 17 ++++++----------- compiler/noirc_frontend/src/node_interner.rs | 10 ++++++++-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 6954d5da58d..fccd39a54de 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1421,24 +1421,19 @@ impl<'a> Resolver<'a> { if hir_ident.id != DefinitionId::dummy_id() { match self.interner.definition(hir_ident.id).kind { - DefinitionKind::Function(id) => { + DefinitionKind::Function(func_id) => { if let Some(current_item) = self.current_item { - self.interner.add_function_dependency(current_item, id); + self.interner.add_function_dependency(current_item, func_id); } - if self.interner.function_visibility(id) - != FunctionVisibility::Public - { + let visibility = self.interner.function_visibility(func_id); + if visibility != FunctionVisibility::Public { let span = hir_ident.location.span; - self.check_can_reference_function( - id, - span, - self.interner.function_visibility(id), - ); + self.check_can_reference_function(func_id, span, visibility); } let variable = DependencyId::Variable(hir_ident.location); - let function = DependencyId::Function(id); + let function = DependencyId::Function(func_id); self.interner.add_reference(function, variable); } DefinitionKind::Global(global_id) => { diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 77b5e1df78f..e421c5b26a4 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -1614,7 +1614,11 @@ impl NodeInterner { } // Mutually recursive functions are allowed DependencyId::Function(_) => (), - _ => (), + // Local variables should never be in a dependency cycle, scoping rules + // prevents referring to them before they're defined + DependencyId::Variable(loc) => unreachable!( + "Variable used at location {loc:?} caught in a dependency cycle" + ), } } } @@ -1636,7 +1640,9 @@ impl NodeInterner { DependencyId::Global(id) => { Cow::Borrowed(self.get_global(id).ident.0.contents.as_ref()) } - _ => Cow::Borrowed(""), + DependencyId::Variable(loc) => { + unreachable!("Variable used at location {loc:?} caught in a dependency cycle") + } }; let mut cycle = index_to_string(scc[start_index]).to_string(); From 33b50dc8f15a5125634bbff2c069834c258fcb8c Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 13 Feb 2024 15:32:54 -0600 Subject: [PATCH 16/36] Fix merge --- compiler/noirc_frontend/src/locations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index a7c8e640a62..157b48fbdbb 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -29,7 +29,7 @@ impl NodeInterner { DependencyId::Function(id) => self.function_modifiers(&id).name_location, DependencyId::Struct(id) => self.get_struct(id).borrow().location, DependencyId::Global(id) => self.get_global(id).location, - DependencyId::Alias(id) => self.get_type_alias(id).location, + DependencyId::Alias(id) => self.get_type_alias(id).borrow().location, DependencyId::Variable(location) => location, } } From 0802086195ffea0adb4ae43b863f152dcd95abae Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Thu, 22 Feb 2024 13:23:51 +0000 Subject: [PATCH 17/36] clippy --- compiler/noirc_frontend/src/locations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index 157b48fbdbb..22f018a6958 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -13,7 +13,7 @@ pub(crate) struct LocationIndices { impl LocationIndices { pub(crate) fn add_location(&mut self, location: Location, node_index: PetGraphIndex) { - let range_map = self.map_file_to_range.entry(location.file).or_insert_with(RangeMap::new); + let range_map = self.map_file_to_range.entry(location.file).or_default(); range_map.insert(location.span.start()..location.span.end(), node_index); } From a9b785c7fc712b1c1ef17ebdd63a82122547f2af Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Thu, 22 Feb 2024 14:39:04 +0000 Subject: [PATCH 18/36] Fmt and clippy --- compiler/noirc_frontend/src/locations.rs | 4 +++- tooling/lsp/src/requests/rename.rs | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index 22f018a6958..acd3abf87c6 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -51,7 +51,9 @@ impl NodeInterner { referenced_id: DependencyId, reference: DependencyId, ) { - let Some(referenced_index) = self.reference_graph_indices.get(&referenced_id) else { panic!("Compiler Error: Referenced index not found") }; + let Some(referenced_index) = self.reference_graph_indices.get(&referenced_id) else { + panic!("Compiler Error: Referenced index not found") + }; let reference_location = self.dependency_location(reference); let reference_index = self.reference_graph.add_node(reference); diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 2621c215418..eb283d61ae8 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -141,13 +141,13 @@ fn on_rename_inner( let span = location.span; let Some(lsp_location) = to_lsp_location(files, file_id, span) else { - return acc; - }; + return acc; + }; let edit = TextEdit { range: lsp_location.range, new_text: params.new_name.clone() }; - acc.entry(lsp_location.uri).or_insert_with(Vec::new).push(edit); + acc.entry(lsp_location.uri).or_default().push(edit); acc }, From d598adfbd3a3daea0d1e86976ce3dda6cc4f1eab Mon Sep 17 00:00:00 2001 From: Tom French Date: Tue, 25 Jun 2024 17:07:01 +0100 Subject: [PATCH 19/36] chore: fix merge --- .../src/hir/def_collector/dc_crate.rs | 16 ---------------- .../src/hir/resolution/resolver.rs | 6 ------ tooling/lsp/src/requests/rename.rs | 4 ++-- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 675de2bc0bf..d0145aeb626 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -475,22 +475,6 @@ fn add_import_reference( } } -fn add_import_reference( - def_id: crate::macros_api::ModuleDefId, - name: &Ident, - interner: &mut NodeInterner, - file_id: FileId, -) { - if name.span() == Span::empty(0) { - // We ignore empty spans at 0 location, this must be Stdlib - return; - } - if let crate::macros_api::ModuleDefId::FunctionId(func_id) = def_id { - let variable = DependencyId::Variable(Location::new(name.span(), file_id)); - interner.add_reference_for(DependencyId::Function(func_id), variable); - } -} - fn inject_prelude( crate_id: CrateId, context: &Context, diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 43bc0660bc6..cdf03c57520 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1519,12 +1519,6 @@ impl<'a> Resolver<'a> { self.interner.add_function_dependency(current_item, func_id); } - let visibility = self.interner.function_visibility(func_id); - if visibility != FunctionVisibility::Public { - let span = hir_ident.location.span; - self.check_can_reference_function(func_id, span, visibility); - } - let variable = DependencyId::Variable(hir_ident.location); let function = DependencyId::Function(func_id); self.interner.add_reference(function, variable); diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index eb283d61ae8..e85cb9cd53c 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -47,7 +47,7 @@ fn on_prepare_rename_inner( interner = def_interner; } else { // We ignore the warnings and errors produced by compilation while resolving the definition - let _ = noirc_driver::check_crate(&mut context, crate_id, false, false); + let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, false); interner = &context.def_interner; } @@ -109,7 +109,7 @@ fn on_rename_inner( interner = def_interner; } else { // We ignore the warnings and errors produced by compilation while resolving the definition - let _ = noirc_driver::check_crate(&mut context, crate_id, false, false); + let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, false); interner = &context.def_interner; } From 7724b01114d177cd2e59ef3c60cda466bedeb208 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 27 Jun 2024 14:32:35 -0300 Subject: [PATCH 20/36] Add tests for lsp rename, and use the legacy resolver to make them work --- tooling/lsp/src/requests/rename.rs | 145 ++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 2 deletions(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index e85cb9cd53c..9bac898fbbd 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -47,7 +47,7 @@ fn on_prepare_rename_inner( interner = def_interner; } else { // We ignore the warnings and errors produced by compilation while resolving the definition - let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, false); + let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, true); interner = &context.def_interner; } @@ -109,7 +109,7 @@ fn on_rename_inner( interner = def_interner; } else { // We ignore the warnings and errors produced by compilation while resolving the definition - let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, false); + let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, true); interner = &context.def_interner; } @@ -160,3 +160,144 @@ fn on_rename_inner( Ok(Some(response)) } + +#[cfg(test)] +mod rename_tests { + use super::*; + use acvm::blackbox_solver::StubbedBlackBoxSolver; + use async_lsp::ClientSocket; + use lsp_types::{Position, Range, WorkDoneProgressParams}; + use tokio::test; + + async fn setup() -> (LspState, Url) { + let client = ClientSocket::new_closed(); + let mut state = LspState::new(&client, StubbedBlackBoxSolver); + + let root_path = std::env::current_dir() + .unwrap() + .join("../../test_programs/execution_success/7_function") + .canonicalize() + .expect("Could not resolve root path"); + let noir_text_document = Url::from_file_path(root_path.join("src/main.nr").as_path()) + .expect("Could not convert text document path to URI"); + let root_uri = Some( + Url::from_file_path(root_path.as_path()).expect("Could not convert root path to URI"), + ); + + #[allow(deprecated)] + let initialize_params = lsp_types::InitializeParams { + process_id: Default::default(), + root_path: None, + root_uri, + initialization_options: None, + capabilities: Default::default(), + trace: Some(lsp_types::TraceValue::Verbose), + workspace_folders: None, + client_info: None, + locale: None, + }; + + let _initialize_response = crate::requests::on_initialize(&mut state, initialize_params) + .await + .expect("Could not initialize LSP server"); + + (state, noir_text_document) + } + + #[test] + async fn test_on_prepare_rename_request_cannot_be_applied() { + let (mut state, noir_text_document) = setup().await; + + let params = TextDocumentPositionParams { + text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, + position: lsp_types::Position { line: 0, character: 0 }, // This is at the "f" of an "fn" keyword + }; + + let response = on_prepare_rename_request(&mut state, params) + .await + .expect("Could not execute on_prepare_rename_request"); + + assert_eq!( + response, + Some(PrepareRenameResponse::DefaultBehavior { default_behavior: false }) + ); + } + + #[test] + async fn test_on_prepare_rename_request_can_be_applied_at_function_declaration() { + let (mut state, noir_text_document) = setup().await; + + let params = TextDocumentPositionParams { + text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, + position: lsp_types::Position { line: 70, character: 3 }, // This is at the "t" of "test_multiple4" + }; + + let response = on_prepare_rename_request(&mut state, params) + .await + .expect("Could not execute on_prepare_rename_request"); + + assert_eq!( + response, + Some(PrepareRenameResponse::DefaultBehavior { default_behavior: true }) + ); + } + + #[test] + async fn test_on_prepare_rename_request_can_be_applied_at_function_reference() { + let (mut state, noir_text_document) = setup().await; + + let params = TextDocumentPositionParams { + text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, + position: lsp_types::Position { line: 79, character: 4 }, // This is at the "t" of "test_multiple4" + }; + + let response = on_prepare_rename_request(&mut state, params) + .await + .expect("Could not execute on_prepare_rename_request"); + + assert_eq!( + response, + Some(PrepareRenameResponse::DefaultBehavior { default_behavior: true }) + ); + } + + #[test] + async fn test_on_rename_request() { + let (mut state, noir_text_document) = setup().await; + + let params = RenameParams { + text_document_position: TextDocumentPositionParams { + text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, + position: lsp_types::Position { line: 79, character: 4 }, // This is at the "t" of "test_multiple4" + }, + new_name: "renamed_test_multiple4".to_string(), + work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, + }; + + let response = on_rename_request(&mut state, params) + .await + .expect("Could not execute on_prepare_rename_request") + .unwrap(); + + let changes = response.changes.expect("Expected to find rename changes"); + let mut changes: Vec = changes.values().flatten().map(|edit| edit.range).collect(); + changes.sort_by_key(|range| range.start.line); + assert_eq!( + changes, + vec![ + Range { + start: Position { line: 70, character: 3 }, + end: Position { line: 70, character: 17 }, + }, + Range { + start: Position { line: 79, character: 4 }, + end: Position { line: 79, character: 18 }, + }, + Range { + start: Position { line: 94, character: 4 }, + end: Position { line: 94, character: 18 }, + }, + ] + ); + } +} From d18e0a9ffa3bd57332ca4736ad632b67d3f9f803 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 27 Jun 2024 14:48:18 -0300 Subject: [PATCH 21/36] Implement lsp rename using elaborator --- compiler/noirc_frontend/src/elaborator/patterns.rs | 14 +++++++++++--- tooling/lsp/src/requests/rename.rs | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index 4f04f5c523c..6966cc50152 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -14,7 +14,7 @@ use crate::{ stmt::HirPattern, }, macros_api::{HirExpression, Ident, Path, Pattern}, - node_interner::{DefinitionId, DefinitionKind, ExprId, GlobalId, TraitImplKind}, + node_interner::{DefinitionId, DefinitionKind, DependencyId, ExprId, GlobalId, TraitImplKind}, Shared, StructType, Type, TypeBindings, }; @@ -418,10 +418,14 @@ impl<'context> Elaborator<'context> { if hir_ident.id != DefinitionId::dummy_id() { match self.interner.definition(hir_ident.id).kind { - DefinitionKind::Function(id) => { + DefinitionKind::Function(func_id) => { if let Some(current_item) = self.current_item { - self.interner.add_function_dependency(current_item, id); + self.interner.add_function_dependency(current_item, func_id); } + + let variable = DependencyId::Variable(hir_ident.location); + let function = DependencyId::Function(func_id); + self.interner.add_reference(function, variable); } DefinitionKind::Global(global_id) => { if let Some(global) = self.unresolved_globals.remove(&global_id) { @@ -430,6 +434,10 @@ impl<'context> Elaborator<'context> { if let Some(current_item) = self.current_item { self.interner.add_global_dependency(current_item, global_id); } + + let variable = DependencyId::Variable(hir_ident.location); + let global = DependencyId::Global(global_id); + self.interner.add_reference(global, variable); } DefinitionKind::GenericType(_) => { // Initialize numeric generics to a polymorphic integer type in case diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 9bac898fbbd..6188a9d2617 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -47,7 +47,7 @@ fn on_prepare_rename_inner( interner = def_interner; } else { // We ignore the warnings and errors produced by compilation while resolving the definition - let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, true); + let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, false); interner = &context.def_interner; } From 52ce9344e497a631769fba5dd826ceba03f4f901 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 27 Jun 2024 15:23:18 -0300 Subject: [PATCH 22/36] Check that matches actually match the name being renamed --- tooling/lsp/src/requests/rename.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 6188a9d2617..aaf2d9b816e 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -265,10 +265,16 @@ mod rename_tests { async fn test_on_rename_request() { let (mut state, noir_text_document) = setup().await; + let main_path = noir_text_document.path(); + let target_name = "test_multiple4"; + let target_position = Position { line: 79, character: 4 }; // This is at the "t" of "test_multiple4" + let params = RenameParams { text_document_position: TextDocumentPositionParams { - text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: lsp_types::Position { line: 79, character: 4 }, // This is at the "t" of "test_multiple4" + text_document: lsp_types::TextDocumentIdentifier { + uri: noir_text_document.clone(), + }, + position: target_position, // This is at the "t" of "test_multiple4" }, new_name: "renamed_test_multiple4".to_string(), work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, @@ -289,15 +295,25 @@ mod rename_tests { start: Position { line: 70, character: 3 }, end: Position { line: 70, character: 17 }, }, - Range { - start: Position { line: 79, character: 4 }, - end: Position { line: 79, character: 18 }, - }, + Range { start: target_position, end: Position { line: 79, character: 18 } }, Range { start: Position { line: 94, character: 4 }, end: Position { line: 94, character: 18 }, }, ] ); + + // Let's check that the above changes actually include the target name + let file_contents = + std::fs::read_to_string(main_path).expect(&format!("Couldn't read file {}", main_path)); + let file_lines: Vec<&str> = file_contents.lines().collect(); + + for change in &changes { + assert_eq!(change.start.line, change.end.line); + + let line = file_lines[change.start.line as usize]; + let chunk = &line[change.start.character as usize..change.end.character as usize]; + assert_eq!(chunk, target_name); + } } } From 4db9e6ccbba8c62080bddeda373e79e0ff60e219 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 27 Jun 2024 15:41:31 -0300 Subject: [PATCH 23/36] Use separate programs for lsp tests --- tooling/lsp/src/requests/goto_definition.rs | 26 ++++++++++++++----- tooling/lsp/src/requests/rename.rs | 24 ++++++++--------- .../test_programs/go_to_definition/Nargo.toml | 6 +++++ .../go_to_definition/src/main.nr | 11 ++++++++ tooling/lsp/test_programs/rename/Nargo.toml | 6 +++++ tooling/lsp/test_programs/rename/src/main.nr | 15 +++++++++++ 6 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 tooling/lsp/test_programs/go_to_definition/Nargo.toml create mode 100644 tooling/lsp/test_programs/go_to_definition/src/main.nr create mode 100644 tooling/lsp/test_programs/rename/Nargo.toml create mode 100644 tooling/lsp/test_programs/rename/src/main.nr diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index 3a92e28cc11..b8e29a32166 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -76,10 +76,11 @@ fn on_goto_definition_inner( #[cfg(test)] mod goto_definition_tests { + use std::panic; use acvm::blackbox_solver::StubbedBlackBoxSolver; use async_lsp::ClientSocket; - use lsp_types::{Position, Url}; + use lsp_types::{Position, Range, Url}; use tokio::test; use super::*; @@ -91,7 +92,7 @@ mod goto_definition_tests { let root_path = std::env::current_dir() .unwrap() - .join("../../test_programs/execution_success/7_function") + .join("test_programs/go_to_definition") .canonicalize() .expect("Could not resolve root path"); let noir_text_document = Url::from_file_path(root_path.join("src/main.nr").as_path()) @@ -119,16 +120,27 @@ mod goto_definition_tests { let params = GotoDefinitionParams { text_document_position_params: lsp_types::TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: Position { line: 95, character: 5 }, + position: Position { line: 9, character: 12 }, // Right at the beginning of "another_function" }, work_done_progress_params: Default::default(), partial_result_params: Default::default(), }; - let response = on_goto_definition_request(&mut state, params) + let response: GotoDefinitionResponse = on_goto_definition_request(&mut state, params) .await - .expect("Could execute on_goto_definition_request"); - - assert!(&response.is_some()); + .expect("Could execute on_goto_definition_request") + .expect("Didn't get a goto definition response"); + + if let GotoDefinitionResponse::Scalar(location) = response { + assert_eq!( + location.range, + Range { + start: Position { line: 4, character: 3 }, + end: Position { line: 4, character: 19 }, + } + ) + } else { + panic!("Expected a scalar response"); + } } } diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index aaf2d9b816e..db58c1e7b3e 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -175,7 +175,7 @@ mod rename_tests { let root_path = std::env::current_dir() .unwrap() - .join("../../test_programs/execution_success/7_function") + .join("test_programs/rename") .canonicalize() .expect("Could not resolve root path"); let noir_text_document = Url::from_file_path(root_path.join("src/main.nr").as_path()) @@ -229,7 +229,7 @@ mod rename_tests { let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: lsp_types::Position { line: 70, character: 3 }, // This is at the "t" of "test_multiple4" + position: lsp_types::Position { line: 4, character: 3 }, // This is at the "a" of "another_function" }; let response = on_prepare_rename_request(&mut state, params) @@ -248,7 +248,7 @@ mod rename_tests { let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: lsp_types::Position { line: 79, character: 4 }, // This is at the "t" of "test_multiple4" + position: lsp_types::Position { line: 9, character: 12 }, // This is at the "a" of "another_function" }; let response = on_prepare_rename_request(&mut state, params) @@ -266,17 +266,17 @@ mod rename_tests { let (mut state, noir_text_document) = setup().await; let main_path = noir_text_document.path(); - let target_name = "test_multiple4"; - let target_position = Position { line: 79, character: 4 }; // This is at the "t" of "test_multiple4" + let target_name = "another_function"; + let target_position = Position { line: 9, character: 12 }; // This is at the "a" of "another_function" let params = RenameParams { text_document_position: TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document.clone(), }, - position: target_position, // This is at the "t" of "test_multiple4" + position: target_position, }, - new_name: "renamed_test_multiple4".to_string(), + new_name: "renamed_function".to_string(), work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, }; @@ -292,13 +292,13 @@ mod rename_tests { changes, vec![ Range { - start: Position { line: 70, character: 3 }, - end: Position { line: 70, character: 17 }, + start: Position { line: 4, character: 3 }, + end: Position { line: 4, character: 19 }, }, - Range { start: target_position, end: Position { line: 79, character: 18 } }, + Range { start: target_position, end: Position { line: 9, character: 28 } }, Range { - start: Position { line: 94, character: 4 }, - end: Position { line: 94, character: 18 }, + start: Position { line: 13, character: 12 }, + end: Position { line: 13, character: 28 }, }, ] ); diff --git a/tooling/lsp/test_programs/go_to_definition/Nargo.toml b/tooling/lsp/test_programs/go_to_definition/Nargo.toml new file mode 100644 index 00000000000..c894a050c40 --- /dev/null +++ b/tooling/lsp/test_programs/go_to_definition/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "go_to_definition" +type = "bin" +authors = [""] + +[dependencies] diff --git a/tooling/lsp/test_programs/go_to_definition/src/main.nr b/tooling/lsp/test_programs/go_to_definition/src/main.nr new file mode 100644 index 00000000000..c27f8fed868 --- /dev/null +++ b/tooling/lsp/test_programs/go_to_definition/src/main.nr @@ -0,0 +1,11 @@ +fn some_function() -> Field { + 1 + 2 +} + +fn another_function() -> Field { + 3 + 4 +} + +fn main() { + let _ = another_function(); +} diff --git a/tooling/lsp/test_programs/rename/Nargo.toml b/tooling/lsp/test_programs/rename/Nargo.toml new file mode 100644 index 00000000000..2d5b6415dc9 --- /dev/null +++ b/tooling/lsp/test_programs/rename/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rename" +type = "bin" +authors = [""] + +[dependencies] diff --git a/tooling/lsp/test_programs/rename/src/main.nr b/tooling/lsp/test_programs/rename/src/main.nr new file mode 100644 index 00000000000..38fc1f122b4 --- /dev/null +++ b/tooling/lsp/test_programs/rename/src/main.nr @@ -0,0 +1,15 @@ +fn some_function() -> Field { + 1 + 2 +} + +fn another_function() -> Field { + 3 + 4 +} + +fn main() { + let _ = another_function(); + + let _ = 1; + + let _ = another_function(); +} From aee04c77f07cced06651b73c69b713fa0cf4a470 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 27 Jun 2024 15:48:16 -0300 Subject: [PATCH 24/36] clippy --- tooling/lsp/src/requests/goto_definition.rs | 4 ++-- tooling/lsp/src/requests/rename.rs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index b8e29a32166..192ef0103c3 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -138,9 +138,9 @@ mod goto_definition_tests { start: Position { line: 4, character: 3 }, end: Position { line: 4, character: 19 }, } - ) + ); } else { panic!("Expected a scalar response"); - } + }; } } diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index db58c1e7b3e..0355c285d4b 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -304,8 +304,9 @@ mod rename_tests { ); // Let's check that the above changes actually include the target name - let file_contents = - std::fs::read_to_string(main_path).expect(&format!("Couldn't read file {}", main_path)); + let file_contents = std::fs::read_to_string(main_path) + .unwrap_or_else(|_| panic!("Couldn't read file {}", main_path)); + let file_lines: Vec<&str> = file_contents.lines().collect(); for change in &changes { From 2d926175d767f5bfcdf8d3171c5fd7fe36c60974 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 27 Jun 2024 16:44:26 -0300 Subject: [PATCH 25/36] Undo changes to resolver --- .../noirc_frontend/src/hir/resolution/resolver.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 67ce9b41d17..2eb33f7603f 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1516,23 +1516,15 @@ impl<'a> Resolver<'a> { if hir_ident.id != DefinitionId::dummy_id() { match self.interner.definition(hir_ident.id).kind { - DefinitionKind::Function(func_id) => { + DefinitionKind::Function(id) => { if let Some(current_item) = self.current_item { - self.interner.add_function_dependency(current_item, func_id); + self.interner.add_function_dependency(current_item, id); } - - let variable = DependencyId::Variable(hir_ident.location); - let function = DependencyId::Function(func_id); - self.interner.add_reference(function, variable); } DefinitionKind::Global(global_id) => { if let Some(current_item) = self.current_item { self.interner.add_global_dependency(current_item, global_id); } - - let variable = DependencyId::Variable(hir_ident.location); - let global = DependencyId::Global(global_id); - self.interner.add_reference(global, variable); } DefinitionKind::GenericType(_) => { // Initialize numeric generics to a polymorphic integer type in case From a2fc465498e4be3d043addfd70aa2840363f2cb8 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 27 Jun 2024 17:13:37 -0300 Subject: [PATCH 26/36] Don't use legacy resolver in another place either --- tooling/lsp/src/requests/rename.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 0355c285d4b..2996a2cbb94 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -109,7 +109,7 @@ fn on_rename_inner( interner = def_interner; } else { // We ignore the warnings and errors produced by compilation while resolving the definition - let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, true); + let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, false); interner = &context.def_interner; } From 8b5aaae1177819b3176418836f9a453d0b783ba1 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 27 Jun 2024 17:13:47 -0300 Subject: [PATCH 27/36] Skip empty location spans (otherwise they produce a panic) --- compiler/noirc_frontend/src/locations.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index acd3abf87c6..dd6a3412a40 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -13,6 +13,11 @@ pub(crate) struct LocationIndices { impl LocationIndices { pub(crate) fn add_location(&mut self, location: Location, node_index: PetGraphIndex) { + // Some location spans are empty: maybe they are from ficticious nodes? + if location.span.start() == location.span.end() { + return; + } + let range_map = self.map_file_to_range.entry(location.file).or_default(); range_map.insert(location.span.start()..location.span.end(), node_index); } From 4da3335de0e8f33a0483852d914bd2130092ba82 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 28 Jun 2024 06:36:59 -0300 Subject: [PATCH 28/36] Remove some code duplication in lsp rename tests --- tooling/lsp/src/requests/rename.rs | 169 ++++++++++++----------------- 1 file changed, 71 insertions(+), 98 deletions(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 2996a2cbb94..c08edf4ab62 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -4,11 +4,15 @@ use std::{ }; use async_lsp::{ErrorCode, ResponseError}; +use fm::FileMap; use lsp_types::{ - PrepareRenameResponse, RenameParams, TextDocumentPositionParams, TextEdit, Url, WorkspaceEdit, + Position, PrepareRenameResponse, RenameParams, TextDocumentIdentifier, + TextDocumentPositionParams, TextEdit, Url, WorkspaceEdit, }; use nargo::insert_all_files_for_workspace_into_file_manager; use noirc_driver::file_manager_with_stdlib; +use noirc_errors::Location; +use noirc_frontend::macros_api::NodeInterner; use crate::{parse_diff, resolve_workspace_for_source_path, LspState}; @@ -18,79 +22,76 @@ pub(crate) fn on_prepare_rename_request( state: &mut LspState, params: TextDocumentPositionParams, ) -> impl Future, ResponseError>> { - let result = on_prepare_rename_inner(state, params); + let result = process_rename_request( + state, + params.text_document, + params.position, + |search_for_location, interner, _| { + let rename_possible = interner.check_rename_possible(search_for_location); + Some(PrepareRenameResponse::DefaultBehavior { default_behavior: rename_possible }) + }, + ); future::ready(result) } -fn on_prepare_rename_inner( - state: &mut LspState, - params: TextDocumentPositionParams, -) -> Result, ResponseError> { - let file_path = params.text_document.uri.to_file_path().map_err(|_| { - ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path") - })?; - - let workspace = resolve_workspace_for_source_path(file_path.as_path()).unwrap(); - let package = workspace.members.first().unwrap(); - - let package_root_path: String = package.root_dir.as_os_str().to_string_lossy().into(); - - let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); - insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); - let parsed_files = parse_diff(&workspace_file_manager, state); - - let (mut context, crate_id) = - nargo::prepare_package(&workspace_file_manager, &parsed_files, package); - - let interner; - if let Some(def_interner) = state.cached_definitions.get(&package_root_path) { - interner = def_interner; - } else { - // We ignore the warnings and errors produced by compilation while resolving the definition - let _ = noirc_driver::check_crate(&mut context, crate_id, false, false, false); - interner = &context.def_interner; - } - - let files = context.file_manager.as_file_map(); - let file_id = context.file_manager.name_to_id(file_path.clone()).ok_or(ResponseError::new( - ErrorCode::REQUEST_FAILED, - format!("Could not find file in file manager. File path: {:?}", file_path), - ))?; - let byte_index = position_to_byte_index(files, file_id, ¶ms.position).map_err(|err| { - ResponseError::new( - ErrorCode::REQUEST_FAILED, - format!("Could not convert position to byte index. Error: {:?}", err), - ) - })?; - - let search_for_location = noirc_errors::Location { - file: file_id, - span: noirc_errors::Span::single_char(byte_index as u32), - }; - - let rename_possible = interner.check_rename_possible(search_for_location); - - let response = PrepareRenameResponse::DefaultBehavior { default_behavior: rename_possible }; - - Ok(Some(response)) -} - pub(crate) fn on_rename_request( state: &mut LspState, params: RenameParams, ) -> impl Future, ResponseError>> { - let result = on_rename_inner(state, params); + let result = process_rename_request( + state, + params.text_document_position.text_document, + params.text_document_position.position, + |search_for_location, interner, files| { + let rename_changes = + interner.find_rename_symbols_at(search_for_location).map(|locations| { + let rs = locations.iter().fold( + HashMap::new(), + |mut acc: HashMap>, location| { + let file_id = location.file; + let span = location.span; + + let Some(lsp_location) = to_lsp_location(files, file_id, span) else { + return acc; + }; + + let edit = TextEdit { + range: lsp_location.range, + new_text: params.new_name.clone(), + }; + + acc.entry(lsp_location.uri).or_default().push(edit); + + acc + }, + ); + rs + }); + + let response = WorkspaceEdit { + changes: rename_changes, + document_changes: None, + change_annotations: None, + }; + + Some(response) + }, + ); future::ready(result) } -fn on_rename_inner( +fn process_rename_request( state: &mut LspState, - params: RenameParams, -) -> Result, ResponseError> { - let file_path = - params.text_document_position.text_document.uri.to_file_path().map_err(|_| { - ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path") - })?; + text_document: TextDocumentIdentifier, + position: Position, + callback: F, +) -> Result +where + F: FnOnce(Location, &NodeInterner, &FileMap) -> T, +{ + let file_path = text_document.uri.to_file_path().map_err(|_| { + ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path") + })?; let workspace = resolve_workspace_for_source_path(file_path.as_path()).unwrap(); let package = workspace.members.first().unwrap(); @@ -118,47 +119,19 @@ fn on_rename_inner( ErrorCode::REQUEST_FAILED, format!("Could not find file in file manager. File path: {:?}", file_path), ))?; - let byte_index = - position_to_byte_index(files, file_id, ¶ms.text_document_position.position).map_err( - |err| { - ResponseError::new( - ErrorCode::REQUEST_FAILED, - format!("Could not convert position to byte index. Error: {:?}", err), - ) - }, - )?; + let byte_index = position_to_byte_index(files, file_id, &position).map_err(|err| { + ResponseError::new( + ErrorCode::REQUEST_FAILED, + format!("Could not convert position to byte index. Error: {:?}", err), + ) + })?; let search_for_location = noirc_errors::Location { file: file_id, span: noirc_errors::Span::single_char(byte_index as u32), }; - let rename_changes = interner.find_rename_symbols_at(search_for_location).map(|locations| { - let rs = locations.iter().fold( - HashMap::new(), - |mut acc: HashMap>, location| { - let file_id = location.file; - let span = location.span; - - let Some(lsp_location) = to_lsp_location(files, file_id, span) else { - return acc; - }; - - let edit = - TextEdit { range: lsp_location.range, new_text: params.new_name.clone() }; - - acc.entry(lsp_location.uri).or_default().push(edit); - - acc - }, - ); - rs - }); - - let response = - WorkspaceEdit { changes: rename_changes, document_changes: None, change_annotations: None }; - - Ok(Some(response)) + Ok(callback(search_for_location, interner, files)) } #[cfg(test)] From b9f3d763e63f83520532bd7921c53c69f82e6f0d Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 28 Jun 2024 06:43:46 -0300 Subject: [PATCH 29/36] Extract test_utils::init_lsp_server --- tooling/lsp/src/lib.rs | 3 ++ tooling/lsp/src/requests/goto_definition.rs | 35 ++-------------- tooling/lsp/src/requests/rename.rs | 46 +++------------------ tooling/lsp/src/test_utils.rs | 39 +++++++++++++++++ 4 files changed, 50 insertions(+), 73 deletions(-) create mode 100644 tooling/lsp/src/test_utils.rs diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index b9b69cfc153..92924e701a6 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -58,6 +58,9 @@ mod requests; mod solver; mod types; +#[cfg(test)] +mod test_utils; + use solver::WrapperSolver; use types::{notification, request, NargoTest, NargoTestId, Position, Range, Url}; diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index 192ef0103c3..4985c565e06 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -78,44 +78,15 @@ fn on_goto_definition_inner( mod goto_definition_tests { use std::panic; - use acvm::blackbox_solver::StubbedBlackBoxSolver; - use async_lsp::ClientSocket; - use lsp_types::{Position, Range, Url}; + use crate::test_utils; + use lsp_types::{Position, Range}; use tokio::test; use super::*; #[test] async fn test_on_goto_definition() { - let client = ClientSocket::new_closed(); - let mut state = LspState::new(&client, StubbedBlackBoxSolver); - - let root_path = std::env::current_dir() - .unwrap() - .join("test_programs/go_to_definition") - .canonicalize() - .expect("Could not resolve root path"); - let noir_text_document = Url::from_file_path(root_path.join("src/main.nr").as_path()) - .expect("Could not convert text document path to URI"); - let root_uri = Some( - Url::from_file_path(root_path.as_path()).expect("Could not convert root path to URI"), - ); - - #[allow(deprecated)] - let initialize_params = lsp_types::InitializeParams { - process_id: Default::default(), - root_path: None, - root_uri, - initialization_options: None, - capabilities: Default::default(), - trace: Some(lsp_types::TraceValue::Verbose), - workspace_folders: None, - client_info: None, - locale: None, - }; - let _initialize_response = crate::requests::on_initialize(&mut state, initialize_params) - .await - .expect("Could not initialize LSP server"); + let (mut state, noir_text_document) = test_utils::init_lsp_server("go_to_definition").await; let params = GotoDefinitionParams { text_document_position_params: lsp_types::TextDocumentPositionParams { diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index c08edf4ab62..793b5d68343 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -137,49 +137,13 @@ where #[cfg(test)] mod rename_tests { use super::*; - use acvm::blackbox_solver::StubbedBlackBoxSolver; - use async_lsp::ClientSocket; + use crate::test_utils; use lsp_types::{Position, Range, WorkDoneProgressParams}; use tokio::test; - async fn setup() -> (LspState, Url) { - let client = ClientSocket::new_closed(); - let mut state = LspState::new(&client, StubbedBlackBoxSolver); - - let root_path = std::env::current_dir() - .unwrap() - .join("test_programs/rename") - .canonicalize() - .expect("Could not resolve root path"); - let noir_text_document = Url::from_file_path(root_path.join("src/main.nr").as_path()) - .expect("Could not convert text document path to URI"); - let root_uri = Some( - Url::from_file_path(root_path.as_path()).expect("Could not convert root path to URI"), - ); - - #[allow(deprecated)] - let initialize_params = lsp_types::InitializeParams { - process_id: Default::default(), - root_path: None, - root_uri, - initialization_options: None, - capabilities: Default::default(), - trace: Some(lsp_types::TraceValue::Verbose), - workspace_folders: None, - client_info: None, - locale: None, - }; - - let _initialize_response = crate::requests::on_initialize(&mut state, initialize_params) - .await - .expect("Could not initialize LSP server"); - - (state, noir_text_document) - } - #[test] async fn test_on_prepare_rename_request_cannot_be_applied() { - let (mut state, noir_text_document) = setup().await; + let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, @@ -198,7 +162,7 @@ mod rename_tests { #[test] async fn test_on_prepare_rename_request_can_be_applied_at_function_declaration() { - let (mut state, noir_text_document) = setup().await; + let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, @@ -217,7 +181,7 @@ mod rename_tests { #[test] async fn test_on_prepare_rename_request_can_be_applied_at_function_reference() { - let (mut state, noir_text_document) = setup().await; + let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, @@ -236,7 +200,7 @@ mod rename_tests { #[test] async fn test_on_rename_request() { - let (mut state, noir_text_document) = setup().await; + let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; let main_path = noir_text_document.path(); let target_name = "another_function"; diff --git a/tooling/lsp/src/test_utils.rs b/tooling/lsp/src/test_utils.rs new file mode 100644 index 00000000000..dcaec2fd615 --- /dev/null +++ b/tooling/lsp/src/test_utils.rs @@ -0,0 +1,39 @@ +use crate::LspState; +use acvm::blackbox_solver::StubbedBlackBoxSolver; +use async_lsp::ClientSocket; +use lsp_types::Url; + +pub(crate) async fn init_lsp_server(directory: &str) -> (LspState, Url) { + let client = ClientSocket::new_closed(); + let mut state = LspState::new(&client, StubbedBlackBoxSolver); + + let root_path = std::env::current_dir() + .unwrap() + .join("test_programs") + .join(directory) + .canonicalize() + .expect("Could not resolve root path"); + let noir_text_document = Url::from_file_path(root_path.join("src/main.nr").as_path()) + .expect("Could not convert text document path to URI"); + let root_uri = + Some(Url::from_file_path(root_path.as_path()).expect("Could not convert root path to URI")); + + #[allow(deprecated)] + let initialize_params = lsp_types::InitializeParams { + process_id: Default::default(), + root_path: None, + root_uri, + initialization_options: None, + capabilities: Default::default(), + trace: Some(lsp_types::TraceValue::Verbose), + workspace_folders: None, + client_info: None, + locale: None, + }; + + let _initialize_response = crate::requests::on_initialize(&mut state, initialize_params) + .await + .expect("Could not initialize LSP server"); + + (state, noir_text_document) +} From bf872318e23bba70fa1e46d47fabd7df61ecb969 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 28 Jun 2024 06:47:56 -0300 Subject: [PATCH 30/36] process_rename_request only needs TextDocumentPositionParams --- tooling/lsp/src/requests/rename.rs | 44 ++++++++++++++---------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 793b5d68343..c9fdfe12859 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -6,8 +6,7 @@ use std::{ use async_lsp::{ErrorCode, ResponseError}; use fm::FileMap; use lsp_types::{ - Position, PrepareRenameResponse, RenameParams, TextDocumentIdentifier, - TextDocumentPositionParams, TextEdit, Url, WorkspaceEdit, + PrepareRenameResponse, RenameParams, TextDocumentPositionParams, TextEdit, Url, WorkspaceEdit, }; use nargo::insert_all_files_for_workspace_into_file_manager; use noirc_driver::file_manager_with_stdlib; @@ -22,15 +21,10 @@ pub(crate) fn on_prepare_rename_request( state: &mut LspState, params: TextDocumentPositionParams, ) -> impl Future, ResponseError>> { - let result = process_rename_request( - state, - params.text_document, - params.position, - |search_for_location, interner, _| { - let rename_possible = interner.check_rename_possible(search_for_location); - Some(PrepareRenameResponse::DefaultBehavior { default_behavior: rename_possible }) - }, - ); + let result = process_rename_request(state, params, |search_for_location, interner, _| { + let rename_possible = interner.check_rename_possible(search_for_location); + Some(PrepareRenameResponse::DefaultBehavior { default_behavior: rename_possible }) + }); future::ready(result) } @@ -40,8 +34,7 @@ pub(crate) fn on_rename_request( ) -> impl Future, ResponseError>> { let result = process_rename_request( state, - params.text_document_position.text_document, - params.text_document_position.position, + params.text_document_position, |search_for_location, interner, files| { let rename_changes = interner.find_rename_symbols_at(search_for_location).map(|locations| { @@ -82,16 +75,16 @@ pub(crate) fn on_rename_request( fn process_rename_request( state: &mut LspState, - text_document: TextDocumentIdentifier, - position: Position, + text_document_position_params: TextDocumentPositionParams, callback: F, ) -> Result where F: FnOnce(Location, &NodeInterner, &FileMap) -> T, { - let file_path = text_document.uri.to_file_path().map_err(|_| { - ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path") - })?; + let file_path = + text_document_position_params.text_document.uri.to_file_path().map_err(|_| { + ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path") + })?; let workspace = resolve_workspace_for_source_path(file_path.as_path()).unwrap(); let package = workspace.members.first().unwrap(); @@ -119,12 +112,15 @@ where ErrorCode::REQUEST_FAILED, format!("Could not find file in file manager. File path: {:?}", file_path), ))?; - let byte_index = position_to_byte_index(files, file_id, &position).map_err(|err| { - ResponseError::new( - ErrorCode::REQUEST_FAILED, - format!("Could not convert position to byte index. Error: {:?}", err), - ) - })?; + let byte_index = + position_to_byte_index(files, file_id, &text_document_position_params.position).map_err( + |err| { + ResponseError::new( + ErrorCode::REQUEST_FAILED, + format!("Could not convert position to byte index. Error: {:?}", err), + ) + }, + )?; let search_for_location = noirc_errors::Location { file: file_id, From 07b2ccb8ceeb1d26f20f20a3b35e209e4cc32238 Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Fri, 28 Jun 2024 12:38:15 +0000 Subject: [PATCH 31/36] chore: refactor tests to make it easier to check all cases --- tooling/lsp/src/requests/rename.rs | 111 ++++++++++++++++------------- 1 file changed, 63 insertions(+), 48 deletions(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index c9fdfe12859..95c34d02fba 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -137,6 +137,46 @@ mod rename_tests { use lsp_types::{Position, Range, WorkDoneProgressParams}; use tokio::test; + const ANOTHER_FUNCTION_REFERENCE: Range = Range { + start: Position { line: 9, character: 12 }, + end: Position { line: 9, character: 28 }, + }; + const ANOTHER_FUNCTION_DECLARATION: Range = Range { + start: Position { line: 4, character: 3 }, + end: Position { line: 4, character: 19 }, + }; + // The ranges of positions which represent the usage of the `another_function` symbol. + const ANOTHER_FUNCTION_RANGES: &[Range] = &[ + ANOTHER_FUNCTION_DECLARATION, + ANOTHER_FUNCTION_REFERENCE, + Range { + start: Position { line: 13, character: 12 }, + end: Position { line: 13, character: 28 }, + }, + ]; + + /// Tests that the contents of `ANOTHER_FUNCTION_RANGES` is valid such that all ranges cover an instance of `another_function`. + #[test] + async fn check_target_ranges() { + let (_, noir_text_document) = test_utils::init_lsp_server("rename").await; + let main_path = noir_text_document.path(); + + // Let's check that the above changes actually include the target name + let file_contents = std::fs::read_to_string(main_path) + .unwrap_or_else(|_| panic!("Couldn't read file {}", main_path)); + + let file_lines: Vec<&str> = file_contents.lines().collect(); + + let target_name = "another_function"; + for range in ANOTHER_FUNCTION_RANGES { + assert_eq!(range.start.line, range.end.line); + + let line = file_lines[range.start.line as usize]; + let chunk = &line[range.start.character as usize..range.end.character as usize]; + assert_eq!(chunk, target_name); + } + } + #[test] async fn test_on_prepare_rename_request_cannot_be_applied() { let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; @@ -162,7 +202,7 @@ mod rename_tests { let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: lsp_types::Position { line: 4, character: 3 }, // This is at the "a" of "another_function" + position: ANOTHER_FUNCTION_DECLARATION }; let response = on_prepare_rename_request(&mut state, params) @@ -181,7 +221,7 @@ mod rename_tests { let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: lsp_types::Position { line: 9, character: 12 }, // This is at the "a" of "another_function" + position: ANOTHER_FUNCTION_REFERENCE }; let response = on_prepare_rename_request(&mut state, params) @@ -198,56 +238,31 @@ mod rename_tests { async fn test_on_rename_request() { let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; - let main_path = noir_text_document.path(); - let target_name = "another_function"; - let target_position = Position { line: 9, character: 12 }; // This is at the "a" of "another_function" - - let params = RenameParams { - text_document_position: TextDocumentPositionParams { - text_document: lsp_types::TextDocumentIdentifier { - uri: noir_text_document.clone(), - }, - position: target_position, - }, - new_name: "renamed_function".to_string(), - work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, - }; - - let response = on_rename_request(&mut state, params) - .await - .expect("Could not execute on_prepare_rename_request") - .unwrap(); + // Test renaming works on any instance of the symbol. + for target_range in ANOTHER_FUNCTION_RANGES { + let target_position = target_range.start; - let changes = response.changes.expect("Expected to find rename changes"); - let mut changes: Vec = changes.values().flatten().map(|edit| edit.range).collect(); - changes.sort_by_key(|range| range.start.line); - assert_eq!( - changes, - vec![ - Range { - start: Position { line: 4, character: 3 }, - end: Position { line: 4, character: 19 }, - }, - Range { start: target_position, end: Position { line: 9, character: 28 } }, - Range { - start: Position { line: 13, character: 12 }, - end: Position { line: 13, character: 28 }, + let params = RenameParams { + text_document_position: TextDocumentPositionParams { + text_document: lsp_types::TextDocumentIdentifier { + uri: noir_text_document.clone(), + }, + position: target_position, }, - ] - ); - - // Let's check that the above changes actually include the target name - let file_contents = std::fs::read_to_string(main_path) - .unwrap_or_else(|_| panic!("Couldn't read file {}", main_path)); - - let file_lines: Vec<&str> = file_contents.lines().collect(); + new_name: "renamed_function".to_string(), + work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, + }; - for change in &changes { - assert_eq!(change.start.line, change.end.line); + let response = on_rename_request(&mut state, params) + .await + .expect("Could not execute on_prepare_rename_request") + .unwrap(); - let line = file_lines[change.start.line as usize]; - let chunk = &line[change.start.character as usize..change.end.character as usize]; - assert_eq!(chunk, target_name); + let changes = response.changes.expect("Expected to find rename changes"); + let mut changes: Vec = + changes.values().flatten().map(|edit| edit.range).collect(); + changes.sort_by_key(|range| range.start.line); + assert_eq!(changes, ANOTHER_FUNCTION_RANGES); } } } From b8dbd04db5dc4c3577ef5877b1c44a31e0561aed Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Fri, 28 Jun 2024 12:40:21 +0000 Subject: [PATCH 32/36] chore: fix type --- tooling/lsp/src/requests/rename.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 95c34d02fba..41915d2dc81 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -202,7 +202,7 @@ mod rename_tests { let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: ANOTHER_FUNCTION_DECLARATION + position: ANOTHER_FUNCTION_DECLARATION.start }; let response = on_prepare_rename_request(&mut state, params) @@ -221,7 +221,7 @@ mod rename_tests { let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: ANOTHER_FUNCTION_REFERENCE + position: ANOTHER_FUNCTION_REFERENCE.start }; let response = on_prepare_rename_request(&mut state, params) From 684389aa661ec995089b984a893c0ad8953a324d Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Fri, 28 Jun 2024 12:42:18 +0000 Subject: [PATCH 33/36] chore: fmt --- tooling/lsp/src/requests/rename.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 41915d2dc81..ef17d91c6ad 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -202,7 +202,7 @@ mod rename_tests { let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: ANOTHER_FUNCTION_DECLARATION.start + position: ANOTHER_FUNCTION_DECLARATION.start, }; let response = on_prepare_rename_request(&mut state, params) @@ -221,7 +221,7 @@ mod rename_tests { let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: ANOTHER_FUNCTION_REFERENCE.start + position: ANOTHER_FUNCTION_REFERENCE.start, }; let response = on_prepare_rename_request(&mut state, params) From 7a2f0f7e41bab9b640820c531dff02ac405f96bf Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Fri, 28 Jun 2024 12:46:24 +0000 Subject: [PATCH 34/36] chore: add instance of qualified path to test program --- tooling/lsp/src/requests/rename.rs | 4 ++++ tooling/lsp/test_programs/rename/src/main.nr | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index ef17d91c6ad..a3dde9453ee 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -153,6 +153,10 @@ mod rename_tests { start: Position { line: 13, character: 12 }, end: Position { line: 13, character: 28 }, }, + Range { + start: Position { line: 19, character: 15 }, + end: Position { line: 19, character: 31 }, + }, ]; /// Tests that the contents of `ANOTHER_FUNCTION_RANGES` is valid such that all ranges cover an instance of `another_function`. diff --git a/tooling/lsp/test_programs/rename/src/main.nr b/tooling/lsp/test_programs/rename/src/main.nr index 38fc1f122b4..4c28249582e 100644 --- a/tooling/lsp/test_programs/rename/src/main.nr +++ b/tooling/lsp/test_programs/rename/src/main.nr @@ -13,3 +13,10 @@ fn main() { let _ = another_function(); } + + +mod foo { + fn yet_another_function() -> Field { + crate::another_function() + } +} \ No newline at end of file From 753271792c5e4d349cb628f2649689d7cb47c41f Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 28 Jun 2024 17:05:33 -0300 Subject: [PATCH 35/36] Let lsp rename function work well with qualified paths --- .../noirc_frontend/src/elaborator/patterns.rs | 5 +- tooling/lsp/src/requests/rename.rs | 131 ++++++++++-------- .../test_programs/rename_qualified/Nargo.toml | 6 + .../rename_qualified/src/main.nr | 9 ++ 4 files changed, 92 insertions(+), 59 deletions(-) create mode 100644 tooling/lsp/test_programs/rename_qualified/Nargo.toml create mode 100644 tooling/lsp/test_programs/rename_qualified/src/main.nr diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index 6966cc50152..58a7a57bb3f 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -583,7 +583,10 @@ impl<'context> Elaborator<'context> { } pub fn get_ident_from_path(&mut self, path: Path) -> (HirIdent, usize) { - let location = Location::new(path.span(), self.file); + let location = Location::new( + path.segments.last().expect("ice: path without segments").span(), + self.file, + ); let error = match path.as_ident().map(|ident| self.use_variable(ident)) { Some(Ok(found)) => return found, diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index a3dde9453ee..6fd30db94e8 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -137,47 +137,51 @@ mod rename_tests { use lsp_types::{Position, Range, WorkDoneProgressParams}; use tokio::test; - const ANOTHER_FUNCTION_REFERENCE: Range = Range { - start: Position { line: 9, character: 12 }, - end: Position { line: 9, character: 28 }, - }; - const ANOTHER_FUNCTION_DECLARATION: Range = Range { - start: Position { line: 4, character: 3 }, - end: Position { line: 4, character: 19 }, - }; - // The ranges of positions which represent the usage of the `another_function` symbol. - const ANOTHER_FUNCTION_RANGES: &[Range] = &[ - ANOTHER_FUNCTION_DECLARATION, - ANOTHER_FUNCTION_REFERENCE, - Range { - start: Position { line: 13, character: 12 }, - end: Position { line: 13, character: 28 }, - }, - Range { - start: Position { line: 19, character: 15 }, - end: Position { line: 19, character: 31 }, - }, - ]; + async fn check_rename_succeeds(directory: &str, name: &str, ranges: &[Range]) { + let (mut state, noir_text_document) = test_utils::init_lsp_server(directory).await; - /// Tests that the contents of `ANOTHER_FUNCTION_RANGES` is valid such that all ranges cover an instance of `another_function`. - #[test] - async fn check_target_ranges() { - let (_, noir_text_document) = test_utils::init_lsp_server("rename").await; let main_path = noir_text_document.path(); - // Let's check that the above changes actually include the target name + // As we process the rename requests we'll check that the request position actually + // includes the target name. let file_contents = std::fs::read_to_string(main_path) .unwrap_or_else(|_| panic!("Couldn't read file {}", main_path)); let file_lines: Vec<&str> = file_contents.lines().collect(); - let target_name = "another_function"; - for range in ANOTHER_FUNCTION_RANGES { - assert_eq!(range.start.line, range.end.line); + // Test renaming works on any instance of the symbol. + for target_range in ranges { + assert_eq!(target_range.start.line, target_range.end.line); + + // Check that the range includes the target name + let line = file_lines[target_range.start.line as usize]; + let chunk = + &line[target_range.start.character as usize..target_range.end.character as usize]; + assert_eq!(chunk, name); - let line = file_lines[range.start.line as usize]; - let chunk = &line[range.start.character as usize..range.end.character as usize]; - assert_eq!(chunk, target_name); + let target_position = target_range.start; + + let params = RenameParams { + text_document_position: TextDocumentPositionParams { + text_document: lsp_types::TextDocumentIdentifier { + uri: noir_text_document.clone(), + }, + position: target_position, + }, + new_name: "renamed_function".to_string(), + work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, + }; + + let response = on_rename_request(&mut state, params) + .await + .expect("Could not execute on_prepare_rename_request") + .unwrap(); + + let changes = response.changes.expect("Expected to find rename changes"); + let mut changes: Vec = + changes.values().flatten().map(|edit| edit.range).collect(); + changes.sort_by_key(|range| range.start.line); + assert_eq!(changes, ranges); } } @@ -200,6 +204,28 @@ mod rename_tests { ); } + const ANOTHER_FUNCTION_REFERENCE: Range = Range { + start: Position { line: 9, character: 12 }, + end: Position { line: 9, character: 28 }, + }; + const ANOTHER_FUNCTION_DECLARATION: Range = Range { + start: Position { line: 4, character: 3 }, + end: Position { line: 4, character: 19 }, + }; + // The ranges of positions which represent the usage of the `another_function` symbol. + const ANOTHER_FUNCTION_RANGES: &[Range] = &[ + ANOTHER_FUNCTION_DECLARATION, + ANOTHER_FUNCTION_REFERENCE, + Range { + start: Position { line: 13, character: 12 }, + end: Position { line: 13, character: 28 }, + }, + Range { + start: Position { line: 19, character: 15 }, + end: Position { line: 19, character: 31 }, + }, + ]; + #[test] async fn test_on_prepare_rename_request_can_be_applied_at_function_declaration() { let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; @@ -240,33 +266,22 @@ mod rename_tests { #[test] async fn test_on_rename_request() { - let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; - - // Test renaming works on any instance of the symbol. - for target_range in ANOTHER_FUNCTION_RANGES { - let target_position = target_range.start; - - let params = RenameParams { - text_document_position: TextDocumentPositionParams { - text_document: lsp_types::TextDocumentIdentifier { - uri: noir_text_document.clone(), - }, - position: target_position, - }, - new_name: "renamed_function".to_string(), - work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, - }; + check_rename_succeeds("rename", "another_function", ANOTHER_FUNCTION_RANGES).await; + } - let response = on_rename_request(&mut state, params) - .await - .expect("Could not execute on_prepare_rename_request") - .unwrap(); + const BAR_FUNCTION_REFERENCE: Range = Range { + start: Position { line: 1, character: 9 }, + end: Position { line: 1, character: 12 }, + }; + const BAR_FUNCTION_DECLARATION: Range = Range { + start: Position { line: 5, character: 11 }, + end: Position { line: 5, character: 14 }, + }; + // The ranges of positions which represent the usage of the `bar` symbol. + const BAR_FUNCTION_RANGES: &[Range] = &[BAR_FUNCTION_REFERENCE, BAR_FUNCTION_DECLARATION]; - let changes = response.changes.expect("Expected to find rename changes"); - let mut changes: Vec = - changes.values().flatten().map(|edit| edit.range).collect(); - changes.sort_by_key(|range| range.start.line); - assert_eq!(changes, ANOTHER_FUNCTION_RANGES); - } + #[test] + async fn test_on_rename_request_works_with_qualified_path() { + check_rename_succeeds("rename_qualified", "bar", BAR_FUNCTION_RANGES).await; } } diff --git a/tooling/lsp/test_programs/rename_qualified/Nargo.toml b/tooling/lsp/test_programs/rename_qualified/Nargo.toml new file mode 100644 index 00000000000..7de13ef6b34 --- /dev/null +++ b/tooling/lsp/test_programs/rename_qualified/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rename_qualified" +type = "bin" +authors = [""] + +[dependencies] diff --git a/tooling/lsp/test_programs/rename_qualified/src/main.nr b/tooling/lsp/test_programs/rename_qualified/src/main.nr new file mode 100644 index 00000000000..f1b77796210 --- /dev/null +++ b/tooling/lsp/test_programs/rename_qualified/src/main.nr @@ -0,0 +1,9 @@ +fn main() -> pub Field { + foo::bar() +} + +mod foo { + pub fn bar() -> Field { + 1 + } +} From 303dc9bc0083daae92425e3c19d10f70115af643 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 28 Jun 2024 17:07:03 -0300 Subject: [PATCH 36/36] Remove extra tests, and move consts inside functions --- tooling/lsp/src/requests/rename.rs | 100 +++++++++-------------------- 1 file changed, 31 insertions(+), 69 deletions(-) diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 6fd30db94e8..9f6416a2c63 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -204,84 +204,46 @@ mod rename_tests { ); } - const ANOTHER_FUNCTION_REFERENCE: Range = Range { - start: Position { line: 9, character: 12 }, - end: Position { line: 9, character: 28 }, - }; - const ANOTHER_FUNCTION_DECLARATION: Range = Range { - start: Position { line: 4, character: 3 }, - end: Position { line: 4, character: 19 }, - }; - // The ranges of positions which represent the usage of the `another_function` symbol. - const ANOTHER_FUNCTION_RANGES: &[Range] = &[ - ANOTHER_FUNCTION_DECLARATION, - ANOTHER_FUNCTION_REFERENCE, - Range { - start: Position { line: 13, character: 12 }, - end: Position { line: 13, character: 28 }, - }, - Range { - start: Position { line: 19, character: 15 }, - end: Position { line: 19, character: 31 }, - }, - ]; - #[test] - async fn test_on_prepare_rename_request_can_be_applied_at_function_declaration() { - let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; - - let params = TextDocumentPositionParams { - text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: ANOTHER_FUNCTION_DECLARATION.start, + async fn test_on_rename_request() { + const ANOTHER_FUNCTION_REFERENCE: Range = Range { + start: Position { line: 9, character: 12 }, + end: Position { line: 9, character: 28 }, }; - - let response = on_prepare_rename_request(&mut state, params) - .await - .expect("Could not execute on_prepare_rename_request"); - - assert_eq!( - response, - Some(PrepareRenameResponse::DefaultBehavior { default_behavior: true }) - ); - } - - #[test] - async fn test_on_prepare_rename_request_can_be_applied_at_function_reference() { - let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; - - let params = TextDocumentPositionParams { - text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, - position: ANOTHER_FUNCTION_REFERENCE.start, + const ANOTHER_FUNCTION_DECLARATION: Range = Range { + start: Position { line: 4, character: 3 }, + end: Position { line: 4, character: 19 }, }; + // The ranges of positions which represent the usage of the `another_function` symbol. + const ANOTHER_FUNCTION_RANGES: &[Range] = &[ + ANOTHER_FUNCTION_DECLARATION, + ANOTHER_FUNCTION_REFERENCE, + Range { + start: Position { line: 13, character: 12 }, + end: Position { line: 13, character: 28 }, + }, + Range { + start: Position { line: 19, character: 15 }, + end: Position { line: 19, character: 31 }, + }, + ]; - let response = on_prepare_rename_request(&mut state, params) - .await - .expect("Could not execute on_prepare_rename_request"); - - assert_eq!( - response, - Some(PrepareRenameResponse::DefaultBehavior { default_behavior: true }) - ); - } - - #[test] - async fn test_on_rename_request() { check_rename_succeeds("rename", "another_function", ANOTHER_FUNCTION_RANGES).await; } - const BAR_FUNCTION_REFERENCE: Range = Range { - start: Position { line: 1, character: 9 }, - end: Position { line: 1, character: 12 }, - }; - const BAR_FUNCTION_DECLARATION: Range = Range { - start: Position { line: 5, character: 11 }, - end: Position { line: 5, character: 14 }, - }; - // The ranges of positions which represent the usage of the `bar` symbol. - const BAR_FUNCTION_RANGES: &[Range] = &[BAR_FUNCTION_REFERENCE, BAR_FUNCTION_DECLARATION]; - #[test] async fn test_on_rename_request_works_with_qualified_path() { + const BAR_FUNCTION_REFERENCE: Range = Range { + start: Position { line: 1, character: 9 }, + end: Position { line: 1, character: 12 }, + }; + const BAR_FUNCTION_DECLARATION: Range = Range { + start: Position { line: 5, character: 11 }, + end: Position { line: 5, character: 14 }, + }; + // The ranges of positions which represent the usage of the `bar` symbol. + const BAR_FUNCTION_RANGES: &[Range] = &[BAR_FUNCTION_REFERENCE, BAR_FUNCTION_DECLARATION]; + check_rename_succeeds("rename_qualified", "bar", BAR_FUNCTION_RANGES).await; } }