Skip to content

Commit

Permalink
feat!: Acir call opcode (AztecProtocol/aztec-packages#4773)
Browse files Browse the repository at this point in the history
  • Loading branch information
AztecBot committed Mar 18, 2024
1 parent d4213a0 commit c4d62e9
Show file tree
Hide file tree
Showing 101 changed files with 2,015 additions and 1,555 deletions.
2 changes: 1 addition & 1 deletion .aztec-sync-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
aa90f6ed7bfae06bdf6990816d154bbd24993689
0b15db2bea70696597911e82b60f0def595c1150
2 changes: 1 addition & 1 deletion .github/scripts/wasm-bindgen-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ cd $(dirname "$0")
./cargo-binstall-install.sh

# Install wasm-bindgen-cli.
if [ "$(wasm-bindgen --version | cut -d' ' -f2)" != "0.2.86" ]; then
if [ "$(wasm-bindgen --version &> /dev/null | cut -d' ' -f2)" != "0.2.86" ]; then
echo "Building wasm-bindgen..."
cargo binstall wasm-bindgen-cli@0.2.86 --force --no-confirm
fi
Expand Down
181 changes: 179 additions & 2 deletions acvm-repo/acir/codegen/acir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,31 @@ namespace Circuit {
static Div bincodeDeserialize(std::vector<uint8_t>);
};

struct IntegerDiv {
friend bool operator==(const IntegerDiv&, const IntegerDiv&);
std::vector<uint8_t> bincodeSerialize() const;
static IntegerDiv bincodeDeserialize(std::vector<uint8_t>);
};

struct Equals {
friend bool operator==(const Equals&, const Equals&);
std::vector<uint8_t> bincodeSerialize() const;
static Equals bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<Add, Sub, Mul, Div, Equals> value;
struct LessThan {
friend bool operator==(const LessThan&, const LessThan&);
std::vector<uint8_t> bincodeSerialize() const;
static LessThan bincodeDeserialize(std::vector<uint8_t>);
};

struct LessThanEquals {
friend bool operator==(const LessThanEquals&, const LessThanEquals&);
std::vector<uint8_t> bincodeSerialize() const;
static LessThanEquals bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<Add, Sub, Mul, Div, IntegerDiv, Equals, LessThan, LessThanEquals> value;

friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -1053,7 +1071,17 @@ namespace Circuit {
static MemoryInit bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<AssertZero, BlackBoxFuncCall, Directive, Brillig, MemoryOp, MemoryInit> value;
struct Call {
uint32_t id;
std::vector<Circuit::Witness> inputs;
std::vector<Circuit::Witness> outputs;

friend bool operator==(const Call&, const Call&);
std::vector<uint8_t> bincodeSerialize() const;
static Call bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<AssertZero, BlackBoxFuncCall, Directive, Brillig, MemoryOp, MemoryInit, Call> value;

friend bool operator==(const Opcode&, const Opcode&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -1317,6 +1345,41 @@ Circuit::BinaryFieldOp::Div serde::Deserializable<Circuit::BinaryFieldOp::Div>::
return obj;
}

namespace Circuit {

inline bool operator==(const BinaryFieldOp::IntegerDiv &lhs, const BinaryFieldOp::IntegerDiv &rhs) {
return true;
}

inline std::vector<uint8_t> BinaryFieldOp::IntegerDiv::bincodeSerialize() const {
auto serializer = serde::BincodeSerializer();
serde::Serializable<BinaryFieldOp::IntegerDiv>::serialize(*this, serializer);
return std::move(serializer).bytes();
}

inline BinaryFieldOp::IntegerDiv BinaryFieldOp::IntegerDiv::bincodeDeserialize(std::vector<uint8_t> input) {
auto deserializer = serde::BincodeDeserializer(input);
auto value = serde::Deserializable<BinaryFieldOp::IntegerDiv>::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 <typename Serializer>
void serde::Serializable<Circuit::BinaryFieldOp::IntegerDiv>::serialize(const Circuit::BinaryFieldOp::IntegerDiv &obj, Serializer &serializer) {
}

template <>
template <typename Deserializer>
Circuit::BinaryFieldOp::IntegerDiv serde::Deserializable<Circuit::BinaryFieldOp::IntegerDiv>::deserialize(Deserializer &deserializer) {
Circuit::BinaryFieldOp::IntegerDiv obj;
return obj;
}

namespace Circuit {

inline bool operator==(const BinaryFieldOp::Equals &lhs, const BinaryFieldOp::Equals &rhs) {
Expand Down Expand Up @@ -1352,6 +1415,76 @@ Circuit::BinaryFieldOp::Equals serde::Deserializable<Circuit::BinaryFieldOp::Equ
return obj;
}

namespace Circuit {

inline bool operator==(const BinaryFieldOp::LessThan &lhs, const BinaryFieldOp::LessThan &rhs) {
return true;
}

inline std::vector<uint8_t> BinaryFieldOp::LessThan::bincodeSerialize() const {
auto serializer = serde::BincodeSerializer();
serde::Serializable<BinaryFieldOp::LessThan>::serialize(*this, serializer);
return std::move(serializer).bytes();
}

inline BinaryFieldOp::LessThan BinaryFieldOp::LessThan::bincodeDeserialize(std::vector<uint8_t> input) {
auto deserializer = serde::BincodeDeserializer(input);
auto value = serde::Deserializable<BinaryFieldOp::LessThan>::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 <typename Serializer>
void serde::Serializable<Circuit::BinaryFieldOp::LessThan>::serialize(const Circuit::BinaryFieldOp::LessThan &obj, Serializer &serializer) {
}

template <>
template <typename Deserializer>
Circuit::BinaryFieldOp::LessThan serde::Deserializable<Circuit::BinaryFieldOp::LessThan>::deserialize(Deserializer &deserializer) {
Circuit::BinaryFieldOp::LessThan obj;
return obj;
}

namespace Circuit {

inline bool operator==(const BinaryFieldOp::LessThanEquals &lhs, const BinaryFieldOp::LessThanEquals &rhs) {
return true;
}

inline std::vector<uint8_t> BinaryFieldOp::LessThanEquals::bincodeSerialize() const {
auto serializer = serde::BincodeSerializer();
serde::Serializable<BinaryFieldOp::LessThanEquals>::serialize(*this, serializer);
return std::move(serializer).bytes();
}

inline BinaryFieldOp::LessThanEquals BinaryFieldOp::LessThanEquals::bincodeDeserialize(std::vector<uint8_t> input) {
auto deserializer = serde::BincodeDeserializer(input);
auto value = serde::Deserializable<BinaryFieldOp::LessThanEquals>::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 <typename Serializer>
void serde::Serializable<Circuit::BinaryFieldOp::LessThanEquals>::serialize(const Circuit::BinaryFieldOp::LessThanEquals &obj, Serializer &serializer) {
}

template <>
template <typename Deserializer>
Circuit::BinaryFieldOp::LessThanEquals serde::Deserializable<Circuit::BinaryFieldOp::LessThanEquals>::deserialize(Deserializer &deserializer) {
Circuit::BinaryFieldOp::LessThanEquals obj;
return obj;
}

namespace Circuit {

inline bool operator==(const BinaryIntOp &lhs, const BinaryIntOp &rhs) {
Expand Down Expand Up @@ -6012,6 +6145,50 @@ Circuit::Opcode::MemoryInit serde::Deserializable<Circuit::Opcode::MemoryInit>::
return obj;
}

namespace Circuit {

inline bool operator==(const Opcode::Call &lhs, const Opcode::Call &rhs) {
if (!(lhs.id == rhs.id)) { return false; }
if (!(lhs.inputs == rhs.inputs)) { return false; }
if (!(lhs.outputs == rhs.outputs)) { return false; }
return true;
}

inline std::vector<uint8_t> Opcode::Call::bincodeSerialize() const {
auto serializer = serde::BincodeSerializer();
serde::Serializable<Opcode::Call>::serialize(*this, serializer);
return std::move(serializer).bytes();
}

inline Opcode::Call Opcode::Call::bincodeDeserialize(std::vector<uint8_t> input) {
auto deserializer = serde::BincodeDeserializer(input);
auto value = serde::Deserializable<Opcode::Call>::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 <typename Serializer>
void serde::Serializable<Circuit::Opcode::Call>::serialize(const Circuit::Opcode::Call &obj, Serializer &serializer) {
serde::Serializable<decltype(obj.id)>::serialize(obj.id, serializer);
serde::Serializable<decltype(obj.inputs)>::serialize(obj.inputs, serializer);
serde::Serializable<decltype(obj.outputs)>::serialize(obj.outputs, serializer);
}

template <>
template <typename Deserializer>
Circuit::Opcode::Call serde::Deserializable<Circuit::Opcode::Call>::deserialize(Deserializer &deserializer) {
Circuit::Opcode::Call obj;
obj.id = serde::Deserializable<decltype(obj.id)>::deserialize(deserializer);
obj.inputs = serde::Deserializable<decltype(obj.inputs)>::deserialize(deserializer);
obj.outputs = serde::Deserializable<decltype(obj.outputs)>::deserialize(deserializer);
return obj;
}

namespace Circuit {

inline bool operator==(const OpcodeLocation &lhs, const OpcodeLocation &rhs) {
Expand Down
16 changes: 16 additions & 0 deletions acvm-repo/acir/src/circuit/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ pub enum Opcode {
block_id: BlockId,
init: Vec<Witness>,
},
/// Calls to functions represented as a separate circuit. A call opcode allows us
/// to build a call stack when executing the outer-most circuit.
Call {
/// Id for the function being called. It is the responsibility of the executor
/// to fetch the appropriate circuit from this id.
id: u32,
/// Inputs to the function call
inputs: Vec<Witness>,
/// Outputs of the function call
outputs: Vec<Witness>,
},
}

impl std::fmt::Display for Opcode {
Expand Down Expand Up @@ -86,6 +97,11 @@ impl std::fmt::Display for Opcode {
write!(f, "INIT ")?;
write!(f, "(id: {}, len: {}) ", block_id.0, init.len())
}
Opcode::Call { id, inputs, outputs } => {
write!(f, "CALL func {}: ", id)?;
writeln!(f, "inputs: {:?}", inputs)?;
writeln!(f, "outputs: {:?}", outputs)
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions acvm-repo/acvm/src/compiler/transformers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ pub(super) fn transform_internal(
new_acir_opcode_positions.push(acir_opcode_positions[index]);
transformed_opcodes.push(opcode);
}
Opcode::Call { .. } => todo!("Handle Call opcodes in the ACVM"),
}
}

Expand Down
1 change: 1 addition & 0 deletions acvm-repo/acvm/src/pwg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
Ok(Some(foreign_call)) => return self.wait_for_foreign_call(foreign_call),
res => res.map(|_| ()),
},
Opcode::Call { .. } => todo!("Handle Call opcodes in the ACVM"),
};
self.handle_opcode_resolution(resolution)
}
Expand Down
7 changes: 7 additions & 0 deletions acvm-repo/brillig/src/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,16 @@ pub enum BinaryFieldOp {
Add,
Sub,
Mul,
/// Field division
Div,
/// Integer division
IntegerDiv,
/// (==) equal
Equals,
/// (<) Field less than
LessThan,
/// (<=) field less or equal
LessThanEquals,
}

/// Binary fixed-length integer expressions
Expand Down
9 changes: 9 additions & 0 deletions acvm-repo/brillig_vm/src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,16 @@ pub(crate) fn evaluate_binary_field_op(
BinaryFieldOp::Sub => a - b,
BinaryFieldOp::Mul => a * b,
BinaryFieldOp::Div => a / b,
BinaryFieldOp::IntegerDiv => {
let a_big = BigUint::from_bytes_be(&a.to_be_bytes());
let b_big = BigUint::from_bytes_be(&b.to_be_bytes());

let result = a_big / b_big;
FieldElement::from_be_bytes_reduce(&result.to_bytes_be())
}
BinaryFieldOp::Equals => (a == b).into(),
BinaryFieldOp::LessThan => (a < b).into(),
BinaryFieldOp::LessThanEquals => (a <= b).into(),
}
}

Expand Down
9 changes: 0 additions & 9 deletions aztec_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,6 @@ fn transform_module(
crate_graph.root_file_id,
));
}

let constructor_defined = module.functions.iter().any(|func| func.name() == "constructor");
if !constructor_defined {
let crate_graph = &context.crate_graph[crate_id];
return Err((
AztecMacroError::ContractConstructorMissing { span: Span::default() },
crate_graph.root_file_id,
));
}
}

Ok(has_transformed_module)
Expand Down
16 changes: 8 additions & 8 deletions aztec_macros/src/transforms/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,9 @@ pub fn transform_function(
func.def.body.0.insert(0, init_check);
}

// Add assertion for initialization arguments
// Add assertion for initialization arguments and sender
if is_initializer {
let assert_init_args = create_assert_init_args();
func.def.body.0.insert(0, assert_init_args);
func.def.body.0.insert(0, create_assert_initializer());
}

// Add access to the storage struct
Expand Down Expand Up @@ -211,18 +210,19 @@ fn create_internal_check(fname: &str) -> Statement {
)))
}

/// Creates a call to assert_initialization_args_match_address_preimage to ensure
/// the initialization arguments used in the init call match the address preimage.
/// Creates a call to assert_initialization_matches_address_preimage to be inserted
/// in the initializer. Checks that the args and sender to the initializer match the
/// commitments from the address preimage.
///
/// ```noir
/// assert_initialization_args_match_address_preimage(context);
/// assert_initialization_matches_address_preimage(context);
/// ```
fn create_assert_init_args() -> Statement {
fn create_assert_initializer() -> Statement {
make_statement(StatementKind::Expression(call(
variable_path(chained_dep!(
"aztec",
"initializer",
"assert_initialization_args_match_address_preimage"
"assert_initialization_matches_address_preimage"
)),
vec![variable("context")],
)))
Expand Down
6 changes: 0 additions & 6 deletions aztec_macros/src/utils/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use super::constants::MAX_CONTRACT_PRIVATE_FUNCTIONS;
pub enum AztecMacroError {
AztecDepNotFound,
ContractHasTooManyPrivateFunctions { span: Span },
ContractConstructorMissing { span: Span },
UnsupportedFunctionArgumentType { span: Span, typ: UnresolvedTypeData },
UnsupportedStorageType { span: Option<Span>, typ: UnresolvedTypeData },
CouldNotAssignStorageSlots { secondary_message: Option<String> },
Expand All @@ -29,11 +28,6 @@ impl From<AztecMacroError> for MacroError {
secondary_message: None,
span: Some(span),
},
AztecMacroError::ContractConstructorMissing { span } => MacroError {
primary_message: "Contract must have a constructor function".to_owned(),
secondary_message: None,
span: Some(span),
},
AztecMacroError::UnsupportedFunctionArgumentType { span, typ } => MacroError {
primary_message: format!("Provided parameter type `{typ:?}` is not supported in Aztec contract interface"),
secondary_message: None,
Expand Down
Loading

0 comments on commit c4d62e9

Please sign in to comment.