1#![no_std]
2
3use soroban_sdk::{
4 Bytes, BytesN, Vec, contracterror, contracttype,
5 crypto::bn254::{Bn254G1Affine, Bn254G2Affine},
6};
7
8#[contracterror]
10#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
11#[repr(u32)]
12pub enum Groth16Error {
13 InvalidProof = 0,
15 MalformedPublicInputs = 1,
17 MalformedProof = 2,
19 NotInitialized = 3,
21}
22
23#[contracttype]
26#[derive(Clone)]
27pub struct VerificationKeyBytes {
28 pub alpha: BytesN<64>,
29 pub beta: BytesN<128>,
30 pub gamma: BytesN<128>,
31 pub delta: BytesN<128>,
32 pub ic: Vec<BytesN<64>>,
33}
34
35#[derive(Clone)]
38#[contracttype]
39pub struct Groth16Proof {
40 pub a: Bn254G1Affine,
41 pub b: Bn254G2Affine,
42 pub c: Bn254G1Affine,
43}
44
45impl Groth16Proof {
46 pub fn is_empty(&self) -> bool {
48 self.a.to_bytes().is_empty() || self.b.to_bytes().is_empty() || self.c.to_bytes().is_empty()
49 }
50}
51
52pub const FIELD_ELEMENT_SIZE: u32 = 32;
54
55pub const G1_SIZE: u32 = FIELD_ELEMENT_SIZE * 2;
57
58pub const G2_SIZE: u32 = FIELD_ELEMENT_SIZE * 4;
60
61pub const PROOF_SIZE: u32 = G1_SIZE + G2_SIZE + G1_SIZE;
63
64impl TryFrom<Bytes> for Groth16Proof {
65 type Error = Groth16Error;
66
67 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
68 if value.len() != PROOF_SIZE {
69 return Err(Groth16Error::MalformedProof);
70 }
71
72 let a = Bn254G1Affine::from_bytes(
73 value
74 .slice(0..G1_SIZE)
75 .try_into()
76 .map_err(|_| Groth16Error::MalformedProof)?,
77 );
78 let b = Bn254G2Affine::from_bytes(
79 value
80 .slice(G1_SIZE..G1_SIZE + G2_SIZE)
81 .try_into()
82 .map_err(|_| Groth16Error::MalformedProof)?,
83 );
84 let c = Bn254G1Affine::from_bytes(
85 value
86 .slice(G1_SIZE + G2_SIZE..)
87 .try_into()
88 .map_err(|_| Groth16Error::MalformedProof)?,
89 );
90
91 Ok(Self { a, b, c })
92 }
93}