Skip to content

Commit

Permalink
bls sig-verify
Browse files Browse the repository at this point in the history
  • Loading branch information
fanhousanbu committed Oct 4, 2024
1 parent 2ca2a60 commit d08096f
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 247 deletions.
2 changes: 1 addition & 1 deletion cache/solidity-files-cache.json

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions lib/BLSOpen.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {BLS} from "./hubble-contracts/libs/BLS.sol";

library BLSOpen {
function verifySingle(uint256[2] memory signature, uint256[4] memory pubkey, uint256[2] memory message)
external
view
returns (bool)
{
uint256[4][] memory pubkeys = new uint256[4][](1);
uint256[2][] memory messages = new uint256[2][](1);
pubkeys[0] = pubkey;
messages[0] = message;

(bool verified, bool callSuccess) = BLS.verifyMultiple(signature, pubkeys, messages);
return callSuccess && verified;

// // NB: (result, success) opposite of `call` convention (success, result).
// (bool verified, bool callSuccess) = BLS.verifySingle(
// signature,
// pubkey,
// message
// );
// return callSuccess && verified;
}

function verifyMultiple(uint256[2] memory signature, uint256[4][] memory pubkeys, uint256[2][] memory messages)
external
view
returns (bool)
{
(bool verified, bool callSuccess) = BLS.verifyMultiple(signature, pubkeys, messages);
return callSuccess && verified;
}

function hashToPoint(bytes32 domain, bytes memory message) external view returns (uint256[2] memory) {
return BLS.hashToPoint(domain, message);
}

function isZeroBLSKey(uint256[4] memory blsKey) public pure returns (bool) {
bool isZero = true;
for (uint256 i = 0; isZero && i < 4; i++) {
isZero = (blsKey[i] == 0);
}
return isZero;
}
}
166 changes: 51 additions & 115 deletions src/hubble-contracts/libs/BLS.sol → lib/hubble-contracts/libs/BLS.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity >= 0.6.12;
pragma solidity ^0.8.23;

import { ModexpInverse, ModexpSqrt } from "./ModExp.sol";
import {
BNPairingPrecompileCostEstimator
} from "./BNPairingPrecompileCostEstimator.sol";
import {ModexpInverse, ModexpSqrt} from "./ModExp.sol";
import {BNPairingPrecompileCostEstimator} from "./BNPairingPrecompileCostEstimator.sol";

