Skip to content

Commit

Permalink
test: add utils for testing
Browse files Browse the repository at this point in the history
  • Loading branch information
stevennevins committed Feb 3, 2025
1 parent 293e919 commit 04eb2db
Show file tree
Hide file tree
Showing 3 changed files with 434 additions and 0 deletions.
337 changes: 337 additions & 0 deletions test/utils/BN256G2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,337 @@
pragma solidity ^0.8.0;

/**
* @title Elliptic curve operations on twist points for alt_bn128
* @author Mustafa Al-Bassam ([email protected])
* @dev Homepage: https://github.com/musalbas/solidity-BN256G2
*/
library BN256G2 {
uint256 internal constant FIELD_MODULUS =
0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47;
uint256 internal constant TWISTBX =
0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5;
uint256 internal constant TWISTBY =
0x9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2;
uint256 internal constant PTXX = 0;
uint256 internal constant PTXY = 1;
uint256 internal constant PTYX = 2;
uint256 internal constant PTYY = 3;
uint256 internal constant PTZX = 4;
uint256 internal constant PTZY = 5;

/**
* @notice Add two twist points
* @param pt1xx Coefficient 1 of x on point 1
* @param pt1xy Coefficient 2 of x on point 1
* @param pt1yx Coefficient 1 of y on point 1
* @param pt1yy Coefficient 2 of y on point 1
* @param pt2xx Coefficient 1 of x on point 2
* @param pt2xy Coefficient 2 of x on point 2
* @param pt2yx Coefficient 1 of y on point 2
* @param pt2yy Coefficient 2 of y on point 2
* @return (pt3xx, pt3xy, pt3yx, pt3yy)
*/
function ECTwistAdd(
uint256 pt1xx,
uint256 pt1xy,
uint256 pt1yx,
uint256 pt1yy,
uint256 pt2xx,
uint256 pt2xy,
uint256 pt2yx,
uint256 pt2yy
) public view returns (uint256, uint256, uint256, uint256) {
if (pt1xx == 0 && pt1xy == 0 && pt1yx == 0 && pt1yy == 0) {
if (!(pt2xx == 0 && pt2xy == 0 && pt2yx == 0 && pt2yy == 0)) {
assert(_isOnCurve(pt2xx, pt2xy, pt2yx, pt2yy));
}
return (pt2xx, pt2xy, pt2yx, pt2yy);
} else if (pt2xx == 0 && pt2xy == 0 && pt2yx == 0 && pt2yy == 0) {
assert(_isOnCurve(pt1xx, pt1xy, pt1yx, pt1yy));
return (pt1xx, pt1xy, pt1yx, pt1yy);
}

assert(_isOnCurve(pt1xx, pt1xy, pt1yx, pt1yy));
assert(_isOnCurve(pt2xx, pt2xy, pt2yx, pt2yy));

uint256[6] memory pt3 =
_ECTwistAddJacobian(pt1xx, pt1xy, pt1yx, pt1yy, 1, 0, pt2xx, pt2xy, pt2yx, pt2yy, 1, 0);

return _fromJacobian(pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]);
}

/**
* @notice Multiply a twist point by a scalar
* @param s Scalar to multiply by
* @param pt1xx Coefficient 1 of x
* @param pt1xy Coefficient 2 of x
* @param pt1yx Coefficient 1 of y
* @param pt1yy Coefficient 2 of y
* @return (pt2xx, pt2xy, pt2yx, pt2yy)
*/
function ECTwistMul(
uint256 s,
uint256 pt1xx,
uint256 pt1xy,
uint256 pt1yx,
uint256 pt1yy
) public view returns (uint256, uint256, uint256, uint256) {
uint256 pt1zx = 1;
if (pt1xx == 0 && pt1xy == 0 && pt1yx == 0 && pt1yy == 0) {
pt1xx = 1;
pt1yx = 1;
pt1zx = 0;
} else {
assert(_isOnCurve(pt1xx, pt1xy, pt1yx, pt1yy));
}

uint256[6] memory pt2 = _ECTwistMulJacobian(s, pt1xx, pt1xy, pt1yx, pt1yy, pt1zx, 0);

return _fromJacobian(pt2[PTXX], pt2[PTXY], pt2[PTYX], pt2[PTYY], pt2[PTZX], pt2[PTZY]);
}

