Skip to content

Commit 7065367

Browse files
committed
feat: proof aggregation service contract
1 parent a0aa4af commit 7065367

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@
3131
[submodule "claim_contracts/lib/openzeppelin-contracts"]
3232
path = claim_contracts/lib/openzeppelin-contracts
3333
url = https://github.com/OpenZeppelin/openzeppelin-contracts
34+
[submodule "contracts/lib/sp1-contracts"]
35+
path = contracts/lib/sp1-contracts
36+
url = https://github.com/succinctlabs/sp1-contracts

contracts/remappings.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ eigenlayer-scripts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/script/
55
forge-std/=lib/forge-std/src/
66
@openzeppelin/contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/contracts/
77
@openzeppelin-upgrades/contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/
8+
@sp1-contracts/=lib/sp1-contracts/contracts/src/
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.12;
3+
4+
import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
5+
import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
6+
import {UUPSUpgradeable} from "@openzeppelin-upgrades/contracts/proxy/utils/UUPSUpgradeable.sol";
7+
import {IAlignedProofAggregationService} from "./IAlignedProofAggregationService.sol";
8+
import {ISP1Verifier} from "@sp1-contracts/ISP1Verifier.sol";
9+
10+
contract AlignedProofAggregationService is
11+
IAlignedProofAggregationService,
12+
Initializable,
13+
OwnableUpgradeable,
14+
UUPSUpgradeable
15+
{
16+
/// @notice Maps the aggregated verification merkle root with the blob transaction hash that contains the leaves
17+
uint64 public currentAggregatedProofNumber;
18+
mapping(uint64 => AggregatedProof) public aggregatedProofs;
19+
20+
/// @notice The address of the SP1 verifier contract.
21+
/// @dev This can either be a specific SP1Verifier for a specific version, or the
22+
/// SP1VerifierGateway which can be used to verify proofs for any version of SP1.
23+
/// For the list of supported verifiers on each chain, see:
24+
/// https://docs.succinct.xyz/onchain-verification/contract-addresses
25+
address public sp1VerifierAddress;
26+
27+
address public alignedAggregatorAddress;
28+
29+
/// @notice whether we are in dev mode or not
30+
/// if the sp1 verifier address is set to this address, then we skip verification
31+
address public constant VERIFIER_MOCK_ADDRESS = address(0xFF);
32+
33+
constructor() {
34+
_disableInitializers();
35+
}
36+
37+
function initialize(address newOwner, address _alignedAggregatorAddress, address _sp1VerifierAddress)
38+
public
39+
initializer
40+
{
41+
__Ownable_init();
42+
__UUPSUpgradeable_init();
43+
_transferOwnership(newOwner);
44+
alignedAggregatorAddress = _alignedAggregatorAddress;
45+
sp1VerifierAddress = _sp1VerifierAddress;
46+
}
47+
48+
function verify(
49+
bytes32 blobTransactionHash,
50+
bytes32 sp1ProgramVKey,
51+
bytes calldata sp1PublicValues,
52+
bytes calldata sp1ProofBytes
53+
) public onlyAlignedAggregator {
54+
// In dev mode, poofs are mocked, so we skip the verification part
55+
if (sp1VerifierAddress == VERIFIER_MOCK_ADDRESS) {
56+
(bytes32 merkleRoot) = abi.decode(sp1PublicValues, (bytes32));
57+
_newAggregatedProof(merkleRoot, blobTransactionHash);
58+
return;
59+
}
60+
61+
try ISP1Verifier(sp1VerifierAddress).verifyProof(sp1ProgramVKey, sp1PublicValues, sp1ProofBytes) {
62+
(bytes32 merkleRoot) = abi.decode(sp1PublicValues, (bytes32));
63+
_newAggregatedProof(merkleRoot, blobTransactionHash);
64+
} catch {
65+
emit AggregatedProofFailed(currentAggregatedProofNumber);
66+
}
67+
}
68+
69+
function markCurrentAggregatedProofAsMissed() public onlyAlignedAggregator {
70+
emit AggregatedProofMissed(currentAggregatedProofNumber);
71+
currentAggregatedProofNumber += 1;
72+
}
73+
74+
function _newAggregatedProof(bytes32 merkleRoot, bytes32 blobHash) internal {
75+
AggregatedProof storage proof = aggregatedProofs[currentAggregatedProofNumber];
76+
proof.merkleRoot = merkleRoot;
77+
proof.blobHash = blobHash;
78+
proof.status = AggregatedProofStatus.Verified;
79+
emit NewAggregatedProofVerified(currentAggregatedProofNumber, merkleRoot, blobHash);
80+
currentAggregatedProofNumber += 1;
81+
}
82+
83+
function _authorizeUpgrade(address newImplementation)
84+
internal
85+
override
86+
onlyOwner // solhint-disable-next-line no-empty-blocks
87+
{}
88+
89+
modifier onlyAlignedAggregator() {
90+
if (msg.sender != alignedAggregatorAddress) {
91+
revert OnlyAlignedAggregator(msg.sender);
92+
}
93+
_;
94+
}
95+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
pragma solidity ^0.8.12;
2+
3+
interface IAlignedProofAggregationService {
4+
/// @notice aggregated proof status
5+
/// Verified -> Verification was successful
6+
/// Failed -> Verification failed
7+
/// Missed -> Internal error in the aligned service could not send the aggregated proof to verify
8+
enum AggregatedProofStatus {
9+
Verified,
10+
Failed,
11+
Missed
12+
}
13+
14+
/// @notice aggregated proof
15+
/// Status -> proof status
16+
/// blobHash -> the hash of the blob transaction containing the hashes of all the proofs that have been aggregated
17+
/// merkleRoot -> the committed merkle root in the aggregated
18+
struct AggregatedProof {
19+
AggregatedProofStatus status;
20+
bytes32 blobHash;
21+
bytes32 merkleRoot;
22+
}
23+
24+
/// @notice Method to verify an aggregated proof from aligned
25+
/// @dev This function is called by the aligned proof aggregator after collecting the proofs and aggregating them
26+
/// to be verified on-chain. We expect the blobTransactionHash to be called before
27+
/// @param blobTransactionHash the hash of the blob transaction that contains the leaves that compose the merkle root.
28+
/// @param sp1ProgramVKey Public verifying key
29+
/// @param sp1PublicValues Values used to perform the execution
30+
/// @param sp1ProofBytes Groth16 proof
31+
function verify(
32+
bytes32 blobTransactionHash,
33+
bytes32 sp1ProgramVKey,
34+
bytes calldata sp1PublicValues,
35+
bytes calldata sp1ProofBytes
36+
) external;
37+
38+
function markCurrentAggregatedProofAsMissed() external;
39+
40+
/// @notice event that gets emitted after a successful aggregated proof verification
41+
event NewAggregatedProofVerified(uint64 indexed proofNumber, bytes32 merkleRoot, bytes32 blobTransactionHash);
42+
/// @notice event that gets emitted after a successful aggregated proof verification
43+
event AggregatedProofMissed(uint64 indexed proofNumber);
44+
/// @notice event that gets emitted after a successful aggregated proof verification
45+
event AggregatedProofFailed(uint64 indexed proofNumber);
46+
47+
error OnlyAlignedAggregator(address sender);
48+
}

0 commit comments

Comments
 (0)