Commit f0f6aa7c authored by clabby's avatar clabby Committed by GitHub

feat(ctb): Blob preimage type in `PreimageOracle` (#9095)

* Add blob preimage type

* Compute versioned hash correctly

* Version byte bump

* @protolambda review

* @refcell review

* rebase
parent 89ea67df
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -1120,10 +1120,10 @@ ...@@ -1120,10 +1120,10 @@
"impact": "Medium", "impact": "Medium",
"confidence": "Medium", "confidence": "Medium",
"check": "uninitialized-local", "check": "uninitialized-local",
"description": "PreimageOracle.challengeFirstLPP(address,uint256,PreimageOracle.Leaf,bytes32[]).stateMatrix (src/cannon/PreimageOracle.sol#446) is a local variable never initialized\n", "description": "PreimageOracle.challengeFirstLPP(address,uint256,PreimageOracle.Leaf,bytes32[]).stateMatrix (src/cannon/PreimageOracle.sol#534) is a local variable never initialized\n",
"type": "variable", "type": "variable",
"name": "stateMatrix", "name": "stateMatrix",
"start": 20750, "start": 25088,
"length": 40, "length": 40,
"filename_relative": "src/cannon/PreimageOracle.sol" "filename_relative": "src/cannon/PreimageOracle.sol"
}, },
......
...@@ -263,6 +263,39 @@ ...@@ -263,6 +263,39 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [
{
"internalType": "uint256",
"name": "_z",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_y",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_commitment",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_proof",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "_partOffset",
"type": "uint256"
}
],
"name": "loadBlobPreimagePart",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
......
...@@ -159,24 +159,23 @@ contract PreimageOracle is IPreimageOracle { ...@@ -159,24 +159,23 @@ contract PreimageOracle is IPreimageOracle {
// revert if part offset >= size+8 (i.e. parts must be within bounds) // revert if part offset >= size+8 (i.e. parts must be within bounds)
if iszero(lt(_partOffset, add(size, 8))) { if iszero(lt(_partOffset, add(size, 8))) {
// Store "PartOffsetOOB()" // Store "PartOffsetOOB()"
mstore(0, 0xfe254987) mstore(0x00, 0xfe254987)
// Revert with "PartOffsetOOB()" // Revert with "PartOffsetOOB()"
revert(0x1c, 4) revert(0x1c, 0x04)
} }
// we leave solidity slots 0x40 and 0x60 untouched, // we leave solidity slots 0x40 and 0x60 untouched, and everything after as scratch-memory.
// and everything after as scratch-memory.
let ptr := 0x80 let ptr := 0x80
// put size as big-endian uint64 at start of pre-image // put size as big-endian uint64 at start of pre-image
mstore(ptr, shl(192, size)) mstore(ptr, shl(192, size))
ptr := add(ptr, 8) ptr := add(ptr, 0x08)
// copy preimage payload into memory so we can hash and read it. // copy preimage payload into memory so we can hash and read it.
calldatacopy(ptr, _preimage.offset, size) calldatacopy(ptr, _preimage.offset, size)
// Note that it includes the 8-byte big-endian uint64 length prefix. // Note that it includes the 8-byte big-endian uint64 length prefix.
// this will be zero-padded at the end, since memory at end is clean. // this will be zero-padded at the end, since memory at end is clean.
part := mload(add(sub(ptr, 8), _partOffset)) part := mload(add(sub(ptr, 0x08), _partOffset))
let h := keccak256(ptr, size) // compute preimage keccak256 hash let h := keccak256(ptr, size) // compute preimage keccak256 hash
// mask out prefix byte, replace with type 2 byte // mask out prefix byte, replace with type 2 byte
key := or(and(h, not(shl(248, 0xFF))), shl(248, 2)) key := or(and(h, not(shl(248, 0xFF))), shl(248, 0x02))
} }
preimagePartOk[key][_partOffset] = true; preimagePartOk[key][_partOffset] = true;
preimageParts[key][_partOffset] = part; preimageParts[key][_partOffset] = part;
...@@ -232,7 +231,96 @@ contract PreimageOracle is IPreimageOracle { ...@@ -232,7 +231,96 @@ contract PreimageOracle is IPreimageOracle {
preimageLengths[key] = size; preimageLengths[key] = size;
} }
// TODO 4844 point-evaluation preimage /// @inheritdoc IPreimageOracle
function loadBlobPreimagePart(
uint256 _z,
uint256 _y,
bytes calldata _commitment,
bytes calldata _proof,
uint256 _partOffset
)
external
{
bytes32 key;
bytes32 part;
assembly {
// Compute the versioned hash. The SHA2 hash of the 48 byte commitment is masked with the version byte,
// which is currently 1. https://eips.ethereum.org/EIPS/eip-4844#parameters
// SAFETY: We're only reading 48 bytes from `_commitment` into scratch space, so we're not reading into the
// free memory ptr region. Since the exact number of btyes that is copied into scratch space is
// the same size as the hash input, there's no concern of dirty memory being read into the hash
// input.
calldatacopy(0x00, _commitment.offset, 0x30)
let success := staticcall(gas(), 0x02, 0x00, 0x30, 0x00, 0x20)
if iszero(success) {
// Store the "ShaFailed()" error selector.
mstore(0x00, 0xf9112969)
// revert with "ShaFailed()"
revert(0x1C, 0x04)
}
// Set the `VERSIONED_HASH_VERSION_KZG` byte = 1 in the high-order byte of the hash.
let versionedHash := or(and(mload(0x00), not(shl(248, 0xFF))), shl(248, 0x01))
// we leave solidity slots 0x40 and 0x60 untouched, and everything after as scratch-memory.
let ptr := 0x80
// Load the inputs for the point evaluation precompile into memory. The inputs to the point evaluation
// precompile are packed, and not supposed to be ABI-encoded.
mstore(ptr, versionedHash)
mstore(add(ptr, 0x20), _z)
mstore(add(ptr, 0x40), _y)
calldatacopy(add(ptr, 0x60), _commitment.offset, 0x30)
calldatacopy(add(ptr, 0x90), _proof.offset, 0x30)
// Verify the KZG proof by calling the point evaluation precompile. If the proof is invalid, the precompile
// will revert.
success :=
staticcall(
gas(), // forward all gas
0x0A, // point evaluation precompile address
ptr, // input ptr
0xC0, // input size = 192 bytes
0x00, // output ptr
0x00 // output size
)
if iszero(success) {
// Store the "InvalidProof()" error selector.
mstore(0x00, 0x09bde339)
// revert with "InvalidProof()"
revert(0x1C, 0x04)
}
// revert if part offset >= 32+8 (i.e. parts must be within bounds)
if iszero(lt(_partOffset, 0x28)) {
// Store "PartOffsetOOB()"
mstore(0x00, 0xfe254987)
// Revert with "PartOffsetOOB()"
revert(0x1C, 0x04)
}
// Clean the word at `ptr + 0x28` to ensure that data out of bounds of the preimage is zero, if the part
// offset requires a partial read.
mstore(add(ptr, 0x28), 0x00)
// put size (32) as a big-endian uint64 at start of pre-image
mstore(ptr, shl(192, 0x20))
// copy preimage payload into memory so we can hash and read it.
mstore(add(ptr, 0x08), _y)
// Note that it includes the 8-byte big-endian uint64 length prefix. This will be zero-padded at the end,
// since memory at end is guaranteed to be clean.
part := mload(add(ptr, _partOffset))
// Compute the key: `keccak256(commitment ++ z)`. Since the exact number of btyes that is copied into
// scratch space is the same size as the hash input, there's no concern of dirty memory being read into
// the hash input.
calldatacopy(ptr, _commitment.offset, 0x30)
mstore(add(ptr, 0x30), _z)
let h := keccak256(ptr, 0x50)
// mask out prefix byte, replace with type 5 byte
key := or(and(h, not(shl(248, 0xFF))), shl(248, 0x05))
}
preimagePartOk[key][_partOffset] = true;
preimageParts[key][_partOffset] = part;
preimageLengths[key] = 32;
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Large Preimage Proposals (External) // // Large Preimage Proposals (External) //
......
...@@ -53,4 +53,20 @@ interface IPreimageOracle { ...@@ -53,4 +53,20 @@ interface IPreimageOracle {
/// @param _partOffset The offset of the preimage to read. /// @param _partOffset The offset of the preimage to read.
/// @param _preimage The preimage data. /// @param _preimage The preimage data.
function loadSha256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external; function loadSha256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external;
/// @notice Verifies that `p(_z) = _y` given `_commitment` that corresponds to the polynomial `p(x)` and a KZG
// proof. The value `y` is the pre-image, and the preimage key is `5 ++ keccak256(_commitment ++ z)[1:]`.
/// @param _z Big endian point value. Part of the preimage key.
/// @param _y Big endian point value. The preimage for the key.
/// @param _commitment The commitment to the polynomial. 48 bytes, part of the preimage key.
/// @param _proof The KZG proof, part of the preimage key.
/// @param _partOffset The offset of the preimage to store.
function loadBlobPreimagePart(
uint256 _z,
uint256 _y,
bytes calldata _commitment,
bytes calldata _proof,
uint256 _partOffset
)
external;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment