Skip to content

Commit

Permalink
feat: cycle scalar <> bigfield interactions (#6744)
Browse files Browse the repository at this point in the history
Adds missing methods in cycle_group and cycle_scalar required for the
PCS in the ECCVM recursive verifier. As a summary, we add missing
cycle_group constructors, a cycle group representation of `one`, a naive
method to convert bigfield to cycle_scalar (but that adds constraints)
and unify the `batch_mul` interface with the others present in our
codebase (i.e. swap points and scalars).

---------

Co-authored-by: codygunton <[email protected]>
  • Loading branch information
maramihali and codygunton authored May 31, 2024
1 parent e1f73e1 commit 6e363ec
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 56 deletions.
42 changes: 14 additions & 28 deletions barretenberg/barretenberg.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -58,26 +58,10 @@
"ms-vscode.cpptools"
]
},
"launch": {
// Configure LLDB
"configurations": [
{
"name": "(lldb) Launch Target",
"type": "lldb",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"args": [],
"cwd": "${workspaceFolder}/cpp/build",
"internalConsoleOptions": "openOnSessionStart",
"console": "internalConsole",
}
],
},
// Global settings which will apply to all subprojects.
// Each subproject may have their own `.vscode/settings.json`
// for configuring extensions which are specific to a certain project.
// Some settings can only be configured here.
// The following are just provided as example.
"settings": {
"files.associations": {
"*.tcc": "cpp",
Expand All @@ -96,7 +80,6 @@
//
// Location of base CMakeLists file
"cmake.sourceDirectory": "${workspaceFolder}/cpp/",
"cmake.buildDirectory": "${workspaceFolder}/cpp/build",
//
// C/C++ (should be disabled)
//
Expand All @@ -116,9 +99,9 @@
//
// Ensures tests are run from the `build` directory
// which ensures SRS can be read
"testMate.cpp.test.workingDirectory": "${workspaceFolder}/cpp/build",
"testMate.cpp.test.workingDirectory": "${command:cmake.buildDirectory}",
// Filter all binaries that are not tests or benchmarks
"testMate.cpp.test.executables": "${workspaceFolder}/cpp/{build}/bin/*{test,Test,TEST,bench}*",
"testMate.cpp.test.executables": "${command:cmake.buildDirectory}/bin/*{test,Test,TEST,bench}*",
//
// Other
//
Expand All @@ -144,21 +127,24 @@
}
]
},
//
// GTest adapter (not currently used)
//
"gtest-adapter.debugConfig": [
"(lldb) Launch Target"
],
"[cpp]": {
"editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd"
},
"cmake.configureArgs": [
"--preset clang16",
"-G Ninja"
],
"cmake.useCMakePresets": "auto",
"cmake.useCMakePresets": "always",
"editor.inlayHints.enabled": "offUnlessPressed",
"git.detectSubmodules": false
"git.detectSubmodules": false,
"testMate.cpp.discovery.loadOnStartup": false,
"testMate.cpp.debug.configTemplate": {
"type": "lldb",
"MIMode": "lldb",
"program": "${exec}",
"args": "${argsArray}",
"cwd": "${command:cmake.buildDirectory}",
"internalConsoleOptions": "openOnSessionStart",
"console": "internalConsole",
}
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ template <typename Builder> void create_multi_scalar_mul_constraint(Builder& bui
}

// Call batch_mul to multiply the points and scalars and sum the results
auto output_point = cycle_group_ct::batch_mul(scalars, points);
auto output_point = cycle_group_ct::batch_mul(points, scalars);

// Add the constraints
builder.assert_equal(output_point.x.get_witness_index(), input.out_point_x);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ cycle_group<C> pedersen_commitment<C>::commit(const std::vector<field_t>& inputs
points.emplace_back(base_points[i]);
}

return cycle_group::batch_mul(scalars, points);
return cycle_group::batch_mul(points, scalars);
}

template <typename C>
Expand All @@ -37,7 +37,7 @@ cycle_group<C> pedersen_commitment<C>::commit(const std::vector<std::pair<field_
points.emplace_back(context.generators->get(1, context.offset, context.domain_separator)[0]);
}

return cycle_group::batch_mul(scalars, points);
return cycle_group::batch_mul(points, scalars);
}

