Skip to content

Commit

Permalink
curves: Tests have full coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
pmerkleplant committed Oct 28, 2023
1 parent f320f9f commit 3d3be23
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 16 deletions.
13 changes: 12 additions & 1 deletion src/curves/Secp256k1Arithmetic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,17 @@ library Secp256k1Arithmetic {
return self.y & 1;
}

//--------------------------------------------------------------------------
// Jacobian Point
//
// Coming soon...

//--------------------------------------------------------------------------
// (De)Serialization

//----------------------------------
// Affine Point

/// @dev Returns Affine point `self` as Jacobian point.
function toJacobianPoint(AffinePoint memory self)
internal
Expand All @@ -152,7 +163,7 @@ library Secp256k1Arithmetic {
return JacobianPoint(self.x, self.y, 1);
}

//--------------------------------------------------------------------------
//----------------------------------
// Jacobian Point

function intoAffinePoint(JacobianPoint memory self)
Expand Down
77 changes: 62 additions & 15 deletions test/curves/secp256k1/Secp256k1Arithmetic.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,28 @@ import {
} from "src/curves/Secp256k1Arithmetic.sol";
import {Secp256k1, PrivateKey, PublicKey} from "src/curves/Secp256k1.sol";

import {Secp256k1ArithmeticWrapper} from "./Secp256k1ArithmeticWrapper.sol";

