@@ -39,8 +39,9 @@ library BlockHistory {
3939 error InvalidProofBlockHash ();
4040 error InvalidProofBlockHeight ();
4141 error InvalidProofCumulativeWork ();
42- error InvalidProof ();
42+ error InvalidProofEpochStartTime ();
4343 error InvalidHistoryBlocksTreeRoot ();
44+ error InvalidProof ();
4445
4546 /**
4647 * @notice Verifies a ZK-SNARK proof for the Bitcoin history.
@@ -55,6 +56,7 @@ library BlockHistory {
5556 bytes32 historyBlocksTreeRoot_ ,
5657 bytes32 blockHash_ ,
5758 uint64 blockHeight_ ,
59+ uint32 currentEpochStartTime_ ,
5860 uint256 cumulativeWork_ ,
5961 HistoryProofData calldata proofData_
6062 ) internal view returns (bool ) {
@@ -64,6 +66,10 @@ library BlockHistory {
6466 cumulativeWork_ == getProofCumulativeWork (proofData_),
6567 InvalidProofCumulativeWork ()
6668 );
69+ require (
70+ currentEpochStartTime_ == getProofEpochStartTime (blockHeight_ + 1 , proofData_),
71+ InvalidProofEpochStartTime ()
72+ );
6773 require (
6874 historyBlocksTreeRoot_ == getHistoryBlocksTreeRoot (blockHeight_ + 1 , proofData_),
6975 InvalidHistoryBlocksTreeRoot ()
@@ -180,11 +186,9 @@ library BlockHistory {
180186 uint64 provedBlocksCount_ ,
181187 HistoryProofData calldata proofData_
182188 ) internal pure returns (bytes32 parsedBlocksTreeRoot_ ) {
183- uint256 frontierLength_ = Math.log2 (provedBlocksCount_ / CHUNK_SIZE) + 1 ;
184-
185- bool isPowOf2_ = provedBlocksCount_ & (provedBlocksCount_ - 1 ) == 0 ;
189+ uint256 frontierLength_ = _countFrontierLength (provedBlocksCount_);
186190
187- if (isPowOf2_ ) {
191+ if (LibBit. isPo2 (provedBlocksCount_) ) {
188192 parsedBlocksTreeRoot_ = _getBytes32FromInputs (
189193 proofData_,
190194 PROOF_FRONTIER_OFFSET + 32 * (frontierLength_ - 1 )
@@ -227,6 +231,26 @@ library BlockHistory {
227231 return uint256 (proofData_.publicInputs[PROOF_CUMULATIVE_WORK_OFFSET]);
228232 }
229233
234+ /**
235+ * @notice Retrieves the last proved epoch start time from the ZK proof's public inputs.
236+ * @param provedBlocksCount_ The total number of blocks included in the proof.
237+ * @param proofData_ The struct containing the proof and public inputs.
238+ * @return The epoch start time.
239+ */
240+ function getProofEpochStartTime (
241+ uint64 provedBlocksCount_ ,
242+ HistoryProofData calldata proofData_
243+ ) internal pure returns (uint32 ) {
244+ return
245+ uint32 (
246+ uint256 (
247+ proofData_.publicInputs[
248+ PROOF_FRONTIER_OFFSET + 32 * _countFrontierLength (provedBlocksCount_)
249+ ]
250+ )
251+ );
252+ }
253+
230254 /**
231255 * @notice Calculates the chunk number for a given block height.
232256 * @param blockHeight_ The height of the block.
@@ -322,7 +346,7 @@ library BlockHistory {
322346 uint256 frontierLength_ ,
323347 HistoryProofData calldata proofData_
324348 ) internal pure returns (bytes32 computedRoot_ ) {
325- for (uint256 i = 0 ; i < frontierLength_; ++ i) {
349+ for (uint256 i = 0 ; i < frontierLength_ - 1 ; ++ i) {
326350 bytes32 currentNode_ = _getBytes32FromInputs (
327351 proofData_,
328352 PROOF_FRONTIER_OFFSET + 32 * i
@@ -348,6 +372,10 @@ library BlockHistory {
348372 }
349373 }
350374
375+ function _countFrontierLength (uint64 provedBlocksCount_ ) private pure returns (uint256 ) {
376+ return Math.log2 (provedBlocksCount_ / CHUNK_SIZE, Math.Rounding.Ceil) + 1 ;
377+ }
378+
351379 function _processProof (
352380 bytes32 [] calldata merkleProof_ ,
353381 bytes32 value_ ,
0 commit comments