diff --git a/Makefile b/Makefile index a355c58..d6f9fac 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ clean :; @forge clean test :; @forge test # deploy :; @forge script script/Deploy.s.sol:Deploy --chain ${chain-id} --broadcast --verify deploy :; @forge script script/Deploy.s.sol:Deploy --rpc-url http://192.168.132.159:9944 --broadcast -e2e-test:; @forge script script/Deploy.s.sol:Deploy --sig "test_import_finalized_header()" --rpc-url http://192.168.132.159:9944 --broadcast --skip-simulation +e2e-test:; @forge script script/Deploy.s.sol:Deploy --sig "test_import_finalized_header()" --rpc-url http://192.168.132.159:9944 --broadcast salt :; @create3 -s 000000000000 sync :; @git submodule update --recursive diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index 0ac5ae7..8ed1a3a 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -19,31 +19,31 @@ contract Deploy is Common, BeaconLightClientUpdate { // super.setUp(); } - function run() public broadcast { - uint64 slot = 7825376; - uint64 proposer_index = 550054; - bytes32 parent_root = 0x43fcc72d547536eeaf4e43454fbc82fbd3d475dbe2890f96281c5d004312ce3e; - bytes32 state_root = 0xcea628f2339d80944daece5214c61effee317f8d9bf71ec21625e98d3c76d022; - bytes32 body_root = 0x4e45b5935b52b809daba32f1ba9faae64af12d3f9d6847db393021c593c904c4; - uint256 block_number = 18633272; - bytes32 merkle_root = 0xf4036d4b1a025802e88b41881d098fd2b63a95f74d961713c2756b253a0391c6; - bytes32 sync_committee_hash = 0x4e6ce20e67e1c347266408d0d58de1dba560025e2b60536d376d9b7af91fed24; - bytes32 genesis_validators_root = 0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078; - new EthereumMessageRootOracle( - slot, - proposer_index, - parent_root, - state_root, - body_root, - block_number, - merkle_root, - sync_committee_hash, - genesis_validators_root - ); - // bytes memory byteCode = type(EthereumMessageRootOracle).creationCode; - // address addr = _deploy3(SALT, abi.encodePacked(byteCode, args())); - // require(addr == ADDR, "!addr"); - } + // function run() public broadcast { + // uint64 slot = 7825376; + // uint64 proposer_index = 550054; + // bytes32 parent_root = 0x43fcc72d547536eeaf4e43454fbc82fbd3d475dbe2890f96281c5d004312ce3e; + // bytes32 state_root = 0xcea628f2339d80944daece5214c61effee317f8d9bf71ec21625e98d3c76d022; + // bytes32 body_root = 0x4e45b5935b52b809daba32f1ba9faae64af12d3f9d6847db393021c593c904c4; + // uint256 block_number = 18633272; + // bytes32 merkle_root = 0xf4036d4b1a025802e88b41881d098fd2b63a95f74d961713c2756b253a0391c6; + // bytes32 sync_committee_hash = 0x4e6ce20e67e1c347266408d0d58de1dba560025e2b60536d376d9b7af91fed24; + // bytes32 genesis_validators_root = 0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078; + // new EthereumMessageRootOracle( + // slot, + // proposer_index, + // parent_root, + // state_root, + // body_root, + // block_number, + // merkle_root, + // sync_committee_hash, + // genesis_validators_root + // ); + // // bytes memory byteCode = type(EthereumMessageRootOracle).creationCode; + // // address addr = _deploy3(SALT, abi.encodePacked(byteCode, args())); + // // require(addr == ADDR, "!addr"); + // } function args() internal pure returns (bytes memory) { uint64 slot = 7825376; diff --git a/src/bls12381/BLS.sol b/src/bls12381/BLS.sol index fda054f..76f741a 100644 --- a/src/bls12381/BLS.sol +++ b/src/bls12381/BLS.sol @@ -33,6 +33,7 @@ library BLS { bytes memory g1 = keys[i]; agg_g1 = agg_g1.add(BLS12G1Affine.deserialize(g1)); } + require(!agg_g1.is_infinity(), "infinity"); return agg_g1; } diff --git a/src/bls12381/Fp.sol b/src/bls12381/Fp.sol index aeffbc6..8f1d72f 100644 --- a/src/bls12381/Fp.sol +++ b/src/bls12381/Fp.sol @@ -28,6 +28,17 @@ library BLS12FP { ); } + function b() internal pure returns (Bls12Fp memory) { + return Bls12Fp(0, 4); + } + + /// @dev (q+1)/4 + function qr() internal pure returns (Bls12Fp memory) { + return Bls12Fp( + 0x680447a8e5ff9a692c6e9ed90d2eb35, 0xd91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffeaab + ); + } + /// @dev Returns the additive identity element of Bls12Fp. /// @return Bls12Fp(0, 0) function zero() internal pure returns (Bls12Fp memory) { @@ -45,6 +56,13 @@ library BLS12FP { return gt(q(), self); } + /// @dev Returns `true` if `self` is equal or larger than r. + /// @param self Bls12Fp. + /// @return Result of check. + function is_geq_modulus(Bls12Fp memory self) internal pure returns (bool) { + return (eq(self, q()) || gt(self, q())); + } + /// @dev Returns `true` if `x` is equal to `y`. /// @param x Bls12Fp. /// @param y Bls12Fp. @@ -83,6 +101,22 @@ library BLS12FP { } } + /// @dev Returns the result of `(x + y) % p`. + /// @param x Bw6Fp. + /// @param y Bw6Fp. + /// @return z `(x + y) % p`. + function add(Bls12Fp memory x, Bls12Fp memory y) internal pure returns (Bls12Fp memory z) { + z = add_nomod(x, y); + z = subtract_modulus_to_norm(z); + } + + function subtract_modulus_to_norm(Bls12Fp memory self) internal pure returns (Bls12Fp memory z) { + z = self; + if (is_geq_modulus(self)) { + z = sub(self, q()); + } + } + /// @dev Returns the result of `(x - y) % p`. /// @param x Bls12Fp. /// @param y Bls12Fp. @@ -129,4 +163,81 @@ library BLS12FP { } return Bls12Fp(output[0], output[1]); } + + /// @dev base^base % modulus + /// @param base Bls12Fp. + /// @param exp Bls12Fp. + /// @param modulus Bls12Fp. + /// @return Result of mod_exp. + function mod_exp( + Bls12Fp memory base, + Bls12Fp memory exp, + Bls12Fp memory modulus + ) + internal + view + returns (Bls12Fp memory) + { + uint256[9] memory input; + input[0] = 0x40; + input[1] = 0x40; + input[2] = 0x40; + input[3] = base.a; + input[4] = base.b; + input[5] = exp.a; + input[6] = exp.b; + input[7] = modulus.a; + input[8] = modulus.b; + uint256[2] memory output; + + assembly ("memory-safe") { + if iszero(staticcall(gas(), MOD_EXP, input, 288, output, 64)) { + let p := mload(0x40) + returndatacopy(p, 0, returndatasize()) + revert(p, returndatasize()) + } + } + + return Bls12Fp(output[0], output[1]); + } + + /// @dev base^base % modulus + /// @param base Bls12Fp. + /// @param exp uint256. + /// @param modulus Bls12Fp. + /// @return Result of mod_exp. + function mod_exp(Bls12Fp memory base, uint256 exp, Bls12Fp memory modulus) internal view returns (Bls12Fp memory) { + uint256[8] memory input; + input[0] = 0x40; + input[1] = 0x40; + input[2] = 0x40; + input[3] = base.a; + input[4] = base.b; + input[5] = exp; + input[6] = modulus.a; + input[7] = modulus.b; + uint256[2] memory output; + + assembly ("memory-safe") { + if iszero(staticcall(gas(), MOD_EXP, input, 256, output, 64)) { + let p := mload(0x40) + returndatacopy(p, 0, returndatasize()) + revert(p, returndatasize()) + } + } + + return Bls12Fp(output[0], output[1]); + } + + // using quadratic residue + function find_y(Bls12Fp memory x) internal view returns (Bls12Fp memory) { + Bls12Fp memory y_square = add(mod_exp(x, 3, q()), b()); + Bls12Fp memory y = mod_exp(y_square, qr(), q()); + return y; + } + + // pow(y, 2, q) == (x**3 + b.n) % q: + function is_on_curve(Bls12Fp memory x, Bls12Fp memory y) internal view returns (bool) { + return eq(mod_exp(y, 2, q()), add(mod_exp(x, 3, q()), b())); + } } diff --git a/src/bls12381/G1.sol b/src/bls12381/G1.sol index 7cae3e8..fd27c2b 100644 --- a/src/bls12381/G1.sol +++ b/src/bls12381/G1.sol @@ -20,10 +20,6 @@ library BLS12G1Affine { /// @dev BLS12_377_G1ADD precompile address. uint256 private constant G1_ADD = 0x0c; - bytes1 private constant COMPRESION_FLAG = bytes1(0x80); - bytes1 private constant INFINITY_FLAG = bytes1(0x40); - bytes1 private constant Y_FLAG = bytes1(0x20); - /// @dev Negative G1 generator /// @return Negative G1 generator function neg_generator() internal pure returns (Bls12G1 memory) { @@ -98,20 +94,33 @@ library BLS12G1Affine { } // Take a 96 byte array and convert to a G1 point (x, y) - function deserialize(bytes memory g1) internal pure returns (Bls12G1 memory) { - require(g1.length == 96, "!g1"); + function deserialize(bytes memory g1) internal view returns (Bls12G1 memory) { + require(g1.length == 48, "!g1"); bytes1 byt = g1[0]; - require(byt & COMPRESION_FLAG == 0, "compressed"); - require(byt & INFINITY_FLAG == 0, "infinity"); - require(byt & Y_FLAG == 0, "y_flag"); + bool c_flag = (byt >> 7) & 0x01 == 0x01; + bool b_flag = (byt >> 6) & 0x01 == 0x01; + bool a_flag = (byt >> 5) & 0x01 == 0x01; + if (a_flag && (!c_flag || b_flag)) { + revert("!flag"); + } + require(c_flag, "uncompressed"); // Zero flags g1[0] = byt & 0x1f; Bls12Fp memory x = Bls12Fp(g1.slice_to_uint(0, 16), g1.slice_to_uint(16, 48)); - Bls12Fp memory y = Bls12Fp(g1.slice_to_uint(48, 64), g1.slice_to_uint(64, 96)); + if (b_flag) { + require(x.is_zero(), "!zero"); + return zero(); + } + + Bls12Fp memory y = x.find_y(); // Require elements less than field modulus - require(x.is_valid() && y.is_valid(), "!pnt"); + require(x.is_valid() && y.is_valid(), "!fp"); + + if (y.add(y).gt(BLS12FP.q()) != a_flag) { + y = BLS12FP.q().sub(y); + } // Convert to G1 Bls12G1 memory p = Bls12G1(x, y);