Skip to content

Commit 241058f

Browse files
authored
feat: release v1.4 (#16)
1 parent 61e4fa2 commit 241058f

File tree

10 files changed

+2306
-1633
lines changed

10 files changed

+2306
-1633
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ forge install openvm-org/openvm-solidity-sdk
1919
If you are using a deployed instance of the verifier contract, then you can import the interfaces in your contract directly.
2020

2121
```solidity
22-
import { IOpenVmHalo2Verifier } from "openvm-solidity-sdk/v1.3/interfaces/IOpenVmHalo2Verifier.sol";
22+
import { IOpenVmHalo2Verifier } from "openvm-solidity-sdk/v1.4/interfaces/IOpenVmHalo2Verifier.sol";
2323
2424
contract MyContract {
2525
function myFunction() public view {
@@ -36,7 +36,7 @@ contract MyContract {
3636
If you want to deploy your own instance of the verifier contract, you can use `forge create`:
3737

3838
```bash
39-
forge create src/v1.3/OpenVmHalo2Verifier.sol:OpenVmHalo2Verifier --rpc-url $RPC --private-key $PRIVATE_KEY --broadcast
39+
forge create src/v1.4/OpenVmHalo2Verifier.sol:OpenVmHalo2Verifier --rpc-url $RPC --private-key $PRIVATE_KEY --broadcast
4040
```
4141

4242
If you want to import the verifier contract into your own repository for testing purposes, note that it is locked to Solidity version `0.8.19`. If your project uses a different version, the import may not compile. As a workaround, you can compile the contract separately and use `vm.etch()` to inject the raw bytecode into your tests.

foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ optimizer = true
88
optimizer_runs = 100000
99
evm_version = "paris"
1010
show_progress = true
11-
fs_permissions = [{ access = "read", path = "./test/v1.2/evm.proof"}, { access = "read", path = "./test/v1.3/evm.proof"}]
11+
fs_permissions = [{ access = "read", path = "./test/v1.2/evm.proof"}, { access = "read", path = "./test/v1.3/evm.proof"}, { access = "read", path = "./test/v1.4/evm.proof"}]
1212

1313
[profile.default.optimizer_details]
1414
constantOptimizer = false

src/v1.4/Halo2Verifier.sol

Lines changed: 2036 additions & 0 deletions
Large diffs are not rendered by default.

src/v1.4/OpenVmHalo2Verifier.sol

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.19;
3+
4+
import { Halo2Verifier } from "./Halo2Verifier.sol";
5+
import { IOpenVmHalo2Verifier } from "./interfaces/IOpenVmHalo2Verifier.sol";
6+
7+
type MemoryPointer is uint256;
8+
9+
/// @notice This contract provides a thin wrapper around the Halo2 verifier
10+
/// outputted by `snark-verifier`, exposing a more user-friendly interface.
11+
contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
12+
/// @dev Invalid public values length
13+
error InvalidPublicValuesLength(uint256 expected, uint256 actual);
14+
15+
/// @dev Invalid proof data length
16+
error InvalidProofDataLength(uint256 expected, uint256 actual);
17+
18+
/// @dev Proof verification failed
19+
error ProofVerificationFailed();
20+
21+
/// @dev The length of the proof data, in bytes.
22+
uint256 private constant PROOF_DATA_LENGTH = (12 + 43) * 32;
23+
24+
/// @dev The length of the public values, in bytes. This value is set by
25+
/// OpenVM and is guaranteed to be no larger than 8192.
26+
uint256 private constant PUBLIC_VALUES_LENGTH = 32;
27+
28+
/// @dev The length of the full proof, in bytes
29+
uint256 private constant FULL_PROOF_LENGTH = (12 + 2 + PUBLIC_VALUES_LENGTH + 43) * 32;
30+
31+
/// @dev The version of OpenVM that generated this verifier.
32+
string public constant OPENVM_VERSION = "1.4";
33+
34+
/// @notice A wrapper that constructs the proof into the right format for
35+
/// use with the `snark-verifier` verification.
36+
///
37+
/// @dev The verifier expected proof format is:
38+
/// proof[..12 * 32]: KZG accumulator
39+
/// proof[12 * 32..13 * 32]: app exe commit
40+
/// proof[13 * 32..14 * 32]: app vm commit
41+
/// proof[14 * 32..(14 + PUBLIC_VALUES_LENGTH) * 32]: publicValues[0..PUBLIC_VALUES_LENGTH]
42+
/// proof[(14 + PUBLIC_VALUES_LENGTH) * 32..]: Proof Suffix
43+
///
44+
/// @param publicValues The PVs revealed by the OpenVM guest program.
45+
/// @param proofData All components of the proof except the public values and
46+
/// app exe and vm commits. The expected format is:
47+
/// `abi.encodePacked(kzgAccumulator, proofSuffix)`
48+
/// @param appExeCommit The commitment to the OpenVM application executable whose execution
49+
/// is being verified.
50+
/// @param appVmCommit The commitment to the VM configuration.
51+
function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit)
52+
external
53+
view
54+
{
55+
if (publicValues.length != PUBLIC_VALUES_LENGTH) {
56+
revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH, publicValues.length);
57+
}
58+
if (proofData.length != PROOF_DATA_LENGTH) revert InvalidProofDataLength(PROOF_DATA_LENGTH, proofData.length);
59+
60+
// We will format the public values and construct the full proof payload
61+
// below.
62+
63+
MemoryPointer proofPtr = _constructProof(publicValues, proofData, appExeCommit, appVmCommit);
64+
65+
uint256 fullProofLength = FULL_PROOF_LENGTH;
66+
67+
/// @solidity memory-safe-assembly
68+
assembly {
69+
// Self-call using the proof as calldata
70+
if iszero(staticcall(gas(), address(), proofPtr, fullProofLength, 0, 0)) {
71+
mstore(0x00, 0xd611c318) // ProofVerificationFailed()
72+
revert(0x1c, 0x04)
73+
}
74+
}
75+
}
76+
77+
/// @dev The assembly code should perform the same function as the following
78+
/// solidity code:
79+
//
80+
/// ```solidity
81+
/// bytes memory proof =
82+
/// abi.encodePacked(proofData[0:0x180], appExeCommit, appVmCommit, publicValuesPayload, proofData[0x180:]);
83+
/// ```
84+
//
85+
/// where `publicValuesPayload` is a memory payload with each byte in
86+
/// `publicValues` separated into its own `bytes32` word.
87+
///
88+
/// This function does not clean the memory it allocates. Since it is the
89+
/// only memory write that occurs in the call frame, we know that
90+
/// the memory region cannot have been dirtied.
91+
///
92+
/// @return proofPtr Memory pointer to the beginning of the constructed
93+
/// proof. This pointer does not follow `bytes memory` semantics.
94+
function _constructProof(
95+
bytes calldata publicValues,
96+
bytes calldata proofData,
97+
bytes32 appExeCommit,
98+
bytes32 appVmCommit
99+
) internal pure returns (MemoryPointer proofPtr) {
100+
uint256 fullProofLength = FULL_PROOF_LENGTH;
101+
102+
// The expected proof format using hex offsets:
103+
//
104+
// proof[..0x180]: KZG accumulator
105+
// proof[0x180..0x1a0]: app exe commit
106+
// proof[0x1a0..0x1c0]: app vm commit
107+
// proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValues[0..PUBLIC_VALUES_LENGTH]
108+
// proof[(0x1c0 + PUBLIC_VALUES_LENGTH * 32)..]: Proof Suffix
109+
110+
/// @solidity memory-safe-assembly
111+
assembly {
112+
proofPtr := mload(0x40)
113+
// Allocate the memory as a safety measure.
114+
mstore(0x40, add(proofPtr, fullProofLength))
115+
116+
// Copy the KZG accumulator (length 0x180) into the beginning of
117+
// the memory buffer
118+
calldatacopy(proofPtr, proofData.offset, 0x180)
119+
120+
// Copy the App Exe Commit and App Vm Commit into the memory buffer
121+
mstore(add(proofPtr, 0x180), appExeCommit)
122+
mstore(add(proofPtr, 0x1a0), appVmCommit)
123+
124+
// Copy the Proof Suffix (length 43 * 32 = 0x560) into the
125+
// end of the memory buffer, leaving PUBLIC_VALUES_LENGTH words in
126+
// between for the publicValuesPayload.
127+
//
128+
// Begin copying from the end of the KZG accumulator in the
129+
// calldata buffer (0x180)
130+
let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH))
131+
calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560)
132+
133+
// Copy each byte of the public values into the proof. It copies the
134+
// most significant bytes of public values first.
135+
let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f)
136+
for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } {
137+
calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, i), 0x01)
138+
}
139+
}
140+
}
141+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
interface IOpenVmHalo2Verifier {
5+
function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit)
6+
external
7+
view;
8+
}

0 commit comments

Comments
 (0)