gen_vk_contract/
main.rs

1//! This executable generates the solidity files with hardcoded verifying keys for
2//! LightClient updates by running `cargo run -p gen-vk-contract --release`.
3//! LightClientMock updates by running `cargo run -p gen-vk-contract --release -- --mock`.
4//! Adapted from [CAPE project][https://github.com/EspressoSystems/cape/blob/main/contracts/rust/src/bin/gen-vk-libraries.rs]
5
6use std::{fs::OpenOptions, io::Write, path::PathBuf, process::Command};
7
8use alloy::hex::ToHexExt;
9use clap::Parser;
10use hotshot_contract_adapter::sol_types::VerifyingKeySol;
11use hotshot_types::light_client::DEFAULT_STAKE_TABLE_CAPACITY;
12use jf_pcs::prelude::UnivariateUniversalParams;
13
14#[derive(Parser)]
15struct Cli {
16    /// indicate if it's for the mock verification key
17    #[arg(long, default_value_t = false)]
18    mock: bool,
19}
20
21fn main() {
22    let mock = Cli::parse().mock;
23
24    let srs = {
25        // load SRS from Aztec's ceremony
26        let srs = if mock {
27            ark_srs::kzg10::aztec20::setup(2u64.pow(16) as usize + 2)
28                .expect("Aztec SRS fail to load")
29        } else {
30            ark_srs::kzg10::aztec20::setup(2u64.pow(20) as usize + 2)
31                .expect("Aztec SRS fail to load")
32        };
33        // convert to Jellyfish type
34        // TODO: (alex) use constructor instead https://github.com/EspressoSystems/jellyfish/issues/440
35        UnivariateUniversalParams {
36            powers_of_g: srs.powers_of_g,
37            h: srs.h,
38            beta_h: srs.beta_h,
39            powers_of_h: vec![srs.h, srs.beta_h],
40        }
41    };
42    let (_, vk) = if mock {
43        hotshot_state_prover::preprocess(&srs, 10).expect("Circuit preprocess failed")
44    } else {
45        hotshot_state_prover::preprocess(&srs, DEFAULT_STAKE_TABLE_CAPACITY)
46            .expect("Circuit preprocess failed")
47    };
48    let vk: VerifyingKeySol = vk.into();
49
50    // calculate the path to solidity file
51    let contract_name = if mock {
52        "LightClientStateUpdateVKMock"
53    } else {
54        "LightClientStateUpdateVK"
55    };
56    let mut path = PathBuf::new();
57    path.push(env!("CARGO_MANIFEST_DIR"));
58    path.pop();
59    path.pop();
60    if mock {
61        path.push("test/mocks");
62    } else {
63        path.push("src/libraries");
64    }
65    path.push(contract_name);
66    path.set_extension("sol");
67    println!("Path:{:?}", path.to_str());
68
69    // overwrite the file
70    let mut file = OpenOptions::new()
71        .write(true)
72        .create(true)
73        .truncate(true)
74        .open(path)
75        .unwrap();
76
77    let import_path = if mock {
78        "import { IPlonkVerifier } from \"../../src/interfaces/IPlonkVerifier.sol\";"
79    } else {
80        "import { IPlonkVerifier } from \"../interfaces/IPlonkVerifier.sol\";"
81    };
82
83    let code = format!(
84                "// SPDX-License-Identifier: GPL-3.0-or-later
85    //
86    // Copyright (c) 2023 Espresso Systems (espressosys.com)
87    // This file is part of the Espresso Sequencer project.
88    //
89    // 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.
90    // 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.
91    // You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
92
93    // NOTE: DO NOT MODIFY! GENERATED BY SCRIPT VIA `cargo run --bin gen-vk-contract --release`.
94    pragma solidity ^0.8.0;
95
96    {}
97
98    /* solhint-disable no-inline-assembly */
99
100    library {} {{
101        function getVk() internal pure returns (IPlonkVerifier.VerifyingKey memory vk) {{
102            assembly {{
103                // domain size
104                mstore(vk, {})
105                // num of public inputs
106                mstore(add(vk, 0x20), {})
107
108                // sigma0
109                mstore(mload(add(vk, 0x40)), {})
110                mstore(add(mload(add(vk, 0x40)), 0x20), {})
111                // sigma1
112                mstore(mload(add(vk, 0x60)), {})
113                mstore(add(mload(add(vk, 0x60)), 0x20), {})
114                // sigma2
115                mstore(mload(add(vk, 0x80)), {})
116                mstore(add(mload(add(vk, 0x80)), 0x20), {})
117                // sigma3
118                mstore(mload(add(vk, 0xa0)), {})
119                mstore(add(mload(add(vk, 0xa0)), 0x20), {})
120                // sigma4
121                mstore(mload(add(vk, 0xc0)), {})
122                mstore(add(mload(add(vk, 0xc0)), 0x20), {})
123
124                // q1
125                mstore(mload(add(vk, 0xe0)), {})
126                mstore(add(mload(add(vk, 0xe0)), 0x20), {})
127                // q2
128                mstore(mload(add(vk, 0x100)), {})
129                mstore(add(mload(add(vk, 0x100)), 0x20), {})
130                // q3
131                mstore(mload(add(vk, 0x120)), {})
132                mstore(add(mload(add(vk, 0x120)), 0x20), {})
133                // q4
134                mstore(mload(add(vk, 0x140)), {})
135                mstore(add(mload(add(vk, 0x140)), 0x20), {})
136
137                // qM12
138                mstore(mload(add(vk, 0x160)), {})
139                mstore(add(mload(add(vk, 0x160)), 0x20), {})
140                // qM34
141                mstore(mload(add(vk, 0x180)), {})
142                mstore(add(mload(add(vk, 0x180)), 0x20), {})
143
144                 // qO
145                mstore(mload(add(vk, 0x1a0)), {})
146                mstore(add(mload(add(vk, 0x1a0)), 0x20), {})
147                 // qC
148                mstore(mload(add(vk, 0x1c0)), {})
149                mstore(add(mload(add(vk, 0x1c0)), 0x20), {})
150                 // qH1
151                mstore(mload(add(vk, 0x1e0)), {})
152                mstore(add(mload(add(vk, 0x1e0)), 0x20), {})
153                 // qH2
154                mstore(mload(add(vk, 0x200)), {})
155                mstore(add(mload(add(vk, 0x200)), 0x20), {})
156                 // qH3
157                mstore(mload(add(vk, 0x220)), {})
158                mstore(add(mload(add(vk, 0x220)), 0x20), {})
159                 // qH4
160                mstore(mload(add(vk, 0x240)), {})
161                mstore(add(mload(add(vk, 0x240)), 0x20), {})
162                 // qEcc
163                mstore(mload(add(vk, 0x260)), {})
164                mstore(add(mload(add(vk, 0x260)), 0x20), {})
165                 // g2LSB
166                mstore(add(vk, 0x280), {})
167                 // g2MSB
168                mstore(add(vk, 0x2A0), {})
169            }}
170        }}
171    }}",
172    import_path,
173                contract_name,
174                vk.domainSize,
175                vk.numInputs,
176                vk.sigma0.x,
177                vk.sigma0.y,
178                vk.sigma1.x,
179                vk.sigma1.y,
180                vk.sigma2.x,
181                vk.sigma2.y,
182                vk.sigma3.x,
183                vk.sigma3.y,
184                vk.sigma4.x,
185                vk.sigma4.y,
186                vk.q1.x,
187                vk.q1.y,
188                vk.q2.x,
189                vk.q2.y,
190                vk.q3.x,
191                vk.q3.y,
192                vk.q4.x,
193                vk.q4.y,
194                vk.qM12.x,
195                vk.qM12.y,
196                vk.qM34.x,
197                vk.qM34.y,
198                vk.qO.x,
199                vk.qO.y,
200                vk.qC.x,
201                vk.qC.y,
202                vk.qH1.x,
203                vk.qH1.y,
204                vk.qH2.x,
205                vk.qH2.y,
206                vk.qH3.x,
207                vk.qH3.y,
208                vk.qH4.x,
209                vk.qH4.y,
210                vk.qEcc.x,
211                vk.qEcc.y,
212                vk.g2LSB.encode_hex(),
213                vk.g2MSB.encode_hex(),
214            )
215            .into_bytes();
216
217    file.write_all(&code).unwrap();
218
219    // format the contract
220    Command::new("just")
221        .arg("sol-lint")
222        .output()
223        .expect("Failed to lint the contract code");
224}