contract Secp256k1ArithmeticTest is Test {
using Secp256k1Arithmetic for AffinePoint;
using Secp256k1Arithmetic for JacobianPoint;

using Secp256k1 for PrivateKey;
using Secp256k1 for PublicKey;

Secp256k1ArithmeticWrapper wrapper;

function setUp() public {
wrapper = new Secp256k1ArithmeticWrapper();
}

//--------------------------------------------------------------------------
// Test: Affine Point

// -- ZeroPoint

function test_ZeroPoint() public {
assertTrue(Secp256k1Arithmetic.ZeroPoint().isZeroPoint());
assertTrue(wrapper.ZeroPoint().isZeroPoint());
}

// -- isZeroPoint
Expand All @@ -33,16 +41,16 @@ contract Secp256k1ArithmeticTest is Test {
public
{
if (point.x == 0 && point.y == 0) {
assertTrue(point.isZeroPoint());
assertTrue(wrapper.isZeroPoint(point));
} else {
assertFalse(point.isZeroPoint());
assertFalse(wrapper.isZeroPoint(point));
}
}

// -- PointAtInfinity

function test_PointAtInfinity() public {
assertTrue(Secp256k1Arithmetic.PointAtInfinity().isPointAtInfinity());
assertTrue(wrapper.PointAtInfinity().isPointAtInfinity());
}

// -- isPointAtInfinity
Expand All @@ -51,43 +59,45 @@ contract Secp256k1ArithmeticTest is Test {
public
{
if (point.x == type(uint).max && point.y == type(uint).max) {
assertTrue(point.isPointAtInfinity());
assertTrue(wrapper.isPointAtInfinity(point));
} else {
assertFalse(point.isPointAtInfinity());
assertFalse(wrapper.isPointAtInfinity(point));
}
}

// -- isOnCurve

function testVectors_AffinePoint_isOnCurve() public {
assertTrue(Secp256k1Arithmetic.G().isOnCurve());
assertTrue(wrapper.isOnCurve(Secp256k1Arithmetic.G()));

// @todo Test some more points.
}

function testFuzz_AffinePoint_isOnCurve(PrivateKey privKey) public {
vm.assume(privKey.isValid());

assertTrue(privKey.toPublicKey().intoAffinePoint().isOnCurve());
AffinePoint memory point = privKey.toPublicKey().intoAffinePoint();

assertTrue(wrapper.isOnCurve(point));
}

// -- yParity

function test_AffinePoint_yParity(uint x, uint y) public {
function testFuzz_AffinePoint_yParity(uint x, uint y) public {
// yParity is 0 if y is even and 1 if y is odd.
uint want = y % 2 == 0 ? 0 : 1;
uint got = AffinePoint(x, y).yParity();
uint got = wrapper.yParity(AffinePoint(x, y));

assertEq(want, got);
}

// -- toJacobianPoint

function test_AffinePoint_toJacobianPoint(PrivateKey privKey) public {
function testFuzz_AffinePoint_toJacobianPoint(PrivateKey privKey) public {
vm.assume(privKey.isValid());

AffinePoint memory want = privKey.toPublicKey().intoAffinePoint();
AffinePoint memory got = want.toJacobianPoint().intoAffinePoint();
AffinePoint memory got = wrapper.toJacobianPoint(want).intoAffinePoint();

assertEq(want.x, got.x);
assertEq(want.y, got.y);
Expand All @@ -97,11 +107,14 @@ contract Secp256k1ArithmeticTest is Test {
// Test: Jacobian Point

// @todo Test no new memory allocation.
function test_JacobianPoint_intoAffinePoint(PrivateKey privKey) public {
// @todo Not a real test. Use vectors from Paul Miller.
function testFuzz_JacobianPoint_intoAffinePoint(PrivateKey privKey)
public
{
vm.assume(privKey.isValid());

AffinePoint memory want = privKey.toPublicKey().intoAffinePoint();
AffinePoint memory got = want.toJacobianPoint().intoAffinePoint();
AffinePoint memory got = wrapper.intoAffinePoint(want.toJacobianPoint());

assertEq(want.x, got.x);
assertEq(want.y, got.y);
Expand All @@ -110,5 +123,39 @@ contract Secp256k1ArithmeticTest is Test {
//--------------------------------------------------------------------------
// Test: Utils

// @todo Test: modularInverseOf()
// @todo Test: modularInverseOf: Differential fuzz against sage?
function testVectors_modularInverseOf() public {
uint x;
uint want;
uint got;

// sage: inverse_mod(1, P) == 1
x = 1;
want = 1;
got = wrapper.modularInverseOf(x);
assertEq(want, got);

// sage: inverse_mod(P - 1, P) == P -1
x = Secp256k1Arithmetic.P - 1;
want = Secp256k1Arithmetic.P - 1;
got = wrapper.modularInverseOf(x);
assertEq(want, got);

// sage: inverse_mod(10, P) == 34737626771194858627071295502606372355980995399692169211837275202372650401499
x = 10;
want =
34737626771194858627071295502606372355980995399692169211837275202372650401499;
got = wrapper.modularInverseOf(x);
assertEq(want, got);
}

function testFuzz_modularInverseOf_RevertsIf_XEqualToOrBiggerThanP(uint x)
public
{
vm.assume(x >= Secp256k1Arithmetic.P);

// @todo Test for proper error message.
vm.expectRevert();
wrapper.modularInverseOf(x);
}
}
91 changes: 91 additions & 0 deletions test/curves/secp256k1/Secp256k1ArithmeticWrapper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import {Secp256k1, PrivateKey, PublicKey} from "src/curves/Secp256k1.sol";
import {
Secp256k1Arithmetic,
AffinePoint,
JacobianPoint
} from "src/curves/Secp256k1Arithmetic.sol";

/**
* @title Secp256k1ArithmeticWrapper
*
* @notice Library wrapper to enable forge coverage reporting
*
* @dev For more info, see https://github.com/foundry-rs/foundry/pull/3128#issuecomment-1241245086.
*/
contract Secp256k1ArithmeticWrapper {
using Secp256k1Arithmetic for AffinePoint;
using Secp256k1Arithmetic for JacobianPoint;

//--------------------------------------------------------------------------
// Constants

function G() public pure returns (AffinePoint memory) {
return Secp256k1Arithmetic.G();
}

//--------------------------------------------------------------------------
// Affine Point

function ZeroPoint() public pure returns (AffinePoint memory) {
return Secp256k1Arithmetic.ZeroPoint();
}

function isZeroPoint(AffinePoint memory point) public pure returns (bool) {
return point.isZeroPoint();
}

function PointAtInfinity() public pure returns (AffinePoint memory) {
return Secp256k1Arithmetic.PointAtInfinity();
}

function isPointAtInfinity(AffinePoint memory point)
public
pure
returns (bool)
{
return point.isPointAtInfinity();
}

function isOnCurve(AffinePoint memory point) public pure returns (bool) {
return point.isOnCurve();
}

function yParity(AffinePoint memory point) public pure returns (uint) {
return point.yParity();
}

//--------------------------------------------------------------------------
// (De)Serialization

//----------------------------------
// Affine Point

function toJacobianPoint(AffinePoint memory point)
public
pure
returns (JacobianPoint memory)
{
return point.toJacobianPoint();
}

//----------------------------------
// Jacobian Point

function intoAffinePoint(JacobianPoint memory jacPoint)
public
pure
returns (AffinePoint memory)
{
return jacPoint.intoAffinePoint();
}

//--------------------------------------------------------------------------
// Utils

function modularInverseOf(uint x) public pure returns (uint) {
return Secp256k1Arithmetic.modularInverseOf(x);
}
}

0 comments on commit 3d3be23

Please sign in to comment.