template class pedersen_commitment<bb::StandardCircuitBuilder>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ std::array<field_t<C>, 2> schnorr_verify_signature_internal(const byte_array<C>&
cycle_group<C> g1(grumpkin::g1::one);
// compute g1 * sig.s + key * sig,e

auto x_3 = cycle_group<C>::batch_mul({ sig.s, sig.e }, { g1, pub_key }).x;
auto x_3 = cycle_group<C>::batch_mul({ g1, pub_key }, { sig.s, sig.e }).x;
// build input (pedersen(([s]g + [e]pub).x | pub.x | pub.y) | message) to hash function
// pedersen hash ([r].x | pub.x) to make sure the size of `hash_input` is <= 64 bytes for a 32 byte message
byte_array<C> hash_input(pedersen_hash<C>::hash({ x_3, pub_key.x, pub_key.y }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ field_t<C> pedersen_hash<C>::hash(const std::vector<field_ct>& inputs, const Gen
points.emplace_back(base_points[i]);
}

auto result = cycle_group::batch_mul(scalars, points);
auto result = cycle_group::batch_mul(points, scalars);
return result.x;
}

Expand All @@ -47,7 +47,7 @@ field_t<C> pedersen_hash<C>::hash_skip_field_validation(const std::vector<field_
points.emplace_back(base_points[i]);
}

auto result = cycle_group::batch_mul(scalars, points);
auto result = cycle_group::batch_mul(points, scalars);
return result.x;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ cycle_group<Builder>::cycle_group(const AffineElement& _in)
, context(nullptr)
{}

/**
* @brief Construct a cycle_group representation of Group::one.
*
* @tparam Builder
* @param _context
* @return cycle_group<Builder>
*/
template <typename Builder> cycle_group<Builder> cycle_group<Builder>::one(Builder* _context)
{
field_t x(_context, Group::one.x);
field_t y(_context, Group::one.y);
return cycle_group<Builder>(x, y, false);
}

/**
* @brief Converts an AffineElement into a circuit witness.
*
Expand Down Expand Up @@ -540,25 +554,28 @@ cycle_group<Builder>::cycle_scalar::cycle_scalar(const field_t& _lo, const field
, hi(_hi)
{}

template <typename Builder> cycle_group<Builder>::cycle_scalar::cycle_scalar(const field_t& _in)
template <typename Builder> cycle_group<Builder>::cycle_scalar::cycle_scalar(const field_t& in)
{
const uint256_t value(_in.get_value());
const uint256_t value(in.get_value());
const uint256_t lo_v = value.slice(0, LO_BITS);
const uint256_t hi_v = value.slice(LO_BITS, HI_BITS);
constexpr uint256_t shift = uint256_t(1) << LO_BITS;
if (_in.is_constant()) {
if (in.is_constant()) {
lo = lo_v;
hi = hi_v;
} else {
lo = witness_t(_in.get_context(), lo_v);
hi = witness_t(_in.get_context(), hi_v);
(lo + hi * shift).assert_equal(_in);
lo = witness_t(in.get_context(), lo_v);
hi = witness_t(in.get_context(), hi_v);
(lo + hi * shift).assert_equal(in);
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1022): ensure lo and hi are in bb::fr modulus not
// bb::fq modulus otherwise we could have two representations for in
validate_scalar_is_in_field();
}
}

template <typename Builder> cycle_group<Builder>::cycle_scalar::cycle_scalar(const ScalarField& _in)
template <typename Builder> cycle_group<Builder>::cycle_scalar::cycle_scalar(const ScalarField& in)
{
const uint256_t value(_in);
const uint256_t value(in);
const uint256_t lo_v = value.slice(0, LO_BITS);
const uint256_t hi_v = value.slice(LO_BITS, HI_BITS);
lo = lo_v;
Expand Down Expand Up @@ -627,6 +644,37 @@ typename cycle_group<Builder>::cycle_scalar cycle_group<Builder>::cycle_scalar::
cycle_scalar result{ lo, hi, NUM_BITS, skip_primality_test, true };
return result;
}
/**
* @brief Construct a new cycle scalar from a bigfield _value, over the same ScalarField Field. If _value is a witness,
* we add constraints to ensure the conversion is correct by reconstructing a bigfield from the limbs of the
* cycle_scalar and checking equality with the initial _value.
*
* @tparam Builder
* @param _value
* @todo (https://github.com/AztecProtocol/barretenberg/issues/1016): Optimise this method
*/
template <typename Builder> cycle_group<Builder>::cycle_scalar::cycle_scalar(BigScalarField& scalar)
{
auto* ctx = get_context() ? get_context() : scalar.get_context();
const uint256_t value((scalar.get_value() % uint512_t(ScalarField::modulus)).lo);
const uint256_t value_lo = value.slice(0, LO_BITS);
const uint256_t value_hi = value.slice(LO_BITS, HI_BITS);
if (scalar.is_constant()) {
lo = value_lo;
hi = value_hi;
// N.B. to be able to call assert equal, these cannot be constants
} else {
lo = witness_t(ctx, value_lo);
hi = witness_t(ctx, value_hi);
field_t zero = field_t(0);
zero.convert_constant_to_fixed_witness(ctx);
BigScalarField lo_big(lo, zero);
BigScalarField hi_big(hi, zero);
BigScalarField res = lo_big + hi_big * BigScalarField((uint256_t(1) << LO_BITS));
scalar.assert_equal(res);
validate_scalar_is_in_field();
}
};

template <typename Builder> bool cycle_group<Builder>::cycle_scalar::is_constant() const
{
Expand Down Expand Up @@ -1186,8 +1234,8 @@ typename cycle_group<Builder>::batch_mul_internal_output cycle_group<Builder>::_
* @return cycle_group<Builder>
*/
template <typename Builder>
cycle_group<Builder> cycle_group<Builder>::batch_mul(const std::vector<cycle_scalar>& scalars,
const std::vector<cycle_group>& base_points,
cycle_group<Builder> cycle_group<Builder>::batch_mul(const std::vector<cycle_group>& base_points,
const std::vector<cycle_scalar>& scalars,
const GeneratorContext context)
{
ASSERT(scalars.size() == base_points.size());
Expand Down Expand Up @@ -1323,7 +1371,7 @@ cycle_group<Builder> cycle_group<Builder>::batch_mul(const std::vector<cycle_sca

template <typename Builder> cycle_group<Builder> cycle_group<Builder>::operator*(const cycle_scalar& scalar) const
{
return batch_mul({ scalar }, { *this });
return batch_mul({ *this }, { scalar });
}

template <typename Builder> cycle_group<Builder>& cycle_group<Builder>::operator*=(const cycle_scalar& scalar)
Expand All @@ -1332,6 +1380,17 @@ template <typename Builder> cycle_group<Builder>& cycle_group<Builder>::operator
return *this;
}

template <typename Builder> cycle_group<Builder> cycle_group<Builder>::operator*(const BigScalarField& scalar) const
{
return batch_mul({ *this }, { scalar });
}

template <typename Builder> cycle_group<Builder>& cycle_group<Builder>::operator*=(const BigScalarField& scalar)
{
*this = operator*(scalar);
return *this;
}

template <typename Builder> bool_t<Builder> cycle_group<Builder>::operator==(const cycle_group& other) const
{
const auto equal_and_not_infinity =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "barretenberg/crypto/pedersen_commitment/pedersen.hpp"
#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp"
#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp"
#include "barretenberg/stdlib/primitives/bool/bool.hpp"
#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp"
#include "barretenberg/stdlib/primitives/field/field.hpp"
Expand Down Expand Up @@ -36,6 +37,7 @@ template <typename Builder> class cycle_group {
using AffineElement = typename Curve::AffineElement;
using GeneratorContext = crypto::GeneratorContext<Curve>;
using ScalarField = typename Curve::ScalarField;
using BigScalarField = stdlib::bigfield<Builder, typename ScalarField::Params>;

static constexpr size_t STANDARD_NUM_TABLE_BITS = 1;
static constexpr size_t ULTRA_NUM_TABLE_BITS = 4;
Expand Down Expand Up @@ -103,6 +105,8 @@ template <typename Builder> class cycle_group {
return _use_bn254_scalar_field_for_primality_test;
}
void validate_scalar_is_in_field() const;

explicit cycle_scalar(BigScalarField&);
};

/**
Expand Down Expand Up @@ -171,6 +175,7 @@ template <typename Builder> class cycle_group {
cycle_group(field_t _x, field_t _y, bool_t _is_infinity);
cycle_group(const FF& _x, const FF& _y, bool _is_infinity);
cycle_group(const AffineElement& _in);
static cycle_group one(Builder* _context);
static cycle_group from_witness(Builder* _context, const AffineElement& _in);
static cycle_group from_constant_witness(Builder* _context, const AffineElement& _in);
Builder* get_context(const cycle_group& other) const;
Expand All @@ -196,11 +201,23 @@ template <typename Builder> class cycle_group {
cycle_group operator-() const;
cycle_group& operator+=(const cycle_group& other);
cycle_group& operator-=(const cycle_group& other);
static cycle_group batch_mul(const std::vector<cycle_scalar>& scalars,
const std::vector<cycle_group>& base_points,
static cycle_group batch_mul(const std::vector<cycle_group>& base_points,
const std::vector<BigScalarField>& scalars,
GeneratorContext context = {})
{
std::vector<cycle_scalar> cycle_scalars;
for (auto scalar : scalars) {
cycle_scalars.emplace_back(scalar);
}
return batch_mul(base_points, cycle_scalars, context);
}
static cycle_group batch_mul(const std::vector<cycle_group>& base_points,
const std::vector<cycle_scalar>& scalars,
GeneratorContext context = {});
cycle_group operator*(const cycle_scalar& scalar) const;
cycle_group& operator*=(const cycle_scalar& scalar);
cycle_group operator*(const BigScalarField& scalar) const;
cycle_group& operator*=(const BigScalarField& scalar);
bool_t operator==(const cycle_group& other) const;
void assert_equal(const cycle_group& other, std::string const& msg = "cycle_group::assert_equal") const;
static cycle_group conditional_assign(const bool_t& predicate, const cycle_group& lhs, const cycle_group& rhs);
Expand Down
Loading

0 comments on commit 6e363ec

Please sign in to comment.