/**
@title Boneh–Lynn–Shacham (BLS) signature scheme on Barreto-Naehrig 254 bit curve (BN-254)
@notice We use BLS signature aggregation to reduce the size of signature data to store on chain.
@dev We use G1 points for signatures and messages, and G2 points for public keys
* @title Boneh–Lynn–Shacham (BLS) signature scheme on Barreto-Naehrig 254 bit curve (BN-254)
* @notice We use BLS signature aggregation to reduce the size of signature data to store on chain.
* @dev We use G1 points for signatures and messages, and G2 points for public keys
*/
library BLS {
// Field order
Expand Down Expand Up @@ -39,62 +37,51 @@ library BLS {
uint256 private constant MASK24 = 0xffffffffffffffffffffffffffffffffffffffffffffffff;

// estimator address
// address private constant COST_ESTIMATOR_ADDRESS = new 0x22E4a5251C1F02de8369Dd6f192033F6CB7531A4;

function verifySingle(
uint256[2] memory signature,
uint256[4] memory pubkey,
uint256[2] memory message
) internal view returns (bool, bool) {
uint256[12] memory input =
[
signature[0],
signature[1],
N_G2_X1,
N_G2_X0,
N_G2_Y1,
N_G2_Y0,
message[0],
message[1],
pubkey[1],
pubkey[0],
pubkey[3],
pubkey[2]
];
// address private constant COST_ESTIMATOR_ADDRESS = new 0x22E4a5251C1F02de8369Dd6f192033F6CB7531A4;

function verifySingle(uint256[2] memory signature, uint256[4] memory pubkey, uint256[2] memory message)
internal
view
returns (bool, bool)
{
uint256[12] memory input = [
signature[0],
signature[1],
N_G2_X1,
N_G2_X0,
N_G2_Y1,
N_G2_Y0,
message[0],
message[1],
pubkey[1],
pubkey[0],
pubkey[3],
pubkey[2]
];
uint256[1] memory out;
uint256 precompileGasCost = gasleft();
// BNPairingPrecompileCostEstimator(COST_ESTIMATOR_ADDRESS).getGasCost(
// 2
// );
// BNPairingPrecompileCostEstimator(COST_ESTIMATOR_ADDRESS).getGasCost(
// 2
// );
bool callSuccess;
// solium-disable-next-line security/no-inline-assembly
assembly {
callSuccess := staticcall(
precompileGasCost,
8,
input,
384,
out,
0x20
)
callSuccess := staticcall(precompileGasCost, 8, input, 384, out, 0x20)
}
if (!callSuccess) {
return (false, false);
}
return (out[0] != 0, true);
}

function verifyMultiple(
uint256[2] memory signature,
uint256[4][] memory pubkeys,
uint256[2][] memory messages
) internal view returns (bool checkResult, bool callSuccess) {
function verifyMultiple(uint256[2] memory signature, uint256[4][] memory pubkeys, uint256[2][] memory messages)
internal
view
returns (bool checkResult, bool callSuccess)
{
uint256 size = pubkeys.length;
require(size > 0, "BLS: number of public key is zero");
require(
size == messages.length,
"BLS: number of public keys and messages must be equal"
);
require(size == messages.length, "BLS: number of public keys and messages must be equal");
uint256 inputSize = (size + 1) * 6;
uint256[] memory input = new uint256[](inputSize);
input[0] = signature[0];
Expand All @@ -115,17 +102,10 @@ library BLS {

// prettier-ignore
uint256 precompileGasCost = gasleft();
// uint256 precompileGasCost = BNPairingPrecompileCostEstimator(COST_ESTIMATOR_ADDRESS).getGasCost(size + 1);
// uint256 precompileGasCost = BNPairingPrecompileCostEstimator(COST_ESTIMATOR_ADDRESS).getGasCost(size + 1);
// solium-disable-next-line security/no-inline-assembly
assembly {
callSuccess := staticcall(
precompileGasCost,
8,
add(input, 0x20),
mul(inputSize, 0x20),
out,
0x20
)
callSuccess := staticcall(precompileGasCost, 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!callSuccess) {
return (false, false);
Expand All @@ -134,13 +114,9 @@ library BLS {
}

/**
@notice Fouque-Tibouchi Hash to Curve
* @notice Fouque-Tibouchi Hash to Curve
*/
function hashToPoint(bytes32 domain, bytes memory message)
internal
view
returns (uint256[2] memory)
{
function hashToPoint(bytes32 domain, bytes memory message) internal view returns (uint256[2] memory) {
uint256[2] memory u = hashToField(domain, message);
uint256[2] memory p0 = mapToPoint(u[0]);
uint256[2] memory p1 = mapToPoint(u[1]);
Expand All @@ -154,19 +130,13 @@ library BLS {
assembly {
success := staticcall(sub(gas(), 2000), 6, bnAddInput, 128, p0, 64)
switch success
case 0 {
invalid()
}
case 0 { invalid() }
}
require(success, "BLS: bn add call failed");
return p0;
}

function mapToPoint(uint256 _x)
internal
pure
returns (uint256[2] memory p)
{
function mapToPoint(uint256 _x) internal pure returns (uint256[2] memory p) {
require(_x < N, "mapToPointFT: invalid field element");
uint256 x = _x;

Expand Down Expand Up @@ -228,23 +198,15 @@ library BLS {
return [x, a1];
}

function isValidSignature(uint256[2] memory signature)
internal
pure
returns (bool)
{
function isValidSignature(uint256[2] memory signature) internal pure returns (bool) {
if ((signature[0] >= N) || (signature[1] >= N)) {
return false;
} else {
return isOnCurveG1(signature);
}
}

function isOnCurveG1(uint256[2] memory point)
internal
pure
returns (bool _isOnCurve)
{
function isOnCurveG1(uint256[2] memory point) internal pure returns (bool _isOnCurve) {
// solium-disable-next-line security/no-inline-assembly
assembly {
let t0 := mload(point)
Expand All @@ -257,11 +219,7 @@ library BLS {
}
}

function isOnCurveG2(uint256[4] memory point)
internal
pure
returns (bool _isOnCurve)
{
function isOnCurveG2(uint256[4] memory point) internal pure returns (bool _isOnCurve) {
// solium-disable-next-line security/no-inline-assembly
assembly {
// x0, x1
Expand All @@ -281,16 +239,8 @@ library BLS {
t3 := mulmod(add(t4, sub(N, t3)), t1, N)

// x ^ 3 + b
t0 := addmod(
t2,
0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5,
N
)
t1 := addmod(
t3,
0x009713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2,
N
)
t0 := addmod(t2, 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5, N)
t1 := addmod(t3, 0x009713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2, N)

// y0, y1
t2 := mload(add(point, 64))
Expand All @@ -313,11 +263,7 @@ library BLS {
return ModexpInverse.run(a);
}

function hashToField(bytes32 domain, bytes memory messages)
internal
pure
returns (uint256[2] memory)
{
function hashToField(bytes32 domain, bytes memory messages) internal pure returns (uint256[2] memory) {
bytes memory _msg = expandMsgTo96(domain, messages);
uint256 u0;
uint256 u1;
Expand All @@ -339,11 +285,7 @@ library BLS {
return [a0, a1];
}

function expandMsgTo96(bytes32 domain, bytes memory message)
internal
pure
returns (bytes memory)
{
function expandMsgTo96(bytes32 domain, bytes memory message) internal pure returns (bytes memory) {
// zero<64>|msg<var>|lib_str<2>|I2OSP(0, 1)<1>|dst<var>|dst_len<1>
uint256 t0 = message.length;
bytes memory msg0 = new bytes(32 + t0 + 64 + 4);
Expand All @@ -352,13 +294,7 @@ library BLS {
// solium-disable-next-line security/no-inline-assembly
assembly {
let p := add(msg0, 96)
for {
let z := 0
} lt(z, t0) {
z := add(z, 32)
} {
mstore(add(p, z), mload(add(message, add(z, 32))))
}
for { let z := 0 } lt(z, t0) { z := add(z, 32) } { mstore(add(p, z), mload(add(message, add(z, 32)))) }
p := add(p, t0)

mstore8(p, 0)
Expand Down
Loading

0 comments on commit d08096f

Please sign in to comment.