diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index c26c4f2551a..94d70614a13 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -140,6 +140,19 @@ contract AvmTest { a + b } + #[aztec(public-vm)] + fn u128_addition_overflow() -> U128 { + let max_u128: U128 = U128::from_hex("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + let one: U128 = U128::from_integer(1); + max_u128 + one + } + + #[aztec(public-vm)] + fn u128_from_integer_overflow() -> U128 { + let should_overflow: Field = 2.pow_32(128); // U128::max() + 1; + U128::from_integer(should_overflow) + } + /************************************************************************ * Hashing functions ************************************************************************/ diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index 9e21712d017..1d0d7f3af50 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -85,22 +85,40 @@ describe('AVM simulator: transpiled Noir contracts', () => { expect(isAvmBytecode(bytecode)); }); - it('U128 addition', async () => { - const calldata: Fr[] = [ - // First U128 - new Fr(1), - new Fr(2), - // Second U128 - new Fr(3), - new Fr(4), - ]; - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); + describe('U128 addition and overflows', () => { + it('U128 addition', async () => { + const calldata: Fr[] = [ + // First U128 + new Fr(1), + new Fr(2), + // Second U128 + new Fr(3), + new Fr(4), + ]; + const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode('add_u128'); - const results = await new AvmSimulator(context).executeBytecode(bytecode); + const bytecode = getAvmTestContractBytecode('add_u128'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); - expect(results.reverted).toBe(false); - expect(results.output).toEqual([new Fr(4), new Fr(6)]); + expect(results.reverted).toBe(false); + expect(results.output).toEqual([new Fr(4), new Fr(6)]); + }); + + it('Expect failure on U128::add() overflow', async () => { + const bytecode = getAvmTestContractBytecode('u128_addition_overflow'); + const results = await new AvmSimulator(initContext()).executeBytecode(bytecode); + expect(results.reverted).toBe(true); + expect(results.revertReason?.message).toEqual('Reverted with output: attempt to add with overflow'); + }); + + it('Expect failure on U128::from_integer() overflow', async () => { + const bytecode = getAvmTestContractBytecode('u128_from_integer_overflow'); + const results = await new AvmSimulator(initContext()).executeBytecode(bytecode); + expect(results.reverted).toBe(true); + expect(results.revertReason?.message).toEqual(undefined); + // Note: compiler intrinsic messages (like below) are not known to the AVM + //expect(results.revertReason?.message).toEqual("Reverted with output: call to assert_max_bit_size 'self.__assert_max_bit_size(bit_size)'"); + }); }); it('Assertion message', async () => {