Skip to content

Commit

Permalink
Refine the new refactored group circuits.
Browse files Browse the repository at this point in the history
In the circuit to enforce that a given point is in the subgroup, tie the witness
values of the internal variables to the witness values of the point. This also
takes care of the TODO that I had initially left.

Adjust variable and constraint counts in tests.
  • Loading branch information
acoglio committed Oct 15, 2023
1 parent d5431e5 commit bd066d0
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 31 deletions.
12 changes: 6 additions & 6 deletions circuit/types/group/src/helpers/from_bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,31 +77,31 @@ mod tests {

#[test]
fn test_from_bits_le_constant() {
check_from_bits_le(Mode::Constant, 11, 0, 0, 0);
check_from_bits_le(Mode::Constant, 9, 0, 0, 0);
}

#[test]
fn test_from_bits_le_public() {
check_from_bits_le(Mode::Public, 4, 0, 267, 268);
check_from_bits_le(Mode::Public, 4, 0, 265, 266);
}

#[test]
fn test_from_bits_le_private() {
check_from_bits_le(Mode::Private, 4, 0, 267, 268);
check_from_bits_le(Mode::Private, 4, 0, 265, 266);
}

#[test]
fn test_from_bits_be_constant() {
check_from_bits_be(Mode::Constant, 11, 0, 0, 0);
check_from_bits_be(Mode::Constant, 9, 0, 0, 0);
}

#[test]
fn test_from_bits_be_public() {
check_from_bits_be(Mode::Public, 4, 0, 267, 268);
check_from_bits_be(Mode::Public, 4, 0, 265, 266);
}

#[test]
fn test_from_bits_be_private() {
check_from_bits_be(Mode::Private, 4, 0, 267, 268);
check_from_bits_be(Mode::Private, 4, 0, 265, 266);
}
}
6 changes: 3 additions & 3 deletions circuit/types/group/src/helpers/from_x_coordinate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,16 @@ mod tests {

#[test]
fn test_from_x_coordinate_constant() {
check_from_x_coordinate(Mode::Constant, 11, 0, 0, 0);
check_from_x_coordinate(Mode::Constant, 9, 0, 0, 0);
}

#[test]
fn test_from_x_coordinate_public() {
check_from_x_coordinate(Mode::Public, 4, 0, 15, 15);
check_from_x_coordinate(Mode::Public, 4, 0, 13, 13);
}

#[test]
fn test_from_x_coordinate_private() {
check_from_x_coordinate(Mode::Private, 4, 0, 15, 15);
check_from_x_coordinate(Mode::Private, 4, 0, 13, 13);
}
}
6 changes: 3 additions & 3 deletions circuit/types/group/src/helpers/from_xy_coordinates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,17 @@ mod tests {

#[test]
fn test_from_xy_coordinates_constant() {
check_from_xy_coordinates(Mode::Constant, 10, 0, 0, 0);
check_from_xy_coordinates(Mode::Constant, 8, 0, 0, 0);
}

#[test]
fn test_from_xy_coordinates_public() {
check_from_xy_coordinates(Mode::Public, 4, 0, 14, 15);
check_from_xy_coordinates(Mode::Public, 4, 0, 12, 13);
}

#[test]
fn test_from_xy_coordinates_private() {
check_from_xy_coordinates(Mode::Private, 4, 0, 14, 15);
check_from_xy_coordinates(Mode::Private, 4, 0, 12, 13);
}

#[test]
Expand Down
40 changes: 21 additions & 19 deletions circuit/types/group/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ impl<E: Environment> Inject for Group<E> {
/// For safety, the resulting point is always enforced to be on the curve with constraints.
/// regardless of whether the y-coordinate was recovered.
fn new(mode: Mode, group: Self::Primitive) -> Self {
// TODO: check if `group` is in the group (in console-land, not circuit-land)

// Allocate two new variables for the coordinates, with the mode and values given as inputs.
let x = Field::new(mode, group.to_x_coordinate());
let y = Field::new(mode, group.to_y_coordinate());
Expand Down Expand Up @@ -99,15 +97,7 @@ impl<E: Environment> Group<E> {
impl<E: Environment> Group<E> {
/// Enforces that `self` is on the curve and in the largest prime-order subgroup.
pub fn enforce_in_group(&self) {
// Postulate a point on the curve.
// The coordinate values are irrelevant; we pick 0 for both.
let point_x = Field::new(Mode::Private, zero());
let point_y = Field::new(Mode::Private, zero());
let point = Self { x: point_x, y: point_y };
point.enforce_on_curve();

// (For advanced users) The cofactor for this curve is `4`. Thus doubling is used to be performant.
debug_assert!(E::Affine::cofactor().len() == 1 && E::Affine::cofactor()[0] == 4);
let self_witness = self.eject_value();

// Each point in the subgroup is the quadruple of some point on the curve,
// where 'quadruple' refers to the cofactor 4 of the curve.
Expand All @@ -116,15 +106,27 @@ impl<E: Environment> Group<E> {
// The point on the curve is existentially quantified,
// so the constraints introduce new coordinate variables for that point.

// Postulate another point that is double of the point on the curve above.
// The coordinate values are irrelevant; we pick 0 for both.
let double_point_x = Field::new(Mode::Private, zero());
let double_point_y = Field::new(Mode::Private, zero());
let double_point = Self { x: double_point_x, y: double_point_y };
point.enforce_double(&double_point);
// For the internal variables of this circuit,
// the mode is constant if the input point is constant, otherwise private.
let mode= if self.eject_mode().is_constant() { Mode::Constant } else {Mode::Private};

// Postulate a point (two new R1CS variables) on the curve,
// whose witness is the witness of the input point divided by the cofactor.
let point_witness = self_witness.div_by_cofactor();
let point_x = Field::new(mode, point_witness.to_x_coordinate());
let point_y = Field::new(mode, point_witness.to_y_coordinate());
let point = Self {x: point_x, y: point_y};
point.enforce_on_curve();

// (For advanced users) The cofactor for this curve is `4`. Thus doubling is used to be performant.
debug_assert!(E::Affine::cofactor().len() == 1 && E::Affine::cofactor()[0] == 4);

// Double the point on the curve.
// This introduces two new R1CS variables for the doubled point.
let double_point = point.double();

// Enforce that the input point (self) is double the double of the point on the curve,
// i.e. that it is 4 (cofactor) times the postulated point on the curve.
// i.e. that it is 4 (= cofactor) times the postulated point on the curve.
double_point.enforce_double(self);
}
}
Expand Down Expand Up @@ -255,7 +257,7 @@ mod tests {
Circuit::scope(&format!("Public {i}"), || {
let affine = Group::<Circuit>::new(Mode::Public, point);
assert_eq!(point, affine.eject_value());
assert_scope!(4, 2, 14, 14);
assert_scope!(4, 2, 12, 13);
});
}

Expand Down

0 comments on commit bd066d0

Please sign in to comment.