Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 511,652 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
New Blocks | 5734633 | 297 days ago | IN | 0 ETH | 0.00029896 | ||||
New Blocks | 5734632 | 297 days ago | IN | 0 ETH | 0.000299 | ||||
New Blocks | 5734631 | 297 days ago | IN | 0 ETH | 0.00022737 | ||||
New Blocks | 5734630 | 297 days ago | IN | 0 ETH | 0.000299 | ||||
New Blocks | 5734629 | 297 days ago | IN | 0 ETH | 0.000299 | ||||
New Blocks | 5734628 | 297 days ago | IN | 0 ETH | 0.00029901 | ||||
New Blocks | 5734627 | 297 days ago | IN | 0 ETH | 0.00029901 | ||||
New Blocks | 5734626 | 297 days ago | IN | 0 ETH | 0.00029902 | ||||
New Blocks | 5734625 | 297 days ago | IN | 0 ETH | 0.00029902 | ||||
New Blocks | 5734624 | 297 days ago | IN | 0 ETH | 0.000299 | ||||
New Blocks | 5734623 | 297 days ago | IN | 0 ETH | 0.00029904 | ||||
New Blocks | 5734622 | 297 days ago | IN | 0 ETH | 0.00029903 | ||||
New Blocks | 5734620 | 297 days ago | IN | 0 ETH | 0.00029902 | ||||
New Blocks | 5734619 | 297 days ago | IN | 0 ETH | 0.00029901 | ||||
New Blocks | 5734618 | 297 days ago | IN | 0 ETH | 0.00029905 | ||||
New Blocks | 5734617 | 297 days ago | IN | 0 ETH | 0.00029905 | ||||
New Blocks | 5734616 | 297 days ago | IN | 0 ETH | 0.00029905 | ||||
New Blocks | 5734615 | 297 days ago | IN | 0 ETH | 0.00029905 | ||||
New Blocks | 5734614 | 297 days ago | IN | 0 ETH | 0.00029898 | ||||
New Blocks | 5734613 | 297 days ago | IN | 0 ETH | 0.00029902 | ||||
New Blocks | 5734612 | 297 days ago | IN | 0 ETH | 0.00029903 | ||||
New Blocks | 5734611 | 297 days ago | IN | 0 ETH | 0.00029907 | ||||
New Blocks | 5734610 | 297 days ago | IN | 0 ETH | 0.00029906 | ||||
New Blocks | 5734609 | 297 days ago | IN | 0 ETH | 0.00029907 | ||||
New Blocks | 5734608 | 297 days ago | IN | 0 ETH | 0.00029906 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x7cc87E6B...fB4776c26 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
HotShot
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.8.0; import { BN254 } from "bn254/BN254.sol"; import { BLSSig } from "./libraries/BLSSig.sol"; contract HotShot { event NewStakingKey(BN254.G2Point stakingKey, uint256 amount, uint256 index); uint256 public constant MAX_BLOCKS = 500; mapping(uint256 blockHeight => uint256 commitment) public commitments; uint256 public blockHeight; // Stake table related data structures mapping(uint256 index => uint256 amount) private _stakeAmounts; BN254.G2Point[] private _stakingKeys; event NewBlocks(uint256 firstBlockNumber, uint256 numBlocks); error TooManyBlocks(uint256 numBlocks); error InvalidQC(uint256 blockNumber); error IncorrectBlockNumber(uint256 blockNumber, uint256 expectedBlockNumber); error NoKeySelected(); error NotEnoughStake(); struct QC { uint256 height; uint256 blockCommitment; // QC validation is currently mocked out, so the rest of the QC data isn't used, and its // format is not finalized. For realism of gas usage, we want something of the correct size. // The plan for on-chain QC validation is for the contract to only take a few 32-byte words // of the QC, with the rest replaced by a short commitment, since the contract doesn't need // all the fields of the QC and storing the whole QC in calldata can be expensive (or even // run into RPC size limits). uint256 pad1; uint256 pad2; } function _verifyQC(QC calldata /* qc */ ) private pure returns (bool) { // TODO Check the QC // TODO Check the block number return true; } function newBlocks(QC[] calldata qcs) external { if (qcs.length > MAX_BLOCKS) { revert TooManyBlocks(qcs.length); } uint256 firstBlockNumber = blockHeight; for (uint256 i = 0; i < qcs.length; ++i) { if (qcs[i].height != blockHeight) { // Fail quickly if this QC is for the wrong block. In particular, this saves the // caller some gas in the race condition where two clients try to sequence the same // block at the same time, and the first one wins. revert IncorrectBlockNumber(qcs[i].height, blockHeight); } // Check that QC is signed and well-formed. if (!_verifyQC(qcs[i])) { revert InvalidQC(blockHeight); } commitments[blockHeight] = qcs[i].blockCommitment; blockHeight += 1; } emit NewBlocks(firstBlockNumber, qcs.length); } /// @dev Stake table related functions /// @notice This function is for testing purposes only. The real sequencer /// contract will perform several checks before adding a new key (e.g. /// validate deposits). /// @param stakingKey public key for the BLS scheme /// @param amount stake corresponding to the staking key function addNewStakingKey(BN254.G2Point memory stakingKey, uint256 amount) public { uint256 index = _stakingKeys.length; _stakeAmounts[index] = amount; _stakingKeys.push(stakingKey); emit NewStakingKey(stakingKey, amount, index); } function getStakingKey(uint256 index) public view returns (BN254.G2Point memory, uint256) { return (_stakingKeys[index], _stakeAmounts[index]); } }
// SPDX-License-Identifier: GPL-3.0-or-later // // Copyright (c) 2022 Espresso Systems (espressosys.com) // This file is part of the solidity-bn254 library. // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. // You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. // // Based on: // - Christian Reitwiessner: https://gist.githubusercontent.com/chriseth/f9be9d9391efc5beb9704255a8e2989d/raw/4d0fb90847df1d4e04d507019031888df8372239/snarktest.solidity // - Aztec: https://github.com/AztecProtocol/aztec-2-bug-bounty pragma solidity ^0.8.0; import { Utils } from "./Utils.sol"; /// @notice Barreto-Naehrig curve over a 254 bit prime field library BN254 { /// @notice type alias for BN254::ScalarField type ScalarField is uint256; /// @notice type alias for BN254::BaseField type BaseField is uint256; // use notation from https://datatracker.ietf.org/doc/draft-irtf-cfrg-pairing-friendly-curves/ // // Elliptic curve is defined over a prime field GF(p), with embedding degree k. // Short Weierstrass (SW form) is, for a, b \in GF(p^n) for some natural number n > 0: // E: y^2 = x^3 + a * x + b // // Pairing is defined over cyclic subgroups G1, G2, both of which are of order r. // G1 is a subgroup of E(GF(p)), G2 is a subgroup of E(GF(p^k)). // // BN family are parameterized curves with well-chosen t, // p = 36 * t^4 + 36 * t^3 + 24 * t^2 + 6 * t + 1 // r = 36 * t^4 + 36 * t^3 + 18 * t^2 + 6 * t + 1 // for some integer t. // E has the equation: // E: y^2 = x^3 + b // where b is a primitive element of multiplicative group (GF(p))^* of order (p-1). // A pairing e is defined by taking G1 as a subgroup of E(GF(p)) of order r, // G2 as a subgroup of E'(GF(p^2)), // and G_T as a subgroup of a multiplicative group (GF(p^12))^* of order r. // // BN254 is defined over a 254-bit prime order p, embedding degree k = 12. uint256 public constant P_MOD = 21888242871839275222246405745257275088696311157297823662689037894645226208583; uint256 public constant R_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; struct G1Point { BaseField x; BaseField y; } // G2 group element where x \in Fp2 = c0 + c1 * X struct G2Point { BaseField x0; BaseField x1; BaseField y0; BaseField y1; } /// @return the generator of G1 // solhint-disable-next-line func-name-mixedcase function P1() internal pure returns (G1Point memory) { return G1Point(BaseField.wrap(1), BaseField.wrap(2)); } /// @return the generator of G2 // solhint-disable-next-line func-name-mixedcase function P2() internal pure returns (G2Point memory) { return G2Point({ x0: BaseField.wrap(0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed), x1: BaseField.wrap(0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2), y0: BaseField.wrap(0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa), y1: BaseField.wrap(0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) }); } /// @notice the neutral/infinity point of G1 function infinity() internal pure returns (G1Point memory) { return G1Point(BaseField.wrap(0), BaseField.wrap(0)); } /// @dev check if a G1 point is Infinity /// @notice precompile bn256Add at address(6) takes (0, 0) as Point of Infinity, /// some crypto libraries (such as arkwork) uses a boolean flag to mark PoI, and /// just use (0, 1) as affine coordinates (not on curve) to represents PoI. function isInfinity(G1Point memory point) internal pure returns (bool result) { assembly { let x := mload(point) let y := mload(add(point, 0x20)) result := and(iszero(x), iszero(y)) } } /// @return r the negation of p, i.e. p.add(p.negate()) should be zero. function negate(G1Point memory p) internal pure returns (G1Point memory) { if (isInfinity(p)) { return p; } return G1Point(p.x, BaseField.wrap(P_MOD - (BaseField.unwrap(p.y) % P_MOD))); } /// @return res = -fr the negation of scalar field element. function negate(ScalarField fr) internal pure returns (ScalarField res) { return ScalarField.wrap(R_MOD - (ScalarField.unwrap(fr) % R_MOD)); } /// @notice res = -fq for base field function negate(BaseField fq) internal pure returns (BaseField) { return BaseField.wrap(P_MOD - (BaseField.unwrap(fq) % P_MOD)); } /// @return r the sum of two points of G1 function add(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { uint256[4] memory input; input[0] = BaseField.unwrap(p1.x); input[1] = BaseField.unwrap(p1.y); input[2] = BaseField.unwrap(p2.x); input[3] = BaseField.unwrap(p2.y); bool success; assembly { success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) // Use "invalid" to make gas estimation work switch success case 0 { revert(0, 0) } } require(success, "Bn254: group addition failed!"); } /// @notice add for BaseField function add(BaseField a, BaseField b) internal pure returns (BaseField) { return BaseField.wrap(addmod(BaseField.unwrap(a), BaseField.unwrap(b), P_MOD)); } /// @notice add for ScalarField function add(ScalarField a, ScalarField b) internal pure returns (ScalarField) { return ScalarField.wrap(addmod(ScalarField.unwrap(a), ScalarField.unwrap(b), R_MOD)); } /// @notice mul for BaseField function mul(BaseField a, BaseField b) internal pure returns (BaseField) { return BaseField.wrap(mulmod(BaseField.unwrap(a), BaseField.unwrap(b), P_MOD)); } /// @notice mul for ScalarField function mul(ScalarField a, ScalarField b) internal pure returns (ScalarField) { return ScalarField.wrap(mulmod(ScalarField.unwrap(a), ScalarField.unwrap(b), R_MOD)); } /// @return r the product of a point on G1 and a scalar, i.e. /// p == p.mul(1) and p.add(p) == p.mul(2) for all points p. function scalarMul(G1Point memory p, ScalarField s) internal view returns (G1Point memory r) { uint256[3] memory input; input[0] = BaseField.unwrap(p.x); input[1] = BaseField.unwrap(p.y); input[2] = ScalarField.unwrap(s); bool success; assembly { success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) // Use "invalid" to make gas estimation work switch success case 0 { revert(0, 0) } } require(success, "Bn254: scalar mul failed!"); } /// @dev Multi-scalar Mulitiplication (MSM) /// @return r = \Prod{B_i^s_i} where {s_i} are `scalars` and {B_i} are `bases` function multiScalarMul(G1Point[] memory bases, ScalarField[] memory scalars) internal view returns (G1Point memory r) { require(scalars.length == bases.length, "MSM error: length does not match"); r = scalarMul(bases[0], scalars[0]); for (uint256 i = 1; i < scalars.length; i++) { r = add(r, scalarMul(bases[i], scalars[i])); } } /// @dev Compute f^-1 for f \in Fr scalar field /// @notice credit: Aztec, Spilsbury Holdings Ltd function invert(ScalarField fr) internal view returns (ScalarField output) { bool success; uint256 p = R_MOD; assembly { let mPtr := mload(0x40) mstore(mPtr, 0x20) mstore(add(mPtr, 0x20), 0x20) mstore(add(mPtr, 0x40), 0x20) mstore(add(mPtr, 0x60), fr) mstore(add(mPtr, 0x80), sub(p, 2)) mstore(add(mPtr, 0xa0), p) success := staticcall(gas(), 0x05, mPtr, 0xc0, 0x00, 0x20) output := mload(0x00) } require(success, "Bn254: pow precompile failed!"); } /** * validate the following: * x < p * y < p * y^2 = x^3 + 3 mod p or Point-of-Infinity */ /// @dev validate G1 point and check if it is on curve /// @notice credit: Aztec, Spilsbury Holdings Ltd function validateG1Point(G1Point memory point) internal pure { bool isWellFormed; uint256 p = P_MOD; if (isInfinity(point)) { return; } assembly { let x := mload(point) let y := mload(add(point, 0x20)) isWellFormed := and( and(lt(x, p), lt(y, p)), eq(mulmod(y, y, p), addmod(mulmod(x, mulmod(x, x, p), p), 3, p)) ) } require(isWellFormed, "Bn254: invalid G1 point"); } /// @dev Validate scalar field, revert if invalid (namely if fr > r_mod). /// @notice Writing this inline instead of calling it might save gas. function validateScalarField(ScalarField fr) internal pure { bool isValid; assembly { isValid := lt(fr, R_MOD) } require(isValid, "Bn254: invalid scalar field"); } /// @dev Evaluate the following pairing product: /// @dev e(a1, a2).e(b1, b2) == 1 /// @dev equality holds for e(a1, a2) == e(-b1, b2) (NOTE: input `b1`=-b1) /// @dev caller needs to ensure that a1, a2, b1 and b2 are within proper group /// @dev Modified from original credit: Aztec, Spilsbury Holdings Ltd function pairingProd2( G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2 ) internal view returns (bool) { uint256 out; bool success; assembly { let mPtr := mload(0x40) mstore(mPtr, mload(a1)) mstore(add(mPtr, 0x20), mload(add(a1, 0x20))) mstore(add(mPtr, 0x40), mload(add(a2, 0x20))) mstore(add(mPtr, 0x60), mload(a2)) mstore(add(mPtr, 0x80), mload(add(a2, 0x60))) mstore(add(mPtr, 0xa0), mload(add(a2, 0x40))) mstore(add(mPtr, 0xc0), mload(b1)) mstore(add(mPtr, 0xe0), mload(add(b1, 0x20))) mstore(add(mPtr, 0x100), mload(add(b2, 0x20))) mstore(add(mPtr, 0x120), mload(b2)) mstore(add(mPtr, 0x140), mload(add(b2, 0x60))) mstore(add(mPtr, 0x160), mload(add(b2, 0x40))) success := staticcall(gas(), 8, mPtr, 0x180, 0x00, 0x20) out := mload(0x00) } require(success, "Bn254: Pairing check failed!"); return (out != 0); } function fromLeBytesModOrder(bytes memory leBytes) internal pure returns (uint256 ret) { for (uint256 i = 0; i < leBytes.length; i++) { ret = mulmod(ret, 256, R_MOD); ret = addmod(ret, uint256(uint8(leBytes[leBytes.length - 1 - i])), R_MOD); } } /// @dev Check if y-coordinate of G1 point is negative. function isYNegative(G1Point memory point) internal pure returns (bool) { return (BaseField.unwrap(point.y) << 1) < P_MOD; } // @dev Perform a modular exponentiation. // @return base^exponent (mod modulus) // This method is ideal for small exponents (~64 bits or less), as it is cheaper than using the pow precompile // @notice credit: credit: Aztec, Spilsbury Holdings Ltd function powSmall(uint256 base, uint256 exponent, uint256 modulus) internal pure returns (uint256) { uint256 result = 1; uint256 input = base; uint256 count = 1; assembly { let endpoint := add(exponent, 0x01) for { } lt(count, endpoint) { count := add(count, count) } { if and(exponent, count) { result := mulmod(result, input, modulus) } input := mulmod(input, input, modulus) } } return result; } function g1Serialize(G1Point memory point) internal pure returns (bytes memory) { uint256 mask = 0; // Set the 254-th bit to 1 for infinity // https://docs.rs/ark-serialize/0.3.0/src/ark_serialize/flags.rs.html#117 if (isInfinity(point)) { mask |= 0x4000000000000000000000000000000000000000000000000000000000000000; } // Set the 255-th bit to 1 for positive Y // https://docs.rs/ark-serialize/0.3.0/src/ark_serialize/flags.rs.html#118 if (!isYNegative(point)) { mask = 0x8000000000000000000000000000000000000000000000000000000000000000; } return abi.encodePacked(Utils.reverseEndianness(BaseField.unwrap(point.x) | mask)); } function g1Deserialize(bytes32 input) internal view returns (G1Point memory point) { uint256 mask = 0x4000000000000000000000000000000000000000000000000000000000000000; uint256 xVal = Utils.reverseEndianness(uint256(input)); bool isQuadraticResidue; bool isYPositive; if (xVal & mask != 0) { // the 254-th bit == 1 for infinity point = infinity(); } else { // Set the 255-th bit to 1 for positive Y mask = 0x8000000000000000000000000000000000000000000000000000000000000000; isYPositive = (xVal & mask != 0); // mask off the first two bits of x mask = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xVal &= mask; // solve for y where E: y^2 = x^3 + 3 BaseField x = BaseField.wrap(xVal); BaseField y = add(mul(mul(x, x), x), BaseField.wrap(3)); (isQuadraticResidue, y) = quadraticResidue(y); require(isQuadraticResidue, "deser fail: not on curve"); if (isYPositive) { y = negate(y); } point = G1Point(x, y); } } function quadraticResidue(BaseField x) internal view returns (bool isQuadraticResidue, BaseField) { bool success; uint256 a; // e = (p+1)/4 uint256 e = 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52; uint256 p = P_MOD; // we have p == 3 mod 4 therefore // a = x^((p+1)/4) assembly { // credit: Aztec let mPtr := mload(0x40) mstore(mPtr, 0x20) mstore(add(mPtr, 0x20), 0x20) mstore(add(mPtr, 0x40), 0x20) mstore(add(mPtr, 0x60), x) mstore(add(mPtr, 0x80), e) mstore(add(mPtr, 0xa0), p) success := staticcall(gas(), 0x05, mPtr, 0xc0, 0x00, 0x20) a := mload(0x00) } require(success, "pow precompile call failed!"); // ensure a < p/2 if (a << 1 > p) { a = p - a; } // check if a^2 = x, if not x is not a quadratic residue e = mulmod(a, a, p); isQuadraticResidue = (e == BaseField.unwrap(x)); return (isQuadraticResidue, BaseField.wrap(a)); } }
// SPDX-License-Identifier: Unlicensed pragma solidity ^0.8.0; import { BN254 } from "bn254/BN254.sol"; /// @dev test top /// This library implements the verification of the BLS signature scheme over the BN254 curve /// following /// the rust implementation at // solhint-disable-next-line /// https://github.com/EspressoSystems/jellyfish/blob/e1e683c287f20160738e6e737295dd8f9e70577a/primitives/src/signatures/bls_over_bn254.rs library BLSSig { error BLSSigVerificationFailed(); // TODO gas optimization function _uint256FromBytesLittleEndian(uint8[] memory input) private pure returns (uint256) { uint256 r = 0; for (uint256 i = 0; i < input.length; i++) { r += 2 ** (8 * i) * input[i]; } return r; } /// @dev Takes a sequence of bytes and turn in into another sequence of bytes with fixed size. /// Equivalent of // solhint-disable-next-line /// https://github.com/arkworks-rs/algebra/blob/1f7b3c6b215e98fa3130b39d2967f6b43df41e04/ff/src/fields/field_hashers/expander/mod.rs#L37 /// @param message message to be "expanded" /// @return fixed size array of bytes function expand(bytes memory message) internal pure returns (bytes memory) { uint8 blockSize = 48; uint256 bLen = 32; // Output length of sha256 in number of bytes bytes1 ell = 0x02; // (n+(bLen-1))/bLen where n=48 // Final value of buffer must be: z_pad || message || lib_str || 0 || dst_prime // z_pad bytes memory buffer = new bytes(blockSize); // message buffer = bytes.concat(buffer, message); // lib_str buffer = bytes.concat(buffer, hex"00", bytes1(blockSize)); // 0 separator buffer = bytes.concat(buffer, hex"00"); // dst_prime = [1,1] bytes2 dstPrime = 0x0101; buffer = bytes.concat(buffer, dstPrime); bytes32 b0 = keccak256(buffer); buffer = bytes.concat(b0, hex"01", dstPrime); bytes32 bi = keccak256(buffer); // Building uniform_bytes bytes memory uniformBytes = new bytes(blockSize); // Copy bi into uniform_bytes bytes memory biBytes = bytes.concat(bi); for (uint256 i = 0; i < biBytes.length; i++) { uniformBytes[i] = biBytes[i]; } bytes memory b0Bytes = bytes.concat(b0); // In our case ell=2 so we do not have an outer loop // solhint-disable-next-line // https://github.com/arkworks-rs/algebra/blob/1f7b3c6b215e98fa3130b39d2967f6b43df41e04/ff/src/fields/field_hashers/expander/mod.rs#L100 buffer = ""; for (uint256 j = 0; j < bLen; j++) { bytes1 v = bytes1(b0Bytes[j] ^ biBytes[j]); buffer = bytes.concat(buffer, v); } buffer = bytes.concat(buffer, ell, dstPrime); bi = keccak256(buffer); biBytes = bytes.concat(bi); for (uint256 i = 0; i < blockSize - bLen; i++) { uniformBytes[bLen + i] = biBytes[i]; } return uniformBytes; } /// @dev Hash a sequence of bytes to a field element in Fq. Equivalent of // solhint-disable-next-line /// https://github.com/arkworks-rs/algebra/blob/1f7b3c6b215e98fa3130b39d2967f6b43df41e04/ff/src/fields/field_hashers/mod.rs#L65 /// @param message input message to be hashed /// @return field element in Fq function hashToField(bytes memory message) internal pure returns (uint256) { bytes memory uniformBytes = expand(message); // Reverse uniform_bytes uint256 n = uniformBytes.length; assert(n == 48); bytes memory uniformBytesReverted = new bytes(n); for (uint256 i = 0; i < n; i++) { uniformBytesReverted[i] = uniformBytes[n - i - 1]; } // solhint-disable-next-line // https://github.com/arkworks-rs/algebra/blob/bc991d44c5e579025b7ed56df3d30267a7b9acac/ff/src/fields/prime.rs#L72 // Do the split uint256 numBytesDirectlyToConvert = 31; // Fixed for Fq // Process the second slice uint8[] memory secondSlice = new uint8[](numBytesDirectlyToConvert); for (uint256 i = 0; i < numBytesDirectlyToConvert; i++) { secondSlice[i] = uint8(uniformBytesReverted[n - numBytesDirectlyToConvert + i]); } uint256 res = _uint256FromBytesLittleEndian(secondSlice); uint256 windowSize = 256; uint256 p = BN254.P_MOD; // Handle the first slice uint256 arrSize = n - numBytesDirectlyToConvert; for (uint256 i = 0; i < arrSize; i++) { // Compute field element from a single byte uint256 fieldElem = uint256(uint8(uniformBytesReverted[arrSize - i - 1])); // In reverse res = mulmod(res, windowSize, p); res = addmod(res, fieldElem, p); } return res; } /// @dev Hash a sequence of bytes to a group element in BN254.G_1. We use the hash-and-pray /// algorithm for now. /// Rust implementation can be found at // solhint-disable-next-line /// https://github.com/EspressoSystems/jellyfish/blob/e1e683c287f20160738e6e737295dd8f9e70577a/primitives/src/signatures/bls_over_bn254.rs#L318 /// @param input message to be hashed /// @return group element in G_1 function hashToCurve(bytes memory input) internal view returns (BN254.G1Point memory) { uint256 x = hashToField(input); uint256 p = BN254.P_MOD; uint256 b = 3; // solhint-disable-next-line var-name-mixedcase uint256 Y = mulmod(x, x, p); Y = mulmod(Y, x, p); Y = addmod(Y, b, p); // Check Y is a quadratic residue BN254.BaseField y; bool isQr; (isQr, y) = BN254.quadraticResidue(BN254.BaseField.wrap(Y)); while (!isQr) { x = addmod(x, 1, p); Y = mulmod(x, x, p); Y = mulmod(Y, x, p); Y = addmod(Y, b, p); (isQr, y) = BN254.quadraticResidue(BN254.BaseField.wrap(Y)); } return BN254.G1Point(BN254.BaseField.wrap(x), y); } /// @dev Verify a bls signature. Reverts if the signature is invalid /// @param message message to check the signature against /// @param sig signature represented as a point in BN254.G_1 /// @param pk public key represented as a point in BN254.G_2 function verifyBlsSig(bytes memory message, BN254.G1Point memory sig, BN254.G2Point memory pk) internal view { // Check the signature is a valid G1 point // Note: checking pk belong to G2 is not possible in practice // https://ethresear.ch/t/fast-mathbb-g-2-subgroup-check-in-bn254/13974 BN254.validateG1Point(sig); // Hardcoded suffix "BLS_SIG_BN254G1_XMD:KECCAK_NCTH_NUL_" // solhint-disable-next-line // https://github.com/EspressoSystems/jellyfish/blob/e1e683c287f20160738e6e737295dd8f9e70577a/primitives/src/constants.rs#L30 bytes memory csidSuffix = "BLS_SIG_BN254G1_XMD:KECCAK_NCTH_NUL_"; bytes memory input = bytes.concat(message, csidSuffix); BN254.G1Point memory hash = hashToCurve(input); if (!BN254.pairingProd2(hash, pk, BN254.negate(sig), BN254.P2())) { revert BLSSigVerificationFailed(); } } }
// SPDX-License-Identifier: GPL-3.0-or-later // // Copyright (c) 2022 Espresso Systems (espressosys.com) // This file is part of the solidity-bn254 library. // // This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. // You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity ^0.8.0; library Utils { function reverseEndianness(uint256 input) internal pure returns (uint256 v) { v = input; // swap bytes v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); // swap 2-byte long pairs v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); // swap 4-byte long pairs v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); // swap 8-byte long pairs v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) | ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); // swap 16-byte long pairs v = (v >> 128) | (v << 128); } }
{ "remappings": [ "bn254/=contracts/lib/bn254/src/", "ds-test/=contracts/lib/forge-std/lib/ds-test/src/", "forge-std/=contracts/lib/forge-std/src/", "solidity-bytes-utils/=contracts/lib/solidity-bytes-utils/contracts/", "solmate/=contracts/lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
[{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"expectedBlockNumber","type":"uint256"}],"name":"IncorrectBlockNumber","type":"error"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"InvalidQC","type":"error"},{"inputs":[],"name":"NoKeySelected","type":"error"},{"inputs":[],"name":"NotEnoughStake","type":"error"},{"inputs":[{"internalType":"uint256","name":"numBlocks","type":"uint256"}],"name":"TooManyBlocks","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"firstBlockNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numBlocks","type":"uint256"}],"name":"NewBlocks","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"BN254.BaseField","name":"x0","type":"uint256"},{"internalType":"BN254.BaseField","name":"x1","type":"uint256"},{"internalType":"BN254.BaseField","name":"y0","type":"uint256"},{"internalType":"BN254.BaseField","name":"y1","type":"uint256"}],"indexed":false,"internalType":"struct BN254.G2Point","name":"stakingKey","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"NewStakingKey","type":"event"},{"inputs":[],"name":"MAX_BLOCKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"BN254.BaseField","name":"x0","type":"uint256"},{"internalType":"BN254.BaseField","name":"x1","type":"uint256"},{"internalType":"BN254.BaseField","name":"y0","type":"uint256"},{"internalType":"BN254.BaseField","name":"y1","type":"uint256"}],"internalType":"struct BN254.G2Point","name":"stakingKey","type":"tuple"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addNewStakingKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"blockHeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockHeight","type":"uint256"}],"name":"commitments","outputs":[{"internalType":"uint256","name":"commitment","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getStakingKey","outputs":[{"components":[{"internalType":"BN254.BaseField","name":"x0","type":"uint256"},{"internalType":"BN254.BaseField","name":"x1","type":"uint256"},{"internalType":"BN254.BaseField","name":"y0","type":"uint256"},{"internalType":"BN254.BaseField","name":"y1","type":"uint256"}],"internalType":"struct BN254.G2Point","name":"","type":"tuple"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"height","type":"uint256"},{"internalType":"uint256","name":"blockCommitment","type":"uint256"},{"internalType":"uint256","name":"pad1","type":"uint256"},{"internalType":"uint256","name":"pad2","type":"uint256"}],"internalType":"struct HotShot.QC[]","name":"qcs","type":"tuple[]"}],"name":"newBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100625760003560e01c80630a321cff1461006757806326833dcc1461007c57806349ce89971461009857806367a21e70146100b8578063f1f45d9914610102578063f44ff71214610115575b600080fd5b61007a61007536600461044e565b61011e565b005b6100856101f481565b6040519081526020015b60405180910390f35b6100856100a63660046104c3565b60006020819052908152604090205481565b6100cb6100c63660046104c3565b610292565b604080518351815260208085015190820152838201519181019190915260609283015192810192909252608082015260a00161008f565b61007a6101103660046104dc565b610326565b61008560015481565b6101f48111156101495760405163e082840b60e01b8152600481018290526024015b60405180910390fd5b60015460005b828110156102525760015484848381811061016c5761016c610562565b90506080020160000135146101be5783838281811061018d5761018d610562565b905060800201600001356001546040516334e423ff60e01b8152600401610140929190918252602082015260400190565b6101dc8484838181106101d3576101d3610562565b90505050600190565b6101ff57600154604051637818671960e01b815260040161014091815260200190565b83838281811061021157610211610562565b9050608002016020013560008060015481526020019081526020016000208190555060018060008282546102459190610578565b909155505060010161014f565b5060408051828152602081018490527f8203a21e4f95f72e5081d5e0929b1a8c52141e123f9a14e1e74b0260fa5f52f191015b60405180910390a1505050565b6102bd6040518060800160405280600081526020016000815260200160008152602001600081525090565b6000600383815481106102d2576102d2610562565b60009182526020808320958352600280825260409384902054845160808101865260049094029097018054845260018101549284019290925281015492820192909252600390910154606082015293915050565b600380546000818152600260209081526040808320869055845460018101865594909252855160049094027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810185905586820180517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c83015587840180517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d8401556060808a0180517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85e9095019490945585519788529151938701939093529151928501929092529051908301526080820183905260a08201819052907fd72fe1ac57d3e6d51c922ae4d811cc50aa3ad7026283aea637494a073252565a9060c001610285565b6000806020838503121561046157600080fd5b823567ffffffffffffffff8082111561047957600080fd5b818501915085601f83011261048d57600080fd5b81358181111561049c57600080fd5b8660208260071b85010111156104b157600080fd5b60209290920196919550909350505050565b6000602082840312156104d557600080fd5b5035919050565b60008082840360a08112156104f057600080fd5b60808112156104fe57600080fd5b506040516080810181811067ffffffffffffffff8211171561053057634e487b7160e01b600052604160045260246000fd5b604090815284358252602080860135908301528481013590820152606080850135908201529460809093013593505050565b634e487b7160e01b600052603260045260246000fd5b8082018082111561059957634e487b7160e01b600052601160045260246000fd5b9291505056fea164736f6c6343000817000a
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.