/**
* @notice Get the field modulus
* @return The field modulus
*/
function GetFieldModulus() public pure returns (uint256) {
return FIELD_MODULUS;
}

function submod(uint256 a, uint256 b, uint256 n) internal pure returns (uint256) {
return addmod(a, n - b, n);
}

function _FQ2Mul(
uint256 xx,
uint256 xy,
uint256 yx,
uint256 yy
) internal pure returns (uint256, uint256) {
return (
submod(mulmod(xx, yx, FIELD_MODULUS), mulmod(xy, yy, FIELD_MODULUS), FIELD_MODULUS),
addmod(mulmod(xx, yy, FIELD_MODULUS), mulmod(xy, yx, FIELD_MODULUS), FIELD_MODULUS)
);
}

function _FQ2Muc(uint256 xx, uint256 xy, uint256 c) internal pure returns (uint256, uint256) {
return (mulmod(xx, c, FIELD_MODULUS), mulmod(xy, c, FIELD_MODULUS));
}

function _FQ2Add(
uint256 xx,
uint256 xy,
uint256 yx,
uint256 yy
) internal pure returns (uint256, uint256) {
return (addmod(xx, yx, FIELD_MODULUS), addmod(xy, yy, FIELD_MODULUS));
}

function _FQ2Sub(
uint256 xx,
uint256 xy,
uint256 yx,
uint256 yy
) internal pure returns (uint256 rx, uint256 ry) {
return (submod(xx, yx, FIELD_MODULUS), submod(xy, yy, FIELD_MODULUS));
}

function _FQ2Div(
uint256 xx,
uint256 xy,
uint256 yx,
uint256 yy
) internal view returns (uint256, uint256) {
(yx, yy) = _FQ2Inv(yx, yy);
return _FQ2Mul(xx, xy, yx, yy);
}

function _FQ2Inv(uint256 x, uint256 y) internal view returns (uint256, uint256) {
uint256 inv = _modInv(
addmod(mulmod(y, y, FIELD_MODULUS), mulmod(x, x, FIELD_MODULUS), FIELD_MODULUS),
FIELD_MODULUS
);
return (mulmod(x, inv, FIELD_MODULUS), FIELD_MODULUS - mulmod(y, inv, FIELD_MODULUS));
}

function _isOnCurve(
uint256 xx,
uint256 xy,
uint256 yx,
uint256 yy
) internal pure returns (bool) {
uint256 yyx;
uint256 yyy;
uint256 xxxx;
uint256 xxxy;
(yyx, yyy) = _FQ2Mul(yx, yy, yx, yy);
(xxxx, xxxy) = _FQ2Mul(xx, xy, xx, xy);
(xxxx, xxxy) = _FQ2Mul(xxxx, xxxy, xx, xy);
(yyx, yyy) = _FQ2Sub(yyx, yyy, xxxx, xxxy);
(yyx, yyy) = _FQ2Sub(yyx, yyy, TWISTBX, TWISTBY);
return yyx == 0 && yyy == 0;
}

function _modInv(uint256 a, uint256 n) internal view returns (uint256 result) {
bool success;
assembly ("memory-safe") {
let freemem := mload(0x40)
mstore(freemem, 0x20)
mstore(add(freemem, 0x20), 0x20)
mstore(add(freemem, 0x40), 0x20)
mstore(add(freemem, 0x60), a)
mstore(add(freemem, 0x80), sub(n, 2))
mstore(add(freemem, 0xA0), n)
success := staticcall(sub(gas(), 2000), 5, freemem, 0xC0, freemem, 0x20)
result := mload(freemem)
}
require(success);
}

function _fromJacobian(
uint256 pt1xx,
uint256 pt1xy,
uint256 pt1yx,
uint256 pt1yy,
uint256 pt1zx,
uint256 pt1zy
) internal view returns (uint256 pt2xx, uint256 pt2xy, uint256 pt2yx, uint256 pt2yy) {
uint256 invzx;
uint256 invzy;
(invzx, invzy) = _FQ2Inv(pt1zx, pt1zy);
(pt2xx, pt2xy) = _FQ2Mul(pt1xx, pt1xy, invzx, invzy);
(pt2yx, pt2yy) = _FQ2Mul(pt1yx, pt1yy, invzx, invzy);
}

