Skip to content
Closed
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
4725f75
the return of ec add unsafe
guipublic Sep 26, 2024
2c35a92
fix test case
guipublic Sep 26, 2024
6c14ad3
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Sep 26, 2024
bbff2f1
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Oct 1, 2024
5b5fc0a
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Oct 1, 2024
32de43a
force CI to run e2e
guipublic Oct 1, 2024
2f3ea01
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Oct 2, 2024
da1604f
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Oct 3, 2024
3c60dcb
chore: remove unused header in public executor (#8990)
Maddiaa0 Oct 3, 2024
6baa710
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Oct 3, 2024
d81f826
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Oct 3, 2024
98c7ebe
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Oct 4, 2024
bab195f
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Oct 4, 2024
bb57173
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Oct 10, 2024
249ab55
Merge branch 'master' into gd/unsafe_ec_add2
TomAFrench Apr 15, 2025
8e08f66
Merge aranch 'master' into gd/unsafe_ec_add2
guipublic Apr 16, 2025
a0576c1
allow infinite points for ec_add
guipublic Apr 16, 2025
2cdf9ad
Merge branch 'master' into gd/unsafe_ec_add2
guipublic Apr 22, 2025
6aa64f2
Merge branch 'master' into gd/unsafe_ec_add2
guipublic May 12, 2025
01a50ac
Merge branch 'master' into gd/unsafe_ec_add2
guipublic May 12, 2025
e3e8220
Merge branch 'master' into gd/unsafe_ec_add2
guipublic May 12, 2025
06ef800
only allow compile time 'is_infinite'
guipublic May 15, 2025
6519918
Merge branch 'master' into gd/unsafe_ec_add2
guipublic May 15, 2025
3a05675
Merge branch 'master' into gd/unsafe_ec_add2
guipublic May 16, 2025
56861f3
avoid failing check when there is no witness assignment
guipublic May 16, 2025
525a63f
Merge branch 'master' into gd/unsafe_ec_add2
guipublic May 20, 2025
304b758
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jun 25, 2025
8b4809c
fix merge
guipublic Jun 25, 2025
403c972
implement the all-or-nothing witness/constant for ec-add
guipublic Jun 27, 2025
99ebdf5
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jun 27, 2025
22b2e93
code review
guipublic Jun 27, 2025
877231c
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jun 27, 2025
b8b5f75
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jun 30, 2025
c78a883
update Noir
guipublic Jun 30, 2025
c5156dc
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jun 30, 2025
cdf21c2
Clean up function descriptions
Rumata888 Jun 30, 2025
298cd7d
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jun 30, 2025
e47b58b
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jul 1, 2025
f899533
Merge branch 'next' into gd/unsafe_ec_add2
TomAFrench Jul 2, 2025
d3a2daf
fix unit test
guipublic Jul 2, 2025
5feed4b
update vks
guipublic Jul 3, 2025
85e2b90
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jul 3, 2025
0cf8994
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jul 3, 2025
f0cf778
update vks
guipublic Jul 3, 2025
b64714b
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jul 4, 2025
6f4a199
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jul 4, 2025
2c133a8
updates cargo.lock
guipublic Jul 4, 2025
ef05a7d
handle opposite points
guipublic Jul 4, 2025
f4ae114
updates cargo.lock
guipublic Jul 4, 2025
b521f62
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jul 8, 2025
c872ab2
update vks
guipublic Jul 9, 2025
ef821e3
code review: check the x coordinates are distinct
guipublic Jul 9, 2025
f8555e8
add unit tests
guipublic Jul 11, 2025
c3bdb9b
Merge branch 'next' into gd/unsafe_ec_add2
guipublic Jul 14, 2025
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
123 changes: 116 additions & 7 deletions barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// =====================

#include "ec_operations.hpp"
#include "barretenberg/dsl/acir_format/witness_constant.hpp"
#include "barretenberg/ecc/curves/bn254/fr.hpp"
#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp"
#include "barretenberg/ecc/groups/affine_element.hpp"
Expand All @@ -13,19 +14,126 @@

namespace acir_format {

// This functions assumes that:
// 1. the points are on the curve

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.

What if the points are not on the curve? Where do we check that?

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.

It is the responsibility of the user, that's the point of this ec-add-unsafe; to avoid as many check as possible.
The checks done by the function have no cost because they are constant-time.
One use case is when you are adding points coming from a previous addition, so you know that the points are on the curve (if you checked the first ones) and there is no need to check this.

Note that the ec-add in Noir performs most of the checks

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.

Right, makes sense

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.

I just noticed that you don't detect the case where x_match by not y_match

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 added a check for this case:

  • if x match and y does not match, at compile time, then return 0
  • else, if x match, then return error
  • else: we assume x-coordinates are distincts and will do the unconditional add

// 2a. the points have not the same abssissa, OR
// 2b. the points are identical (same witness index or same value)
// If the points at infinity are known and constant, the function will work properly
// If not, and if the points are not identical, it is an error.
template <typename Builder>
void create_ec_add_constraint(Builder& builder, const EcAdd& input, bool has_valid_witness_assignments)
{
// Input to cycle_group points
// Cycle_group points are used by BB to lay out constraints on Grumpkin curve points
using cycle_group_ct = bb::stdlib::cycle_group<Builder>;

auto input1_point = to_grumpkin_point(
input.input1_x, input.input1_y, input.input1_infinite, has_valid_witness_assignments, builder);
auto input2_point = to_grumpkin_point(
input.input2_x, input.input2_y, input.input2_infinite, has_valid_witness_assignments, builder);
// Check if operands are the 'same' (same witness or same constant value).
bool x_match = false;
if (!input.input1_x.is_constant && !input.input2_x.is_constant) {
x_match = (input.input1_x.index == input.input2_x.index);
} else {
if (input.input1_x.is_constant && input.input2_x.is_constant) {
x_match = (input.input1_x.value == input.input2_x.value);
}
}
bool y_match = false;
if (!input.input1_y.is_constant && !input.input2_y.is_constant) {
y_match = (input.input1_y.index == input.input2_y.index);
} else {
if (input.input1_y.is_constant && input.input2_y.is_constant) {
y_match = (input.input1_y.value == input.input2_y.value);
}
}

cycle_group_ct result;
// If operands are the same, we double.
// Note that the doubling function handles the infinity case
if (x_match && y_match) {
cycle_group_ct input1_point;

// When there are no valid witness assignements, we need to define dummy values that will
// satisfy the doubling constraints, which we can do easily when the inputs are witness.
// If the is_infinity is a witness, we can simply set it to 1
// Or, if the coordinates are witness, we can simply set them to a valid point on the curve (G1)
if (!input.input1_infinite.is_constant || (!input.input1_x.is_constant && !input.input1_y.is_constant)) {
input1_point = to_grumpkin_point(
input.input1_x, input.input1_y, input.input1_infinite, has_valid_witness_assignments, true, builder);
} else {
// If not, the coordinates are mixed constant/witness, and we generate witness so that the point is using
// only witnesses.
input1_point = to_witness_grumpkin_point(
input.input1_x, input.input1_y, input.input1_infinite, has_valid_witness_assignments, true, builder);
}
result = input1_point.dbl();
} else {
// Regular addition
// if one point is (constant) zero, we simply return the other point.
if (input.input2_infinite.is_constant && input.input1_infinite.is_constant) {
if (get_value(input.input1_infinite, builder) == 1) {
// input1 is infinity, so we can just return input2
result = to_grumpkin_point(input.input2_x,
input.input2_y,
input.input2_infinite,
has_valid_witness_assignments,
false,

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.

These two ifs are equivalent, but you create the point with 'use_g1' being set to different values

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.

Any valid point would do here, it is just for consistency, as I use G1 for point1 and G2=2G1 for point2 elsewhere in the file.
But I don't mind changing it.

builder);

} else if (get_value(input.input2_infinite, builder) == 1) {
// input2 is infinity, so we can just return input1
result = to_grumpkin_point(input.input1_x,
input.input1_y,
input.input1_infinite,
has_valid_witness_assignments,
true,
builder);
} else {

cycle_group_ct input1_point;
cycle_group_ct input2_point;
// all or nothing: the inputs must be all constant or all witness. Cf #1108 for more details.
if (!input.input1_x.is_constant || !input.input1_y.is_constant || !input.input1_infinite.is_constant ||
!input.input2_x.is_constant || !input.input2_y.is_constant || !input.input2_infinite.is_constant) {
// One of the input is a witness, so we ensure that all inputs are witness, by creating witness for
// constant values.
input1_point = to_witness_grumpkin_point(input.input1_x,
input.input1_y,
input.input1_infinite,
has_valid_witness_assignments,
true,

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.

Same here. Why is 1 true and 2 false?

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.

Here it matters, because the two points must be distinct (else it would be a doubling).

builder);
input2_point = to_witness_grumpkin_point(input.input2_x,
input.input2_y,
input.input2_infinite,
has_valid_witness_assignments,
false,
builder);

} else {
input1_point = to_grumpkin_point(input.input1_x,
input.input1_y,
input.input1_infinite,
has_valid_witness_assignments,
true,
builder);
input2_point = to_grumpkin_point(input.input2_x,
input.input2_y,
input.input2_infinite,
has_valid_witness_assignments,
false,
builder);
}
// both points are not infinity, so we can use unconditional_add
if (has_valid_witness_assignments) {
// Runtime check that the inputs have not the same x coordinate, as assumed by the function.
ASSERT(input1_point.x.get_value() != input2_point.x.get_value());
}
result = input1_point.unconditional_add(input2_point);

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.

Why are you using unconditional add? Are you checking that the inputs are different? If the values are the same, this could allow you to create any point as a result

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.

This is the whole point of the PR, the checks have been moved on the Noir side so that we can avoid them in some cases. See this comment in the PR description:
"It will allow Aztec protocol circuit to use directly the opcode when the 'safety' is already known (and implied by previous operations)."

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.

You shouldn't remove the difference!=zero check. It is always necessary. There is no case that it is not necessary, when you are performing non-doubling additions.

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 disagree, else the function unconditional_add() would not exist. See the comments of the function:

  •    Only use this method if you know the x-coordinates of the operands cannot collide and none of the operands is a point at infinity
    

For instance it is used for batch mul:

  •     If `unconditional_add = true`, we use `::unconditional_add` instead of `::checked_unconditional_add`. Use with caution! Only should be `true` if we're doing an ULTRA fixed-base MSM so we know the points cannot collide with the offset generators.
    

@Rumata888 Rumata888 Jul 4, 2025

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.

The function unconditional add is only used in 2 cases:

  1. We know that the values provided are from a CRS and getting a combination of those that would be equal is tantamount to solving the discrete log
  2. We use it in our own batch mul, when we specifically want to save 1 gate by batching non-zero checks.

However, these are extremely rare situations. It is extremely dangerous to leave the operation like this by default, because then it does not ensure the correctness of additions at all in 99% of cases. If you really want to allow the developer to disable this particular check, then there should be a setting that allows this (with loud disclaimers). It shouldn't be by default

@guipublic guipublic Jul 4, 2025

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 will add a setting then.
In fact no, I will add the check because I don't want to have to change ACIR format.
I'll add the setting later, if this PR manage to go through!

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

}
} else {
// Some points could be at infinity, which is not supported by the function
ASSERT(false, "Unsupported EC ADDITION UNSAFE; is_infinite status must be known at compile time");
}
}

// Addition
cycle_group_ct result = input1_point + input2_point;
cycle_group_ct standard_result = result.get_standard_form();
auto x_normalized = standard_result.x.normalize();
auto y_normalized = standard_result.y.normalize();
Expand All @@ -41,6 +149,7 @@ void create_ec_add_constraint(Builder& builder, const EcAdd& input, bool has_val
} else {
builder.assert_equal(y_normalized.witness_index, input.result_y);
}

if (infinite.is_constant()) {
builder.fix_witness(input.result_infinite, infinite.get_value());
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,18 @@ class EcOperations : public ::testing::Test {

size_t generate_ec_add_constraint(EcAdd& ec_add_constraint, WitnessVector& witness_values)
{
using cycle_group_ct = bb::stdlib::cycle_group<Builder>;
witness_values.push_back(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.

Could you please add tests for all the edgecases? Right now we are only testing 1 case out of all the possibilities

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 am not sure because the edge cases are not expected to work.

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.

I mean the various combinations of constant and witness elements, cases where it turns into a double, etc.

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

auto g1 = grumpkin::g1::affine_one;
cycle_group_ct input_point(g1);
// Doubling
cycle_group_ct result = input_point.dbl();
auto g2 = g1 + g1;
auto affine_result = g1 + g2;

// add: x,y,x2,y2
witness_values.push_back(g1.x);
witness_values.push_back(g1.y);
witness_values.push_back(g1.x);
witness_values.push_back(g1.y);
witness_values.push_back(result.x.get_value());
witness_values.push_back(result.y.get_value());
witness_values.push_back(g2.x);
witness_values.push_back(g2.y);
witness_values.push_back(affine_result.x);
witness_values.push_back(affine_result.y);
witness_values.push_back(fr(0));
witness_values.push_back(fr(0));
ec_add_constraint = EcAdd{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void create_multi_scalar_mul_constraint(Builder& builder,
for (size_t i = 0; i < input.points.size(); i += 3) {
// Instantiate the input point/variable base as `cycle_group_ct`
cycle_group_ct input_point = to_grumpkin_point(
input.points[i], input.points[i + 1], input.points[i + 2], has_valid_witness_assignments, builder);
input.points[i], input.points[i + 1], input.points[i + 2], has_valid_witness_assignments, true, builder);
Comment thread
guipublic marked this conversation as resolved.

// Reconstruct the scalar from the low and high limbs
field_ct scalar_low_as_field = to_field_ct(input.scalars[2 * (i / 3)], builder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// =====================

#include "witness_constant.hpp"
#include "barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp"
#include "barretenberg/ecc/curves/bn254/fr.hpp"

namespace acir_format {
Expand All @@ -16,12 +17,20 @@ bb::stdlib::cycle_group<Builder> to_grumpkin_point(const WitnessOrConstant<FF>&
const WitnessOrConstant<FF>& input_y,
const WitnessOrConstant<FF>& input_infinite,
bool has_valid_witness_assignments,
bool use_g1,
Comment thread
guipublic marked this conversation as resolved.
Builder& builder)
{
using bool_ct = bb::stdlib::bool_t<Builder>;
auto point_x = to_field_ct(input_x, builder);
auto point_y = to_field_ct(input_y, builder);
auto infinite = bool_ct(to_field_ct(input_infinite, builder));
// We assume input_infinite is boolean, so we do not add a boolean gate
bool_t infinite(&builder);
if (!input_infinite.is_constant) {
infinite.witness_index = input_infinite.index;
infinite.witness_bool = get_value(input_infinite, builder) == FF::one();
} else {
infinite.witness_index = IS_CONSTANT;
infinite.witness_bool = input_infinite.value == FF::one();
}

// When we do not have the witness assignments, we set is_infinite value to true if it is not constant
// else default values would give a point which is not on the curve and this will fail verification
Expand All @@ -32,8 +41,15 @@ bb::stdlib::cycle_group<Builder> to_grumpkin_point(const WitnessOrConstant<FF>&
// else, if is_infinite is false, but the coordinates (x, y) are witness (and not constant)
// then we set their value to an arbitrary valid curve point (in our case G1).
auto g1 = bb::grumpkin::g1::affine_one;
builder.set_variable(input_x.index, g1.x);
builder.set_variable(input_y.index, g1.y);

if (use_g1) {
Comment thread
Rumata888 marked this conversation as resolved.
builder.set_variable(input_x.index, g1.x);
builder.set_variable(input_y.index, g1.y);
} else {
auto g2 = g1 + g1;
builder.set_variable(input_x.index, g2.x);
builder.set_variable(input_y.index, g2.y);
}
}
}
cycle_group<Builder> input_point(point_x, point_y, infinite);
Expand All @@ -44,11 +60,80 @@ template bb::stdlib::cycle_group<UltraCircuitBuilder> to_grumpkin_point(const Wi
const WitnessOrConstant<fr>& input_y,
const WitnessOrConstant<fr>& input_infinite,
bool has_valid_witness_assignments,
bool use_g1,
UltraCircuitBuilder& builder);
template bb::stdlib::cycle_group<MegaCircuitBuilder> to_grumpkin_point(const WitnessOrConstant<fr>& input_x,
const WitnessOrConstant<fr>& input_y,
const WitnessOrConstant<fr>& input_infinite,
bool has_valid_witness_assignments,
bool use_g1,
MegaCircuitBuilder& builder);

template <typename Builder, typename FF>
bb::stdlib::cycle_group<Builder> to_witness_grumpkin_point(const WitnessOrConstant<FF>& input_x,
const WitnessOrConstant<FF>& input_y,
const WitnessOrConstant<FF>& input_infinite,
bool has_valid_witness_assignments,
bool use_g1,
Builder& builder)
{
// Creates a Grumpkin point(cycle_group) from WitnessOrConstant inputs by always using
// witnesses, even if the inputs are constant.
auto point_x = to_field_ct(input_x, builder);
if (point_x.is_constant()) {
point_x.convert_constant_to_fixed_witness(&builder);
}
auto point_y = to_field_ct(input_y, builder);
if (point_y.is_constant()) {
point_y.convert_constant_to_fixed_witness(&builder);
}
// We assume input_infinite is boolean, so we do not add a boolean gate
bool_t infinite(&builder);
if (!input_infinite.is_constant) {
infinite.witness_index = input_infinite.index;
infinite.witness_bool = get_value(input_infinite, builder) == FF::one();
} else {
infinite.witness_index = IS_CONSTANT;
infinite.witness_bool = input_infinite.value == FF::one();
infinite.convert_constant_to_fixed_witness(&builder);
}

// When we do not have the witness assignments, we set is_infinite value to true if it is not constant
// else default values would give a point which is not on the curve and this will fail verification
// If is_infinite is constant and false, and since the created point is using witnesses for the coordinates,
// we set their value to a valid curve point (in our case G1).
if (!has_valid_witness_assignments) {
if (!input_infinite.is_constant) {
builder.set_variable(input_infinite.index, fr(1));
} else if (input_infinite.value == fr::zero() && !point_x.is_constant() && !point_x.is_constant()) {

auto g1 = bb::grumpkin::g1::affine_one;
if (use_g1) {
builder.set_variable(point_x.witness_index, g1.x);
builder.set_variable(point_y.witness_index, g1.y);
} else {
auto g2 = g1 + g1;
builder.set_variable(point_x.witness_index, g2.x);
builder.set_variable(point_y.witness_index, g2.y);
}
}
}
cycle_group<Builder> input_point(point_x, point_y, infinite);
return input_point;
}

template bb::stdlib::cycle_group<UltraCircuitBuilder> to_witness_grumpkin_point(
const WitnessOrConstant<fr>& input_x,
const WitnessOrConstant<fr>& input_y,
const WitnessOrConstant<fr>& input_infinite,
bool has_valid_witness_assignments,
bool use_g1,
UltraCircuitBuilder& builder);
template bb::stdlib::cycle_group<MegaCircuitBuilder> to_witness_grumpkin_point(
const WitnessOrConstant<fr>& input_x,
const WitnessOrConstant<fr>& input_y,
const WitnessOrConstant<fr>& input_infinite,
bool has_valid_witness_assignments,
bool use_g1,
MegaCircuitBuilder& builder);
} // namespace acir_format
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ bb::stdlib::cycle_group<Builder> to_grumpkin_point(const WitnessOrConstant<FF>&
const WitnessOrConstant<FF>& input_y,
const WitnessOrConstant<FF>& input_infinite,
bool has_valid_witness_assignments,
bool use_g1,
Builder& builder);

} // namespace acir_format
template <typename Builder, typename FF>
bb::stdlib::cycle_group<Builder> to_witness_grumpkin_point(const WitnessOrConstant<FF>& input_x,
const WitnessOrConstant<FF>& input_y,
const WitnessOrConstant<FF>& input_infinite,
bool has_valid_witness_assignments,
bool use_g1,
Builder& builder);

template <typename Builder, typename FF> FF get_value(const WitnessOrConstant<FF>& input, Builder& builder)
{
if (input.is_constant) {
return input.value;
}
return builder.get_variable(input.index);
}

} // namespace acir_format
13 changes: 13 additions & 0 deletions barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,19 @@ template <typename Builder> class bool_t {
mutable bool witness_inverted = false;
mutable uint32_t witness_index = IS_CONSTANT;
mutable OriginTag tag{};

/**
* Create a witness from a constant. This way the value of the witness is fixed and public (public, because the
* value becomes hard-coded as an element of the q_c selector vector).
*/
void convert_constant_to_fixed_witness(Builder* ctx)
Comment thread
guipublic marked this conversation as resolved.
Outdated
{
ASSERT(is_constant() && ctx);
context = ctx;
(*this) = bool_t<Builder>(witness_t<Builder>(context, get_value()));
context->fix_witness(witness_index, get_value());
unset_free_witness_tag();
}
};

template <typename T> inline std::ostream& operator<<(std::ostream& os, bool_t<T> const& v)
Expand Down
Loading