Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(avm): pedersen commit in avm #7634

Merged
merged 2 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions avm-transpiler/src/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ pub enum AvmOpcode {
PEDERSEN, // temp - may be removed, but alot of contracts rely on it
ECADD,
MSM,
PEDERSENCOMMITMENT, // temp
// Conversions
TORADIXLE,
// Other
Expand Down Expand Up @@ -170,6 +171,7 @@ impl AvmOpcode {
AvmOpcode::PEDERSEN => "PEDERSEN",
AvmOpcode::ECADD => "ECADD",
AvmOpcode::MSM => "MSM",
AvmOpcode::PEDERSENCOMMITMENT => "PEDERSENCOMMITMENT",
// Conversions
AvmOpcode::TORADIXLE => "TORADIXLE",
// Other
Expand Down
18 changes: 18 additions & 0 deletions avm-transpiler/src/transpile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,24 @@ fn handle_black_box_function(avm_instrs: &mut Vec<AvmInstruction>, operation: &B
..Default::default()
});
}
// Temporary while we dont have efficient noir implementations (again)
BlackBoxOp::PedersenCommitment { inputs, domain_separator, output } => {
let input_offset = inputs.pointer.0;
let input_size_offset = inputs.size.0;
let index_offset = domain_separator.0;
let output_offset = output.pointer.0;
avm_instrs.push(AvmInstruction {
opcode: AvmOpcode::PEDERSENCOMMITMENT,
indirect: Some(ZEROTH_OPERAND_INDIRECT | FIRST_OPERAND_INDIRECT),
operands: vec![
AvmOperand::U32 { value: input_offset as u32 },
AvmOperand::U32 { value: output_offset as u32 },
AvmOperand::U32 { value: input_size_offset as u32 },
AvmOperand::U32 { value: index_offset as u32 },
],
..Default::default()
});
}
_ => panic!("Transpiler doesn't know how to process {:?}", operation),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,11 @@ const std::unordered_map<OpCode, std::vector<OperandType>> OPCODE_WIRE_FORMAT =
OperandType::UINT32 } }, // dst_offset
{ OpCode::MSM,
{ OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } },
{ OpCode::PEDERSENCOMMITMENT,
{ OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } },
// Gadget - Conversion
{ OpCode::TORADIXLE,
{ OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } },

