spawn-zk-snarks 0.1.5

Zero-knowledge proof library with EVM compatibility
Documentation
// Copyright (c) 2023 spawn-zk-snarks developers
//
// Licensed under the MIT License
// <LICENSE-MIT or http://opensource.org/licenses/MIT>

use ark_bn254::{Bn254, Fr};
use ark_groth16::VerifyingKey;
use ark_serialize::CanonicalSerialize;
use ethabi::{Token, encode};
use primitive_types::U256;
use crate::groth16::{Groth16Error, Groth16Setup};

/// Converts a field element to U256 format for EVM compatibility.
/// 
/// This function handles the conversion of arkworks field elements to
/// Ethereum's U256 format, ensuring proper padding and serialization.
fn fr_to_u256(fr: &Fr) -> Result<U256, Groth16Error> {
    let mut bytes = Vec::new();
    fr.serialize_compressed(&mut bytes)
        .map_err(|_| Groth16Error::SerializationError)?;
    
    // Ensure we have 32 bytes
    let mut padded = [0u8; 32];
    if bytes.len() <= 32 {
        padded[32 - bytes.len()..].copy_from_slice(&bytes);
    } else {
        return Err(Groth16Error::SerializationError);
    }

    Ok(U256::from_big_endian(&padded))
}

/// Converts a Groth16 proof and public inputs into EVM-compatible calldata.
/// 
/// This function takes a proof and its public inputs and formats them in a way
/// that can be directly used as calldata for the Solidity verifier contract.
/// 
/// # Arguments
/// * `proof` - The Groth16 proof to convert
/// * `public_inputs` - The public inputs used in the proof
/// 
/// # Returns
/// * `Vec<u8>` - The encoded calldata ready for EVM use
pub fn proof_to_calldata(
    proof: &ark_groth16::Proof<Bn254>,
    public_inputs: &[Fr],
) -> Result<Vec<u8>, Groth16Error> {
    let proof_bytes = Groth16Setup::<Bn254>::proof_to_evm_format(proof)?;
    
    let inputs: Result<Vec<Token>, _> = public_inputs
        .iter()
        .map(|x| fr_to_u256(x).map(Token::Uint))
        .collect();
    let inputs = inputs?;

    Ok(encode(&[
        Token::Bytes(proof_bytes),
        Token::Array(inputs),
    ]))
}

/// Generates a Solidity verifier contract for the given verification key.
/// 
/// This function creates a Solidity contract that can verify proofs on-chain
/// using the provided verification key.
/// 
/// # Arguments
/// * `vk` - The verification key to embed in the contract
/// 
/// # Returns
/// * `String` - The complete Solidity contract code
pub fn generate_verifier_contract(vk: &VerifyingKey<Bn254>) -> Result<String, Groth16Error> {
    let template = include_str!("../contracts/verifier_template.sol");
    
    let mut vk_bytes = Vec::new();
    vk.serialize_compressed(&mut vk_bytes)
        .map_err(|_| Groth16Error::SerializationError)?;
        
    Ok(template.replace(
        "{{VERIFYING_KEY}}",
        &format!("0x{}", hex::encode(&vk_bytes))
    ))
}