function _ECTwistAddJacobian(
uint256 pt1xx,
uint256 pt1xy,
uint256 pt1yx,
uint256 pt1yy,
uint256 pt1zx,
uint256 pt1zy,
uint256 pt2xx,
uint256 pt2xy,
uint256 pt2yx,
uint256 pt2yy,
uint256 pt2zx,
uint256 pt2zy
) internal pure returns (uint256[6] memory pt3) {
if (pt1zx == 0 && pt1zy == 0) {
(pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) =
(pt2xx, pt2xy, pt2yx, pt2yy, pt2zx, pt2zy);
return pt3;
} else if (pt2zx == 0 && pt2zy == 0) {
(pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) =
(pt1xx, pt1xy, pt1yx, pt1yy, pt1zx, pt1zy);
return pt3;
}

(pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // U1 = y2 * z1
(pt3[PTYX], pt3[PTYY]) = _FQ2Mul(pt1yx, pt1yy, pt2zx, pt2zy); // U2 = y1 * z2
(pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // V1 = x2 * z1
(pt3[PTZX], pt3[PTZY]) = _FQ2Mul(pt1xx, pt1xy, pt2zx, pt2zy); // V2 = x1 * z2

if (pt2xx == pt3[PTZX] && pt2xy == pt3[PTZY]) {
if (pt2yx == pt3[PTYX] && pt2yy == pt3[PTYY]) {
(pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) =
_ECTwistDoubleJacobian(pt1xx, pt1xy, pt1yx, pt1yy, pt1zx, pt1zy);
return pt3;
}
(pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) = (1, 0, 1, 0, 0, 0);
return pt3;
}

(pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // W = z1 * z2
(pt1xx, pt1xy) = _FQ2Sub(pt2yx, pt2yy, pt3[PTYX], pt3[PTYY]); // U = U1 - U2
(pt1yx, pt1yy) = _FQ2Sub(pt2xx, pt2xy, pt3[PTZX], pt3[PTZY]); // V = V1 - V2
(pt1zx, pt1zy) = _FQ2Mul(pt1yx, pt1yy, pt1yx, pt1yy); // V_squared = V * V
(pt2yx, pt2yy) = _FQ2Mul(pt1zx, pt1zy, pt3[PTZX], pt3[PTZY]); // V_squared_times_V2 = V_squared * V2
(pt1zx, pt1zy) = _FQ2Mul(pt1zx, pt1zy, pt1yx, pt1yy); // V_cubed = V * V_squared
(pt3[PTZX], pt3[PTZY]) = _FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // newz = V_cubed * W
(pt2xx, pt2xy) = _FQ2Mul(pt1xx, pt1xy, pt1xx, pt1xy); // U * U
(pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // U * U * W
(pt2xx, pt2xy) = _FQ2Sub(pt2xx, pt2xy, pt1zx, pt1zy); // U * U * W - V_cubed
(pt2zx, pt2zy) = _FQ2Muc(pt2yx, pt2yy, 2); // 2 * V_squared_times_V2
(pt2xx, pt2xy) = _FQ2Sub(pt2xx, pt2xy, pt2zx, pt2zy); // A = U * U * W - V_cubed - 2 * V_squared_times_V2
(pt3[PTXX], pt3[PTXY]) = _FQ2Mul(pt1yx, pt1yy, pt2xx, pt2xy); // newx = V * A
(pt1yx, pt1yy) = _FQ2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // V_squared_times_V2 - A
(pt1yx, pt1yy) = _FQ2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // U * (V_squared_times_V2 - A)
(pt1xx, pt1xy) = _FQ2Mul(pt1zx, pt1zy, pt3[PTYX], pt3[PTYY]); // V_cubed * U2
(pt3[PTYX], pt3[PTYY]) = _FQ2Sub(pt1yx, pt1yy, pt1xx, pt1xy); // newy = U * (V_squared_times_V2 - A) - V_cubed * U2
}

function _ECTwistDoubleJacobian(
uint256 pt1xx,
uint256 pt1xy,
uint256 pt1yx,
uint256 pt1yy,
uint256 pt1zx,
uint256 pt1zy
)
internal
pure
returns (
uint256 pt2xx,
uint256 pt2xy,
uint256 pt2yx,
uint256 pt2yy,
uint256 pt2zx,
uint256 pt2zy
)
{
(pt2xx, pt2xy) = _FQ2Muc(pt1xx, pt1xy, 3); // 3 * x
(pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1xx, pt1xy); // W = 3 * x * x
(pt1zx, pt1zy) = _FQ2Mul(pt1yx, pt1yy, pt1zx, pt1zy); // S = y * z
(pt2yx, pt2yy) = _FQ2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // x * y
(pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // B = x * y * S
(pt1xx, pt1xy) = _FQ2Mul(pt2xx, pt2xy, pt2xx, pt2xy); // W * W
(pt2zx, pt2zy) = _FQ2Muc(pt2yx, pt2yy, 8); // 8 * B
(pt1xx, pt1xy) = _FQ2Sub(pt1xx, pt1xy, pt2zx, pt2zy); // H = W * W - 8 * B
(pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt1zx, pt1zy); // S_squared = S * S
(pt2yx, pt2yy) = _FQ2Muc(pt2yx, pt2yy, 4); // 4 * B
(pt2yx, pt2yy) = _FQ2Sub(pt2yx, pt2yy, pt1xx, pt1xy); // 4 * B - H
(pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt2xx, pt2xy); // W * (4 * B - H)
(pt2xx, pt2xy) = _FQ2Muc(pt1yx, pt1yy, 8); // 8 * y
(pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1yx, pt1yy); // 8 * y * y
(pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // 8 * y * y * S_squared
(pt2yx, pt2yy) = _FQ2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // newy = W * (4 * B - H) - 8 * y * y * S_squared
(pt2xx, pt2xy) = _FQ2Muc(pt1xx, pt1xy, 2); // 2 * H
(pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // newx = 2 * H * S
(pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // S * S_squared
(pt2zx, pt2zy) = _FQ2Muc(pt2zx, pt2zy, 8); // newz = 8 * S * S_squared
}

function _ECTwistMulJacobian(
uint256 d,
uint256 pt1xx,
uint256 pt1xy,
uint256 pt1yx,
uint256 pt1yy,
uint256 pt1zx,
uint256 pt1zy
) internal pure returns (uint256[6] memory pt2) {
while (d != 0) {
if ((d & 1) != 0) {
pt2 = _ECTwistAddJacobian(
pt2[PTXX],
pt2[PTXY],
pt2[PTYX],
pt2[PTYY],
pt2[PTZX],
pt2[PTZY],
pt1xx,
pt1xy,
pt1yx,
pt1yy,
pt1zx,
pt1zy
);
}
(pt1xx, pt1xy, pt1yx, pt1yy, pt1zx, pt1zy) =
_ECTwistDoubleJacobian(pt1xx, pt1xy, pt1yx, pt1yy, pt1zx, pt1zy);

d = d / 2;
}
}
}
9 changes: 9 additions & 0 deletions test/utils/MockAVSDeployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {BLSApkRegistryHarness} from "../harnesses/BLSApkRegistryHarness.sol";
import {EmptyContract} from "eigenlayer-contracts/src/test/mocks/EmptyContract.sol";

import {StakeRegistryHarness} from "../harnesses/StakeRegistryHarness.sol";
import {OperatorLib} from "../utils/OperatorLib.sol";

import "forge-std/Test.sol";

Expand Down Expand Up @@ -547,4 +548,12 @@ contract MockAVSDeployer is Test {
salt: salt
});
}

function _createOperators(uint256 numOperators, uint256 startIndex) internal returns (OperatorLib.Operator[] memory) {
OperatorLib.Operator[] memory operators = new OperatorLib.Operator[](numOperators);
for (uint256 i = 0; i < numOperators; i++) {
operators[i] = OperatorLib.createOperator(string(abi.encodePacked("operator-", i + startIndex)));
}
return operators;
}
}
Loading

0 comments on commit 04eb2db

Please sign in to comment.