Skip to main content

Serialize

The serialize module converts Groth16 proof elements and verification keys from arkworks in-memory representations into hex-encoded byte strings that Soroban contracts can consume.

Byte Order Reference​

ElementByte OrderRaw SizeHex Length
G1 (BLS12-381)Little-endian96 bytes192 hex chars
G2 (BLS12-381)Little-endian192 bytes384 hex chars
Fr (scalar)Big-endian32 bytes64 hex chars

Important: Arkworks internally stores Fr scalars in little-endian limb order. serialize_fr reverses the bytes to produce big-endian output, matching the byte order expected by Soroban's U256 type.

Structs​

SerializedProof​

pub struct SerializedProof {
pub a: String, // G1 - 192 hex chars
pub b: String, // G2 - 384 hex chars
pub c: String, // G1 - 192 hex chars
}

Maps directly to the three elements of a Groth16 proof (A, B, C).

SerializedVK​

pub struct SerializedVK {
pub alpha_g1: String, // G1 - 192 hex chars
pub beta_g2: String, // G2 - 384 hex chars
pub gamma_g2: String, // G2 - 384 hex chars
pub delta_g2: String, // G2 - 384 hex chars
pub gamma_abc_g1: Vec<String>, // Vec<G1> - each 192 hex chars
}

The verification key fields correspond to the standard Groth16 VK structure. gamma_abc_g1 contains one entry per public input plus one.

Functions​

serialize_g1​

pub fn serialize_g1(point: &G1Affine) -> String

Serializes a BLS12-381 G1 affine point to a 192-character hex string using arkworks' uncompressed little-endian serialization.

serialize_g2​

pub fn serialize_g2(point: &G2Affine) -> String

Serializes a BLS12-381 G2 affine point to a 384-character hex string using arkworks' uncompressed little-endian serialization.

serialize_fr​

pub fn serialize_fr(scalar: &Fr) -> String

Serializes an Fr scalar to a 64-character hex string. Internally serializes with arkworks (little-endian), then reverses the byte array to produce big-endian output matching Soroban's U256 expectations.

let hex = serialize_fr(&public_input);
assert_eq!(hex.len(), 64);

serialize_proof_for_soroban​

pub fn serialize_proof_for_soroban(proof: &Proof<Bls12_381>) -> SerializedProof

Converts a complete Groth16 proof into its hex-encoded form ready for on-chain submission.

let serialized = serialize_proof_for_soroban(&proof);
// serialized.a - 192 hex chars (G1)
// serialized.b - 384 hex chars (G2)
// serialized.c - 192 hex chars (G1)

serialize_vk_for_soroban​

pub fn serialize_vk_for_soroban(vk: &VerifyingKey<Bls12_381>) -> SerializedVK

Converts a Groth16 verification key into its hex-encoded form for registration on the r14 core contract.

let serialized_vk = serialize_vk_for_soroban(&proving_key.vk);
// Pass to R14Client::init_contracts or submit manually

End-to-End Example​

use r14_sdk::serialize::{serialize_proof_for_soroban, serialize_vk_for_soroban};

// After proving
let (pk, proof) = /* ... generate proof ... */;

let ser_proof = serialize_proof_for_soroban(&proof);
let ser_vk = serialize_vk_for_soroban(&pk.vk);

// Submit proof on-chain
client.transfer_with_proof(&ser_proof, &recipient_note, &change_note, idx).await?;