Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
43 changes: 32 additions & 11 deletions simf/lib/secp256k1/operations.simf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::lib::binary::and;
use crate::lib::asserts::{assert_eq_1, assert_eq_256};
use crate::lib::asserts::assert_eq_1;

/// Compress an affine point to `(parity, x)`, where `parity = 1` iff `y` is odd.
pub fn ge_to_point(p: Ge) -> Point {
Expand All @@ -12,11 +12,17 @@ pub fn ge_to_point(p: Ge) -> Point {
}

/// Decompress a `Point` into a Jacobian point with `z = 1`.
///
/// ## Panics
/// - if `x` is not the x-coordinate of a curve point
pub fn point_to_gej(p: Point) -> Gej {
(unwrap(jet::decompress(p)), 1)
}

/// Convert the point into affine coordinates.
///
/// ## Panics
/// - if `p` is the point at infinity
pub fn safe_gej_normalize(p: Gej) -> Ge {
unwrap(jet::gej_normalize(p))
}
Expand Down Expand Up @@ -53,16 +59,25 @@ pub fn ge_eq(a: Ge, b: Ge) -> bool {
and(fe_eq(ax, bx), fe_eq(ay, by))
}

/// Check if two points are equal.
/// Compressed point equality, with `x` compared modulo `p`.
pub fn point_point_eq(a: Point, b: Point) -> bool {
let (ap, ax): (u1, u256) = a;
let (bp, bx): (u1, u256) = b;
and(jet::eq_256(ax, bx), jet::eq_1(ap, bp))
let (ap, ax): (u1, Fe) = a;
let (bp, bx): (u1, Fe) = b;
and(fe_eq(ax, bx), jet::eq_1(ap, bp))
}

/// Check if two points represent the same point
/// Check if two points represent the same point.
/// Returns `false` if `a` is off-curve or `p` does not decompress to a curve point.
pub fn gej_point_eq(a: Gej, p: Point) -> bool {
jet::gej_ge_equiv(a, unwrap(jet::decompress(p)))
let (parity, x): (u1, Fe) = p;

// Cheaper than `decompress`: an on-curve `a` with matching `x` and `y` parity is exactly `p`.
let parity_eq: bool = match jet::gej_y_is_odd(a) {
true => jet::eq_1(parity, 1),
false => jet::eq_1(parity, 0),
};

and(and(jet::gej_is_on_curve(a), jet::gej_x_equiv(x, a)), parity_eq)
}

/// Field equality modulo `p`.
Expand All @@ -84,12 +99,12 @@ pub fn assert_ge_eq(a: Ge, b: Ge) {
assert_fe_eq(ay, by);
}

/// Check if two points are equal.
/// Compressed point equality, with `x` compared modulo `p`.
pub fn assert_point_eq(a: Point, b: Point) {
let (ap, ax): (u1, u256) = a;
let (bp, bx): (u1, u256) = b;
let (ap, ax): (u1, Fe) = a;
let (bp, bx): (u1, Fe) = b;

assert_eq_256(ax, bx);
assert_fe_eq(ax, bx);
assert_eq_1(ap, bp);
}

Expand All @@ -99,11 +114,17 @@ pub fn assert_gej_point_eq(a: Gej, p: Point) {
}

/// Assert two points represent the same curve point.
/// Both points must be on the curve: `gej_equiv` only rejects `y = -b.y` for a matching `x`.
pub fn assert_gej_eq(a: Gej, b: Gej) {
assert!(jet::gej_is_on_curve(a));
assert!(jet::gej_is_on_curve(b));
assert!(jet::gej_equiv(a, b));
}

/// Assert point equal an affine point (no normalize required).
/// Both points must be on the curve: `gej_ge_equiv` only rejects `y = -b.y` for a matching `x`.
pub fn assert_gej_ge_eq(a: Gej, b: Ge) {
assert!(jet::gej_is_on_curve(a));
assert!(jet::ge_is_on_curve(b));
assert!(jet::gej_ge_equiv(a, b));
}
23 changes: 23 additions & 0 deletions tests/stdlib/secp256k1/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,29 @@ fn gej_point_eq_rejects_negation(context: simplex::TestContext) -> anyhow::Resul
.expecting(&context, Expect::AssertFailed)
}

#[simplex::test]
fn gej_point_eq_off_curve_is_false(context: simplex::TestContext) -> anyhow::Result<()> {
// x = 0 is off-curve.
case(GejPointEq)
.gej(ge_to_gej(random_ge_bytes()))
.point((0, [0u8; 32]))
.expecting(&context, Expect::AssertFailed)
}

#[simplex::test]
fn gej_point_eq_rejects_off_curve_gej(context: simplex::TestContext) -> anyhow::Result<()> {
// (x, 1, 1) shares x with P but is off-curve. The equivalence jet only
// rejects y = -P.y, so without an on-curve check this would pass.
let ge = random_ge_bytes();
let mut one = [0u8; 32];
one[31] = 1;

case(GejPointEq)
.gej(((ge.0, one), one))
.point(compress(ge))
.expecting(&context, Expect::AssertFailed)
}

// 9. safe_gej_normalize
#[simplex::test]
fn safe_gej_normalize_roundtrip(context: simplex::TestContext) -> anyhow::Result<()> {
Expand Down
Loading