diff --git a/compiler/noirc_driver/src/abi_gen.rs b/compiler/noirc_driver/src/abi_gen.rs index 1cad67ba5b7..9d0d64b6300 100644 --- a/compiler/noirc_driver/src/abi_gen.rs +++ b/compiler/noirc_driver/src/abi_gen.rs @@ -2,11 +2,12 @@ use std::collections::BTreeMap; use acvm::acir::native_types::Witness; use iter_extended::{btree_map, vecmap}; -use noirc_abi::{Abi, AbiParameter, AbiType}; +use noirc_abi::{Abi, AbiParameter, AbiReturnType, AbiType}; use noirc_frontend::{ hir::Context, hir_def::{function::Param, stmt::HirPattern}, node_interner::{FuncId, NodeInterner}, + Visibility, }; use std::ops::Range; @@ -17,9 +18,12 @@ pub(super) fn gen_abi( func_id: &FuncId, input_witnesses: Vec, return_witnesses: Vec, + return_visibility: Visibility, ) -> Abi { let (parameters, return_type) = compute_function_abi(context, func_id); let param_witnesses = param_witnesses_from_abi_param(¶meters, input_witnesses); + let return_type = return_type + .map(|typ| AbiReturnType { abi_type: typ, visibility: return_visibility.into() }); Abi { parameters, return_type, param_witnesses, return_witnesses } } diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 93ed26fb91a..23869fc2a61 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -346,11 +346,12 @@ pub fn compile_no_check( if !force_compile && hashes_match { return Ok(cached_program.expect("cache must exist for hashes to match")); } - + let visibility = program.return_visibility; let (circuit, debug, input_witnesses, return_witnesses, warnings) = create_circuit(program, options.show_ssa, options.show_brillig)?; - let abi = abi_gen::gen_abi(context, &main_function, input_witnesses, return_witnesses); + let abi = + abi_gen::gen_abi(context, &main_function, input_witnesses, return_witnesses, visibility); let file_map = filter_relevant_files(&[debug.clone()], &context.file_manager); Ok(CompiledProgram { diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 186e260a52a..d73bb514e02 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -5,6 +5,7 @@ use std::collections::HashSet; use std::fmt::Debug; use self::acir_ir::acir_variable::{AcirContext, AcirType, AcirVar}; +use super::function_builder::data_bus::DataBus; use super::ir::dfg::CallStack; use super::{ ir::{ @@ -90,6 +91,8 @@ struct Context { /// Maps SSA array values to their slice size and any nested slices internal to the parent slice. /// This enables us to maintain the slice structure of a slice when performing an array get. slice_sizes: HashMap, Vec>, + + data_bus: DataBus, } #[derive(Clone)] @@ -199,6 +202,7 @@ impl Context { internal_mem_block_lengths: HashMap::default(), max_block_id: 0, slice_sizes: HashMap::default(), + data_bus: DataBus::default(), } } @@ -226,6 +230,8 @@ impl Context { let dfg = &main_func.dfg; let entry_block = &dfg[main_func.entry_block()]; let input_witness = self.convert_ssa_block_params(entry_block.parameters(), dfg)?; + + self.data_bus = dfg.data_bus.to_owned(); let mut warnings = Vec::new(); for instruction_id in entry_block.instructions() { warnings.extend(self.convert_ssa_instruction( @@ -892,10 +898,26 @@ impl Context { dfg: &DataFlowGraph, ) -> Result { let (array_id, _, block_id) = self.check_array_is_initialized(array, dfg)?; - let results = dfg.instruction_results(instruction); let res_typ = dfg.type_of_value(results[0]); + // Get operations to call-data parameters are replaced by a get to the call-data-bus array + if let Some(call_data) = self.data_bus.call_data { + if self.data_bus.call_data_map.contains_key(&array_id) { + // TODO: the block_id of call-data must be notified to the backend + // TODO: should we do the same for return-data? + let type_size = res_typ.flattened_size(); + let type_size = + self.acir_context.add_constant(FieldElement::from(type_size as i128)); + let offset = self.acir_context.mul_var(var_index, type_size)?; + let bus_index = self.acir_context.add_constant(FieldElement::from( + self.data_bus.call_data_map[&array_id] as i128, + )); + let new_index = self.acir_context.add_var(offset, bus_index)?; + return self.array_get(instruction, call_data, new_index, dfg); + } + } + let value = if !res_typ.contains_slice_element() { self.array_get_value(&res_typ, block_id, &mut var_index, &[])? } else { diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs b/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs new file mode 100644 index 00000000000..7f337089321 --- /dev/null +++ b/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs @@ -0,0 +1,144 @@ +use std::rc::Rc; + +use crate::ssa::ir::{types::Type, value::ValueId}; +use acvm::FieldElement; +use fxhash::FxHashMap as HashMap; +use noirc_frontend::hir_def::function::FunctionSignature; + +use super::FunctionBuilder; + +/// Used to create a data bus, which is an array of private inputs +/// replacing public inputs +pub(crate) struct DataBusBuilder { + pub(crate) values: im::Vector, + index: usize, + pub(crate) map: HashMap, + pub(crate) databus: Option, +} + +impl DataBusBuilder { + pub(crate) fn new() -> DataBusBuilder { + DataBusBuilder { + index: 0, + map: HashMap::default(), + databus: None, + values: im::Vector::new(), + } + } + + /// Generates a boolean vector telling which (ssa) parameter from the given function signature + /// are tagged with databus visibility + pub(crate) fn is_databus(main_signature: &FunctionSignature) -> Vec { + let mut params_is_databus = Vec::new(); + + for param in &main_signature.0 { + let is_databus = match param.2 { + noirc_frontend::Visibility::Public | noirc_frontend::Visibility::Private => false, + noirc_frontend::Visibility::DataBus => true, + }; + let len = param.1.field_count() as usize; + params_is_databus.extend(vec![is_databus; len]); + } + params_is_databus + } +} + +#[derive(Clone, Default, Debug)] +pub(crate) struct DataBus { + pub(crate) call_data: Option, + pub(crate) call_data_map: HashMap, + pub(crate) return_data: Option, +} + +impl DataBus { + /// Updates the databus values with the provided function + pub(crate) fn map_values(&self, mut f: impl FnMut(ValueId) -> ValueId) -> DataBus { + let mut call_data_map = HashMap::default(); + for (k, v) in self.call_data_map.iter() { + call_data_map.insert(f(*k), *v); + } + DataBus { + call_data: self.call_data.map(&mut f), + call_data_map, + return_data: self.return_data.map(&mut f), + } + } + + /// Construct a databus from call_data and return_data data bus builders + pub(crate) fn get_data_bus(call_data: DataBusBuilder, return_data: DataBusBuilder) -> DataBus { + DataBus { + call_data: call_data.databus, + call_data_map: call_data.map, + return_data: return_data.databus, + } + } +} + +impl FunctionBuilder { + /// Insert a value into a data bus builder + fn add_to_data_bus(&mut self, value: ValueId, databus: &mut DataBusBuilder) { + assert!(databus.databus.is_none(), "initialising finalized call data"); + let typ = self.current_function.dfg[value].get_type().clone(); + match typ { + Type::Numeric(_) => { + databus.values.push_back(value); + databus.index += 1; + } + Type::Reference(_) => unreachable!(), + Type::Array(typ, len) => { + assert!(typ.len() == 1, "unsupported composite type"); + databus.map.insert(value, databus.index); + for i in 0..len { + // load each element of the array + let index = self + .current_function + .dfg + .make_constant(FieldElement::from(i as i128), Type::field()); + let element = self.insert_array_get(value, index, typ[0].clone()); + self.add_to_data_bus(element, databus); + } + } + Type::Slice(_) => unreachable!(), + Type::Function => unreachable!(), + } + } + + /// Create a data bus builder from a list of values + pub(crate) fn initialize_data_bus( + &mut self, + values: &[ValueId], + mut databus: DataBusBuilder, + ) -> DataBusBuilder { + for value in values { + self.add_to_data_bus(*value, &mut databus); + } + let len = databus.values.len(); + + let array = if len > 0 { + let array = + self.array_constant(databus.values, Type::Array(Rc::new(vec![Type::field()]), len)); + Some(array) + } else { + None + }; + + DataBusBuilder { index: 0, map: databus.map, databus: array, values: im::Vector::new() } + } + + /// Generate the data bus for call-data, based on the parameters of the entry block + /// and a boolean vector telling which ones are call-data + pub(crate) fn call_data_bus(&mut self, is_params_databus: Vec) -> DataBusBuilder { + //filter parameters of the first block that have call-data visilibity + let first_block = self.current_function.entry_block(); + let params = self.current_function.dfg[first_block].parameters(); + let mut databus_param = Vec::new(); + for (param, is_databus) in params.iter().zip(is_params_databus) { + if is_databus { + databus_param.push(param.to_owned()); + } + } + // create the call-data-bus from the filtered list + let call_data = DataBusBuilder::new(); + self.initialize_data_bus(&databus_param, call_data) + } +} diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index e01e1fe1a1d..f143ca7ee86 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -1,3 +1,5 @@ +pub(crate) mod data_bus; + use std::{borrow::Cow, rc::Rc}; use acvm::FieldElement; diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index 75b2cf962f7..abddbfb74c7 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use crate::ssa::ir::instruction::SimplifyResult; +use crate::ssa::{function_builder::data_bus::DataBus, ir::instruction::SimplifyResult}; use super::{ basic_block::{BasicBlock, BasicBlockId}, @@ -80,6 +80,8 @@ pub(crate) struct DataFlowGraph { /// Instructions inserted by internal SSA passes that don't correspond to user code /// may not have a corresponding location. locations: HashMap, + + pub(crate) data_bus: DataBus, } pub(crate) type CallStack = im::Vector; diff --git a/compiler/noirc_evaluator/src/ssa/opt/die.rs b/compiler/noirc_evaluator/src/ssa/opt/die.rs index 53cdf72bbbf..492e96dc08c 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/die.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/die.rs @@ -33,6 +33,10 @@ impl Ssa { /// of its instructions are needed elsewhere. fn dead_instruction_elimination(function: &mut Function) { let mut context = Context::default(); + if let Some(call_data) = function.dfg.data_bus.call_data { + context.mark_used_instruction_results(&function.dfg, call_data); + } + let blocks = PostOrder::with_function(function); for block in blocks.as_slice() { diff --git a/compiler/noirc_evaluator/src/ssa/opt/fill_internal_slices.rs b/compiler/noirc_evaluator/src/ssa/opt/fill_internal_slices.rs index fede0e540e2..f5e9598114c 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/fill_internal_slices.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/fill_internal_slices.rs @@ -67,8 +67,11 @@ impl Ssa { // The pass is also currently only setup to handle a function with a single flattened block. // For complex Brillig functions we can expect this pass to panic. if function.runtime() == RuntimeType::Acir { + let databus = function.dfg.data_bus.clone(); let mut context = Context::new(function); context.process_blocks(); + // update the databus with the new array instructions + function.dfg.data_bus = databus.map_values(|t| context.inserter.resolve(t)); } } self diff --git a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index ed2484febac..b4f12b2f897 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -139,11 +139,15 @@ impl InlineContext { context.blocks.insert(context.source_function.entry_block(), entry_block); context.inline_blocks(ssa); + // translate databus values + let databus = entry_point.dfg.data_bus.map_values(|t| context.translate_value(t)); // Finally, we should have 1 function left representing the inlined version of the target function. let mut new_ssa = self.builder.finish(); assert_eq!(new_ssa.functions.len(), 1); - new_ssa.functions.pop_first().unwrap().1 + let mut new_func = new_ssa.functions.pop_first().unwrap().1; + new_func.dfg.data_bus = databus; + new_func } /// Inlines a function into the current function and returns the translated return values diff --git a/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs b/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs index fba6e6ab989..ce205c8d883 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs @@ -91,6 +91,7 @@ impl Ssa { let mut context = PerFunctionContext::new(function); context.mem2reg(); context.remove_instructions(); + context.update_data_bus(); } self } @@ -362,6 +363,11 @@ impl<'f> PerFunctionContext<'f> { } } + fn update_data_bus(&mut self) { + let databus = self.inserter.function.dfg.data_bus.clone(); + self.inserter.function.dfg.data_bus = databus.map_values(|t| self.inserter.resolve(t)); + } + fn handle_terminator(&mut self, block: BasicBlockId, references: &mut Block) { self.inserter.map_terminator_in_place(block); diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index 53f1bc863be..acf60cd6799 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -1,4 +1,4 @@ -mod context; +pub(crate) mod context; mod program; mod value; @@ -9,12 +9,15 @@ use iter_extended::{try_vecmap, vecmap}; use noirc_errors::Location; use noirc_frontend::{ monomorphization::ast::{self, Binary, Expression, Program}, - BinaryOpKind, + BinaryOpKind, Visibility, }; use crate::{ errors::RuntimeError, - ssa::ir::{instruction::Intrinsic, types::NumericType}, + ssa::{ + function_builder::data_bus::DataBusBuilder, + ir::{instruction::Intrinsic, types::NumericType}, + }, }; use self::{ @@ -22,17 +25,25 @@ use self::{ value::{Tree, Values}, }; -use super::ir::{ - function::RuntimeType, - instruction::{BinaryOp, TerminatorInstruction}, - types::Type, - value::ValueId, +use super::{ + function_builder::data_bus::DataBus, + ir::{ + function::RuntimeType, + instruction::{BinaryOp, TerminatorInstruction}, + types::Type, + value::ValueId, + }, }; /// Generates SSA for the given monomorphized program. /// /// This function will generate the SSA but does not perform any optimizations on it. pub(crate) fn generate_ssa(program: Program) -> Result { + // see which parameter has call_data/return_data attribute + let is_databus = DataBusBuilder::is_databus(&program.main_function_signature); + + let is_return_data = matches!(program.return_visibility, Visibility::DataBus); + let return_location = program.return_location; let context = SharedContext::new(program); @@ -48,20 +59,41 @@ pub(crate) fn generate_ssa(program: Program) -> Result { if main.unconstrained { RuntimeType::Brillig } else { RuntimeType::Acir }, &context, ); + + // Generate the call_data bus from the relevant parameters. We create it *before* processing the function body + let call_data = function_context.builder.call_data_bus(is_databus); + function_context.codegen_function_body(&main.body)?; + let mut return_data = DataBusBuilder::new(); if let Some(return_location) = return_location { let block = function_context.builder.current_block(); - if function_context.builder.current_function.dfg[block].terminator().is_some() { - let return_instruction = - function_context.builder.current_function.dfg[block].unwrap_terminator_mut(); - match return_instruction { - TerminatorInstruction::Return { call_stack, .. } => { - call_stack.clear(); - call_stack.push_back(return_location); + if function_context.builder.current_function.dfg[block].terminator().is_some() + && is_return_data + { + // initialize the return_data bus from the return values + let return_data_values = + match function_context.builder.current_function.dfg[block].unwrap_terminator() { + TerminatorInstruction::Return { return_values, .. } => return_values.to_owned(), + _ => unreachable!("ICE - expect return on the last block"), + }; + + return_data = + function_context.builder.initialize_data_bus(&return_data_values, return_data); + } + let return_instruction = + function_context.builder.current_function.dfg[block].unwrap_terminator_mut(); + match return_instruction { + TerminatorInstruction::Return { return_values, call_stack } => { + call_stack.clear(); + call_stack.push_back(return_location); + // replace the returned values with the return data array + if let Some(return_data_bus) = return_data.databus { + return_values.clear(); + return_values.push(return_data_bus); } - _ => unreachable!("ICE - expect return on the last block"), } + _ => unreachable!("ICE - expect return on the last block"), } } @@ -74,6 +106,9 @@ pub(crate) fn generate_ssa(program: Program) -> Result { function_context.new_function(dest_id, function); function_context.codegen_function_body(&function.body)?; } + // we save the data bus inside the dfg + function_context.builder.current_function.dfg.data_bus = + DataBus::get_data_bus(call_data, return_data); Ok(function_context.builder.finish()) } diff --git a/compiler/noirc_frontend/src/ast/mod.rs b/compiler/noirc_frontend/src/ast/mod.rs index 5cbed19620d..2fbe73dafef 100644 --- a/compiler/noirc_frontend/src/ast/mod.rs +++ b/compiler/noirc_frontend/src/ast/mod.rs @@ -15,6 +15,7 @@ pub use expression::*; pub use function::*; use noirc_errors::Span; +use serde::{Deserialize, Serialize}; pub use statement::*; pub use structure::*; pub use traits::*; @@ -281,13 +282,16 @@ pub enum FunctionVisibility { PublicCrate, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Represents whether the parameter is public or known only to the prover. pub enum Visibility { Public, // Constants are not allowed in the ABI for main at the moment. // Constant, Private, + /// DataBus is public input handled as private input. We use the fact that return values are properly computed by the program to avoid having them as public inputs + /// it is useful for recursion and is handled by the proving system. + DataBus, } impl std::fmt::Display for Visibility { @@ -295,6 +299,7 @@ impl std::fmt::Display for Visibility { match self { Self::Public => write!(f, "pub"), Self::Private => write!(f, "priv"), + Self::DataBus => write!(f, "databus"), } } } diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index a788137a545..4e7ed7e2ea9 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -794,7 +794,7 @@ impl<'a> Resolver<'a> { // 'pub_allowed' also implies 'pub' is required on return types if self.pub_allowed(func) && return_type.as_ref() != &Type::Unit - && func.def.return_visibility != Visibility::Public + && func.def.return_visibility == Visibility::Private { self.push_err(ResolverError::NecessaryPub { ident: func.name_ident().clone() }); } diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index b16de42c0ba..ba93e52e1a8 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -644,6 +644,7 @@ pub enum Keyword { Assert, AssertEq, Bool, + CallData, Char, CompTime, Constrain, @@ -667,6 +668,7 @@ pub enum Keyword { Open, Pub, Return, + ReturnData, String, Struct, Trait, @@ -685,6 +687,7 @@ impl fmt::Display for Keyword { Keyword::AssertEq => write!(f, "assert_eq"), Keyword::Bool => write!(f, "bool"), Keyword::Char => write!(f, "char"), + Keyword::CallData => write!(f, "call_data"), Keyword::CompTime => write!(f, "comptime"), Keyword::Constrain => write!(f, "constrain"), Keyword::Contract => write!(f, "contract"), @@ -707,6 +710,7 @@ impl fmt::Display for Keyword { Keyword::Open => write!(f, "open"), Keyword::Pub => write!(f, "pub"), Keyword::Return => write!(f, "return"), + Keyword::ReturnData => write!(f, "return_data"), Keyword::String => write!(f, "str"), Keyword::Struct => write!(f, "struct"), Keyword::Trait => write!(f, "trait"), @@ -727,6 +731,7 @@ impl Keyword { "assert" => Keyword::Assert, "assert_eq" => Keyword::AssertEq, "bool" => Keyword::Bool, + "call_data" => Keyword::CallData, "char" => Keyword::Char, "comptime" => Keyword::CompTime, "constrain" => Keyword::Constrain, @@ -750,6 +755,7 @@ impl Keyword { "open" => Keyword::Open, "pub" => Keyword::Pub, "return" => Keyword::Return, + "return_data" => Keyword::ReturnData, "str" => Keyword::String, "struct" => Keyword::Struct, "trait" => Keyword::Trait, diff --git a/compiler/noirc_frontend/src/monomorphization/ast.rs b/compiler/noirc_frontend/src/monomorphization/ast.rs index 0a005d766fe..5a5f07b0a38 100644 --- a/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -2,7 +2,9 @@ use acvm::FieldElement; use iter_extended::vecmap; use noirc_errors::Location; -use crate::{hir_def::function::FunctionSignature, BinaryOpKind, Distinctness, Signedness}; +use crate::{ + hir_def::function::FunctionSignature, BinaryOpKind, Distinctness, Signedness, Visibility, +}; /// The monomorphized AST is expression-based, all statements are also /// folded into this expression enum. Compared to the HIR, the monomorphized @@ -243,6 +245,7 @@ pub struct Program { /// forwarding to the next phase. pub return_distinctness: Distinctness, pub return_location: Option, + pub return_visibility: Visibility, } impl Program { @@ -251,8 +254,15 @@ impl Program { main_function_signature: FunctionSignature, return_distinctness: Distinctness, return_location: Option, + return_visibility: Visibility, ) -> Program { - Program { functions, main_function_signature, return_distinctness, return_location } + Program { + functions, + main_function_signature, + return_distinctness, + return_location, + return_visibility, + } } pub fn main(&self) -> &Function { diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index 57e4e6cdeb0..4f035e0fc2e 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -105,8 +105,14 @@ pub fn monomorphize(main: node_interner::FuncId, interner: &NodeInterner) -> Pro } let functions = vecmap(monomorphizer.finished_functions, |(_, f)| f); - let FuncMeta { return_distinctness, .. } = interner.function_meta(&main); - Program::new(functions, function_sig, return_distinctness, monomorphizer.return_location) + let FuncMeta { return_distinctness, return_visibility, .. } = interner.function_meta(&main); + Program::new( + functions, + function_sig, + return_distinctness, + monomorphizer.return_location, + return_visibility, + ) } impl<'interner> Monomorphizer<'interner> { diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index 4c0500a0599..cc85fe88205 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -1034,10 +1034,18 @@ fn parenthesized_type( } fn optional_visibility() -> impl NoirParser { - keyword(Keyword::Pub).or_not().map(|opt| match opt { - Some(_) => Visibility::Public, - None => Visibility::Private, - }) + keyword(Keyword::Pub) + .or(keyword(Keyword::CallData)) + .or(keyword(Keyword::ReturnData)) + .or_not() + .map(|opt| match opt { + Some(Token::Keyword(Keyword::Pub)) => Visibility::Public, + Some(Token::Keyword(Keyword::CallData)) | Some(Token::Keyword(Keyword::ReturnData)) => { + Visibility::DataBus + } + None => Visibility::Private, + _ => unreachable!("unexpected token found"), + }) } fn optional_distinctness() -> impl NoirParser { diff --git a/docs/docs/language_concepts/12_data_bus.md b/docs/docs/language_concepts/12_data_bus.md new file mode 100644 index 00000000000..9ef5c33fcf6 --- /dev/null +++ b/docs/docs/language_concepts/12_data_bus.md @@ -0,0 +1,23 @@ +--- +title: Data Bus +--- +**Disclaimer** this feature is experimental, do not use it! + +The data bus is an optimization that the backend can use to make recursion more efficient. +In order to use it, you must define some inputs of the program entry points (usually the `main()` +function) with the `call_data` modifier, and the return values with the `return_data` modifier. +These modifiers are incompatible with `pub` and `mut` modifiers. + + +## Example + + +```rust +fn main(mut x: u32, y: call_data u32, z: call_data [u32;4] ) -> return_data u32 { + let a = z[x]; + a+y +} +``` + +As a result, both call_data and return_data will be treated as private inputs and encapsulated into a read-only array each, for the backend to process. + diff --git a/tooling/nargo_cli/src/cli/fs/inputs.rs b/tooling/nargo_cli/src/cli/fs/inputs.rs index f3f0baf10f4..023195010ac 100644 --- a/tooling/nargo_cli/src/cli/fs/inputs.rs +++ b/tooling/nargo_cli/src/cli/fs/inputs.rs @@ -73,7 +73,7 @@ mod tests { use nargo::constants::VERIFIER_INPUT_FILE; use noirc_abi::{ input_parser::{Format, InputValue}, - Abi, AbiParameter, AbiType, AbiVisibility, + Abi, AbiParameter, AbiReturnType, AbiType, AbiVisibility, }; use tempfile::TempDir; @@ -98,7 +98,10 @@ mod tests { visibility: AbiVisibility::Private, }, ], - return_type: Some(AbiType::Field), + return_type: Some(AbiReturnType { + abi_type: AbiType::Field, + visibility: AbiVisibility::Public, + }), // Input serialization is only dependent on types, not position in witness map. // Neither of these should be relevant so we leave them empty. diff --git a/tooling/nargo_cli/tests/execution_success/databus/Nargo.toml b/tooling/nargo_cli/tests/execution_success/databus/Nargo.toml new file mode 100644 index 00000000000..72360f7aefe --- /dev/null +++ b/tooling/nargo_cli/tests/execution_success/databus/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "databus" +type = "bin" +authors = [""] + +[dependencies] diff --git a/tooling/nargo_cli/tests/execution_success/databus/Prover.toml b/tooling/nargo_cli/tests/execution_success/databus/Prover.toml new file mode 100644 index 00000000000..2d034508dd8 --- /dev/null +++ b/tooling/nargo_cli/tests/execution_success/databus/Prover.toml @@ -0,0 +1,3 @@ +x = "3" +y = "4" +z = [1,2,3,4] diff --git a/tooling/nargo_cli/tests/execution_success/databus/src/main.nr b/tooling/nargo_cli/tests/execution_success/databus/src/main.nr new file mode 100644 index 00000000000..631331ef2d7 --- /dev/null +++ b/tooling/nargo_cli/tests/execution_success/databus/src/main.nr @@ -0,0 +1,10 @@ +// Test unsafe integer multiplication with overflow: 12^8 = 429 981 696 +// The circuit should handle properly the growth of the bit size +use dep::std; + +fn main(mut x: u32, y: call_data u32, z: call_data [u32;4] ) -> return_data u32 { + +let a = z[x]; + a+y + +} diff --git a/tooling/nargo_fmt/src/utils.rs b/tooling/nargo_fmt/src/utils.rs index 4fbc1e8f85b..1160f01972f 100644 --- a/tooling/nargo_fmt/src/utils.rs +++ b/tooling/nargo_fmt/src/utils.rs @@ -254,6 +254,7 @@ impl Item for Param { 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); diff --git a/tooling/noir_codegen/src/noir_types.ts b/tooling/noir_codegen/src/noir_types.ts index d1a22a3e2da..ba4f8650b3b 100644 --- a/tooling/noir_codegen/src/noir_types.ts +++ b/tooling/noir_codegen/src/noir_types.ts @@ -170,7 +170,7 @@ export function generateTsInterface( // Generating Return type, if it exists if (abiObj.return_type != null) { - result += generateStructInterfaces(abiObj.return_type, outputStructs, primitiveTypeMap); + result += generateStructInterfaces(abiObj.return_type.abi_type, outputStructs, primitiveTypeMap); } return [result, getTsFunctionSignature(abiObj, primitiveTypeMap)]; @@ -184,6 +184,6 @@ function getTsFunctionSignature( param.name, abiTypeToTs(param.type, primitiveTypeMap), ]); - const returnValue = abi.return_type ? abiTypeToTs(abi.return_type, primitiveTypeMap) : null; + const returnValue = abi.return_type ? abiTypeToTs(abi.return_type.abi_type, primitiveTypeMap) : null; return { inputs, returnValue }; } diff --git a/tooling/noir_codegen/test/assert_lt/target/assert_lt.json b/tooling/noir_codegen/test/assert_lt/target/assert_lt.json index 6d928a26d43..a1ab87a99fe 100644 --- a/tooling/noir_codegen/test/assert_lt/target/assert_lt.json +++ b/tooling/noir_codegen/test/assert_lt/target/assert_lt.json @@ -1 +1 @@ -{"noir_version":"0.19.3+e9322d14070fa444d77ee5c43c905dd86a67c6e3","hash":9449934793688855780,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"},{"name":"array","type":{"kind":"array","length":5,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"},{"name":"my_struct","type":{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]},"visibility":"private"},{"name":"string","type":{"kind":"string","length":5},"visibility":"private"}],"param_witnesses":{"array":[{"start":3,"end":8}],"my_struct":[{"start":8,"end":24}],"string":[{"start":24,"end":29}],"x":[{"start":1,"end":2}],"y":[{"start":2,"end":3}]},"return_type":{"kind":"tuple","fields":[{"kind":"integer","sign":"unsigned","width":64},{"kind":"integer","sign":"unsigned","width":64},{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]}]},"return_witnesses":[31,32,33,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]},"bytecode":"H4sIAAAAAAAA/81XbU/CMBDu5hv4gopvvGw49JOJH1q2wfaN+E+AddFEgzGL/H250Go5dInumnhJ0z2jXJ9er7s+t4yxe7YyZ9lc1Y8N7CK8tWw1A28jvIPwLsJ7Cus5mfIPxquZqBlzmX5DPowiORpIEYoJH6TTJOZRPB0mIhFxEmeDJAxlEiWjdJqOeCqiUIo8TsNcOa7RceQ6DnUUl32EDxA+RPgI4QbCxwifIHyKcBPhM4TPEb5A+BLhK4RbCLcR7iDcRdhjX3mjzUb+jIlyxibPFgFPmYNlVnm2yXjOcps8O3Q8pU2eXTqemU2eHh3PGdQbl22aS8zZYXRn3/07L4FffLN0Mt9mXH3V99iqhuu80GOgzj+wzZxxjGdXjXFLxjg/+Kkb7/T/G8bvVRe/EQxzciqfvgok9QXEp+P4eQHpGT61bRHHw9ahqurrhjCeZfH7JU+OeAqfcM09wn2tEL/SD9x/Pjdl+8yr2do54dVMUJ6Ta0b/3TF92tr3gI53aJNnn3DfuwZHyE8o2FDIQYBr0Q1FFoQmiEsQlCAiociCWASBCKIQhCCIPxB8IPJA2IGYA9EBF3q4LMNcHlsv/E31XGUOyI1g2fpsvfDfqd5T/aQo5MtrERTzYJJlweKpeAzm7/Itf54vPgBYg2KL1RAAAA=="} \ No newline at end of file +{"noir_version":"0.19.4+55670ff82c270534a4bdb999ab0de5cea7017093","hash":11505576107297330043,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"},{"name":"array","type":{"kind":"array","length":5,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"},{"name":"my_struct","type":{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]},"visibility":"private"},{"name":"string","type":{"kind":"string","length":5},"visibility":"private"}],"param_witnesses":{"array":[{"start":3,"end":8}],"my_struct":[{"start":8,"end":24}],"string":[{"start":24,"end":29}],"x":[{"start":1,"end":2}],"y":[{"start":2,"end":3}]},"return_type":{"abi_type":{"kind":"tuple","fields":[{"kind":"integer","sign":"unsigned","width":64},{"kind":"integer","sign":"unsigned","width":64},{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]}]},"visibility":"public"},"return_witnesses":[31,32,33,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]},"bytecode":"H4sIAAAAAAAA/81XbU/CMBDu5hv4gopvvGw49JOJH1q2wfaN+E+AddFEgzGL/H250Go5dInumnhJ0z2jXJ9er7s+t4yxe7YyZ9lc1Y8N7CK8tWw1A28jvIPwLsJ7Cus5mfIPxquZqBlzmX5DPowiORpIEYoJH6TTJOZRPB0mIhFxEmeDJAxlEiWjdJqOeCqiUIo8TsNcOa7RceQ6DnUUl32EDxA+RPgI4QbCxwifIHyKcBPhM4TPEb5A+BLhK4RbCLcR7iDcRdhjX3mjzUb+jIlyxibPFgFPmYNlVnm2yXjOcps8O3Q8pU2eXTqemU2eHh3PGdQbl22aS8zZYXRn3/07L4FffLN0Mt9mXH3V99iqhuu80GOgzj+wzZxxjGdXjXFLxjg/+Kkb7/T/G8bvVRe/EQxzciqfvgok9QXEp+P4eQHpGT61bRHHw9ahqurrhjCeZfH7JU+OeAqfcM09wn2tEL/SD9x/Pjdl+8yr2do54dVMUJ6Ta0b/3TF92tr3gI53aJNnn3DfuwZHyE8o2FDIQYBr0Q1FFoQmiEsQlCAiociCWASBCKIQhCCIPxB8IPJA2IGYA9EBF3q4LMNcHlsv/E31XGUOyI1g2fpsvfDfqd5T/aQo5MtrERTzYJJlweKpeAzm7/Itf54vPgBYg2KL1RAAAA=="} \ No newline at end of file diff --git a/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json b/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json index c01b2c5d3f5..7c9b30daa9e 100644 --- a/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json +++ b/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json @@ -1 +1 @@ -{"hash":13834844072603749544,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"}],"param_witnesses":{"x":[{ "start": 1, "end": 2 }],"y":[{ "start": 2, "end": 3 }]},"return_type":{"kind":"integer","sign":"unsigned","width":64},"return_witnesses":[12]},"bytecode":"H4sIAAAAAAAA/+1WUW6DMAx1QksZoGr72jUcAiX8VbvJ0Oj9j7ChJpKbtXw0NpvUWkImUXixn53w3gDgHc6mfh7t/ZGMtR9TU96HeYuHtp36ZjLWfGIzjK7DthsPzjjTue6rcdZOrnX9MA49Dqa1kzl1gz3h2bL7sTDCMhmJbylmTDOT8WEhjXfjH/DcB8u8zwVygWifmL/9lTnWzSWKsxHA3QJf00vlveWvERJIUU4x0eb86aEJppljVox9oO+Py8QTV1Jnw6a85t7vSL8pwvN89j7gd88o8q79Gr2wRt3AeSFz4XvRSyokl5MAtSfgGO2ZCewdsDibLRVrDzIXTMxfqiLIGXPeMdY1gb/Fg8+tznJY50eSGmfB2DNrqciCD+tCRc4X5FNFJmIWnkhu3BL+t4qc8y75aySqIkvGOP9CRWKaGQ0ydUrsgUUVWXlfw4OpyAouVWQN66pITDPDqSJfQaZxuVVkxZhzzVgLTv5uHbDwXhN+vwGywklHPBQAAA=="} \ No newline at end of file +{"noir_version":"0.19.4+55670ff82c270534a4bdb999ab0de5cea7017093","hash":4729344722355302200,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"}],"param_witnesses":{"x":[{"start":1,"end":2}],"y":[{"start":2,"end":3}]},"return_type":{"abi_type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"},"return_witnesses":[5]},"bytecode":"H4sIAAAAAAAA/81V4WrDIBDWmGxsP/YE+5FH8KI2+q/0TRJi2GAjY8j6+itM4eraQOsVeiCnF/1y9513PjLGntmf8MOoot6idRXXIs5zSbZt1LJMgCMsJTda+77zoGCQnRutkdqMGwsWjDVTZ5XyVtveja6XDrTyMBun5ghWXe8X5IYToZNhY15F1PVhNFlukn2H9nOkOcrJDp05tYefwXlCtnT+BX0vDf4fGfjnVJgiEpnjll4oQeejTEmtEWYSQczHrYqqFOuBkM81/i70U2Z+giCMuSbMawF/qw3unutmLc+yTI7qRJYJUNZJw+j7TsI894CkecOOm396IF6jHkLwn1+hDUs7TFO7fw9v7fLjv+ePZf8LJenp6WEIAAA="} \ No newline at end of file diff --git a/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts b/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts index 98189eaed5f..dab1c56436a 100644 --- a/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts +++ b/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts @@ -38,18 +38,21 @@ const abi: Abi = { ], }, return_type: { - kind: 'tuple', - fields: [ - { - kind: 'field', - }, - { - kind: 'field', - }, - { - kind: 'field', - }, - ], + abi_type: { + kind: 'tuple', + fields: [ + { + kind: 'field', + }, + { + kind: 'field', + }, + { + kind: 'field', + }, + ], + }, + visibility: 'public', }, return_witnesses: [2, 13, 13], }; diff --git a/tooling/noirc_abi/src/input_parser/json.rs b/tooling/noirc_abi/src/input_parser/json.rs index e2b1a83ee6b..7618cd6c15a 100644 --- a/tooling/noirc_abi/src/input_parser/json.rs +++ b/tooling/noirc_abi/src/input_parser/json.rs @@ -28,8 +28,11 @@ pub(crate) fn parse_json( if let (Some(return_type), Some(json_return_value)) = (&abi.return_type, data.get(MAIN_RETURN_NAME)) { - let return_value = - InputValue::try_from_json(json_return_value.clone(), return_type, MAIN_RETURN_NAME)?; + let return_value = InputValue::try_from_json( + json_return_value.clone(), + &return_type.abi_type, + MAIN_RETURN_NAME, + )?; parsed_inputs.insert(MAIN_RETURN_NAME.to_owned(), return_value); } @@ -48,7 +51,7 @@ pub(crate) fn serialize_to_json( if let (Some(return_type), Some(return_value)) = (&abi.return_type, input_map.get(MAIN_RETURN_NAME)) { - let return_value = JsonTypes::try_from_input_value(return_value, return_type)?; + let return_value = JsonTypes::try_from_input_value(return_value, &return_type.abi_type)?; json_map.insert(MAIN_RETURN_NAME.to_owned(), return_value); } diff --git a/tooling/noirc_abi/src/input_parser/mod.rs b/tooling/noirc_abi/src/input_parser/mod.rs index 7bbcb42296c..e1265da1c85 100644 --- a/tooling/noirc_abi/src/input_parser/mod.rs +++ b/tooling/noirc_abi/src/input_parser/mod.rs @@ -130,7 +130,8 @@ mod serialization_tests { use strum::IntoEnumIterator; use crate::{ - input_parser::InputValue, Abi, AbiParameter, AbiType, AbiVisibility, Sign, MAIN_RETURN_NAME, + input_parser::InputValue, Abi, AbiParameter, AbiReturnType, AbiType, AbiVisibility, Sign, + MAIN_RETURN_NAME, }; use super::Format; @@ -159,7 +160,10 @@ mod serialization_tests { visibility: AbiVisibility::Private, }, ], - return_type: Some(AbiType::String { length: 5 }), + return_type: Some(AbiReturnType { + abi_type: AbiType::String { length: 5 }, + visibility: AbiVisibility::Public, + }), // These two fields are unused when serializing/deserializing to file. param_witnesses: BTreeMap::new(), return_witnesses: Vec::new(), diff --git a/tooling/noirc_abi/src/input_parser/toml.rs b/tooling/noirc_abi/src/input_parser/toml.rs index 645b59b00cd..b216fe58794 100644 --- a/tooling/noirc_abi/src/input_parser/toml.rs +++ b/tooling/noirc_abi/src/input_parser/toml.rs @@ -28,8 +28,11 @@ pub(crate) fn parse_toml( if let (Some(return_type), Some(toml_return_value)) = (&abi.return_type, data.get(MAIN_RETURN_NAME)) { - let return_value = - InputValue::try_from_toml(toml_return_value.clone(), return_type, MAIN_RETURN_NAME)?; + let return_value = InputValue::try_from_toml( + toml_return_value.clone(), + &return_type.abi_type, + MAIN_RETURN_NAME, + )?; parsed_inputs.insert(MAIN_RETURN_NAME.to_owned(), return_value); } @@ -48,7 +51,7 @@ pub(crate) fn serialize_to_toml( if let (Some(return_type), Some(return_value)) = (&abi.return_type, input_map.get(MAIN_RETURN_NAME)) { - let return_value = TomlTypes::try_from_input_value(return_value, return_type)?; + let return_value = TomlTypes::try_from_input_value(return_value, &return_type.abi_type)?; toml_map.insert(MAIN_RETURN_NAME.to_owned(), return_value); } diff --git a/tooling/noirc_abi/src/lib.rs b/tooling/noirc_abi/src/lib.rs index 7092f05c26e..41ef7cde628 100644 --- a/tooling/noirc_abi/src/lib.rs +++ b/tooling/noirc_abi/src/lib.rs @@ -78,6 +78,7 @@ pub enum AbiVisibility { // Constants are not allowed in the ABI for main at the moment. // Constant, Private, + DataBus, } impl From for AbiVisibility { @@ -85,6 +86,7 @@ impl From for AbiVisibility { match value { Visibility::Public => AbiVisibility::Public, Visibility::Private => AbiVisibility::Private, + Visibility::DataBus => AbiVisibility::DataBus, } } } @@ -94,6 +96,7 @@ impl From<&Visibility> for AbiVisibility { match value { Visibility::Public => AbiVisibility::Public, Visibility::Private => AbiVisibility::Private, + Visibility::DataBus => AbiVisibility::DataBus, } } } @@ -212,6 +215,11 @@ impl AbiParameter { } } +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AbiReturnType { + pub abi_type: AbiType, + pub visibility: AbiVisibility, +} #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Abi { /// An ordered list of the arguments to the program's `main` function, specifying their types and visibility. @@ -219,7 +227,7 @@ pub struct Abi { /// A map from the ABI's parameters to the indices they are written to in the [`WitnessMap`]. /// This defines how to convert between the [`InputMap`] and [`WitnessMap`]. pub param_witnesses: BTreeMap>>, - pub return_type: Option, + pub return_type: Option, pub return_witnesses: Vec, } @@ -327,7 +335,7 @@ impl Abi { // When encoding public inputs to be passed to the verifier, the user can must provide a return value // to be inserted into the witness map. This is not needed when generating a witness when proving the circuit. match (&self.return_type, return_value) { - (Some(return_type), Some(return_value)) => { + (Some(AbiReturnType { abi_type: return_type, .. }), Some(return_value)) => { if !return_value.matches_abi(return_type) { return Err(AbiError::ReturnTypeMismatch { return_type: return_type.clone(), @@ -426,7 +434,7 @@ impl Abi { .copied() }) { - Some(decode_value(&mut return_witness_values.into_iter(), return_type)?) + Some(decode_value(&mut return_witness_values.into_iter(), &return_type.abi_type)?) } else { // Unlike for the circuit inputs, we tolerate not being able to find the witness values for the return value. // This is because the user may be decoding a partial witness map for which is hasn't been calculated yet. @@ -546,7 +554,10 @@ mod test { use acvm::{acir::native_types::Witness, FieldElement}; - use crate::{input_parser::InputValue, Abi, AbiParameter, AbiType, AbiVisibility, InputMap}; + use crate::{ + input_parser::InputValue, Abi, AbiParameter, AbiReturnType, AbiType, AbiVisibility, + InputMap, + }; #[test] fn witness_encoding_roundtrip() { @@ -568,7 +579,10 @@ mod test { ("thing1".to_string(), vec![(Witness(1)..Witness(3))]), ("thing2".to_string(), vec![(Witness(3)..Witness(4))]), ]), - return_type: Some(AbiType::Field), + return_type: Some(AbiReturnType { + abi_type: AbiType::Field, + visibility: AbiVisibility::Public, + }), return_witnesses: vec![Witness(3)], }; diff --git a/tooling/noirc_abi_wasm/src/lib.rs b/tooling/noirc_abi_wasm/src/lib.rs index a3d829dd40f..fb4c295b8c8 100644 --- a/tooling/noirc_abi_wasm/src/lib.rs +++ b/tooling/noirc_abi_wasm/src/lib.rs @@ -47,7 +47,7 @@ extern "C" { #[wasm_bindgen(typescript_custom_section)] const ABI: &'static str = r#" -export type Visibility = "public" | "private"; +export type Visibility = "public" | "private" | "databus"; export type Sign = "unsigned" | "signed"; export type AbiType = { kind: "field" } | @@ -67,7 +67,7 @@ export type AbiParameter = { export type Abi = { parameters: AbiParameter[], param_witnesses: Record, - return_type: AbiType | null, + return_type: {abi_type: AbiType, visibility: Visibility} | null, return_witnesses: number[], } "#; @@ -96,7 +96,7 @@ pub fn abi_encode( .expect("could not decode return value"); InputValue::try_from_json( toml_return_value, - abi.return_type.as_ref().unwrap(), + &abi.return_type.as_ref().unwrap().abi_type, MAIN_RETURN_NAME, ) }) @@ -134,7 +134,7 @@ pub fn abi_decode(abi: JsAbi, witness_map: JsWitnessMap) -> Result