light_circuitlib_rs/gnark/
proof_helpers.rs

1use serde::{Deserialize, Serialize};
2type G1 = ark_bn254::g1::G1Affine;
3use std::ops::Neg;
4
5use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate};
6use num_traits::Num;
7use solana_program::alt_bn128::compression::prelude::{
8    alt_bn128_g1_compress, alt_bn128_g2_compress, convert_endianness,
9};
10
11#[derive(Serialize, Deserialize, Debug)]
12pub struct GnarkProofJson {
13    pub ar: Vec<String>,
14    pub bs: Vec<Vec<String>>,
15    pub krs: Vec<String>,
16}
17
18pub fn deserialize_gnark_proof_json(json_data: &str) -> serde_json::Result<GnarkProofJson> {
19    let deserialized_data: GnarkProofJson = serde_json::from_str(json_data)?;
20    Ok(deserialized_data)
21}
22
23pub fn deserialize_hex_string_to_be_bytes(hex_str: &str) -> [u8; 32] {
24    let trimmed_str = hex_str.trim_start_matches("0x");
25    let big_int = num_bigint::BigInt::from_str_radix(trimmed_str, 16).unwrap();
26    let big_int_bytes = big_int.to_bytes_be().1;
27    if big_int_bytes.len() < 32 {
28        let mut result = [0u8; 32];
29        result[32 - big_int_bytes.len()..].copy_from_slice(&big_int_bytes);
30        result
31    } else {
32        big_int_bytes.try_into().unwrap()
33    }
34}
35
36pub fn compress_proof(
37    proof_a: &[u8; 64],
38    proof_b: &[u8; 128],
39    proof_c: &[u8; 64],
40) -> ([u8; 32], [u8; 64], [u8; 32]) {
41    let proof_a = alt_bn128_g1_compress(proof_a).unwrap();
42    let proof_b = alt_bn128_g2_compress(proof_b).unwrap();
43    let proof_c = alt_bn128_g1_compress(proof_c).unwrap();
44    (proof_a, proof_b, proof_c)
45}
46
47pub fn proof_from_json_struct(json: GnarkProofJson) -> ([u8; 64], [u8; 128], [u8; 64]) {
48    let proof_a_x = deserialize_hex_string_to_be_bytes(&json.ar[0]);
49    let proof_a_y = deserialize_hex_string_to_be_bytes(&json.ar[1]);
50    let proof_a: [u8; 64] = [proof_a_x, proof_a_y].concat().try_into().unwrap();
51    let proof_a = negate_g1(&proof_a);
52    let proof_b_x_0 = deserialize_hex_string_to_be_bytes(&json.bs[0][0]);
53    let proof_b_x_1 = deserialize_hex_string_to_be_bytes(&json.bs[0][1]);
54    let proof_b_y_0 = deserialize_hex_string_to_be_bytes(&json.bs[1][0]);
55    let proof_b_y_1 = deserialize_hex_string_to_be_bytes(&json.bs[1][1]);
56    let proof_b: [u8; 128] = [proof_b_x_0, proof_b_x_1, proof_b_y_0, proof_b_y_1]
57        .concat()
58        .try_into()
59        .unwrap();
60
61    let proof_c_x = deserialize_hex_string_to_be_bytes(&json.krs[0]);
62    let proof_c_y = deserialize_hex_string_to_be_bytes(&json.krs[1]);
63    let proof_c: [u8; 64] = [proof_c_x, proof_c_y].concat().try_into().unwrap();
64    (proof_a, proof_b, proof_c)
65}
66
67pub fn negate_g1(g1_be: &[u8; 64]) -> [u8; 64] {
68    let g1_le = convert_endianness::<32, 64>(g1_be);
69    let g1: G1 = G1::deserialize_with_mode(g1_le.as_slice(), Compress::No, Validate::No).unwrap();
70
71    let g1_neg = g1.neg();
72    let mut g1_neg_be = [0u8; 64];
73    g1_neg
74        .x
75        .serialize_with_mode(&mut g1_neg_be[..32], Compress::No)
76        .unwrap();
77    g1_neg
78        .y
79        .serialize_with_mode(&mut g1_neg_be[32..], Compress::No)
80        .unwrap();
81    let g1_neg_be: [u8; 64] = convert_endianness::<32, 64>(&g1_neg_be);
82    g1_neg_be
83}