Compare commits

...

2 Commits

Author SHA1 Message Date
28cf9d6de8
apply exodus/bip-340 and other fun stuff
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-09-09 15:27:38 +03:00
4327971456
all-weather Schnorr verifier with hybrid gas strategy (Spectre/Banshee paths)
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2026-09-09 15:26:11 +03:00
9 changed files with 509 additions and 174 deletions

View File

@ -10,6 +10,7 @@ import {StorageHistory} from "./types/StorageHistory.sol";
import {Weaver} from "./types/Weaver.sol";
import {FullMath} from "./libraries/FullMath.sol";
import {Verifier} from "./libraries/Verifier.sol";
import {Checkpoints} from "./libraries/Checkpoints.sol";
import {RotationPacking, RequestPacking, GovernancePacking} from "./libraries/Packing.sol";
import {ReentrancyGuard} from "@openzeppelin-contracts/utils/ReentrancyGuard.sol";
@ -22,7 +23,7 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
uint256 private constant BOUNTY_DIVISOR = type(uint32).max;
uint256 private constant SECP256K1_N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
uint256 private constant SECP256K1_Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
uint256 private constant SECP256K1_Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
uint256 private constant SHIFT_FACTOR = (2**128) % SECP256K1_N;
uint256 public constant GAS_RECALL_SPENDING = 329188;
@ -113,12 +114,14 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
function verify(
bytes calldata call,
bytes calldata nonce,
bytes32 s
) external nonReentrant payable returns (bytes memory) {
_verifySchnorrSignature(call, nonce, s);
uint256 rx,
uint256 s
) external nonReentrant returns (bytes memory) {
uint256 px = _extractPublicKey(call);
bool validSignature = Verifier.verifyGhost(call, px, rx, s);
if (!validSignature) revert BadSignature();
(bool success, bytes memory data) = address(this).call{ value: msg.value }(call);
(bool success, bytes memory data) = address(this).call(call);
if (!success) revert ExecutionReverted();
return data;
@ -138,7 +141,7 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
uint256 exodusSession,
uint256 amount,
uint256 packed
) external override payable {
) external override {
if (msg.sender != address(this)) revert NotGatekeeper();
RequestPacking.RequestPayload memory payload = RequestPacking.unpack(packed);
@ -173,8 +176,9 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
uint8 newParity
) external override {
if (msg.sender != address(this)) revert NotGatekeeper();
StorageHistory(storageHistory).trySetTransactionExecuted(exodusSession);
if (newParity % 2 != 0) revert InvalidPublicKey();
StorageHistory(storageHistory).trySetTransactionExecuted(exodusSession);
// forge-lint: disable-next-line(unsafe-typecast)
uint256 packedRotationState = RotationPacking.pack(newParity, uint64(exodusSession));
@ -202,85 +206,15 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
return data;
}
function _verifySchnorrSignature(bytes calldata call, bytes calldata nonce, bytes32 s) internal view {
(bytes32 px, uint8 p) = _extractPublicKey(call);
uint8 v = p == 0 ? 27 : 28;
bytes32 e = _challenge(call, nonce, px, p);
bytes32 sp = bytes32(SECP256K1_Q - mulmod(uint256(s), uint256(px), SECP256K1_Q));
bytes32 ep = bytes32(SECP256K1_Q - mulmod(uint256(e), uint256(px), SECP256K1_Q));
address recoveredR = ecrecover(sp, v, px, ep);
if (sp == 0) revert BadSignature();
if (recoveredR == address(0)) revert BadSignature();
if (recoveredR != _uncompressedPointToAddress(nonce)) revert BadSignature();
}
function _uncompressedPointToAddress(bytes calldata nonce) internal pure returns (address) {
if (nonce.length != 65) revert BadSignature();
if (nonce[0] != 0x04) revert BadSignature();
bytes32 rx = bytes32(nonce[1:33]);
bytes32 ry = bytes32(nonce[33:65]);
return address(uint160(uint256(keccak256(abi.encodePacked(rx, ry)))));
}
function _extractPublicKey(bytes calldata call) internal view returns (bytes32, uint8) {
function _extractPublicKey(bytes calldata call) internal view returns (uint256) {
if (call.length < 36) revert InvalidCalldata();
uint256 exodusSession;
assembly {
exodusSession := calldataload(add(call.offset, 4))
}
(bytes32 publicKey, uint8 parity,) = getRotationInfoAt(exodusSession);
(bytes32 publicKey,,) = getRotationInfoAt(exodusSession);
return (publicKey, parity);
}
function _challenge(
bytes calldata call,
bytes calldata r,
bytes32 pk,
uint8 v
) internal pure returns (bytes32) {
if (r.length != 65) revert BadSignature();
bytes32 rx = bytes32(r[1:33]);
bytes1 rv;
{
bytes32 ry = bytes32(r[33:65]);
uint8 rParityByte = (uint256(ry) & 1) == 0 ? 0x02 : 0x03;
rv = bytes1(rParityByte);
}
uint8 pv = v == 0 ? 0x02 : 0x03;
bytes memory message = abi.encodePacked(rv, rx, pv, pk, call);
bytes memory domain = "FROST-secp256k1-SHA256-v1chal";
uint8 dstlen = uint8(domain.length);
bytes32 b0 = sha256(abi.encodePacked(
bytes32(0),
bytes32(0),
message,
hex"0030",
uint8(0),
domain,
dstlen
));
bytes32 b1 = sha256(abi.encodePacked(b0, uint8(1), domain, dstlen));
bytes32 b2 = sha256(abi.encodePacked(b0 ^ b1, uint8(2), domain, dstlen));
uint256 high32 = uint256(b1);
uint256 lowPart = uint256(b2) >> 128;
uint256 highReduced = mulmod(high32, SHIFT_FACTOR, SECP256K1_N);
uint256 finalChallenge = addmod(highReduced, lowPart, SECP256K1_N);
return bytes32(finalChallenge);
return uint256(publicKey);
}
}

View File

@ -9,6 +9,7 @@ interface IGatekeeper {
error NotGatekeeper();
error AlreadyExecuted();
error InvalidCalldata();
error InvalidPublicKey();
error NonExistentAmount();
error InsufficientValue();
error ExecutionReverted();
@ -25,7 +26,7 @@ interface IGatekeeper {
function getRotationInfoAt(uint256 session) external view returns (bytes32, uint8, uint64);
function govern(uint256 session, uint256 payload, bytes calldata call) external returns (bytes calldata);
function recall(uint256 session, uint256 amount, uint256 payload) external payable;
function recall(uint256 session, uint256 amount, uint256 payload) external;
function rotate(uint256 session, bytes32 publicKey, uint8 parity) external;
function ghost(bytes32 receiver, uint256 amount) external returns (uint256);
function initialize(address previousAddress) external;

View File

@ -17,12 +17,30 @@ library Hashes {
}
}
function efficientKeccak256(bytes32 a, bytes32 b, bytes32 c) internal pure returns (bytes32 value) {
function efficientKeccak256(uint256 a, uint256 b) internal pure returns (bytes32 value) {
assembly ("memory-safe") {
mstore(0x00, a)
mstore(0x20, b)
mstore(0x40, c)
value := keccak256(0x00, 0x60)
value := keccak256(0x00, 0x40)
}
}
function efficientKeccak256Prefixed(bytes32 a) internal pure returns (bytes32 value) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore8(ptr, 0x00)
mstore(add(ptr, 0x01), a)
value := keccak256(ptr, 0x21)
}
}
function efficientKeccak256Prefixed(bytes32 a, bytes32 b) internal pure returns (bytes32 value) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore8(ptr, 0x01)
mstore(add(ptr, 0x01), a)
mstore(add(ptr, 0x21), b)
value := keccak256(ptr, 0x41)
}
}
}

