Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
139 changes: 139 additions & 0 deletions barretenberg/cpp/pil/vm2/address_derivation.pil
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
include "constants_gen.pil";
include "ecc.pil";
include "poseidon2_hash.pil";
include "precomputed.pil";
include "scalar_mul.pil";

namespace address_derivation;

pol commit sel;
sel * (1 - sel) = 0;

#[skippable_if]
sel = 0;

// Address preimage components
pol commit salt;
pol commit deployer_addr;
pol commit class_id;
pol commit init_hash;
pol commit nullifier_key_x;
pol commit nullifier_key_y;
pol commit incoming_viewing_key_x;
pol commit incoming_viewing_key_y;
pol commit outgoing_viewing_key_x;
pol commit outgoing_viewing_key_y;
pol commit tagging_key_x;
pol commit tagging_key_y;

// Expected derived address
pol commit address;


// Computation of salted initialization hash

pol commit salted_init_hash;

// It's reused between the partial address and salted initialization hash. Weird.
pol commit partial_address_domain_separator;
sel * (partial_address_domain_separator - constants.GENERATOR_INDEX__PARTIAL_ADDRESS) = 0;

#[SALTED_INITIALIZATION_HASH_POSEIDON2_0]
sel { partial_address_domain_separator, salt, init_hash, salted_init_hash }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IIRC, we do not support a constant nor alias in a lookup tuple?
Because otherwise, we could inline constants.GENERATOR_INDEX__PARTIAL_ADDRESS in the tuple and get rid of
the above relation.
I suggest to write a TODO so that we can simplify once we support constants in lookups.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll write a todo, unfortunately we can't, on lookups we need to use real columns ):

in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };

#[SALTED_INITIALIZATION_HASH_POSEIDON2_1]
sel { deployer_addr, precomputed.zero, precomputed.zero, salted_init_hash}
in poseidon2_hash.end { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Poseidon2 was changed to propagate the final output on the whole run. It's however still incomplete, I talked with Ilyas about it because we need to lookup also the iteration index. This hash run in poseidon looks like this:


+----------------------------------+---------+-----------+------------------+-------+-----+-----+
|             input_0              | input_1 |  input_2  |      output      | start | end | sel |
+----------------------------------+---------+-----------+------------------+-------+-----+-----+
| 0                                | 0       | 0         | 0                |     0 |   0 |   0 |
| partial_address_domain_separator | salt    | init_hash | salted_init_hash |     1 |   0 |   1 |
| deployer_addr                    | 0       | 0         | salted_init_hash |     0 |   1 |   1 |
| 0                                | 0       | 0         | 0                |     0 |   0 |   0 |
+----------------------------------+---------+-----------+------------------+-------+-----+-----+

In order for it to be safe I need to assert that start is on on the first one and end is on in the second one. However, a malicious prover could still insert more rounds between the two rows, that's why poseidon will need to be improved to include a round_index column, so I can lookup with 0 on start and 1 on end so I can be safe that a malicious prover hasn't inserted more rounds

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please file an issue to fix poseidon if there's not already one (and to update all callers), assign to ilyas, and add it to this doc since this seems quite important.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done



// Computation of partial address

pol commit partial_address;

#[PARTIAL_ADDRESS_POSEIDON2]
sel { partial_address_domain_separator, class_id, salted_init_hash, partial_address }
in poseidon2_hash.end { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };


// Hash the public keys

pol commit public_keys_hash;

pol commit public_keys_hash_domain_separator;
sel * (public_keys_hash_domain_separator - constants.GENERATOR_INDEX__PUBLIC_KEYS_HASH) = 0;

// Remove all the 0s for is_infinite when removed from public_keys.nr
// https://github.com/AztecProtocol/aztec-packages/issues/7529
#[PUBLIC_KEYS_HASH_POSEIDON2_0]
sel { public_keys_hash_domain_separator, nullifier_key_x, nullifier_key_y, public_keys_hash }
in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };

#[PUBLIC_KEYS_HASH_POSEIDON2_1]
sel { precomputed.zero, incoming_viewing_key_x, incoming_viewing_key_y, public_keys_hash }
in poseidon2_hash.sel { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };

#[PUBLIC_KEYS_HASH_POSEIDON2_2]
sel { precomputed.zero, outgoing_viewing_key_x, outgoing_viewing_key_y, public_keys_hash }
in poseidon2_hash.sel { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };

#[PUBLIC_KEYS_HASH_POSEIDON2_3]
sel { precomputed.zero, tagging_key_x, tagging_key_y, public_keys_hash }
in poseidon2_hash.sel { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };

#[PUBLIC_KEYS_HASH_POSEIDON2_4]
sel { precomputed.zero, precomputed.zero, precomputed.zero, public_keys_hash }
in poseidon2_hash.end { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };


