export_sui_verifier_core/
model.rs1use crate::error::{Error, Result};
2use crate::snarkjs::{
3 validate_curve_match, validate_protocol, validate_public_counts,
4 validate_verification_key_geometry, Proof as LegacyProof, SnarkJsG1, SnarkJsG2,
5 VerificationKey as LegacyVerificationKey,
6};
7
8pub type DecimalValue = String;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum CurveKind {
12 Bn254,
13 Bls12_381,
14}
15
16impl CurveKind {
17 pub fn from_name(value: &str) -> Result<Self> {
18 match normalize_curve_name(value).as_str() {
19 "bn128" | "bn254" | "altbn128" => Ok(Self::Bn254),
20 "bls12381" => Ok(Self::Bls12_381),
21 _ => Err(Error::UnsupportedCurve(format!(
22 "unsupported curve: {value}"
23 ))),
24 }
25 }
26
27 pub fn canonical_name(self) -> &'static str {
28 match self {
29 Self::Bn254 => "bn254",
30 Self::Bls12_381 => "bls12381",
31 }
32 }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum SourceFormat {
37 SnarkjsJson,
38 Arkworks,
39 GnarkJson,
40 GnarkBin,
41 Sp1,
42}
43
44#[derive(Debug, Clone)]
45pub struct Groth16G1Point {
46 pub x: DecimalValue,
47 pub y: DecimalValue,
48 pub z: DecimalValue,
49}
50
51#[derive(Debug, Clone)]
52pub struct Groth16G2Point {
53 pub x0: DecimalValue,
54 pub x1: DecimalValue,
55 pub y0: DecimalValue,
56 pub y1: DecimalValue,
57 pub z0: DecimalValue,
58 pub z1: DecimalValue,
59}
60
61#[derive(Debug, Clone)]
62pub struct Groth16VerificationKey {
63 pub n_public: usize,
64 pub vk_alpha_1: Groth16G1Point,
65 pub vk_beta_2: Groth16G2Point,
66 pub vk_gamma_2: Groth16G2Point,
67 pub vk_delta_2: Groth16G2Point,
68 pub ic: Vec<Groth16G1Point>,
69}
70
71#[derive(Debug, Clone)]
72pub struct Groth16Proof {
73 pub pi_a: Groth16G1Point,
74 pub pi_b: Groth16G2Point,
75 pub pi_c: Groth16G1Point,
76}
77
78#[derive(Debug, Clone)]
79pub struct Groth16VerifierInputs {
80 pub curve: CurveKind,
81 pub protocol: String,
82 pub verifying_key: Groth16VerificationKey,
83 pub proof: Option<Groth16Proof>,
84 pub public_inputs: Vec<DecimalValue>,
85 pub source_format: SourceFormat,
86}
87
88impl Groth16VerifierInputs {
89 pub fn from_legacy(
90 vk: LegacyVerificationKey,
91 proof: LegacyProof,
92 public_inputs: Vec<DecimalValue>,
93 source_format: SourceFormat,
94 ) -> Result<Self> {
95 validate_protocol(vk.protocol.as_ref(), proof.protocol.as_ref())?;
96 validate_verification_key_geometry(&vk)?;
97 validate_public_counts(&vk, &public_inputs)?;
98
99 let curve_name = validate_curve_match(vk.curve.as_ref(), proof.curve.as_ref())?;
100 let curve = CurveKind::from_name(&curve_name)?;
101 let protocol = vk
102 .protocol
103 .clone()
104 .or_else(|| proof.protocol.clone())
105 .unwrap_or_else(|| "groth16".to_string());
106
107 Ok(Self {
108 curve,
109 protocol,
110 verifying_key: Groth16VerificationKey {
111 n_public: vk.n_public,
112 vk_alpha_1: vk.vk_alpha_1.into(),
113 vk_beta_2: vk.vk_beta_2.into(),
114 vk_gamma_2: vk.vk_gamma_2.into(),
115 vk_delta_2: vk.vk_delta_2.into(),
116 ic: vk.ic.into_iter().map(Into::into).collect(),
117 },
118 proof: Some(Groth16Proof {
119 pi_a: proof.pi_a.into(),
120 pi_b: proof.pi_b.into(),
121 pi_c: proof.pi_c.into(),
122 }),
123 public_inputs,
124 source_format,
125 })
126 }
127
128 pub fn from_legacy_vk_only(
129 vk: LegacyVerificationKey,
130 public_inputs: Vec<DecimalValue>,
131 source_format: SourceFormat,
132 ) -> Result<Self> {
133 validate_protocol(vk.protocol.as_ref(), None)?;
134 validate_verification_key_geometry(&vk)?;
135
136 if vk.ic.len() != vk.n_public + 1 {
137 return Err(Error::IcLengthMismatch(format!(
138 "expected IC length = nPublic + 1, got {}",
139 vk.ic.len()
140 )));
141 }
142 if !public_inputs.is_empty() && vk.n_public != public_inputs.len() {
143 return Err(Error::PublicInputCountMismatch(format!(
144 "expected nPublic={}, got {}",
145 vk.n_public,
146 public_inputs.len()
147 )));
148 }
149
150 let curve_name = validate_curve_match(vk.curve.as_ref(), None)?;
151 let curve = CurveKind::from_name(&curve_name)?;
152 let protocol = vk.protocol.clone().unwrap_or_else(|| "groth16".to_string());
153
154 Ok(Self {
155 curve,
156 protocol,
157 verifying_key: Groth16VerificationKey {
158 n_public: vk.n_public,
159 vk_alpha_1: vk.vk_alpha_1.into(),
160 vk_beta_2: vk.vk_beta_2.into(),
161 vk_gamma_2: vk.vk_gamma_2.into(),
162 vk_delta_2: vk.vk_delta_2.into(),
163 ic: vk.ic.into_iter().map(Into::into).collect(),
164 },
165 proof: None,
166 public_inputs,
167 source_format,
168 })
169 }
170
171 pub fn from_parts(
172 curve: CurveKind,
173 verifying_key: Groth16VerificationKey,
174 proof: Option<Groth16Proof>,
175 public_inputs: Vec<DecimalValue>,
176 source_format: SourceFormat,
177 ) -> Result<Self> {
178 if verifying_key.ic.len() != verifying_key.n_public + 1 {
179 return Err(Error::IcLengthMismatch(format!(
180 "expected {} IC points, got {}",
181 verifying_key.n_public + 1,
182 verifying_key.ic.len()
183 )));
184 }
185 if proof.is_some() && public_inputs.len() != verifying_key.n_public {
186 return Err(Error::PublicInputCountMismatch(format!(
187 "verification key expects {} public inputs, got {}",
188 verifying_key.n_public,
189 public_inputs.len()
190 )));
191 }
192 if proof.is_none()
193 && !public_inputs.is_empty()
194 && public_inputs.len() != verifying_key.n_public
195 {
196 return Err(Error::PublicInputCountMismatch(format!(
197 "verification key expects {} public inputs, got {}",
198 verifying_key.n_public,
199 public_inputs.len()
200 )));
201 }
202
203 Ok(Self {
204 curve,
205 protocol: "groth16".to_string(),
206 verifying_key,
207 proof,
208 public_inputs,
209 source_format,
210 })
211 }
212
213 pub fn has_test_vectors(&self) -> bool {
214 self.proof.is_some()
215 }
216}
217
218impl From<SnarkJsG1> for Groth16G1Point {
219 fn from(value: SnarkJsG1) -> Self {
220 Self {
221 x: value.x,
222 y: value.y,
223 z: value.z,
224 }
225 }
226}
227
228impl From<SnarkJsG2> for Groth16G2Point {
229 fn from(value: SnarkJsG2) -> Self {
230 Self {
231 x0: value.x0,
232 x1: value.x1,
233 y0: value.y0,
234 y1: value.y1,
235 z0: value.z0,
236 z1: value.z1,
237 }
238 }
239}
240
241fn normalize_curve_name(value: &str) -> String {
242 value.to_lowercase().replace(['-', '_'], "")
243}