380
src/libraries/Verifier.sol Normal file
View File

@ -0,0 +1,380 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Hashes} from "./Hashes.sol";
// https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
library Verifier {
// Constants: https://en.bitcoin.it/wiki/Secp256k1
uint256 internal constant N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
uint256 internal constant P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
uint256 internal constant GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;
uint256 internal constant GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;
uint256 internal constant EXP = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFF0C;
uint256 internal constant B = 7;
function verifyGhost(
bytes memory call,
uint256 px,
uint256 rx,
uint256 s
) internal view returns (bool) {
if (px >= P || rx >= P || s >= N || s == 0) { return false; }
if (rx < N) { return verifySpectre(call, px, rx, s); }
(uint256 py, bool success1) = liftPoint(px);
(uint256 ry, bool success2) = liftPoint(rx);
if (!success1 || !success2) { return false; }
return verifyBanshee(call, px, py, rx, ry, s);
}
function verifySpectre(
bytes memory call,
uint256 px,
uint256 rx,
uint256 s
) internal view returns (bool) {
uint256 e = computeChallenge(call, rx, px);
(address convertedR, bool success) = point2Address(rx);
if (!success) { return false; }
// Explanation: https://hackmd.io/@nZ-twauPRISEa6G9zg3XRw/SyjJzSLt9
bytes32 sp = bytes32(N - mulmod(s, px, N));
bytes32 ep = bytes32(N - mulmod(e, px, N));
// Parity should be always even
address recoveredR = ecrecover(sp, 27, bytes32(px), ep);
return recoveredR == convertedR;
}
function verifyBanshee(
bytes memory call,
uint256 px,
uint256 py,
uint256 rx,
uint256 ry,
uint256 s
) internal pure returns (bool) {
// TODO: because I lift it before, do I need to check is it on curve?
// both of them Px,Py and Rx,Ry
if (!isOnCurve(rx, ry) || !isOnCurve(px, py)) { return false; }
uint256 e = computeChallenge(call, rx, px);
if (e == 0) return false; // Cheap and safe
// s ⋅ G = R + hash(R || m) ⋅ Y
// R = s ⋅ G + hash(R || m) ⋅ Y
(uint256 x, uint256 y, uint256 z) = multiScalarMulAdd(GX, GY, s, px, py, N - e);
(x, y) = toAffine(x, y, z);
if (!isOnCurve(x, y)) return false;
return x == rx && y == ry;
}
function point2Address(uint256 rx) internal view returns (address, bool) {
(uint256 ry, bool success) = liftPoint(rx);
if (!success) { return (address(0), false); }
bytes32 encodedR = Hashes.efficientKeccak256(rx, ry);
address addressR = address(uint160(uint256(encodedR)));
return (addressR, true);
}
function liftPoint(uint256 x) internal view returns (uint256, bool) {
if (x >= P) { return (0, false); }
// y^2 = x^3 + 7 (mod P)
uint256 y2 = addmod(mulmod(x, mulmod(x, x, P), P), B, P);
y2 = expModPrecompile(y2);
uint256 y = (y2 & 1) == 0 ? y2 : P - y2; // BIP-340: point is always even
if (!isOnCurve(x, y)) { return (0, false); } // point does not exist on curve
return (y, true);
}
function expModPrecompile(uint256 base) internal view returns (uint256 result) {
uint256 localEXP = EXP;
uint256 localP = P;
assembly {
let pointer := mload(0x40)
mstore(pointer, 0x20)
mstore(add(pointer, 0x20), 0x20)
mstore(add(pointer, 0x40), 0x20)
mstore(add(pointer, 0x60), base)
mstore(add(pointer, 0x80), localEXP)
mstore(add(pointer, 0xa0), localP)
// Modular Exponentiation Precompile (modexp)
let success := staticcall(gas(), 0x05, pointer, 0xc0, pointer, 0x20)
if iszero(success) { revert(0, 0) }
result := mload(pointer)
}
}
function computeChallenge(bytes memory call, uint256 rx, uint256 px) internal pure returns (uint256) {
// Precomputed `sha256("BIP0340/challenge")`
bytes32 tag = 0x7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c;
return uint256(sha256(abi.encodePacked(tag, tag, rx, px, call))) % N;
}
function findMaxBitLength(uint256 k1, uint256 k2) internal pure returns (uint256 bits) {
assembly {
// Find maximum of the three scalars
let max := k1
if gt(k2, max) { max := k2 }
// if (v >> 128 != 0) { v >>= 128; bits += 128; }
if gt(max, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
max := shr(128, max)
bits := 128
}
// if (v >> 64 != 0) { v >>= 64; bits += 64; }
if gt(max, 0xFFFFFFFFFFFFFFFF) {
max := shr(64, max)
bits := add(bits, 64)
}
// if (v >> 32 != 0) { v >>= 32; bits += 32; }
if gt(max, 0xFFFFFFFF) {
max := shr(32, max)
bits := add(bits, 32)
}
// if (v >> 16 != 0) { v >>= 16; bits += 16; }
if gt(max, 0xFFFF) {
max := shr(16, max)
bits := add(bits, 16)
}
// if (v >> 8 != 0) { v >>= 8; bits += 8; }
if gt(max, 0xFF) {
max := shr(8, max)
bits := add(bits, 8)
}
// if (v >> 4 != 0) { v >>= 4; bits += 4; }
if gt(max, 0xF) {
max := shr(4, max)
bits := add(bits, 4)
}
// if (v >> 2 != 0) { v >>= 2; bits += 2; }
if gt(max, 0x3) {
max := shr(2, max)
bits := add(bits, 2)
}
// if (v >> 1 != 0) { /* v >>= 1; */ bits += 1; }
if gt(max, 0x1) {
bits := add(bits, 1)
}
bits := add(bits, 1)
}
}
function toAffine(uint256 x, uint256 y, uint256 z) internal pure returns (uint256, uint256) {
if (z == 0) return (0, 0); // Identity point
uint256 t0;
assembly {
// Extended Euclidean algorithm (iterative, assembly)
// Typically lower average gas than the modexp precompile for single inversions,
// but execution time (and gas) depends on input values — not constant-time.
let t1 := 1
let r0 := P
let r1 := z
for {} r1 {} {
let q := div(r0, r1)
// t0, t1 = t1, t0 - q * t1
let t1_new := sub(t0, mul(q, t1))
t0 := t1
t1 := t1_new
// r0, r1 = r1, r0 - q * r1
let r1_new := sub(r0, mul(q, r1))
r0 := r1
r1 := r1_new
}
if slt(t0, 0) {
t0 := add(t0, P)
}
}
return (mulmod(x, t0, P), mulmod(y, t0, P));
}
function isOnCurve(uint256 x, uint256 y) internal pure returns (bool) {
if (x >= P || y >= P) return false;
if (x == 0 && y == 0) return false; // Identity point
uint lhs = mulmod(y, y, P); // y^2
uint rhs = mulmod(mulmod(x, x, P), x, P); // x^3
rhs = addmod(rhs, B, P); // x^3 + 7
return lhs == rhs;
}
function multiScalarMulAdd(
uint256 x1, uint256 y1, uint256 k1,
uint256 x2, uint256 y2, uint256 k2
) internal pure returns (uint256 x3, uint256 y3, uint256 z3) {
// Implementation of the Straus-Shamir trick described in
// Trading Inversions for Multiplications in Elliptic Curve Cryptography.
// (https://eprint.iacr.org/2003/257.pdf Page 7).
uint256 bits = findMaxBitLength(k1, k2);
uint256[4] memory precomputedXs;
uint256[4] memory precomputedYs;
uint256[4] memory precomputedZs;
precomputedXs[1] = x2; precomputedYs[1] = y2; precomputedZs[1] = 1; // 01: P2
precomputedXs[2] = x1; precomputedYs[2] = y1; precomputedZs[2] = 1; // 10: P1
(precomputedXs[3], precomputedYs[3], precomputedZs[3]) = projectiveAdd(x1, y1, 1, x2, y2, 1); // 11: P1+P2
y3 = 1;
for (; bits > 0;) {
unchecked { --bits; }
(x3, y3, z3) = projectiveDouble(x3, y3, z3);
uint8 mask;
assembly {
mask := or(
shl(1, and(shr(bits, k1), 1)),
and(shr(bits, k2), 1)
)
}
if (mask == 0) { continue; }
if (mask == 3) {
(x3, y3, z3) = projectiveAdd(
x3, y3, z3, precomputedXs[mask], precomputedYs[mask], precomputedZs[mask]
);
} else {
(x3, y3, z3) = projectiveAddMixed(
x3, y3, z3, precomputedXs[mask], precomputedYs[mask]
);
}
}
}
function projectiveDouble(
uint256 x,
uint256 y,
uint256 z
) internal pure returns (uint256 x3, uint256 y3, uint256 z3) {
// Implementation of the complete addition formula from Renes-Costello-Batina 2015
// (https://eprint.iacr.org/2015/1060 Algorithm 9).
// X3 = 2XY (Y^2 − 9bZ^2), (ok)
// Y3 = (Y^2 − 9bZ^2)(Y^2 + 3bZ^2) + 24bY^2Z^2,
// Z3 = 8Y^3Z
assembly {
let t0 := mulmod(y, y, P) // t0 = y²
z3 := mulmod(8, t0, P) // z3 = 8y²
let t1 := mulmod(y, z, P) // t1 = y·z
let t2 := mulmod(z, z, P) // t2 = z²
t2 := mulmod(21, t2, P) // t2 = 3b·z² (b=7 → 3b=21)
x3 := mulmod(t2, z3, P) // x3 = (3b·z²)(8y²) = 24b·y²·z²
y3 := addmod(t0, t2, P) // y3 = y² + 3b·z²
z3 := mulmod(t1, z3, P) // z3 = (y·z)(8y²) = 8y³·z
t1 := addmod(t0, sub(P, mulmod(3, t2, P)), P) // t1 = y² − 9b·z²
y3 := addmod(x3, mulmod(t1, y3, P), P) // y3 = 24b·y²·z² + (y²−9b·z²)(y²+3b·z²)
x3 := mulmod(t1, mulmod(x, y, P), P) // x3 = (y²−9b·z²)·x·y
x3 := addmod(x3, x3, P) // x3 = 2xy·(y²−9b·z²)
}
}
function projectiveAdd(
uint256 x1, uint256 y1, uint256 z1,
uint256 x2, uint256 y2,uint256 z2
) internal pure returns (uint256 x3, uint256 y3, uint256 z3) {
// Implementation of the complete addition formula from Renes-Costello-Batina 2015
// (https://eprint.iacr.org/2015/1060 Algorithm 7).
// X3 = (X1Y2 + X2Y1)(Y1Y2 − 3bZ1Z2) − 3b(Y1Z2 + Y2Z1)(X1Z2 + X2Z1),
// Y3 = (Y1Y2 + 3bZ1Z2)(Y1Y2 − 3bZ1Z2) + 9bX1X2(X1Z2 + X2Z1),
// Z3 = (Y1Z2 + Y2Z1)(Y1Y2 + 3bZ1Z2) + 3X1X2(X1Y2 + X2Y1),
assembly {
let t0 := mulmod(x1, x2, P) // 1. t0 ← X1 · X2 => (X1·X2)
let t1 := mulmod(y1, y2, P) // 2. t1 ← Y1 · Y2 => (Y1·Y2)
let t2 := mulmod(z1, z2, P) // 3. t2 ← Z1 · Z2 => (Z1·Z2)
let t3 := addmod(x1, y1, P) // 4. t3 ← X1 + Y1 => (X1 + Y1)
let t4 := addmod(x2, y2, P) // 5. t4 ← X2 + Y2 => (X2 + Y2)
t3 := mulmod(t3, t4, P) // 6. t3 ← t3 · t4 => ((X1 + Y1) · (X2 + Y2))
t4 := addmod(t0, t1, P) // 7. t4 ← t0 + t1 => (X1·X2 + Y1·Y2)
t3 := addmod(t3, sub(P, t4), P) // 8. t3 ← t3 - t4 => ((X1 + Y1)·(X2 + Y2) - X1·X2 - Y1·Y2)
t4 := addmod(y1, z1, P) // 9. t4 ← Y1 + Z1 => (Y1 + Z1)
x3 := addmod(y2, z2, P) // 10. X3 ← Y2 + Z2 => (Y2 + Z2)
t4 := mulmod(t4, x3, P) // 11. t4 ← t4 · X3 => ((Y1 + Z1) · (Y2 + Z2))
x3 := addmod(t1, t2, P) // 12. X3 ← t1 + t2 => (Y1·Y2 + Z1·Z2)
t4 := addmod(t4, sub(P, x3), P) // 13. t4 ← t4 - X3 => ((Y1 + Z1)·(Y2 + Z2) - Y1·Y2 - Z1·Z2)
x3 := addmod(x1, z1, P) // 14. X3 ← X1 + Z1 => (X1 + Z1)
y3 := addmod(x2, z2, P) // 15. Y3 ← X2 + Z2 => (X2 + Z2)
x3 := mulmod(x3, y3, P) // 16. X3 ← X3 · Y3 => ((X1 + Z1) · (X2 + Z2))
y3 := addmod(t0, t2, P) // 17. Y3 ← t0 + t2 => (X1·X2 + Z1·Z2)
y3 := addmod(x3, sub(P, y3), P) // 18. Y3 ← X3 - Y3 => ((X1 + Z1)·(X2 + Z2) - X1·X2 - Z1·Z2)
x3 := addmod(t0, t0, P) // 19. X3 ← t0 + t0 => (2·X1·X2)
t0 := addmod(x3, t0, P) // 20. t0 ← X3 + t0 => (3·X1·X2)
t2 := mulmod(21, t2, P) // 21. t2 ← B3 · t2 => 3b · Z1·Z2
z3 := addmod(t1, t2, P) // 22. Z3 ← t1 + t2 => Y1·Y2 + 3·b·Z1·Z2
t1 := addmod(t1, sub(P, t2), P) // 23. t1 ← t1 - t2 => Y1·Y2 - 3·b·Z1·Z2
y3 := mulmod(21, y3, P) // 24. Y3 ← B3 · Y3 => 3b · ((X1+Z1)(X2+Z2) - X1·X2 - Z1·Z2)
x3 := mulmod(t4, y3, P) // 25. X3 ← t4 · Y3 => 3b·((Y1+Z1)(Y2+Z2)-Y1·Y2-Z1·Z2) · ((X1+Z1)(X2+Z2)-X1·X2-Z1·Z2)
t2 := mulmod(t3, t1, P) // 26. t2 ← t3 · t1 => ((X1+Y1)(X2+Y2)-X1·X2-Y1·Y2) · (Y1·Y2 - 3·b·Z1·Z2)
x3 := addmod(t2, sub(P, x3), P) // 27. X3 ← t2 - X3 => (X1Y2+X2Y1)(Y1·Y2-3·b·Z1·Z2) - 3b(Y1·Z2+Y2·Z1)(X1·Z2+X2·Z1)
y3 := mulmod(y3, t0, P) // 28. Y3 ← Y3 · t0 => 3·b·((X1+Z1)(X2+Z2) - X1·X2 - Z1·Z2) · 3·X1·X2 = 9·b·X1·X2·(X1·Z2+X2·Z1)
t1 := mulmod(t1, z3, P) // 29. t1 ← t1 · Z3 => (Y1·Y2-3·b·Z1·Z2) · (Y1·Y2+3·b·Z1·Z2)
y3 := addmod(t1, y3, P) // 30. Y3 ← t1 + Y3 => (Y1Y2+3·b·Z1·Z2)(Y1·Y2-3·b·Z1·Z2) + 9b·X1·X2·(X1·Z2+X2·Z1)
t0 := mulmod(t0, t3, P) // 31. t0 ← t0 · t3 => (3·X1·X2) · ((X1+Y1)(X2+Y2)-X1·X2-Y1·Y2)
z3 := mulmod(z3, t4, P) // 32. Z3 ← Z3 · t4 => (Y1·Y2+3·b·Z1·Z2) · ((Y1+Z1)(Y2+Z2)-Y1·Y2-Z1·Z2)
z3 := addmod(z3, t0, P) // 33. Z3 ← Z3 + t0 => (Y1·Z2+Y2·Z1)·(Y1·Y2+3·b·Z1·Z2) + 3·X1·X2·(X1·Y2+X2·Y1)
}
}
function projectiveAddMixed(
uint256 x1, uint256 y1, uint256 z1,
uint256 x2, uint256 y2
) internal pure returns (uint256 x3, uint256 y3, uint256 z3) {
// Implementation of the complete addition formula from Renes-Costello-Batina 2015
// (https://eprint.iacr.org/2015/1060 Algorithm 8).
// X3 = (X1Y2 + X2Y1)(Y1Y2 − 3bZ1) − 3b(Y1 + Y2Z1)(X1 + X2Z1),
// Y3 = (Y1Y2 + 3bZ1)(Y1Y2 − 3bZ1) + 9bX1X2(X1 + X2Z1),
// Z3 = (Y1 + Y2Z1)(Y1Y2 + 3bZ1) + 3X1X2(X1Y2 + X2Y1),
assembly {
let t0 := mulmod(x1, x2, P) // 1. t0 ← X1 · X2 => (X1·X2)
let t1 := mulmod(y1, y2, P) // 2. t1 ← Y1 · Y2 => (Y1·Y2)
let t3 := mulmod(x2, y1, P) // 3. t3 ← X2 + Y2 => (X2·Y1)
let t4 := mulmod(x1, y2, P) // 4. t4 ← X1 + Y1 => (X1·Y2)
t3 := addmod(t3, t4, P) // 5. t3 ← t3 − t4 => (X2·Y1 + X1·Y2)
t4 := mulmod(y2, z1, P) // 6. t4 ← Y2 · Z1 => (Y2·Z1)
t4 := addmod(t4, y1, P) // 7. t4 ← t4 + Y1 => (Y2·Z1 + Y1)
y3 := mulmod(x2, z1, P) // 8. Y3 ← X2 · Z1 => (X2·Z1)
y3 := addmod(y3, x1, P) // 9. Y3 ← Y3 + X1 => (X2·Z1 + X1)
t0 := mulmod(3, t0, P) // 10. t0 ← X3 + t0 => (3·(X1·X2))
let t2 := mulmod(21, z1, P) // 11. t2 ← b3 · Z1 => (b3·Z1)
z3 := addmod(t1, t2, P) // 12. Z3 ← t1 + t2 => (Y1·Y2 + b·3·Z1)
t1 := addmod(t1, sub(P, t2), P) // 13. t1 ← t1 − t2 => (Y1·Y2 - b·3·Z1)
y3 := mulmod(21, y3, P) // 14. Y3 ← b3 · Y3 => 3·b·(X2·Z1 + X1)
x3 := mulmod(t4, y3, P) // 15. X3 ← t4 · Y3 => (Y2·Z1 + Y1)·b·3·(X2·Z1 + X1)
t2 := mulmod(t3, t1, P) // 16. t2 ← t3 · t1 => ((X2·Y1 + X1·Y2)·(Y1·Y2 - b3·Z1))
x3 := addmod(t2, sub(P, x3), P) // 17. X3 ← t2 − X3 => ((X2·Y1 + X1·Y2)·(Y1·Y2 - b3·Z1) - 3·B·(Y2·Z1 + Y1)·(X2·Z1 + X1))
y3 := mulmod(y3, t0, P) // 18. Y3 ← Y3 · t0 => (9·b·(X2·Z1 + X1)·X1·X2)
t1 := mulmod(t1, z3, P) // 19. t1 ← t1 · Z3 => (Y1·Y2 - b·3·Z1)·(Y1·Y2 + b·3·Z1)
y3 := addmod(t1, y3, P) // 20. Y3 ← t1 + Y3 => ((Y1·Y2 - b·3·Z1)·(Y1·Y2 + 3·b·Z1) + 9·b·(X2·Z1 + X1)·X1·X2)
t0 := mulmod(t0, t3, P) // 21. t0 ← t0 · t3 => (3·X2·Y1 + (X2·Y1 + X1·Y2))
z3 := mulmod(z3, t4, P) // 22. Z3 ← Z3 · t4 => (Y1·Y2 + b·3·Z1)·(Y2·Z1 + Y1)
z3 := addmod(z3, t0, P) // 23. Z3 ← Z3 + t0 => ((Y1·Y2 + b·3·Z1)·(Y2·Z1 + Y1) + 3·X2·Y1·(X2·Y1 + X1·Y2))
}
}
}