// Compute the preaddress

pol commit preaddress;

pol commit preaddress_domain_separator;
sel * (preaddress_domain_separator - constants.GENERATOR_INDEX__CONTRACT_ADDRESS_V1) = 0;

#[PREADDRESS_POSEIDON2]
sel { preaddress_domain_separator, public_keys_hash, partial_address, preaddress }
in poseidon2_hash.end { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };


// Derive preaddress public key

pol commit preaddress_public_key_x;
pol commit preaddress_public_key_y;

pol commit g1_x;
sel * (g1_x - 1) = 0;

pol commit g1_y;
sel * (g1_y - 17631683881184975370165255887551781615748388533673675138860) = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We could define a constant for this monster literal and add a comment about what it is.


#[PREADDRESS_SCALAR_MUL]
sel {
preaddress,
g1_x, g1_y, precomputed.zero,
preaddress_public_key_x, preaddress_public_key_y, precomputed.zero
} in scalar_mul.start {
scalar_mul.scalar,
scalar_mul.point_x, scalar_mul.point_y, scalar_mul.point_inf,
scalar_mul.res_x, scalar_mul.res_y, scalar_mul.res_inf
};


// Finally, the address must be the x coordinate of preaddress_public_key + incoming_viewing_key

pol commit address_y;

#[ADDRESS_ECADD]
sel {
preaddress_public_key_x, preaddress_public_key_y, precomputed.zero,
incoming_viewing_key_x, incoming_viewing_key_y, precomputed.zero,
address, address_y, precomputed.zero
} in ecc.sel {
ecc.p_x, ecc.p_y, ecc.p_is_inf,
ecc.q_x, ecc.q_y, ecc.q_is_inf,
ecc.r_x, ecc.r_y, ecc.r_is_inf
};


1 change: 1 addition & 0 deletions barretenberg/cpp/pil/vm2/execution.pil
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
include "alu.pil";
include "addressing.pil";
include "address_derivation.pil";
include "bc_decomposition.pil";
include "bc_hashing.pil";
include "bc_retrieval.pil";
Expand Down
7 changes: 5 additions & 2 deletions barretenberg/cpp/src/barretenberg/vm2/common/aztec_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,18 @@ struct PublicKeys {
return { nullifier_key.x, nullifier_key.y, incoming_viewing_key.x, incoming_viewing_key.y,
outgoing_viewing_key.x, outgoing_viewing_key.y, tagging_key.x, tagging_key.y };
}

bool operator==(const PublicKeys& other) const = default;
};

struct ContractInstance {
AztecAddress address;
FF salt;
AztecAddress deployer_addr;
ContractClassId contract_class_id;
FF initialisation_hash;
PublicKeys public_keys;

bool operator==(const ContractInstance& other) const = default;
};

struct ContractClass {
Expand All @@ -40,4 +43,4 @@ struct ContractClass {
std::vector<uint8_t> packed_bytecode;
};

} // namespace bb::avm2
} // namespace bb::avm2
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <cstdint>
#include <ostream>

namespace bb::avm2 {

Expand Down Expand Up @@ -51,15 +52,27 @@ template <typename AffinePoint> class StandardAffinePoint {

constexpr const BaseField& y() const noexcept { return point.is_point_at_infinity() ? zero : point.y; }

static StandardAffinePoint& infinity()
static const StandardAffinePoint& infinity()
{
static auto infinity = StandardAffinePoint(AffinePoint::infinity());
return infinity;
}

static const StandardAffinePoint& one()
{
static auto one = StandardAffinePoint(AffinePoint::one());
return one;
}

private:
AffinePoint point;
static constexpr const auto zero = BaseField::zero();
};

template <typename T> std::ostream& operator<<(std::ostream& os, const StandardAffinePoint<T>& point)
{
os << "StandardAffinePoint(" << point.x() << ", " << point.y() << ", " << point.is_infinity() << ")";
return os;
}

} // namespace bb::avm2
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "barretenberg/crypto/poseidon2/poseidon2.hpp"
#include "barretenberg/crypto/poseidon2/poseidon2_params.hpp"
#include "barretenberg/vm2/constraining/testing/check_relation.hpp"
#include "barretenberg/vm2/generated/columns.hpp"
#include "barretenberg/vm2/generated/flavor_settings.hpp"
#include "barretenberg/vm2/generated/relations/address_derivation.hpp"
#include "barretenberg/vm2/generated/relations/lookups_address_derivation.hpp"
#include "barretenberg/vm2/simulation/address_derivation.hpp"
#include "barretenberg/vm2/simulation/events/address_derivation_event.hpp"
#include "barretenberg/vm2/simulation/events/ecc_events.hpp"
#include "barretenberg/vm2/simulation/events/event_emitter.hpp"
#include "barretenberg/vm2/simulation/lib/contract_crypto.hpp"
#include "barretenberg/vm2/simulation/to_radix.hpp"
#include "barretenberg/vm2/testing/fixtures.hpp"
#include "barretenberg/vm2/tracegen/address_derivation_trace.hpp"
#include "barretenberg/vm2/tracegen/ecc_trace.hpp"
#include "barretenberg/vm2/tracegen/lib/lookup_builder.hpp"
#include "barretenberg/vm2/tracegen/poseidon2_trace.hpp"
#include "barretenberg/vm2/tracegen/test_trace_container.hpp"
#include "barretenberg/vm2/tracegen/to_radix_trace.hpp"

