rings_node/extension/snark/
builder.rs1#![warn(missing_docs)]
2use rings_derive::wasm_export;
7use rings_snark::circuit;
8use rings_snark::prelude::nova::provider;
9use rings_snark::prelude::nova::provider::hyperkzg;
10use rings_snark::prelude::nova::provider::ipa_pc;
11use rings_snark::prelude::nova::spartan;
12use rings_snark::prelude::nova::traits::Engine;
13use rings_snark::r1cs;
14use rings_snark::snark::SNARK;
15
16use super::Circuit;
17use super::CircuitEnum;
18use super::CircuitGenerator;
19use super::FieldEnum;
20use super::Input;
21use super::SNARKGenerator;
22use super::SupportedPrimeField;
23use crate::error::Result;
24use crate::extension::types::snark::SNARKProofTask;
25
26#[wasm_export]
28pub struct SNARKTaskBuilder {
29 circuit_generator: CircuitGenerator,
30}
31
32#[wasm_export]
33impl SNARKTaskBuilder {
34 pub async fn from_local(
36 r1cs_path: String,
37 witness_wasm_path: String,
38 field: SupportedPrimeField,
39 ) -> Result<SNARKTaskBuilder> {
40 match field {
41 SupportedPrimeField::Vesta => {
42 type F = <provider::VestaEngine as Engine>::Scalar;
43 let r1cs =
44 r1cs::load_r1cs::<F>(r1cs::Path::Local(r1cs_path), r1cs::Format::Bin).await?;
45 let witness_calculator =
46 r1cs::load_circom_witness_calculator(r1cs::Path::Local(witness_wasm_path))
47 .await?;
48 let circuit_generator =
49 circuit::WasmCircuitGenerator::<F>::new(r1cs, witness_calculator);
50 Ok(Self {
51 circuit_generator: CircuitGenerator::Vesta(circuit_generator),
52 })
53 }
54 SupportedPrimeField::Pallas => {
55 type F = <provider::PallasEngine as Engine>::Scalar;
56 let r1cs =
57 r1cs::load_r1cs::<F>(r1cs::Path::Local(r1cs_path), r1cs::Format::Bin).await?;
58 let witness_calculator =
59 r1cs::load_circom_witness_calculator(r1cs::Path::Local(witness_wasm_path))
60 .await?;
61 let circuit_generator =
62 circuit::WasmCircuitGenerator::<F>::new(r1cs, witness_calculator);
63 Ok(Self {
64 circuit_generator: CircuitGenerator::Pallas(circuit_generator),
65 })
66 }
67 SupportedPrimeField::Bn256KZG => {
68 type F = <provider::Bn256EngineKZG as Engine>::Scalar;
69 let r1cs =
70 r1cs::load_r1cs::<F>(r1cs::Path::Local(r1cs_path), r1cs::Format::Bin).await?;
71 let witness_calculator =
72 r1cs::load_circom_witness_calculator(r1cs::Path::Local(witness_wasm_path))
73 .await?;
74 let circuit_generator =
75 circuit::WasmCircuitGenerator::<F>::new(r1cs, witness_calculator);
76 Ok(Self {
77 circuit_generator: CircuitGenerator::Bn256KZG(circuit_generator),
78 })
79 }
80 }
81 }
82
83 pub async fn from_remote(
85 r1cs_path: String,
86 witness_wasm_path: String,
87 field: SupportedPrimeField,
88 ) -> Result<SNARKTaskBuilder> {
89 match field {
90 SupportedPrimeField::Vesta => {
91 type F = <provider::VestaEngine as Engine>::Scalar;
92 let r1cs =
93 r1cs::load_r1cs::<F>(r1cs::Path::Remote(r1cs_path), r1cs::Format::Bin).await?;
94 let witness_calculator =
95 r1cs::load_circom_witness_calculator(r1cs::Path::Remote(witness_wasm_path))
96 .await?;
97 let circuit_generator =
98 circuit::WasmCircuitGenerator::<F>::new(r1cs, witness_calculator);
99 Ok(Self {
100 circuit_generator: CircuitGenerator::Vesta(circuit_generator),
101 })
102 }
103 SupportedPrimeField::Pallas => {
104 type F = <provider::PallasEngine as Engine>::Scalar;
105 let r1cs =
106 r1cs::load_r1cs::<F>(r1cs::Path::Remote(r1cs_path), r1cs::Format::Bin).await?;
107 let witness_calculator =
108 r1cs::load_circom_witness_calculator(r1cs::Path::Remote(witness_wasm_path))
109 .await?;
110 let circuit_generator =
111 circuit::WasmCircuitGenerator::<F>::new(r1cs, witness_calculator);
112 Ok(Self {
113 circuit_generator: CircuitGenerator::Pallas(circuit_generator),
114 })
115 }
116 SupportedPrimeField::Bn256KZG => {
117 type F = <provider::Bn256EngineKZG as Engine>::Scalar;
118 let r1cs =
119 r1cs::load_r1cs::<F>(r1cs::Path::Remote(r1cs_path), r1cs::Format::Bin).await?;
120 let witness_calculator =
121 r1cs::load_circom_witness_calculator(r1cs::Path::Remote(witness_wasm_path))
122 .await?;
123 let circuit_generator =
124 circuit::WasmCircuitGenerator::<F>::new(r1cs, witness_calculator);
125 Ok(Self {
126 circuit_generator: CircuitGenerator::Bn256KZG(circuit_generator),
127 })
128 }
129 }
130 }
131
132 pub fn gen_circuits(
134 &self,
135 public_input: Input,
136 private_inputs: Vec<Input>,
137 round: usize,
138 ) -> Result<Vec<Circuit>> {
139 match &self.circuit_generator {
140 CircuitGenerator::Vesta(g) => {
141 type F = <provider::VestaEngine as Engine>::Scalar;
142
143 let input: circuit::Input<F> = public_input
144 .into_iter()
145 .map(|(s, v)| {
146 (
147 s,
148 v.into_iter()
149 .map(|inp| {
150 if let FieldEnum::Vesta(x) = inp.value {
151 x
152 } else {
153 panic!("Wrong curve, expect Vesta")
154 }
155 })
156 .collect(),
157 )
158 })
159 .collect::<Vec<(String, Vec<F>)>>()
160 .into();
161
162 let private_inputs: Vec<circuit::Input<F>> = private_inputs
163 .into_iter()
164 .map(|inp| {
165 inp.into_iter()
166 .map(|(s, v)| {
167 let fields: Vec<F> = v
168 .into_iter()
169 .map(|inp| {
170 if let FieldEnum::Vesta(x) = inp.value {
171 x
172 } else {
173 panic!("Wrong curve, expect Vesta")
174 }
175 })
176 .collect();
177 (s, fields)
178 })
179 .collect::<Vec<(String, Vec<F>)>>()
180 .into()
181 })
182 .collect();
183
184 let circuits = g
185 .gen_recursive_circuit(input, private_inputs, round, true)?
186 .iter()
187 .map(|c| Circuit {
188 inner: CircuitEnum::Vesta(c.clone()),
189 })
190 .collect::<Vec<Circuit>>();
191 Ok(circuits)
192 }
193 CircuitGenerator::Pallas(g) => {
194 type F = <provider::PallasEngine as Engine>::Scalar;
195
196 let input: circuit::Input<F> = public_input
197 .into_iter()
198 .map(|(s, v)| {
199 (
200 s,
201 v.into_iter()
202 .map(|inp| {
203 if let FieldEnum::Pallas(x) = inp.value {
204 x
205 } else {
206 panic!("Wrong curve, expect pallas")
207 }
208 })
209 .collect(),
210 )
211 })
212 .collect::<Vec<(String, Vec<F>)>>()
213 .into();
214
215 let private_inputs: Vec<circuit::Input<F>> = private_inputs
216 .into_iter()
217 .map(|inp| {
218 inp.into_iter()
219 .map(|(s, v)| {
220 let fields: Vec<F> = v
221 .into_iter()
222 .map(|inp| {
223 if let FieldEnum::Pallas(x) = inp.value {
224 x
225 } else {
226 panic!("Wrong curve, expect Vesta")
227 }
228 })
229 .collect();
230 (s, fields)
231 })
232 .collect::<Vec<(String, Vec<F>)>>()
233 .into()
234 })
235 .collect();
236
237 let circuits = g
238 .gen_recursive_circuit(input, private_inputs, round, true)?
239 .iter()
240 .map(|c| Circuit {
241 inner: CircuitEnum::Pallas(c.clone()),
242 })
243 .collect::<Vec<Circuit>>();
244 Ok(circuits)
245 }
246 CircuitGenerator::Bn256KZG(g) => {
247 type F = <provider::Bn256EngineKZG as Engine>::Scalar;
248
249 let input: circuit::Input<F> = public_input
250 .into_iter()
251 .map(|(s, v)| {
252 (
253 s,
254 v.into_iter()
255 .map(|inp| {
256 if let FieldEnum::Bn256KZG(x) = inp.value {
257 x
258 } else {
259 panic!("Wrong curve, expect bn256")
260 }
261 })
262 .collect(),
263 )
264 })
265 .collect::<Vec<(String, Vec<F>)>>()
266 .into();
267
268 let private_inputs: Vec<circuit::Input<F>> = private_inputs
269 .into_iter()
270 .map(|inp| {
271 inp.into_iter()
272 .map(|(s, v)| {
273 let fields: Vec<F> = v
274 .into_iter()
275 .map(|inp| {
276 if let FieldEnum::Bn256KZG(x) = inp.value {
277 x
278 } else {
279 panic!("Wrong curve, expect bn256")
280 }
281 })
282 .collect();
283 (s, fields)
284 })
285 .collect::<Vec<(String, Vec<F>)>>()
286 .into()
287 })
288 .collect();
289
290 let circuits = g
291 .gen_recursive_circuit(input, private_inputs, round, true)?
292 .iter()
293 .map(|c| Circuit {
294 inner: CircuitEnum::Bn256KZG(c.clone()),
295 })
296 .collect::<Vec<Circuit>>();
297 Ok(circuits)
298 }
299 }
300 }
301}
302
303impl SNARKTaskBuilder {
304 pub fn gen_proof_task(circuits: Vec<Circuit>) -> Result<SNARKProofTask> {
306 let task = match &circuits[0].inner {
307 CircuitEnum::Vesta(_) => {
308 type E1 = provider::VestaEngine;
309 type E2 = provider::PallasEngine;
310 type EE1 = ipa_pc::EvaluationEngine<E1>;
311 type EE2 = ipa_pc::EvaluationEngine<E2>;
312 type S1 = spartan::snark::RelaxedR1CSSNARK<E1, EE1>;
313 type S2 = spartan::snark::RelaxedR1CSSNARK<E2, EE2>;
314 let circuits: Vec<circuit::Circuit<<E1 as Engine>::Scalar>> = circuits
315 .into_iter()
316 .map(|circ| {
317 if let CircuitEnum::Vesta(c) = circ.inner {
318 c
319 } else {
320 panic!("Wrong curve, expect vesta")
321 }
322 })
323 .collect();
324 let inputs = circuits[0].get_public_inputs();
325 let pp = SNARK::<E1, E2>::gen_pp::<S1, S2>(circuits[0].clone())?;
326 let snark = SNARK::<E1, E2>::new(&circuits[0], &pp, &inputs, &vec![
327 <E2 as Engine>::Scalar::from(0),
328 ])?;
329
330 SNARKProofTask::VastaPallas(SNARKGenerator {
331 pp: pp.into(),
332 snark,
333 circuits,
334 })
335 }
336 CircuitEnum::Pallas(_) => {
337 type E1 = provider::PallasEngine;
338 type E2 = provider::VestaEngine;
339 type EE1 = ipa_pc::EvaluationEngine<E1>;
340 type EE2 = ipa_pc::EvaluationEngine<E2>;
341 type S1 = spartan::snark::RelaxedR1CSSNARK<E1, EE1>;
342 type S2 = spartan::snark::RelaxedR1CSSNARK<E2, EE2>;
343 let circuits: Vec<circuit::Circuit<<E1 as Engine>::Scalar>> = circuits
344 .into_iter()
345 .map(|circ| {
346 if let CircuitEnum::Pallas(c) = circ.inner {
347 c
348 } else {
349 panic!("Wrong curve, expect vesta")
350 }
351 })
352 .collect();
353 let inputs = circuits[0].get_public_inputs();
354 let pp = SNARK::<E1, E2>::gen_pp::<S1, S2>(circuits[0].clone())?;
355 let snark = SNARK::<E1, E2>::new(&circuits[0], &pp, &inputs, &vec![
356 <E2 as Engine>::Scalar::from(0),
357 ])?;
358 SNARKProofTask::PallasVasta(SNARKGenerator {
359 pp: pp.into(),
360 snark,
361 circuits,
362 })
363 }
364 CircuitEnum::Bn256KZG(_) => {
365 type E1 = provider::Bn256EngineKZG;
366 type E2 = provider::GrumpkinEngine;
367 type EE1 = hyperkzg::EvaluationEngine<E1>;
368 type EE2 = ipa_pc::EvaluationEngine<E2>;
369 type S1 = spartan::snark::RelaxedR1CSSNARK<E1, EE1>; type S2 = spartan::snark::RelaxedR1CSSNARK<E2, EE2>; let circuits: Vec<circuit::Circuit<<E1 as Engine>::Scalar>> = circuits
372 .into_iter()
373 .map(|circ| {
374 if let CircuitEnum::Bn256KZG(c) = circ.inner {
375 c
376 } else {
377 panic!("Wrong curve, expect vesta")
378 }
379 })
380 .collect();
381 let inputs = circuits[0].get_public_inputs();
382 let pp = SNARK::<E1, E2>::gen_pp::<S1, S2>(circuits[0].clone())?;
383 let snark = SNARK::<E1, E2>::new(&circuits[0], &pp, &inputs, &vec![
384 <E2 as Engine>::Scalar::from(0),
385 ])?;
386 SNARKProofTask::Bn256KZGGrumpkin(SNARKGenerator {
387 pp: pp.into(),
388 snark,
389 circuits,
390 })
391 }
392 };
393 Ok(task)
394 }
395}