1use std::sync::Arc;
5
6use bytes::Bytes;
7use dashmap::DashMap;
8use rings_core::dht::Did;
9use rings_derive::wasm_export;
10use rings_snark::circuit;
11use rings_snark::prelude::nova::provider;
12use rings_snark::prelude::nova::provider::hyperkzg;
13use rings_snark::prelude::nova::provider::ipa_pc;
14use rings_snark::prelude::nova::spartan;
15use rings_snark::prelude::nova::traits::snark::RelaxedR1CSSNARKTrait;
16use rings_snark::prelude::nova::traits::Engine;
17use rings_snark::snark::CompressedSNARK;
18use rings_snark::snark::ProverKey;
19use rings_snark::snark::PublicParams;
20use rings_snark::snark::VerifierKey;
21use rings_snark::snark::SNARK;
22use serde::Deserialize;
23use serde::Serialize;
24
25use super::types::snark::SNARKProofTask;
26use super::types::snark::SNARKTask;
27use super::types::snark::SNARKTaskMessage;
28use super::types::snark::SNARKVerifyTask;
29use crate::error::Error;
30use crate::error::Result;
31use crate::provider::Provider;
32
33type TaskId = uuid::Uuid;
34
35pub const NAMESPACE: &str = "snark";
37
38#[cfg(feature = "browser")]
39pub mod browser;
40mod builder;
41mod protocol;
42
43pub use builder::SNARKTaskBuilder;
44pub use protocol::SnarkProtocol;
45
46#[derive(Default, Clone)]
48pub struct SNARKTaskManager {
49 task: DashMap<TaskId, SNARKProofTask>,
51 verified: DashMap<TaskId, bool>,
53}
54
55#[wasm_export]
57#[derive(Default, Clone)]
58pub struct SNARKBehaviour {
59 inner: Arc<SNARKTaskManager>,
60}
61
62impl std::ops::Deref for SNARKBehaviour {
63 type Target = Arc<SNARKTaskManager>;
64 fn deref(&self) -> &Self::Target {
65 &self.inner
66 }
67}
68
69impl AsRef<SNARKProofTask> for &SNARKProofTask {
70 fn as_ref(&self) -> &SNARKProofTask {
71 self
72 }
73}
74
75impl AsRef<SNARKVerifyTask> for &SNARKVerifyTask {
76 fn as_ref(&self) -> &SNARKVerifyTask {
77 self
78 }
79}
80
81impl SNARKBehaviour {
82 pub fn gen_proof_task(circuits: Vec<Circuit>) -> Result<SNARKProofTask> {
84 SNARKTaskBuilder::gen_proof_task(circuits)
85 }
86
87 pub async fn gen_and_send_proof_task(
89 &self,
90 provider: Arc<Provider>,
91 circuits: Vec<Circuit>,
92 did: Did,
93 ) -> Result<String> {
94 let task = Self::gen_proof_task(circuits)?;
95 self.send_proof_task(provider.clone(), &task, did).await
96 }
97
98 pub async fn send_proof_task(
104 &self,
105 provider: Arc<Provider>,
106 task_ref: impl AsRef<SNARKProofTask>,
107 did: Did,
108 ) -> Result<String> {
109 let task_id = uuid::Uuid::new_v4();
110 let task = task_ref.as_ref();
111 let msg = SNARKTaskMessage {
112 task_id,
113 task: SNARKTask::SNARKProof(Box::new(task.clone())),
114 };
115 let payload = bincode::serialize(&msg).map_err(|_| Error::EncodeError)?;
116 self.task.insert(task_id, task.clone());
119 if let Err(e) = provider.send(did, NAMESPACE, Bytes::from(payload)).await {
120 self.task.remove(&task_id);
121 return Err(e);
122 }
123 tracing::info!("sent proof request");
124 Ok(task_id.to_string())
125 }
126
127 pub fn register(&self, provider: &Provider) -> Result<()> {
133 provider.register_protocol(SnarkProtocol, protocol::SnarkShell::new(self.inner.clone()))
134 }
135}
136
137#[wasm_export]
143#[derive(Clone, Copy, PartialEq, Eq, Debug)]
144pub enum ProofResult {
145 Pending,
147 Verified,
149 Invalid,
151}
152
153#[wasm_export]
154impl SNARKBehaviour {
155 pub fn get_task_result(&self, task_id: String) -> Result<ProofResult> {
159 let task_id = uuid::Uuid::parse_str(&task_id)?;
160 Ok(match self.inner.verified.get(&task_id) {
161 Some(v) if *v.value() => ProofResult::Verified,
162 Some(_) => ProofResult::Invalid,
163 None => ProofResult::Pending,
164 })
165 }
166}
167
168pub enum CircuitGenerator {
170 Vesta(circuit::WasmCircuitGenerator<<provider::VestaEngine as Engine>::Scalar>),
172 Pallas(circuit::WasmCircuitGenerator<<provider::PallasEngine as Engine>::Scalar>),
174 Bn256KZG(circuit::WasmCircuitGenerator<<provider::Bn256EngineKZG as Engine>::Scalar>),
176}
177
178#[wasm_export]
180#[derive(Clone)]
181pub enum SupportedPrimeField {
182 Vesta,
184 Pallas,
186 Bn256KZG,
188}
189
190#[wasm_export]
192#[derive(Deserialize, Serialize)]
193pub struct Input(Vec<(String, Vec<Field>)>);
194
195impl From<Vec<(String, Vec<Field>)>> for Input {
196 fn from(data: Vec<(String, Vec<Field>)>) -> Self {
197 Self(data)
198 }
199}
200
201#[wasm_export]
202impl Input {
203 pub fn to_json(&self) -> Result<String> {
205 Ok(serde_json::to_string(self)?)
206 }
207
208 pub fn from_json(s: String) -> Result<Input> {
210 Ok(serde_json::from_str(&s)?)
211 }
212}
213
214impl std::ops::Deref for Input {
215 type Target = Vec<(String, Vec<Field>)>;
216 fn deref(&self) -> &Self::Target {
217 &self.0
218 }
219}
220
221impl IntoIterator for Input {
222 type Item = (String, Vec<Field>);
223 type IntoIter = <Vec<Self::Item> as IntoIterator>::IntoIter;
224 fn into_iter(self) -> Self::IntoIter {
225 self.0.into_iter()
226 }
227}
228
229impl<'a> IntoIterator for &'a Input {
230 type Item = <&'a Vec<(String, Vec<Field>)> as IntoIterator>::Item;
231 type IntoIter = <&'a Vec<(String, Vec<Field>)> as IntoIterator>::IntoIter;
232
233 fn into_iter(self) -> Self::IntoIter {
234 self.0.iter()
235 }
236}
237
238#[wasm_export]
240#[derive(Deserialize, Serialize)]
241pub struct Circuit {
242 inner: CircuitEnum,
243}
244
245#[derive(Deserialize, Serialize)]
247pub enum CircuitEnum {
248 Vesta(circuit::Circuit<<provider::VestaEngine as Engine>::Scalar>),
250 Pallas(circuit::Circuit<<provider::PallasEngine as Engine>::Scalar>),
252 Bn256KZG(circuit::Circuit<<provider::Bn256EngineKZG as Engine>::Scalar>),
254}
255
256#[wasm_export]
257impl Circuit {
258 pub fn to_json(&self) -> Result<String> {
260 Ok(serde_json::to_string(self)?)
261 }
262
263 pub fn from_json(s: String) -> Result<Circuit> {
265 Ok(serde_json::from_str(&s)?)
266 }
267}
268
269#[wasm_export]
271#[derive(Deserialize, Serialize)]
272pub struct Field {
273 value: FieldEnum,
274}
275
276#[derive(Deserialize, Serialize)]
278pub enum FieldEnum {
279 Vesta(<provider::VestaEngine as Engine>::Scalar),
281 Pallas(<provider::PallasEngine as Engine>::Scalar),
283 Bn256KZG(<provider::Bn256EngineKZG as Engine>::Scalar),
285}
286
287#[wasm_export]
288impl Field {
289 pub fn from_u64(v: u64, ty: SupportedPrimeField) -> Self {
291 match ty {
292 SupportedPrimeField::Vesta => Self {
293 value: FieldEnum::Vesta(<provider::VestaEngine as Engine>::Scalar::from(v)),
294 },
295 SupportedPrimeField::Pallas => Self {
296 value: FieldEnum::Pallas(<provider::PallasEngine as Engine>::Scalar::from(v)),
297 },
298 SupportedPrimeField::Bn256KZG => Self {
299 value: FieldEnum::Bn256KZG(<provider::Bn256EngineKZG as Engine>::Scalar::from(v)),
300 },
301 }
302 }
303}
304
305#[derive(Serialize, Deserialize)]
307pub struct SNARKProof<E1, E2, S1, S2>
308where
309 S1: RelaxedR1CSSNARKTrait<E1>,
310 S2: RelaxedR1CSSNARKTrait<E2>,
311 E1: Engine<Base = <E2 as Engine>::Scalar>,
312 E2: Engine<Base = <E1 as Engine>::Scalar>,
313{
314 #[serde(
316 serialize_with = "crate::util::serialize_forward",
317 deserialize_with = "crate::util::deserialize_forward"
318 )]
319 pub vk: VerifierKey<E1, E2, S1, S2>,
320 #[serde(
321 serialize_with = "crate::util::serialize_forward",
322 deserialize_with = "crate::util::deserialize_forward"
323 )]
324 pub proof: CompressedSNARK<E1, E2, S1, S2>,
326}
327
328#[derive(Serialize, Deserialize, Debug, Clone)]
330pub struct SNARKGenerator<E1, E2>
331where
332 E1: Engine<Base = <E2 as Engine>::Scalar>,
333 E2: Engine<Base = <E1 as Engine>::Scalar>,
334{
335 snark: SNARK<E1, E2>,
336 circuits: Vec<circuit::Circuit<<E1 as Engine>::Scalar>>,
337 pp: Arc<PublicParams<E1, E2>>,
338}
339
340impl SNARKProofTask {
341 pub fn split(&self, n: usize) -> Vec<SNARKProofTask> {
343 match self {
344 SNARKProofTask::PallasVasta(g) => g
345 .split(n)
346 .into_iter()
347 .map(SNARKProofTask::PallasVasta)
348 .collect(),
349 SNARKProofTask::VastaPallas(g) => g
350 .split(n)
351 .into_iter()
352 .map(SNARKProofTask::VastaPallas)
353 .collect(),
354 SNARKProofTask::Bn256KZGGrumpkin(g) => g
355 .split(n)
356 .into_iter()
357 .map(SNARKProofTask::Bn256KZGGrumpkin)
358 .collect(),
359 }
360 }
361}
362
363impl<E1, E2> SNARKGenerator<E1, E2>
364where
365 E1: Engine<Base = <E2 as Engine>::Scalar>,
366 E2: Engine<Base = <E1 as Engine>::Scalar>,
367{
368 pub fn fold(&mut self, check: bool) -> Result<()> {
370 self.snark.fold_all(&self.pp, &self.circuits)?;
371 if check {
372 let steps = self.circuits.len();
373 let first_input = self.circuits.first().unwrap().get_public_inputs();
374 self.snark
375 .verify(&self.pp, steps, first_input, vec![E2::Scalar::from(0)])?;
376 }
377 Ok(())
378 }
379
380 pub fn split(&self, n: usize) -> Vec<Self> {
382 let SNARKGenerator {
383 snark,
384 circuits,
385 pp,
386 } = self;
387
388 let mut split = Vec::new();
389 let chunk_size = circuits.len().div_ceil(n);
390
391 for circuit_chunk in circuits.chunks(chunk_size) {
392 let new_generator = SNARKGenerator {
393 snark: snark.clone(),
394 circuits: circuit_chunk.to_vec(),
395 pp: Arc::clone(pp),
396 };
397 split.push(new_generator);
398 }
399 split
400 }
401
402 #[allow(clippy::type_complexity)]
404 pub fn setup<S1: RelaxedR1CSSNARKTrait<E1>, S2: RelaxedR1CSSNARKTrait<E2>>(
405 &self,
406 ) -> Result<(ProverKey<E1, E2, S1, S2>, VerifierKey<E1, E2, S1, S2>)> {
407 Ok(SNARK::<E1, E2>::compress_setup(&self.pp)?)
408 }
409
410 pub fn prove<S1: RelaxedR1CSSNARKTrait<E1>, S2: RelaxedR1CSSNARKTrait<E2>>(
412 &self,
413 pk: impl AsRef<ProverKey<E1, E2, S1, S2>>,
414 ) -> Result<CompressedSNARK<E1, E2, S1, S2>> {
415 Ok(self.snark.compress_prove(&self.pp, pk)?)
416 }
417
418 #[allow(clippy::type_complexity)]
420 pub fn verify<S1: RelaxedR1CSSNARKTrait<E1>, S2: RelaxedR1CSSNARKTrait<E2>>(
421 &self,
422 proof: impl AsRef<CompressedSNARK<E1, E2, S1, S2>>,
423 vk: impl AsRef<VerifierKey<E1, E2, S1, S2>>,
424 ) -> Result<(Vec<E1::Scalar>, Vec<E2::Scalar>)> {
425 let steps = self.circuits.len();
426 let first_input = self.circuits.first().unwrap().get_public_inputs();
427 Ok(SNARK::<E1, E2>::compress_verify(
428 proof,
429 vk,
430 steps,
431 first_input,
432 )?)
433 }
434}
435
436impl SNARKBehaviour {
437 pub fn handle_snark_proof_task<T: AsRef<SNARKProofTask>>(data: T) -> Result<SNARKVerifyTask> {
439 tracing::debug!("SNARK proof start");
440 let ret = match data.as_ref() {
441 SNARKProofTask::VastaPallas(s) => {
442 type E1 = provider::VestaEngine;
443 type E2 = provider::PallasEngine;
444 type EE1 = ipa_pc::EvaluationEngine<E1>;
445 type EE2 = ipa_pc::EvaluationEngine<E2>;
446 type S1 = spartan::snark::RelaxedR1CSSNARK<E1, EE1>;
447 type S2 = spartan::snark::RelaxedR1CSSNARK<E2, EE2>;
448 let mut snark = s.clone();
449 snark.fold(false)?;
450 let (pk, vk) = snark.setup()?;
451 let compressed_proof = snark.prove::<S1, S2>(&pk)?;
452 let proof = SNARKProof::<E1, E2, S1, S2> {
453 vk,
454 proof: compressed_proof,
455 };
456 Ok(SNARKVerifyTask::VastaPallas(serde_json::to_string(&proof)?))
457 }
458 SNARKProofTask::PallasVasta(s) => {
459 type E1 = provider::PallasEngine;
460 type E2 = provider::VestaEngine;
461 type EE1 = ipa_pc::EvaluationEngine<E1>;
462 type EE2 = ipa_pc::EvaluationEngine<E2>;
463 type S1 = spartan::snark::RelaxedR1CSSNARK<E1, EE1>;
464 type S2 = spartan::snark::RelaxedR1CSSNARK<E2, EE2>;
465 let mut snark = s.clone();
466 snark.fold(false)?;
467 let (pk, vk) = snark.setup()?;
468 let compressed_proof = snark.prove::<S1, S2>(&pk)?;
469 let proof = SNARKProof::<E1, E2, S1, S2> {
470 vk,
471 proof: compressed_proof,
472 };
473 Ok(SNARKVerifyTask::PallasVasta(serde_json::to_string(&proof)?))
474 }
475 SNARKProofTask::Bn256KZGGrumpkin(s) => {
476 type E1 = provider::Bn256EngineKZG;
477 type E2 = provider::GrumpkinEngine;
478 type EE1 = hyperkzg::EvaluationEngine<E1>;
479 type EE2 = ipa_pc::EvaluationEngine<E2>;
480 type S1 = spartan::snark::RelaxedR1CSSNARK<E1, EE1>; type S2 = spartan::snark::RelaxedR1CSSNARK<E2, EE2>; let mut snark = s.clone();
483 snark.fold(false)?;
484 let (pk, vk) = snark.setup()?;
485 let compressed_proof = snark.prove::<S1, S2>(&pk)?;
486 let proof = SNARKProof::<E1, E2, S1, S2> {
487 vk,
488 proof: compressed_proof,
489 };
490 Ok(SNARKVerifyTask::Bn256KZGGrumpkin(serde_json::to_string(
491 &proof,
492 )?))
493 }
494 };
495 tracing::debug!("SNARK proof success");
496 ret
497 }
498
499 pub fn handle_snark_verify_task<T: AsRef<SNARKVerifyTask>, F: AsRef<SNARKProofTask>>(
501 data: T,
502 snark: F,
503 ) -> Result<bool> {
504 tracing::debug!("SNARK verify start");
505 let snark = snark.as_ref();
506 let ret = match data.as_ref() {
507 SNARKVerifyTask::PallasVasta(p) => {
508 type E1 = provider::PallasEngine;
509 type E2 = provider::VestaEngine;
510 type EE1 = ipa_pc::EvaluationEngine<E1>;
511 type EE2 = ipa_pc::EvaluationEngine<E2>;
512 type S1 = spartan::snark::RelaxedR1CSSNARK<E1, EE1>;
513 type S2 = spartan::snark::RelaxedR1CSSNARK<E2, EE2>;
514 let proof = serde_json::from_str::<SNARKProof<E1, E2, S1, S2>>(p)?;
515 if let SNARKProofTask::PallasVasta(t) = snark {
516 let ret = t.verify::<S1, S2>(proof.proof, proof.vk);
517 Ok(ret.is_ok())
518 } else {
519 Err(Error::SNARKCurveNotMatch())
520 }
521 }
522 SNARKVerifyTask::VastaPallas(p) => {
523 type E1 = provider::VestaEngine;
524 type E2 = provider::PallasEngine;
525 type EE1 = ipa_pc::EvaluationEngine<E1>;
526 type EE2 = ipa_pc::EvaluationEngine<E2>;
527 type S1 = spartan::snark::RelaxedR1CSSNARK<E1, EE1>;
528 type S2 = spartan::snark::RelaxedR1CSSNARK<E2, EE2>;
529 let proof = serde_json::from_str::<SNARKProof<E1, E2, S1, S2>>(p)?;
530 if let SNARKProofTask::VastaPallas(t) = snark {
531 let ret = t.verify::<S1, S2>(proof.proof, proof.vk);
532 Ok(ret.is_ok())
533 } else {
534 Err(Error::SNARKCurveNotMatch())
535 }
536 }
537 SNARKVerifyTask::Bn256KZGGrumpkin(p) => {
538 type E1 = provider::Bn256EngineKZG;
539 type E2 = provider::GrumpkinEngine;
540 type EE1 = hyperkzg::EvaluationEngine<E1>;
541 type EE2 = ipa_pc::EvaluationEngine<E2>;
542 type S1 = spartan::snark::RelaxedR1CSSNARK<E1, EE1>; type S2 = spartan::snark::RelaxedR1CSSNARK<E2, EE2>; let proof = serde_json::from_str::<SNARKProof<E1, E2, S1, S2>>(p)?;
545 if let SNARKProofTask::Bn256KZGGrumpkin(t) = snark {
546 let ret = t.verify::<S1, S2>(proof.proof, proof.vk);
547 Ok(ret.is_ok())
548 } else {
549 Err(Error::SNARKCurveNotMatch())
550 }
551 }
552 };
553 tracing::debug!("SNARK verify success");
554 ret
555 }
556}
557
558impl From<SNARKGenerator<provider::PallasEngine, provider::VestaEngine>> for SNARKProofTask {
559 fn from(snark: SNARKGenerator<provider::PallasEngine, provider::VestaEngine>) -> Self {
560 Self::PallasVasta(snark)
561 }
562}
563
564impl From<SNARKGenerator<provider::VestaEngine, provider::PallasEngine>> for SNARKProofTask {
565 fn from(snark: SNARKGenerator<provider::VestaEngine, provider::PallasEngine>) -> Self {
566 Self::VastaPallas(snark)
567 }
568}
569
570impl From<SNARKGenerator<provider::Bn256EngineKZG, provider::GrumpkinEngine>> for SNARKProofTask {
571 fn from(snark: SNARKGenerator<provider::Bn256EngineKZG, provider::GrumpkinEngine>) -> Self {
572 Self::Bn256KZGGrumpkin(snark)
573 }
574}