namespace bb::avm2::constraining {
namespace {

using tracegen::AddressDerivationTraceBuilder;
using tracegen::EccTraceBuilder;
using tracegen::LookupIntoDynamicTableSequential;
using tracegen::Poseidon2TraceBuilder;
using tracegen::TestTraceContainer;

using simulation::AddressDerivation;
using simulation::AddressDerivationEvent;
using simulation::compute_contract_address;
using simulation::Ecc;
using simulation::EccAddEvent;
using simulation::EventEmitter;
using simulation::hash_public_keys;
using simulation::NoopEventEmitter;
using simulation::Poseidon2;
using simulation::Poseidon2HashEvent;
using simulation::Poseidon2PermutationEvent;
using simulation::ScalarMulEvent;
using simulation::ToRadix;
using simulation::ToRadixEvent;

using FF = AvmFlavorSettings::FF;
using C = Column;
using address_derivation_relation = bb::avm2::address_derivation<FF>;
using poseidon2_relation = bb::avm2::poseidon2_hash<FF>;
using ecadd_relation = bb::avm2::ecc<FF>;
using scalar_mul_relation = bb::avm2::scalar_mul<FF>;
using poseidon2 = crypto::Poseidon2<crypto::Poseidon2Bn254ScalarFieldParams>;

using lookup_salted_initialization_hash_poseidon2_0 =
bb::avm2::lookup_address_derivation_salted_initialization_hash_poseidon2_0_relation<FF>;
using lookup_salted_initialization_hash_poseidon2_1 =
bb::avm2::lookup_address_derivation_salted_initialization_hash_poseidon2_1_relation<FF>;
using lookup_partial_address_poseidon2 = bb::avm2::lookup_address_derivation_partial_address_poseidon2_relation<FF>;
using lookup_public_keys_hash_poseidon2_0 =
bb::avm2::lookup_address_derivation_public_keys_hash_poseidon2_0_relation<FF>;
using lookup_public_keys_hash_poseidon2_1 =
bb::avm2::lookup_address_derivation_public_keys_hash_poseidon2_1_relation<FF>;
using lookup_public_keys_hash_poseidon2_2 =
bb::avm2::lookup_address_derivation_public_keys_hash_poseidon2_2_relation<FF>;
using lookup_public_keys_hash_poseidon2_3 =
bb::avm2::lookup_address_derivation_public_keys_hash_poseidon2_3_relation<FF>;
using lookup_public_keys_hash_poseidon2_4 =
bb::avm2::lookup_address_derivation_public_keys_hash_poseidon2_4_relation<FF>;
using lookup_public_preaddress_poseidon2 = bb::avm2::lookup_address_derivation_preaddress_poseidon2_relation<FF>;
using lookup_public_preaddress_scalar_mul = bb::avm2::lookup_address_derivation_preaddress_scalar_mul_relation<FF>;
using lookup_address_ecadd = bb::avm2::lookup_address_derivation_address_ecadd_relation<FF>;

TEST(AddressDerivationConstrainingTest, EmptyRow)
{
check_relation<address_derivation_relation>(testing::empty_trace());
}

TEST(AddressDerivationConstrainingTest, Basic)
{
TestTraceContainer trace;
AddressDerivationTraceBuilder builder;

auto instance = testing::random_contract_instance();

FF salted_initialization_hash = poseidon2::hash(
{ GENERATOR_INDEX__PARTIAL_ADDRESS, instance.salt, instance.initialisation_hash, instance.deployer_addr });

FF partial_address =
poseidon2::hash({ GENERATOR_INDEX__PARTIAL_ADDRESS, instance.contract_class_id, salted_initialization_hash });

FF public_keys_hash = hash_public_keys(instance.public_keys);
FF preaddress = poseidon2::hash({ GENERATOR_INDEX__CONTRACT_ADDRESS_V1, public_keys_hash, partial_address });

EmbeddedCurvePoint g1 = EmbeddedCurvePoint::one();
EmbeddedCurvePoint preaddress_public_key = g1 * Fq(preaddress);
EmbeddedCurvePoint address_point = preaddress_public_key + instance.public_keys.incoming_viewing_key;

builder.process({ { .address = address_point.x(),
.instance = instance,
.salted_initialization_hash = salted_initialization_hash,
.partial_address = partial_address,
.public_keys_hash = public_keys_hash,
.preaddress = preaddress,
.preaddress_public_key = preaddress_public_key,
.address_point = address_point } },
trace);

EXPECT_EQ(trace.get_num_rows(), 1);
check_relation<address_derivation_relation>(trace);
Comment thread
sirasistant marked this conversation as resolved.
}

TEST(AddressDerivationConstrainingTest, WithInteractions)
{
NoopEventEmitter<ToRadixEvent> to_radix_event_emitter;
EventEmitter<EccAddEvent> ecadd_event_emitter;
EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
EventEmitter<Poseidon2HashEvent> hash_event_emitter;
NoopEventEmitter<Poseidon2PermutationEvent> perm_event_emitter;
EventEmitter<AddressDerivationEvent> address_derivation_event_emitter;

ToRadix to_radix_simulator(to_radix_event_emitter);
Ecc ecc_simulator(to_radix_simulator, ecadd_event_emitter, scalar_mul_event_emitter);
Poseidon2 poseidon2_simulator(hash_event_emitter, perm_event_emitter);

AddressDerivation address_derivation(poseidon2_simulator, ecc_simulator, address_derivation_event_emitter);

TestTraceContainer trace = TestTraceContainer::from_rows({
{ .precomputed_first_row = 1 },
});

AddressDerivationTraceBuilder builder;
Poseidon2TraceBuilder poseidon2_builder;
EccTraceBuilder ecc_builder;

ContractInstance instance = testing::random_contract_instance();
AztecAddress address = compute_contract_address(instance);
address_derivation.assert_derivation(address, instance);

builder.process(address_derivation_event_emitter.dump_events(), trace);
poseidon2_builder.process_hash(hash_event_emitter.dump_events(), trace);
ecc_builder.process_add(ecadd_event_emitter.dump_events(), trace);
ecc_builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);

LookupIntoDynamicTableSequential<lookup_salted_initialization_hash_poseidon2_0::Settings>().process(trace);
LookupIntoDynamicTableSequential<lookup_salted_initialization_hash_poseidon2_1::Settings>().process(trace);
LookupIntoDynamicTableSequential<lookup_partial_address_poseidon2::Settings>().process(trace);
LookupIntoDynamicTableSequential<lookup_public_keys_hash_poseidon2_0::Settings>().process(trace);
LookupIntoDynamicTableSequential<lookup_public_keys_hash_poseidon2_1::Settings>().process(trace);
LookupIntoDynamicTableSequential<lookup_public_keys_hash_poseidon2_2::Settings>().process(trace);
LookupIntoDynamicTableSequential<lookup_public_keys_hash_poseidon2_3::Settings>().process(trace);
LookupIntoDynamicTableSequential<lookup_public_keys_hash_poseidon2_4::Settings>().process(trace);
LookupIntoDynamicTableSequential<lookup_public_preaddress_poseidon2::Settings>().process(trace);
LookupIntoDynamicTableSequential<lookup_public_preaddress_scalar_mul::Settings>().process(trace);
LookupIntoDynamicTableSequential<lookup_address_ecadd::Settings>().process(trace);

check_relation<address_derivation_relation>(trace);
check_interaction<lookup_salted_initialization_hash_poseidon2_0>(trace);
check_interaction<lookup_salted_initialization_hash_poseidon2_1>(trace);
check_interaction<lookup_partial_address_poseidon2>(trace);
check_interaction<lookup_public_keys_hash_poseidon2_0>(trace);
check_interaction<lookup_public_keys_hash_poseidon2_1>(trace);
check_interaction<lookup_public_keys_hash_poseidon2_2>(trace);
check_interaction<lookup_public_keys_hash_poseidon2_3>(trace);
check_interaction<lookup_public_keys_hash_poseidon2_4>(trace);
check_interaction<lookup_public_preaddress_poseidon2>(trace);
check_interaction<lookup_public_preaddress_scalar_mul>(trace);
check_interaction<lookup_address_ecadd>(trace);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There are no negative tests but not sure what is meaningful to test as it consists mainly in lookups and therefore we would test that lookups are working as expected.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes the only relations are trivial constants and lookups


} // namespace
} // namespace bb::avm2::constraining
8 changes: 4 additions & 4 deletions barretenberg/cpp/src/barretenberg/vm2/generated/columns.hpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/vm2/generated/flavor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,4 @@ std::vector<AvmFlavor::VerificationKey::FF> AvmFlavor::VerificationKey::to_field
return elements;
}

} // namespace bb::avm2
} // namespace bb::avm2
Loading