diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.cpp index cf95b59b6c51..031e86f6ba4c 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.cpp @@ -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" @@ -13,19 +14,165 @@ namespace acir_format { +/** + * @brief Creates a constraint for an EC addition operation + * + * @param builder Circuit builder + * @param input The input to the EC addition operation (contains information about input witnesses/constants) + * @param has_valid_witness_assignments Whether the witness assignments are valid (if we are just constructing a circuit + * to get the verification key, we might not have a valid witness) + * + * @details This function creates a constraint for an EC addition operation. The mode of operation is as follows: + * It assumes that the points are on the curve. Then: + * - If it is known that the points are the same (either witness ids are identical or constant values are identical), + * it doubles the point. In this case, it can handle the case of a point at infinity. + * - If it is known that the points are at infinity or not (controlling boolean for both is a constant), it will return + * the other point if one is at infinity. + * - If it is known that the points are opposite, it will return the infinity point. + * - If it is known that the points have the same abscissa at this stage, it will return an error. + * - If none of the points are at infinity, it assumes that they have distinct abscissa and adds them. + * - If it is not known whether the points are points at infinity, it will return an error. + * + */ template 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; - 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, + /*use_g1=*/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, + /*use_g1=*/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_witness_grumpkin_point(input.input2_x, + input.input2_y, + input.input2_infinite, + has_valid_witness_assignments, + /*use_g1=*/false, + builder); + + } else if (get_value(input.input2_infinite, builder) == 1) { + // input2 is infinity, so we can just return input1 + result = to_witness_grumpkin_point(input.input1_x, + input.input1_y, + input.input1_infinite, + has_valid_witness_assignments, + /*use_g1=*/true, + builder); + } else if (x_match && !y_match) { + if (input.input1_y.is_constant && input.input2_y.is_constant) { + // we know x1==x2 and y1!=y2, so we assume the points are opposite + result = cycle_group_ct(bb::fr::zero(), bb::fr::zero(), true); + } else { + ASSERT(false, + "Unsupported EC ADDITION UNSAFE; asbcissas should be disctinct, or the points should be " + "identical " + "(doubling)"); + } + } 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, + /*use_g1=*/true, + builder); + input2_point = to_witness_grumpkin_point(input.input2_x, + input.input2_y, + input.input2_infinite, + has_valid_witness_assignments, + /*use_g1=*/false, + builder); + + } else { + input1_point = to_grumpkin_point(input.input1_x, + input.input1_y, + input.input1_infinite, + has_valid_witness_assignments, + /*use_g1=*/true, + builder); + input2_point = to_grumpkin_point(input.input2_x, + input.input2_y, + input.input2_infinite, + has_valid_witness_assignments, + /*use_g1=*/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()); + } + // Check that the x coordinates are distincts. + // This function is not supposed to make any check so that the checks can be added by the developer + // when required, for best performance. However this is a critical assumption so we still check it for + // now. We should make the test optional via an additional parameter in the future. + auto x_match = input1_point.x - input2_point.x; + x_match.assert_is_not_zero( + "Unsupported EC ADDITION UNSAFE; asbcissas should be disctinct, or the points should be identical " + "(doubling)"); + result = input1_point.unconditional_add(input2_point); + } + } 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(); @@ -41,6 +188,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 { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp index c4f1c038c0fc..5b7c7b538cac 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp @@ -6,6 +6,7 @@ #include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" #include "barretenberg/stdlib/primitives/group/cycle_group.hpp" +#include #include #include @@ -20,28 +21,31 @@ 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; witness_values.push_back(0); 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(fr(0)); - witness_values.push_back(fr(0)); + 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); + + auto is_infinite_false = WitnessOrConstant{ + .index = 0, + .value = bb::fr::zero(), + .is_constant = true, + }; ec_add_constraint = EcAdd{ .input1_x = WitnessOrConstant::from_index(1), .input1_y = WitnessOrConstant::from_index(2), - .input1_infinite = WitnessOrConstant::from_index(7), + .input1_infinite = is_infinite_false, .input2_x = WitnessOrConstant::from_index(3), .input2_y = WitnessOrConstant::from_index(4), - .input2_infinite = WitnessOrConstant::from_index(7), + .input2_infinite = is_infinite_false, .result_x = 5, .result_y = 6, .result_infinite = 8, @@ -224,4 +228,167 @@ TEST_F(EcOperations, TestECMultiScalarMul) EXPECT_TRUE(CircuitChecker::check(builder)); } +// generates an EcAdd constraint, updating the witness values based on +// the desired outcome: constant or witness input, zero, or doubling. +size_t generate_more_ec_add_constraint(EcAdd& ec_add_constraint, + WitnessVector& witness_values, + bool lhs_is_zero, + bool rhs_is_zero, + bool lhs_is_constant, + bool rhs_is_constant, + bool doubling) +{ + witness_values.push_back(0); + auto g1 = grumpkin::g1::affine_one; + auto g2 = g1 + g1; + if (lhs_is_zero) { + g1 = grumpkin::g1::point_at_infinity; + } + if (rhs_is_zero) { + g2 = grumpkin::g1::point_at_infinity; + } + if (doubling) { + g2 = g1; + rhs_is_constant = lhs_is_constant; + rhs_is_zero = lhs_is_zero; + } + auto affine_result = g1 + g2; + + uint32_t witness_idx = static_cast(witness_values.size()); + if (!lhs_is_constant) { + witness_values.push_back(g1.x); + witness_values.push_back(g1.y); + } + if (!rhs_is_constant && !doubling) { + witness_values.push_back(g2.x); + witness_values.push_back(g2.y); + } + if (affine_result.is_point_at_infinity()) { + witness_values.push_back(bb::fr::zero()); + witness_values.push_back(bb::fr::zero()); + witness_values.push_back(bb::fr::one()); + } else { + witness_values.push_back(affine_result.x); + witness_values.push_back(affine_result.y); + witness_values.push_back(bb::fr::zero()); + } + + auto is_infinite_false = WitnessOrConstant{ + .index = 0, + .value = bb::fr::zero(), + .is_constant = true, + }; + auto is_infinite_true = WitnessOrConstant{ + .index = 0, + .value = bb::fr::one(), + .is_constant = true, + }; + auto lhs_x = WitnessOrConstant::from_index(witness_idx); + auto lhs_y = WitnessOrConstant::from_index(witness_idx + 1); + if (lhs_is_constant) { + lhs_x = WitnessOrConstant{ + .index = 0, + .value = lhs_is_zero ? bb::fr::zero() : g1.x, + .is_constant = true, + }; + lhs_y = WitnessOrConstant{ + .index = 0, + .value = rhs_is_zero ? bb::fr::zero() : g1.y, + .is_constant = true, + }; + } else if (!doubling) { + witness_idx += 2; + } + auto rhs_x = WitnessOrConstant::from_index(witness_idx); + auto rhs_y = WitnessOrConstant::from_index(witness_idx + 1); + if (rhs_is_constant) { + rhs_x = WitnessOrConstant{ + .index = 0, + .value = g2.x, + .is_constant = true, + }; + rhs_y = WitnessOrConstant{ + .index = 0, + .value = g2.y, + .is_constant = true, + }; + } else { + witness_idx += 2; + } + ec_add_constraint = EcAdd{ + .input1_x = lhs_x, + .input1_y = lhs_y, + .input1_infinite = is_infinite_false, + .input2_x = rhs_x, + .input2_y = rhs_y, + .input2_infinite = is_infinite_false, + .result_x = witness_idx, + .result_y = witness_idx + 1, + .result_infinite = witness_idx + 2, + }; + if (lhs_is_zero) { + ec_add_constraint.input1_infinite = is_infinite_true; + } + if (rhs_is_zero) { + ec_add_constraint.input2_infinite = is_infinite_true; + } + return witness_values.size(); +} + +// Test various scenarios, adding x + y, where x, y are: witness, constant, zero, or identical. +TEST_F(EcOperations, TestMoreECOperations) +{ + WitnessVector witness_values; + size_t num_variables = 0; + std::vector constraints; + for (int i = 0; i < 32; ++i) { + bool lhs_is_zero = (i & 1) != 0; + bool rhs_is_zero = (i & 2) != 0; + bool lhs_is_constant = (i & 4) != 0; + bool rhs_is_constant = (i & 8) != 0; + bool doubling = (i & 16) != 0; + EcAdd ec_add_constraint; + num_variables = generate_more_ec_add_constraint( + ec_add_constraint, witness_values, lhs_is_zero, rhs_is_zero, lhs_is_constant, rhs_is_constant, doubling); + constraints.push_back(ec_add_constraint); + } + AcirFormat constraint_system{ + .varnum = static_cast(num_variables + 1), + .num_acir_opcodes = 1, + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .aes128_constraints = {}, + .sha256_compression = {}, + + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_permutations = {}, + .poseidon2_constraints = {}, + .multi_scalar_mul_constraints = {}, + .ec_add_constraints = constraints, + .recursion_constraints = {}, + .honk_recursion_constraints = {}, + .avm_recursion_constraints = {}, + .ivc_recursion_constraints = {}, + .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, + .bigint_operations = {}, + .assert_equalities = {}, + .poly_triple_constraints = {}, + .quad_constraints = {}, + .big_quad_constraints = {}, + .block_constraints = {}, + .original_opcode_indices = create_empty_original_opcode_indices(), + }; + mock_opcode_indices(constraint_system); + + AcirProgram program{ constraint_system, witness_values }; + auto builder = create_circuit(program); + + EXPECT_TRUE(CircuitChecker::check(builder)); +} + } // namespace acir_format::tests diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.cpp index 3d399ca238c2..3f06dd9b0fc1 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.cpp @@ -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); // Reconstruct the scalar from the low and high limbs field_ct scalar_low_as_field = to_field_ct(input.scalars[2 * (i / 3)], builder); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/witness_constant.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/witness_constant.cpp index f2c17a24da0d..b4f9611b7f51 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/witness_constant.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/witness_constant.cpp @@ -5,23 +5,43 @@ // ===================== #include "witness_constant.hpp" +#include "barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" namespace acir_format { using namespace bb; using namespace bb::stdlib; + +/** + * @brief Generates a cycle_group point from the inputs, taking care of their witness/constant nature + * + * @details If has_valid_witness_assignments is false, then it will assign dummy values representing + * a point on the curve: + * - the infinite point if input_infinite is a witness + * - else, if input_infinite is a constant and false, and input_x and input_y are witnesses: + * it will assign G1 if use_g1 is true, else 2*G1 + * It will not assign anything otherwise. + */ template bb::stdlib::cycle_group to_grumpkin_point(const WitnessOrConstant& input_x, const WitnessOrConstant& input_y, const WitnessOrConstant& input_infinite, bool has_valid_witness_assignments, + bool use_g1, Builder& builder) { - using bool_ct = bb::stdlib::bool_t; 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 @@ -32,8 +52,15 @@ bb::stdlib::cycle_group to_grumpkin_point(const WitnessOrConstant& // 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) { + 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 input_point(point_x, point_y, infinite); @@ -44,11 +71,87 @@ template bb::stdlib::cycle_group to_grumpkin_point(const Wi const WitnessOrConstant& input_y, const WitnessOrConstant& input_infinite, bool has_valid_witness_assignments, + bool use_g1, UltraCircuitBuilder& builder); template bb::stdlib::cycle_group to_grumpkin_point(const WitnessOrConstant& input_x, const WitnessOrConstant& input_y, const WitnessOrConstant& input_infinite, bool has_valid_witness_assignments, + bool use_g1, MegaCircuitBuilder& builder); +/** + * @brief This function also generates a cycle_group point from the inputs, like to_grumpkin_point(), + * but it creates and use a witness for each constant input. + * The assignment of dummy values is the same as in to_grumpkin_point(), except that + * here the point will always use witness, so the second case (x and y are witness) + * will always be true. + */ +template +bb::stdlib::cycle_group to_witness_grumpkin_point(const WitnessOrConstant& input_x, + const WitnessOrConstant& input_y, + const WitnessOrConstant& 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 input_point(point_x, point_y, infinite); + return input_point; +} + +template bb::stdlib::cycle_group to_witness_grumpkin_point( + const WitnessOrConstant& input_x, + const WitnessOrConstant& input_y, + const WitnessOrConstant& input_infinite, + bool has_valid_witness_assignments, + bool use_g1, + UltraCircuitBuilder& builder); +template bb::stdlib::cycle_group to_witness_grumpkin_point( + const WitnessOrConstant& input_x, + const WitnessOrConstant& input_y, + const WitnessOrConstant& input_infinite, + bool has_valid_witness_assignments, + bool use_g1, + MegaCircuitBuilder& builder); } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/witness_constant.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/witness_constant.hpp index ecfcca619f37..d33bff12089b 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/witness_constant.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/witness_constant.hpp @@ -43,6 +43,23 @@ bb::stdlib::cycle_group to_grumpkin_point(const WitnessOrConstant& const WitnessOrConstant& input_y, const WitnessOrConstant& input_infinite, bool has_valid_witness_assignments, + bool use_g1, Builder& builder); -} // namespace acir_format \ No newline at end of file +template +bb::stdlib::cycle_group to_witness_grumpkin_point(const WitnessOrConstant& input_x, + const WitnessOrConstant& input_y, + const WitnessOrConstant& input_infinite, + bool has_valid_witness_assignments, + bool use_g1, + Builder& builder); + +template FF get_value(const WitnessOrConstant& input, Builder& builder) +{ + if (input.is_constant) { + return input.value; + } + return builder.get_variable(input.index); +} + +} // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.cpp index 5bd05826fede..2f2ff12ba049 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.cpp @@ -506,6 +506,19 @@ template bool_t bool_t::normalize() const return *this; } +/** + * 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). + */ +template void bool_t::convert_constant_to_fixed_witness(Builder* ctx) +{ + ASSERT(is_constant() && ctx); + context = ctx; + (*this) = bool_t(witness_t(context, get_value())); + context->fix_witness(witness_index, get_value()); + unset_free_witness_tag(); +} + template class bool_t; template class bool_t; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.hpp index 8c070b823ade..5a118ac8b0ef 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.hpp @@ -125,6 +125,8 @@ template class bool_t { mutable bool witness_inverted = false; mutable uint32_t witness_index = IS_CONSTANT; mutable OriginTag tag{}; + + void convert_constant_to_fixed_witness(Builder* ctx); }; template inline std::ostream& operator<<(std::ostream& os, bool_t const& v) diff --git a/noir/noir-repo-ref b/noir/noir-repo-ref index c220f7580c44..21a6f3d0a974 100644 --- a/noir/noir-repo-ref +++ b/noir/noir-repo-ref @@ -1 +1 @@ -8988213085075ee6c5f8843f767ae9a9a204e2cf +gd/ec-add-unsafe