// Gadgets - Unused for now
{ OpCode::SHA256COMPRESSION,
{ OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,14 @@ std::vector<Row> Execution::gen_trace(std::vector<Instruction> const& instructio
std::get<uint32_t>(inst.operands.at(2)),
std::get<uint32_t>(inst.operands.at(3)));

break;
case OpCode::PEDERSENCOMMITMENT:
trace_builder.op_pedersen_commit(std::get<uint8_t>(inst.operands.at(0)),
std::get<uint32_t>(inst.operands.at(1)),
std::get<uint32_t>(inst.operands.at(2)),
std::get<uint32_t>(inst.operands.at(3)),
std::get<uint32_t>(inst.operands.at(4)));

break;
default:
throw_or_abort("Don't know how to execute opcode " + to_hex(inst.op_code) + " at pc " + std::to_string(pc) +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ enum class OpCode : uint8_t {
PEDERSEN,
ECADD,
MSM,
PEDERSENCOMMITMENT,
// Conversions
TORADIXLE,
// Future Gadgets -- pending changes in noir
Expand Down
92 changes: 92 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <vector>

#include "barretenberg/common/throw_or_abort.hpp"
#include "barretenberg/crypto/pedersen_commitment/pedersen.hpp"
#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp"
#include "barretenberg/numeric/uint256/uint256.hpp"
#include "barretenberg/polynomials/univariate.hpp"
Expand Down Expand Up @@ -3430,6 +3431,97 @@ void AvmTraceBuilder::op_variable_msm(uint8_t indirect,
pc++;
}

void AvmTraceBuilder::op_pedersen_commit(uint8_t indirect,
uint32_t input_offset,
uint32_t output_offset,
uint32_t input_size_offset,
uint32_t gen_ctx_offset)
{
auto clk = static_cast<uint32_t>(main_trace.size()) + 1;
auto [resolved_input_offset, resolved_output_offset, resolved_input_size_offset, resolved_gen_ctx_offset] =
unpack_indirects<4>(indirect, { input_offset, output_offset, input_size_offset, gen_ctx_offset });

auto input_length_read = constrained_read_from_memory(
call_ptr, clk, resolved_input_size_offset, AvmMemoryTag::U32, AvmMemoryTag::U0, IntermRegister::IA);
auto gen_ctx_read = constrained_read_from_memory(
call_ptr, clk, resolved_gen_ctx_offset, AvmMemoryTag::U32, AvmMemoryTag::U0, IntermRegister::IB);

main_trace.push_back(Row{
.main_clk = clk,
.main_ia = input_length_read.val,
.main_ib = gen_ctx_read.val,
.main_ind_addr_a = FF(input_length_read.indirect_address),
.main_ind_addr_b = FF(gen_ctx_read.indirect_address),
.main_internal_return_ptr = FF(internal_return_ptr),
.main_mem_addr_a = FF(input_length_read.direct_address),
.main_mem_addr_b = FF(gen_ctx_read.direct_address),
.main_pc = FF(pc),
.main_r_in_tag = FF(static_cast<uint32_t>(AvmMemoryTag::U32)),
.main_sel_mem_op_a = FF(1),
.main_sel_mem_op_b = FF(1),
.main_sel_resolve_ind_addr_a = FF(static_cast<uint32_t>(input_length_read.is_indirect)),
.main_sel_resolve_ind_addr_b = FF(static_cast<uint32_t>(gen_ctx_read.is_indirect)),
});
clk++;

std::vector<FF> inputs;
auto num_rows = read_slice_to_memory<FF>(call_ptr,
clk,
resolved_input_offset,
AvmMemoryTag::FF,
AvmMemoryTag::U0,
FF(internal_return_ptr),
uint32_t(input_length_read.val),
inputs);
clk += num_rows;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh my


grumpkin::g1::affine_element result =
crypto::pedersen_commitment::commit_native(inputs, uint32_t(gen_ctx_read.val));

auto write_x = constrained_write_to_memory(
call_ptr, clk, resolved_output_offset, result.x, AvmMemoryTag::U0, AvmMemoryTag::FF, IntermRegister::IA);

mem_trace_builder.write_into_memory(
call_ptr, clk, IntermRegister::IB, write_x.direct_address + 1, result.y, AvmMemoryTag::U0, AvmMemoryTag::FF);

main_trace.push_back(Row{
.main_clk = clk,
.main_ia = result.x,
.main_ib = result.y,
.main_ind_addr_a = FF(write_x.indirect_address),
.main_internal_return_ptr = FF(internal_return_ptr),
.main_mem_addr_a = FF(write_x.direct_address),
.main_mem_addr_b = FF(write_x.direct_address + 1),
.main_pc = FF(pc),
.main_rwa = FF(1),
.main_rwb = FF(1),
.main_sel_mem_op_a = FF(1),
.main_sel_mem_op_b = FF(1),
.main_sel_resolve_ind_addr_a = FF(static_cast<uint32_t>(write_x.is_indirect)),
.main_w_in_tag = FF(static_cast<uint32_t>(AvmMemoryTag::FF)),
});

clk++;
mem_trace_builder.write_into_memory(call_ptr,
clk,
IntermRegister::IA,
write_x.direct_address + 2,
result.is_point_at_infinity(),
AvmMemoryTag::U0,
AvmMemoryTag::U8);
main_trace.push_back(Row{
.main_clk = clk,
.main_ia = static_cast<uint8_t>(result.is_point_at_infinity()),
.main_internal_return_ptr = FF(internal_return_ptr),
.main_mem_addr_a = FF(write_x.direct_address + 2),
.main_pc = FF(pc),
.main_rwa = FF(1),
.main_sel_mem_op_a = FF(1),
.main_w_in_tag = FF(static_cast<uint32_t>(AvmMemoryTag::U8)),
});
pc++;
}

/**************************************************************************************************
* CONVERSIONS
**************************************************************************************************/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ class AvmTraceBuilder {
uint32_t scalars_offset,
uint32_t output_offset,
uint32_t point_length_offset);
void op_pedersen_commit(uint8_t indirect,
uint32_t output_offset,
uint32_t input_offset,
uint32_t input_size_offset,
uint32_t gen_ctx_offset);
// Conversions
void op_to_radix_le(uint8_t indirect, uint32_t src_offset, uint32_t dst_offset, uint32_t radix, uint32_t num_limbs);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1261,7 +1261,7 @@ TEST_F(AvmExecutionTests, msmOpCode)
// Send all the input as Fields and cast them to U8 later
std::vector<FF> calldata = { FF(a.x), FF(a.y), a_is_inf, FF(b.x), FF(b.y),
b_is_inf, scalar_a_lo, scalar_a_hi, scalar_b_lo, scalar_b_hi };
std::string bytecode_hex = to_hex(OpCode::CALLDATACOPY) + // Calldatacopy...should fix the limit on calldatacopy
std::string bytecode_hex = to_hex(OpCode::CALLDATACOPY) + // Calldatacopy
"00" // Indirect flag
"00000000" // cd_offset 0
"0000000a" // copy_size (10 elements)
Expand Down Expand Up @@ -1319,6 +1319,69 @@ TEST_F(AvmExecutionTests, msmOpCode)
validate_trace(std::move(trace), public_inputs, calldata, returndata);
}

// Positive test with pedersen commitment
TEST_F(AvmExecutionTests, pedersenCommitmentOpcode)
{
auto expected_result =
grumpkin::g1::affine_element(fr(uint256_t("054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402")),
fr(uint256_t("209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126")));
// grumpkin::g1::affine_eleelement;
// grumpkin::g1::affine_element b = grumpkin::g1::affine_element::one();

// Remmeber that grumpkin Fq == BN254 Fr => aka FF
grumpkin::g1::Fq scalar_a = grumpkin::g1::Fq::zero();
grumpkin::g1::Fq scalar_b = grumpkin::g1::Fq::one();
std::vector<FF> expected_output = { expected_result.x, expected_result.y, expected_result.is_point_at_infinity() };
// Send all the input as Fields and cast them to U8 later
std::vector<FF> calldata = { scalar_a, scalar_b };
std::string bytecode_hex = to_hex(OpCode::CALLDATACOPY) + // Calldatacopy
"00" // Indirect flag
"00000000" // cd_offset 0
"00000002" // copy_size (2 elements)
"00000000" // dst_offset 0
+ to_hex(OpCode::SET) + // opcode SET for indirect input
"00" // Indirect flag
"03" // U32
"00000000" // Input stored at memory 0
"0000000b" // dst offset (11)
+ to_hex(OpCode::SET) + // opcode SET for indirect output
"00" // Indirect flag
"03" // U32
"00000020" // output offset
"0000000d" // dst offset
+ to_hex(OpCode::SET) + // opcode SET for input length
"00" // Indirect flag
"03" // U32
"00000002" // scalars length (2)
"00000002" + // dst offset (2)
to_hex(OpCode::SET) + // opcode SET for ctx index
"00" // Indirect flag
"03" // U32
"00000000" // ctx index (0)
"0000000f" + // dst offset
to_hex(OpCode::PEDERSENCOMMITMENT) + // opcode MSM
"03" // Indirect flag (first 2 indirect)
"0000000b" // inputs offset
"0000000d" // outputs offset
"00000002" // inputs length offset
"0000000f" // gen ctx index offset
+ to_hex(OpCode::RETURN) + // opcode RETURN
"00" // Indirect flag
"00000020" // ret offset
"00000003"; // ret size 3

auto bytecode = hex_to_bytes(bytecode_hex);
auto instructions = Deserialization::parse(bytecode);

// Assign a vector that we will mutate internally in gen_trace to store the return values;
std::vector<FF> returndata;
auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec);

EXPECT_EQ(returndata, expected_output);

validate_trace(std::move(trace), public_inputs, calldata, returndata);
}

// Positive test for Kernel Input opcodes
TEST_F(AvmExecutionTests, kernelInputOpcodes)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ contract AvmTest {
global big_field_136_bits: Field = 0x991234567890abcdef1234567890abcdef;

// Libs
use std::embedded_curve_ops::multi_scalar_mul;
use std::embedded_curve_ops::{multi_scalar_mul, EmbeddedCurvePoint};
use dep::aztec::protocol_types::constants::CONTRACT_INSTANCE_LENGTH;
use dep::aztec::prelude::{Map, Deserialize};
use dep::aztec::state_vars::PublicMutable;
Expand Down Expand Up @@ -153,6 +153,12 @@ contract AvmTest {
triple_g
}

#[aztec(public)]
fn pedersen_commit(x: Field, y: Field) -> EmbeddedCurvePoint {
let commitment = dep::std::hash::pedersen_commitment([x, y]);
commitment
}

/************************************************************************
* Misc
************************************************************************/
Expand Down
10 changes: 7 additions & 3 deletions yarn-project/bb-prover/src/avm_proving.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,15 @@ describe('AVM WitGen, proof generation and verification', () => {
* Avm Embedded Curve functions
************************************************************************/
describe('AVM Embedded Curve functions', () => {
const avmEmbeddedCurveFunctions: string[] = ['elliptic_curve_add_and_double', 'variable_base_msm'];
const avmEmbeddedCurveFunctions: [string, Fr[]][] = [
['elliptic_curve_add_and_double', []],
['variable_base_msm', []],
['pedersen_commit', [new Fr(1), new Fr(100)]],
];
it.each(avmEmbeddedCurveFunctions)(
'Should prove %s',
async name => {
await proveAndVerifyAvmTestContract(name);
async (name, calldata) => {
await proveAndVerifyAvmTestContract(name, calldata);
},
TIMEOUT,
);
Expand Down
1 change: 1 addition & 0 deletions yarn-project/simulator/src/avm/avm_gas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ const BaseGasCosts: Record<Opcode, Gas> = {
[Opcode.PEDERSEN]: DefaultBaseGasCost,
[Opcode.ECADD]: DefaultBaseGasCost,
[Opcode.MSM]: DefaultBaseGasCost,
[Opcode.PEDERSENCOMMITMENT]: DefaultBaseGasCost,
// Conversions
[Opcode.TORADIXLE]: DefaultBaseGasCost,
// Other
Expand Down
18 changes: 17 additions & 1 deletion yarn-project/simulator/src/avm/avm_simulator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg';
import { computeVarArgsHash } from '@aztec/circuits.js/hash';
import { FunctionSelector } from '@aztec/foundation/abi';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { keccak256, keccakf1600, pedersenHash, poseidon2Hash, sha256 } from '@aztec/foundation/crypto';
import { keccak256, keccakf1600, pedersenCommit, pedersenHash, poseidon2Hash, sha256 } from '@aztec/foundation/crypto';
import { Fq, Fr } from '@aztec/foundation/fields';
import { type Fieldable } from '@aztec/foundation/serialize';

Expand Down Expand Up @@ -140,6 +140,22 @@ describe('AVM simulator: transpiled Noir contracts', () => {
expect(results.output).toEqual([expectedResult.x, expectedResult.y, Fr.ZERO]);
});

it('pedersen commitment operations', async () => {
const calldata: Fr[] = [new Fr(100), new Fr(1)];
const context = initContext({ env: initExecutionEnvironment({ calldata }) });

const bytecode = getAvmTestContractBytecode('pedersen_commit');
const results = await new AvmSimulator(context).executeBytecode(bytecode);

expect(results.reverted).toBe(false);
// This doesnt include infinites
const expectedResult = pedersenCommit([Buffer.from([100]), Buffer.from([1])]).map(f => new Fr(f));
// TODO: Come back to the handling of infinities when we confirm how they're handled in bb
const isInf = expectedResult[0] === new Fr(0) && expectedResult[1] === new Fr(0);
expectedResult.push(new Fr(isInf));
expect(results.output).toEqual(expectedResult);
});

describe('U128 addition and overflows', () => {
it('U128 addition', async () => {
const calldata: Fr[] = [
Expand Down
Loading
Loading