sigma-protocols 0.5.1

SIGMA zero-knowledge proof protocols
Documentation
//! Fiat-Shamir transform for non-interactive proofs.
//!
//! This module implements the Fiat-Shamir transform which converts
//! interactive SIGMA protocols into non-interactive zero-knowledge proofs.

use crate::error::{Error, Result};
use crate::transcript::DuplexSponge;

/// Fiat-Shamir transform for converting interactive proofs to non-interactive.
///
/// Uses a duplex sponge construction based on SHAKE128 for challenge generation.
pub struct FiatShamirTransform {
    sponge: DuplexSponge,
}

impl FiatShamirTransform {
    /// Create a new Fiat-Shamir transform.
    ///
    /// # Arguments
    ///
    /// * `domain_separator` - Application-specific domain separator
    /// * `protocol_id` - Identifier for the protocol being used
    /// * `session_id` - Unique session identifier
    pub fn new(domain_separator: &[u8], protocol_id: &[u8], session_id: &[u8]) -> Self {
        let mut iv = [0u8; 32];

        let mut offset = 0;
        let ds_len = domain_separator.len().min(10);
        iv[offset..offset + ds_len].copy_from_slice(&domain_separator[..ds_len]);
        offset += ds_len;

        let proto_len = protocol_id.len().min(10);
        iv[offset..offset + proto_len].copy_from_slice(&protocol_id[..proto_len]);
        offset += proto_len;

        let session_len = session_id.len().min(32 - offset);
        iv[offset..offset + session_len].copy_from_slice(&session_id[..session_len]);

        Self {
            sponge: DuplexSponge::new(&iv),
        }
    }

    /// Absorb a commitment into the transcript.
    pub fn absorb_commitment(&mut self, commitment: &[u8]) {
        self.sponge.prover_message(commitment);
    }

    /// Generate a challenge from the current transcript state.
    pub fn generate_challenge(&mut self, challenge_len: usize) -> Vec<u8> {
        self.sponge.verifier_challenge(challenge_len)
    }

    /// Absorb a response into the transcript.
    pub fn absorb_response(&mut self, response: &[u8]) {
        self.sponge.absorb(response);
    }

    /// Verify a complete proof transcript.
    ///
    /// Reconstructs the challenge and verifies it matches the provided one.
    pub fn verify_transcript(
        &mut self,
        commitment: &[u8],
        challenge: &[u8],
        response: &[u8],
    ) -> Result<()> {
        self.absorb_commitment(commitment);

        let generated_challenge = self.generate_challenge(challenge.len());

        if generated_challenge != challenge {
            return Err(Error::InvalidChallenge);
        }

        self.absorb_response(response);

        Ok(())
    }
}