View File

@ -7,7 +7,6 @@ contract WeaverMock is Weaver {
address private _previousAddress;
constructor(address previousWeaver) {
Weaver._initialize(previousWeaver);
_previousAddress = previousWeaver;
}

View File

@ -61,10 +61,10 @@ abstract contract Weaver is IWeaver {
bytes32 left = bytes32(_treeNodes[session][j].upperLookup(atBlock));
bytes32 right = bytes32(_treeNodes[session][j | 1].upperLookup(atBlock));
bytes32 leftHash = Hashes.efficientKeccak256(left);
bytes32 rightHash = Hashes.efficientKeccak256(right);
bytes32 leftHash = Hashes.efficientKeccak256Prefixed(left);
bytes32 rightHash = Hashes.efficientKeccak256Prefixed(right);
currentLevel[i] = Hashes.efficientKeccak256(leftHash, rightHash);
currentLevel[i] = Hashes.efficientKeccak256Prefixed(leftHash, rightHash);
unchecked { ++i; }
}
@ -73,10 +73,10 @@ abstract contract Weaver is IWeaver {
i = 0;
for (; i < currentLevelCount;) {
uint256 j = i << 1;
bytes32 left = currentLevel[j];
bytes32 right = currentLevel[j | 1];
bytes32 leftHash = currentLevel[j];
bytes32 rightHash = currentLevel[j | 1];
currentLevel[i] = Hashes.efficientKeccak256(left, right);
currentLevel[i] = Hashes.efficientKeccak256Prefixed(leftHash, rightHash);
unchecked { ++i; }
}
}
@ -106,7 +106,7 @@ abstract contract Weaver is IWeaver {
for (; i < currentLevelCount;) {
bytes32 leaf = bytes32(_treeNodes[session][i].upperLookup(atBlock));
currentLevel[i] = Hashes.efficientKeccak256(leaf);
currentLevel[i] = Hashes.efficientKeccak256Prefixed(leaf);
unchecked { ++i; }
}
@ -123,7 +123,7 @@ abstract contract Weaver is IWeaver {
bytes32 left = currentLevel[j];
bytes32 right = currentLevel[j | 1];
currentLevel[i] = Hashes.efficientKeccak256(left, right);
currentLevel[i] = Hashes.efficientKeccak256Prefixed(left, right);
unchecked { ++i; }
}

View File

@ -4,6 +4,7 @@ import {Test} from "forge-std/Test.sol";
import {Gatekeeper} from "../../src/Gatekeeper.sol";
import {FullMath} from "../../src/libraries/FullMath.sol";
import {Verifier} from "../../src/libraries/Verifier.sol";
import {RequestPacking} from "../../src/libraries/Packing.sol";
import {IStorageHistory} from "../../src/interfaces/IStorageHistory.sol";
import {StorageHistory} from "../../src/types/StorageHistory.sol";
@ -159,13 +160,9 @@ contract MockStaking is Test {
uint256 amount,
uint256 packed,
address caller
) external payable {
if (msg.value > 0) {
vm.deal(address(gatekeeper), address(gatekeeper).balance + msg.value);
}
) external {
vm.prank(address(gatekeeper), caller);
gatekeeper.recall{value: msg.value}(exodusSession, amount, packed);
gatekeeper.recall(exodusSession, amount, packed);
}
function recall(address receiver, uint256 amount) external {
@ -273,10 +270,22 @@ contract GatekeeperTest is Test {
assert(IStorageHistory(storageHistory).isTransactionExecuted(exodusSession));
}
function test_rotateWork(bytes32 aggregatedPublicKey) public {
function test_rotateWork() public {
vm.warp(block.timestamp + 1);
vm.prank(address(gatekeeper));
gatekeeper.rotate(block.timestamp, aggregatedPublicKey, 0);
gatekeeper.rotate(block.timestamp, 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0);
vm.warp(block.timestamp + 1);
vm.prank(address(gatekeeper));
gatekeeper.rotate(block.timestamp, 0xF9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9, 0);
vm.warp(block.timestamp + 1);
vm.prank(address(gatekeeper));
gatekeeper.rotate(block.timestamp, 0x3590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66, 0);
vm.warp(block.timestamp + 1);
vm.prank(address(gatekeeper));
gatekeeper.rotate(block.timestamp, 0xD4E0D4642DB1613B2C94A81FCD34E39A2A31ACD774CD42525A88CF69EBA2E611, 0);
}
function test_couldNotBridgeBelowExistential(uint256 amount) public {
@ -297,16 +306,16 @@ contract GatekeeperTest is Test {
staking.runGhost(bytes32(abi.encodePacked(ALICE)), type(uint104).max);
vm.prank(ALICE);
gatekeeper.updatePublicKeyMetadata(0, 0x875cdcba4ae5494518fa2602791e667ca0998402b6a69e5b7cb4c72dba4e4669, 0);
gatekeeper.updatePublicKeyMetadata(0, 0x36ff5b7f0fc50100b563c6072e499980d6e6aa8528ea0ae6d776cf7e8e96c374, 0);
(bytes32 prevPublicKey, uint8 prevParity,) = gatekeeper.latestPublicKeyInfo();
// genesis validators 4 validators, DKG #0
// exodus session #0
gatekeeper.verify(
hex"49f03a670000000000000000000000000000000000000000000000000000000000000000875cdcba4ae5494518fa2602791e667ca0998402b6a69e5b7cb4c72dba4e46690000000000000000000000000000000000000000000000000000000000000000",
hex"044d9fa18df9da04381ed256981570a6ef6a0893496ded966fc994662df931ed423b29e2737394b31d8498594caad7b77e36ab31ac79df3796a1b6f26baa5552ae",
0x24029a571fcaeadd14f4afe8be62afe3d07876ae270c3caf446ecb6cfc7c08f2
hex"49f03a67000000000000000000000000000000000000000000000000000000000000000036ff5b7f0fc50100b563c6072e499980d6e6aa8528ea0ae6d776cf7e8e96c3740000000000000000000000000000000000000000000000000000000000000000",
0x58a4ef4e4f9cad19e9bb3707a48f01920ba309f69892609b196bbc112b6aebea,
0x2de1a8116c65a290c51fee3bac24546c09522423640ae0e38f45791b1d81a069
);
(bytes32 publicKey, uint8 parity, uint64 session) = gatekeeper.latestPublicKeyInfo();
@ -317,17 +326,17 @@ contract GatekeeperTest is Test {
// could not apply signature from DKG #2
vm.expectRevert();
gatekeeper.verify(
hex"49f03a6700000000000000000000000000000000000000000000000000000000000000133492bc8bb10848f1f788496ccadde7d458eac4ac2c1eca2dd2c7a506d8fa2c5b0000000000000000000000000000000000000000000000000000000000000000",
hex"0434c3b37293516c6204dc291821e19ab5b3d8afb0947a0a2dffc91600fbd3f6b9783a66887d515e774b98a63a35a08bb3d914407fd768e92020b0ebaa3c8602b3",
0x71cd57e697af70f84a960cc94fcbae5889efbf919df410282a04c6d19f92609e
hex"49f03a6700000000000000000000000000000000000000000000000000000000000000135353a4ce3430b37cabb7c495aabfec94895183672738873f4b227bf4ce31fbe50000000000000000000000000000000000000000000000000000000000000000",
0xd1e4b50b4ff3e9b98ce17b375d6007cf0cf9d65e795cbe682609c1343361a81c,
0x0cdd6c13658d862e7f816c59ad9cb1b6f5b3b981f019e698f27d1a354dc69cd5
);
// genesis validators 7 validators, DKG #1
// exodus session #11
gatekeeper.verify(
hex"49f03a67000000000000000000000000000000000000000000000000000000000000000b4e8c1fe96d6737cdabbcc96501d6656b9d0b659b3a528ef507f2d52bef29e1570000000000000000000000000000000000000000000000000000000000000000",
hex"04b51db09ec2f4bebdb65c5352efa75f8d07088408e3ff907c74b0d7928a40dbe06f864364a3e6d219849ca8e7d47e6c66f8a18ca9f4fa4752df13bb6c2eae1172",
0x072e625bdd3ff7d09f2bf896b5e261efa007f8d81a9e2c828525ec74bd3ee08d
hex"49f03a67000000000000000000000000000000000000000000000000000000000000000bb5cd0d028a5e1b6a4eecb113b7e49c8176385eb77c8f134bc1db4bddd7654de60000000000000000000000000000000000000000000000000000000000000000",
0x993fc0c870e1010f4933cbdb17b4539aea07234ff787eb3185d03ef8c0d2787e,
0x4bfe369753a3125a37d13db08ea9125fe2280b70aa47e5890bf9401c785bdb92
);
(publicKey, parity, session) = gatekeeper.latestPublicKeyInfo();
@ -341,9 +350,9 @@ contract GatekeeperTest is Test {
// genesis validators 5 validators, DKG #2
// exodus session #19
gatekeeper.verify(
hex"49f03a6700000000000000000000000000000000000000000000000000000000000000133492bc8bb10848f1f788496ccadde7d458eac4ac2c1eca2dd2c7a506d8fa2c5b0000000000000000000000000000000000000000000000000000000000000000",
hex"0434c3b37293516c6204dc291821e19ab5b3d8afb0947a0a2dffc91600fbd3f6b9783a66887d515e774b98a63a35a08bb3d914407fd768e92020b0ebaa3c8602b3",
0x71cd57e697af70f84a960cc94fcbae5889efbf919df410282a04c6d19f92609e
hex"49f03a6700000000000000000000000000000000000000000000000000000000000000135353a4ce3430b37cabb7c495aabfec94895183672738873f4b227bf4ce31fbe50000000000000000000000000000000000000000000000000000000000000000",
0xd1e4b50b4ff3e9b98ce17b375d6007cf0cf9d65e795cbe682609c1343361a81c,
0x0cdd6c13658d862e7f816c59ad9cb1b6f5b3b981f019e698f27d1a354dc69cd5
);
(publicKey, parity, session) = gatekeeper.latestPublicKeyInfo();
@ -351,23 +360,22 @@ contract GatekeeperTest is Test {
assertEq(parity, prevParity);
assertEq(session, 19);
uint256 aliceAmountBefore = staking.recalledAmount(ALICE);
uint256 bobAmountBefore = staking.recalledAmount(BOB);
uint256 aliceBalanceBefore = ALICE.balance;
uint256 bobBalanceBefore = BOB.balance;
// execute bridge out, happened on DKG #0
// amount: 69; commission: 0%; ALICE
// execute bridge out, happened on DKG #1
// amount: 34; commission: 0%; ALICE
// exodus session #1
vm.prank(ALICE, ALICE);
gatekeeper.verify(
hex"bf06188a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000010000000000007a6900000000",
hex"04bccb4cd4633e2c61ca5c65006a6a09baa893be219b21509866123a8d6299f92aefe9c380bd9728dbe0b93a8042f431636d08ed191b5c04062bf14e1347059cb9",
0xe579753d931a78b143d7e3d86e1117ccbc9d2d7357b0207ea682046a0b06d798
hex"bf06188a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000010000000000007a6900000000",
0x74e1ee0256e3a1f6c38744fff8d72ffb905d660679e69c76b0af2e75db9fbfcc,
0x4c512ab429d8c38a199daaa7f2c3d74956d2ff435871b160946b69804a1e5d54
);
assertEq(aliceAmountBefore + 69, staking.recalledAmount(ALICE));
assertEq(aliceAmountBefore + 34, staking.recalledAmount(ALICE));
assertEq(bobAmountBefore, staking.recalledAmount(BOB));
assertEq(aliceBalanceBefore, ALICE.balance);
assertEq(bobBalanceBefore, BOB.balance);
@ -379,139 +387,138 @@ contract GatekeeperTest is Test {
aliceBalanceBefore = ALICE.balance;
bobBalanceBefore = BOB.balance;
uint256 buyback = 220;
// execute bridge out, happened on DKG #1
// amount: 420; commission: 50%; BOB
// TODO: revisit
// execute bridge out, happened on DKG #2
// amount: 210; commission: 50%; BOB
// exodus session #12
vm.prank(ALICE, ALICE);
gatekeeper.verify{value: buyback}(
hex"bf06188a000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000020000000000007a6980000000",
hex"049f458500a78f56420380f0c6863905f1181e705f6b562eb469bd81a03676a2d9b436a53d2356ea0a5bb175ca837655fab8114c6e64cfdd47f3d36d1a945d7122",
0x772731b359ee7ecac7830438333e4ffb61759b36610f69cef20f66f7a79a405f
gatekeeper.verify(
hex"bf06188a000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000d200000000000000000000000000000000000000020000000000007a6980000000",
0x99c5f02bf312fc6b1a125b83397aa87df369738f85275bc42d249660abb1f0e1,
0x8326ee3fc1cbb1421e2c974d6cc7cb2bfdc9c4f6ebfd403363f6b3a3bc8e9bef
);
assertApproxEqAbs(aliceAmountBefore + 210, staking.recalledAmount(ALICE), 1);
assertApproxEqAbs(bobAmountBefore + 210, staking.recalledAmount(BOB), 1);
assertApproxEqAbs(aliceAmountBefore + 105, staking.recalledAmount(ALICE), 1);
assertApproxEqAbs(bobAmountBefore + 105, staking.recalledAmount(BOB), 1);
// execute setDistributor, exodusSession: 2
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000020000000000007a690101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002475619ab5000000000000000000000000010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000",
hex"049f222e7ec776c390c7fe96b9c2034c37f4fc71a9714588a5d98ccb50dc748c98fe375c628e7bcc4db4f204a2a168b22ecbc631616a69987ef42601ad239b2ab5",
0x515539c5b713900a4dd4b3b119b22a47f862c90fdff9da91ed3fca687ea8db06
0x45a9889cb48e0eca44c3add96dc68d6ab728c1a7e4eab14323f0dcfe67472c1f,
0x40e6980e96efc0fc6acf47aa0cd665bc5d85a01b909fc4d960948c76f45723b4
);
// execute setWarmupPeriod, exodusSession: 3
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000030000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000024a85667c5000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000",
hex"04c2d9b903c0bd640ff858de3518c64965e2ff07215a131c85a8febec629999cfd60970a3a99d0d04ba08a334f2aa865842ebde37407c6fee2b17f820c8104fc88",
0xe1727e132cbb7502a60bab56c5dedce1abca8130792ddd6d9ba59918766688e8
0x356ef46cfd654b0b609bdff33147df25c20ff9ca7ac3334c57f12e99b6248112,
0xa6363286f97c02a39aa5280d74f8dc02dabd078911eef60e4848b7d5deeb325b
);
// execute setBounty, exodusSession: 4
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000040000000000007a69010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000245d87d363000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000",
hex"04ec7d454696833a1c9c04d79be81e0dfe8a4791862f1dc5d4e908338df30621911fb182e6f204699c53ea5b11db1c855f55dfd149d4882a80afa437d80c58d9cd",
0x22d3138ed4e72f104c5d86814c1b4e6eeed39cdcf97e087effe33f860d06f133
0xe6a419a5314afed1ff25df0cbf76f2002bfa9d7746817670f2487be5d7774118,
0x7ce4c7207efdfdb9c71b26c7dd071572544fb27a329b348379d70b2e7a5f21fc
);
// execute setAdjustment, exodusSession: 5
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000050000000000007a690101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006446d36ab5000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000",
hex"0484819be6cb8879179f91aaf94c1513234d9068052dd42bf067606033c2d173efe85e87acf5bc1020cab6ec67d5ec8f7b237c5f315b825b56e915e4736c2b7b62",
0x865b1e9006973e8b5b5492f2f6a0c85ee69ee7ae72f714ee076035865cd26a72
0x649a51e565d154f549e24aaf400ed9a2bb8812ed87eeac36372f36ac8cd6aa34,
0xc9decb2fa41d9217f9a609d568f86bf92b66d6a91ed3c34031025d3845e34b09
);
// execute updateGatekeeperAddress, exodusSession: 6
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000060000000000007a690101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002484f157cd000000000000000000000000010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000",
hex"040bfec065e85cb245d891a94b50b12ea8f91d27a90e113c0bf47f93e76c0c21380e6ff8dc05406d1e8ec34b2c90cc345fea1245c1ca3eb7ecccd8606bfb334f76",
0x15141679af9a42a9228adc686f802fe183515180bed3de3933e1622668e06796
0xb445285e36eb120a47bd995ce7ecc07f73bf1ec99b5024ef14e87aa1bffd8b39,
0x8f7241cd388505b0f964dd54243c968559ba603400ee71dea0738a9084f5cf50
);
// execute addPool, exodusSession: 7
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000070000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000024d914cd4b000000000000000000000000010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000",
hex"04eb497652f4ad64ddd9223cd1af4785b37c6b2a41f8c1f54b906d595ab0d2b53305cd006238ca4eaf7eede77b3e2c0d1019e9f9d505fe80e86240e0d83051dcf2",
0xa93dcb9c9c399973a17abc3b3667e37da716bdd5e9ed9c0b99d9fc869a886700
0x83cdbf2cee6f13d60c2261feed4d0643e847cfba6af316722538281c9cb433c8,
0xdd0c8c1d6d154c951a4171ff9a40084afbfe5f7b3c70c0521e5b6605310e77cb
);
// execute removePool, exodusSession: 8
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000080000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000024a38dcbd0000000000000000000000000000000000000000000000000000000000000053900000000000000000000000000000000000000000000000000000000",
hex"0446039e3eec08f356c0a6e9fdd243aed6d840c1d9d973d1496db70499061055d45faf8e945d2fb87016cdcfda040df8fcaf22fe9a466dbdd4687cbfde7c87d0d8",
0x110eedf82f6533d95a43a19de3da026c51557e552bd4c5b6f06ca94d6ab2c8db
0x622a8a5d57b10682a90e1b92f797375a6bcbb78f30c45877ea570091af1b2831,
0xd72cd8354a7be788b801e19994a8155f3938ef58005095b398bc96cd2dc77166
);
// execute close, exodusSession: 9
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000090000000000007a69010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000240aebeb4e00000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000",
hex"048da83909e645cf4313d00985c86bcbd24f584512f2279476767fb94829a2a9c7b95bcfeacc3bee2fe4710bfc2bcf2e72e58bcd37fc02293b660a7b70e2efd184",
0x8a28d3b7b5db6564e4abb846bc662a69d9b52ed08bd2ce2dbc6af4e86167f55e
0x0ad9c560affebaea5c589fe831033bac2d9c828aacf58559bbf5b2d00f7842b2,
0x10121ffe0cc95cf3cbb4e92d72d61feec3e94045185cd7f3c5ce0d01e3a644ea
);
// execute close, exodusSession: 10
vm.prank(ALICE);
gatekeeper.verify(
hex"31371426000000000000000000000000000000000000000000000000000000000000000a0000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000144a0139f41000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000053900000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000005390000000000000000000000000101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000",
hex"0417bd8b7509486284c1f613117c61abc39cee8a24422fce457099e430b805468be33547f272d8123e9aa6f8895babbaa3a3731eaeda7d8ad4286c9fb117034d21",
0x0b71c4d8ca7748ec35257a42f26e09aaab9fa4a03e40d50a96bfdfdce10ce7e5
0xb354049d0012ef7ec3edac6aba453daf4bdc2d28fe1d88138f94459799e2343f,
0x13a6f8b10007b41fa08c8efee85501fac2554571af99fe587b534fe28fdb82a3
);
// execute enable, exodusSession: 13
vm.prank(ALICE);
gatekeeper.verify(
hex"31371426000000000000000000000000000000000000000000000000000000000000000d0000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000064e4e33ef800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000101010101010101010101010101010101010101000000000000000000000000010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000",
hex"04f34417b947a4da097ca9596838430bf40587339fb42a09210ceb0dbbcfd98a99b1e8fd8f4d2301ee5b5d304e1d8b8e8b81ac14688f1e7de41d65c09a65975f01",
0xa4084ea553df2f808c86437547550be910554d41d33a5d66a4643c9792c4f56f
0x0716f763060cfd52339544a203d0e156a42370b0e22d78ea9bf8766b0b66682b,
0xc2da93948f869c5102992bd1cbd70ef5f821ff522305c69d113faf2e89570ce7
);
// execute disable, exodusSession: 14
vm.prank(ALICE);
gatekeeper.verify(
hex"31371426000000000000000000000000000000000000000000000000000000000000000e0000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044529918310000000000000000000000000000000000000000000000000000000000000003000000000000000000000000010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000",
hex"04f94dad10974c9f0b9307444dc4c660f1f169b25fd3ed9fd563df74714e73c2d4e92b3429505989327d449d9a68e6cce0f557574c92c0ca7bc8126dd710094e9e",
0xb6b75ed763f4d06b9d7a7557ca8d095df656ca25db74645fb47a0b45d27ec501
0x7ed91b176c29b73a077e51de0c2a12f6df5e7e04862eb07f9c393f6fc1cd3a8f,
0x798563362adaade33f39266bb3fa233ac9161ca55d532ca65d5b6d4d0f1edbd2
);
// execute forfeitReserves, exodusSession: 15
vm.prank(ALICE);
gatekeeper.verify(
hex"31371426000000000000000000000000000000000000000000000000000000000000000f0000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000064f0de236c000000000000000000000000010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000",
hex"04af06146f4ca63ef11b82ad891d8e03525a11922316a7dd3f71ff4b6aa5ee6793d29e6af2355d26bc173bb52c1f5eb7d8b279ed40bef2d1cd521da33517b6d3cd",
0x6343b047bb8fe39200758de1e874ddfaf296e1f9259f0b720a070a69e7a3ee08
0x7f90802deb959f3bea4aa2cda26dad5ec601fc6e45dcd941a19ee9ff57e3f571,
0xf61bb645ce15a7e4d0a693e0e4defe1f58fa1b113818a083b582fce05ec728f5
);
// execute redeemReserve, exodusSession: 16
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000100000000000007a690101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004482a21577000000000000000000000000010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000",
hex"041ff894074000f2d934cf3b136165766044b177e69de4c36fac4d1265b855e1a5b4b7b2b25400fbf4d5eb4619039ffc95555db216991d3050bb6fd966f6e3eeab",
0x7d31ebf1e510616e541795b6448d387d2119b3fdd0124e5116c53726b6b1cc15
0x197fd53cb6c9c89e8689419c2ea745233487ba7666f896a2469fc5269c785160,
0x79480d2dfee9c8dcdc2a28a22b3d49ed193c912390c0be655253028fd8ca883d
);
// execute withdraw, exodusSession: 17
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000110000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044f3fef3a3000000000000000000000000010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000",
hex"04f31030cf8563dd976d1a823a84e43ebdcc13bb5e5e0d7a2ff372006c71e6ab3d4d0770771682dcd6eff9e13fb3d113b484d7384d08f247760b07149dca1aa234",
0x06aad271d98e69d1ff18bf39e6713f347aba0df04d99bc4a9304b780431d12ae
0x53a249b4952662c3a86a810cff1e530ba354761e4091dee9a8997279160b017b,
0x8042a9b2521d07612ef0fdccaa98ce9561914b20bf75af49310fc36c240073c7
);
// execute auditReserves, exodusSession: 18
vm.prank(ALICE);
gatekeeper.verify(
hex"3137142600000000000000000000000000000000000000000000000000000000000000120000000000007a69010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000042b7ce50000000000000000000000000000000000000000000000000000000000",
hex"049e5d54fd32dcec64b20943a61763dc760b1e3e9d31948780e2193480d904984c0cdaa8074196c06104557b1a04de6aeeda135e0c3413192f9e4331f3b7447ff2",
0x43ed5301b16b4b2bc91c28dcfbaecc9949a7fc8fe5c57dfef6229f62493da6d2
0xf1f4d62d27c3d0388b2298b621b23cd5791e1b97d4423ffc16b14e81ff0df97c,
0xdbeed3eb94a829710147595c1b10f2ac6ec761c9721d8cc4711842c212ac517e
);
address storageHistory = gatekeeper.storageHistory();

View File

@ -8,15 +8,10 @@ import {Ghost} from "../../src/GhstERC20.sol";
import {GhostAuthority} from "../../src/GhostAuthority.sol";
import {GhostTreasury} from "../../src/Treasury.sol";
import {GhostStaking} from "../../src/Staking.sol";
import {GhostBondDepository} from "../../src/BondDepository.sol";
import {ERC20Mock} from "../../src/mocks/ERC20Mock.sol";
import {WETH9} from "../../src/mocks/WETH9.sol";
import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol";
import {Gatekeeper} from "../../src/Gatekeeper.sol";
import {ITreasury} from "../../src/interfaces/ITreasury.sol";
import {IGatekeeper} from "../../src/interfaces/IGatekeeper.sol";
import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol";
contract GatekeeperRecallTest is Test {
uint256 public constant TOTAL_INITIAL_SUPPLY = 5000000000000000;
@ -100,7 +95,8 @@ contract GatekeeperRecallTest is Test {
function test_recallChainWorks() public {
vm.startPrank(INITIALIZER);
Gatekeeper gatekeeper = Gatekeeper(payable(staking.gatekeeper()));
gatekeeper.updatePublicKeyMetadata(0, 0x4e8c1fe96d6737cdabbcc96501d6656b9d0b659b3a528ef507f2d52bef29e157, 0);
gatekeeper.updatePublicKeyMetadata(0, 0x36ff5b7f0fc50100b563c6072e499980d6e6aa8528ea0ae6d776cf7e8e96c374, 0);
vm.stopPrank();
vm.startPrank(ALICE);
@ -126,9 +122,9 @@ contract GatekeeperRecallTest is Test {
vm.txGasPrice(2 gwei);
vm.startPrank(BOB, BOB);
gatekeeper.verify(
hex"bf06188a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000009536c70891000000000000000000000000000000000000000000020000000000007a6980000000",
hex"046566d4b0904bf35afd25dff583d53bd30e50f57cc790ad08377e0b85006b38b85046b527098f3dfdadc30d6623b6b1c4644306dd56d39f7c9d6b3b295d005c33",
0x942fb44ad0422c197f9c3016ff7c7e574a9f86182c5485e39fc9bebf61228ad6
hex"bf06188a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000007a919134c0400000000000000000000000000000000000000000010000000000007a6900000000",
0x938640689e6f52929acf2714c5c785e8e725b5df616c449a19bca8a8b300ec8b,
0x15b8b8c2934ee96d6a83a24055d83ea4074d251c207584e66d9caf8d653cabf2
);
vm.stopPrank();

View File

@ -95,14 +95,14 @@ contract GatekeeperWeaver is Gatekeeper {
unchecked { ++i; }
}
computedHash = Hashes.efficientKeccak256(computedHash);
computedHash = Hashes.efficientKeccak256Prefixed(computedHash);
i = 0;
for (; i < proof.length; ) {
if (slotIndex % 2 == 0) {
computedHash = Hashes.efficientKeccak256(computedHash, proof[i]);
computedHash = Hashes.efficientKeccak256Prefixed(computedHash, proof[i]);
} else {
computedHash = Hashes.efficientKeccak256(proof[i], computedHash);
computedHash = Hashes.efficientKeccak256Prefixed(proof[i], computedHash);
}
slotIndex >>= 1;
unchecked { ++i; }