risc0_ethereum_contracts/
selector.rs

1// Copyright 2025 RISC Zero, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::{self, Display, Formatter};
16
17use hex::FromHex;
18use risc0_zkvm::sha::Digest;
19use thiserror::Error;
20
21#[derive(Debug, Error)]
22#[non_exhaustive]
23pub enum SelectorError {
24    #[error("Unsupported selector")]
25    UnsupportedSelector,
26    #[error("Selector {0} does not have verifier parameters")]
27    NoVerifierParameters(Selector),
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31#[non_exhaustive]
32pub enum SelectorType {
33    FakeReceipt,
34    Groth16,
35    SetVerifier,
36}
37
38#[repr(u32)]
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40#[non_exhaustive]
41pub enum Selector {
42    FakeReceipt = 0xFFFFFFFF,
43    Groth16V1_1 = 0x50bd1769,
44    Groth16V1_2 = 0xc101b42b,
45    Groth16V2_0 = 0x9f39696c,
46    Groth16V2_1 = 0xf536085a,
47    Groth16V2_2 = 0xbb001d44,
48    Groth16V3_0 = 0x73c457ba,
49    SetVerifierV0_1 = 0xbfca9ccb,
50    SetVerifierV0_2 = 0x16a15cc8,
51    SetVerifierV0_4 = 0xf443ad7b,
52    SetVerifierV0_5 = 0xf2e6e6dc,
53    SetVerifierV0_6 = 0x80479d24,
54    SetVerifierV0_7 = 0x0f63ffd5,
55    SetVerifierV0_9 = 0x242f9d5b,
56}
57
58impl Display for Selector {
59    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
60        write!(f, "{:#010x}", *self as u32)
61    }
62}
63
64impl TryFrom<u32> for Selector {
65    type Error = SelectorError;
66
67    fn try_from(value: u32) -> Result<Self, Self::Error> {
68        match value {
69            0xFFFFFFFF => Ok(Selector::FakeReceipt),
70            0x50bd1769 => Ok(Selector::Groth16V1_1),
71            0xc101b42b => Ok(Selector::Groth16V1_2),
72            0x9f39696c => Ok(Selector::Groth16V2_0),
73            0xf536085a => Ok(Selector::Groth16V2_1),
74            0xbb001d44 => Ok(Selector::Groth16V2_2),
75            0x73c457ba => Ok(Selector::Groth16V3_0),
76            0xbfca9ccb => Ok(Selector::SetVerifierV0_1),
77            0x16a15cc8 => Ok(Selector::SetVerifierV0_2),
78            0xf443ad7b => Ok(Selector::SetVerifierV0_4),
79            0xf2e6e6dc => Ok(Selector::SetVerifierV0_5),
80            0x80479d24 => Ok(Selector::SetVerifierV0_6),
81            0x0f63ffd5 => Ok(Selector::SetVerifierV0_7),
82            0x242f9d5b => Ok(Selector::SetVerifierV0_9),
83            _ => Err(SelectorError::UnsupportedSelector),
84        }
85    }
86}
87
88impl Selector {
89    pub fn verifier_parameters_digest(self) -> Result<Digest, SelectorError> {
90        match self {
91            Selector::FakeReceipt => {
92                Err(SelectorError::NoVerifierParameters(Selector::FakeReceipt))
93            }
94            Selector::Groth16V1_1 => Ok(Digest::from_hex(
95                "50bd1769093e74abda3711c315d84d78e3e282173f6304a33272d92abb590ef5",
96            )
97            .unwrap()),
98            Selector::Groth16V1_2 => Ok(Digest::from_hex(
99                "c101b42bcacd62e35222b1207223250814d05dd41d41f8cadc1f16f86707ae15",
100            )
101            .unwrap()),
102            Selector::Groth16V2_0 => Ok(Digest::from_hex(
103                "9f39696cb3ae9d6038d6b7a55c09017f0cf35e226ad7582b82dbabb0dae53385",
104            )
105            .unwrap()),
106            Selector::Groth16V2_1 => Ok(Digest::from_hex(
107                "f536085a791bdbc6cb46ab3074f88e9e94eabb192de8daca3caee1f4ed811b08",
108            )
109            .unwrap()),
110            Selector::Groth16V2_2 => Ok(Digest::from_hex(
111                "bb001d444841d70e8bc0c7d034b349044bf3cf0117afb702b2f1e898b7dd13cc",
112            )
113            .unwrap()),
114            Selector::Groth16V3_0 => Ok(Digest::from_hex(
115                "73c457ba541936f0d907daf0c7253a39a9c5c427c225ba7709e44702d3c6eedc",
116            )
117            .unwrap()),
118            Selector::SetVerifierV0_1 => Ok(Digest::from_hex(
119                "bfca9ccb59eb38b8c78ddc399a734d8e0e84e8028b7d616fa54fe707a1ff1b3b",
120            )
121            .unwrap()),
122            Selector::SetVerifierV0_2 => Ok(Digest::from_hex(
123                "16a15cc8c94a59dc3e4e41226bc560ecda596a371a487b7ecc6b65d9516dfbdb",
124            )
125            .unwrap()),
126            Selector::SetVerifierV0_4 => Ok(Digest::from_hex(
127                "f443ad7bfe538ec90fa38498afd30b27b7d06336f20249b620a6d85ab3c615b6",
128            )
129            .unwrap()),
130            Selector::SetVerifierV0_5 => Ok(Digest::from_hex(
131                "f2e6e6dc660ed3ec9d8abb666cd481509c74990fc4d599f3f4a34b9df151f3fd",
132            )
133            .unwrap()),
134            Selector::SetVerifierV0_6 => Ok(Digest::from_hex(
135                "80479d24c20613acbaae52f5498cb60f661a26c0681ff2b750611dbaf9ecaa66",
136            )
137            .unwrap()),
138            Selector::SetVerifierV0_7 => Ok(Digest::from_hex(
139                "0f63ffd5b1579bf938597f82089ca639a393341e888f58c12d0c91065eb2a3de",
140            )
141            .unwrap()),
142            Selector::SetVerifierV0_9 => Ok(Digest::from_hex(
143                "242f9d5b8df6e1660fd7cadeec6f213501adaadb3d03d76b2ba400cf25366e2b",
144            )
145            .unwrap()),
146        }
147    }
148
149    pub fn get_type(self) -> SelectorType {
150        match self {
151            Selector::FakeReceipt => SelectorType::FakeReceipt,
152            Selector::Groth16V1_1
153            | Selector::Groth16V1_2
154            | Selector::Groth16V2_0
155            | Selector::Groth16V2_1
156            | Selector::Groth16V2_2
157            | Selector::Groth16V3_0 => SelectorType::Groth16,
158            Selector::SetVerifierV0_1
159            | Selector::SetVerifierV0_2
160            | Selector::SetVerifierV0_4
161            | Selector::SetVerifierV0_5
162            | Selector::SetVerifierV0_6
163            | Selector::SetVerifierV0_7
164            | Selector::SetVerifierV0_9 => SelectorType::SetVerifier,
165        }
166    }
167
168    pub fn from_bytes(bytes: [u8; 4]) -> Option<Self> {
169        Self::try_from(u32::from_be_bytes(bytes)).ok()
170    }
171
172    /// Returns the selector corresponding to the Groth16 verifier for the latest zkVM version.
173    pub const fn groth16_latest() -> Self {
174        Self::Groth16V3_0
175    }
176
177    /// Returns the selector corresponding to the latest version of the set inclusion verifier (aka
178    /// aggregation verifier).
179    pub const fn set_inclusion_latest() -> Self {
180        Self::SetVerifierV0_9
181    }
182}
183
184#[cfg(test)]
185mod tests {
186    use super::Selector;
187    use hex::FromHex;
188    use risc0_aggregation::SetInclusionReceiptVerifierParameters;
189    use risc0_zkvm::{
190        sha::{Digest, Digestible},
191        Groth16ReceiptVerifierParameters,
192    };
193
194    // SetBuilder image ID v0.9.0 (built using cargo risczero build v3.0.3)
195    const SET_BUILDER_ID: &str = "70909b25db0db00f1d4b4016aeb876f53568a3e5a8e6397cb562d79947a02cc9";
196
197    #[test]
198    fn print_verifier_parameters() {
199        let groth16_digest = Groth16ReceiptVerifierParameters::default().digest();
200        println!("Groth16ReceiptVerifierParameters {groth16_digest}");
201
202        let set_inclusion_digest = SetInclusionReceiptVerifierParameters {
203            image_id: Digest::from_hex(SET_BUILDER_ID).unwrap(),
204        }
205        .digest();
206        println!("SetInclusionReceiptVerifierParameters {set_inclusion_digest}");
207
208        assert_eq!(
209            groth16_digest,
210            Selector::groth16_latest()
211                .verifier_parameters_digest()
212                .unwrap()
213        );
214        assert_eq!(
215            set_inclusion_digest,
216            Selector::set_inclusion_latest()
217                .verifier_parameters_digest()
218                .unwrap()
219        );
220    }
221}