zyga 0.5.1

ZYGA zero-knowledge proof system - CLI and library for generating ZK proofs
Documentation
#[cfg(not(feature = "std"))]
extern crate alloc;

#[cfg(feature = "solana")]
use borsh::{BorshDeserialize, BorshSerialize};

#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};

#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};

/// G1 point on BN254 curve (64 bytes - uncompressed x||y coordinates)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "solana", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(transparent))]
pub struct G1Point(#[cfg_attr(feature = "std", serde(with = "hex_serde"))] pub [u8; 64]);

/// G2 point on BN254 curve (128 bytes - uncompressed x||y coordinates)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "solana", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(transparent))]
pub struct G2Point(#[cfg_attr(feature = "std", serde(with = "hex_serde"))] pub [u8; 128]);

// Implement hex serialization for std feature
#[cfg(feature = "std")]
mod hex_serde {
    use serde::de::Error;
    use serde::{Deserialize, Deserializer, Serializer};

    pub fn serialize<S, const N: usize>(bytes: &[u8; N], serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        if serializer.is_human_readable() {
            serializer.serialize_str(&hex::encode(bytes))
        } else {
            serializer.serialize_bytes(bytes)
        }
    }

    pub fn deserialize<'de, D, const N: usize>(deserializer: D) -> Result<[u8; N], D::Error>
    where
        D: Deserializer<'de>,
    {
        if deserializer.is_human_readable() {
            let s = String::deserialize(deserializer)?;
            let bytes = hex::decode(s).map_err(D::Error::custom)?;
            let mut array = [0u8; N];
            if bytes.len() != N {
                return Err(D::Error::custom(format!(
                    "Expected {} bytes, got {}",
                    N,
                    bytes.len()
                )));
            }
            array.copy_from_slice(&bytes);
            Ok(array)
        } else {
            let bytes = Vec::<u8>::deserialize(deserializer)?;
            let mut array = [0u8; N];
            if bytes.len() != N {
                return Err(D::Error::custom(format!(
                    "Expected {} bytes, got {}",
                    N,
                    bytes.len()
                )));
            }
            array.copy_from_slice(&bytes);
            Ok(array)
        }
    }
}

impl G1Point {
    pub const BYTES: usize = 64;

    pub fn from_bytes(bytes: [u8; 64]) -> Self {
        G1Point(bytes)
    }

    pub fn from_vec(vec: Vec<u8>) -> Result<Self, String> {
        if vec.len() != Self::BYTES {
            #[cfg(feature = "std")]
            return Err(format!(
                "Expected {} bytes for G1Point, got {}",
                Self::BYTES,
                vec.len()
            ));
            #[cfg(not(feature = "std"))]
            return Err(alloc::format!(
                "Expected {} bytes for G1Point, got {}",
                Self::BYTES,
                vec.len()
            ));
        }
        let mut bytes = [0u8; 64];
        bytes.copy_from_slice(&vec);
        Ok(G1Point(bytes))
    }

    pub fn as_bytes(&self) -> &[u8; 64] {
        &self.0
    }

    pub fn to_bytes(self) -> [u8; 64] {
        self.0
    }

    pub fn to_vec(&self) -> Vec<u8> {
        self.0.to_vec()
    }
}

impl G2Point {
    pub const BYTES: usize = 128;

    pub fn from_bytes(bytes: [u8; 128]) -> Self {
        G2Point(bytes)
    }

    pub fn from_vec(vec: Vec<u8>) -> Result<Self, String> {
        if vec.len() != Self::BYTES {
            #[cfg(feature = "std")]
            return Err(format!(
                "Expected {} bytes for G2Point, got {}",
                Self::BYTES,
                vec.len()
            ));
            #[cfg(not(feature = "std"))]
            return Err(alloc::format!(
                "Expected {} bytes for G2Point, got {}",
                Self::BYTES,
                vec.len()
            ));
        }
        let mut bytes = [0u8; 128];
        bytes.copy_from_slice(&vec);
        Ok(G2Point(bytes))
    }

    pub fn as_bytes(&self) -> &[u8; 128] {
        &self.0
    }

    pub fn to_bytes(self) -> [u8; 128] {
        self.0
    }

    pub fn to_vec(&self) -> Vec<u8> {
        self.0.to_vec()
    }
}

impl AsRef<[u8]> for G1Point {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl AsRef<[u8]> for G2Point {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

#[derive(Debug, Clone)]
#[cfg_attr(feature = "solana", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct TrustedSetup {
    pub alpha: String, // Field element as string
    pub beta: String,  // Field element as string
    pub h1: Vec<u8>,   // G1 point serialized
    pub h2: Vec<u8>,   // G2 point serialized
}

#[derive(Debug, Clone)]
#[cfg_attr(feature = "solana", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct Proof {
    /// A curve point (G1) - Private part: h1^a1 where a1 is sum of private witness coefficients
    pub a_curve: G1Point,
    /// Public B component (G2): g2^b2
    pub g2_b2: G2Point,
    /// C curve point (G1) - Private part adjusted by delta
    pub c_curve: G1Point,
    /// Pre-computed g1^a2 (G1) - Public contribution for A
    pub g1_a2: G1Point,
    /// Pre-computed g1^c2 (G1) - Public contribution for C (non-negated)
    pub g1_c2: G1Point,
    /// g1^(H*Z) (G1) - Quotient polynomial times vanishing polynomial (non-negated)
    pub g1_hz: G1Point,
}