Source code for ZKProof

"""
Base class for Zero-Knowledge Proof systems.

This module provides a base class for implementing zero-knowledge proof schemes
in the Charm cryptographic library. Zero-knowledge proofs allow a prover to
convince a verifier that a statement is true without revealing any additional
information beyond the validity of the statement.

The module defines:
    - Security definitions for ZK proofs (HVZK, ZK, NIZK, SIM)
    - Exception classes for error handling
    - ZKProofBase class for implementing concrete ZK proof schemes
    - Proof dataclass for storing proof components

Security Properties:
    - HVZK: Honest-Verifier Zero-Knowledge - secure against honest verifiers
    - ZK: Zero-Knowledge - secure against malicious verifiers
    - NIZK: Non-Interactive Zero-Knowledge - no interaction required
    - SIM: Simulation Sound - proofs cannot be simulated without witness

Example:
    class SchnorrProof(ZKProofBase):
        def setup(self, group):
            # Initialize with the group
            ...
        def prove(self, statement, witness):
            # Generate Schnorr proof
            ...
        def verify(self, statement, proof):
            # Verify Schnorr proof
            ...
"""
from charm.toolbox.schemebase import *
from charm.toolbox.enum import *
from dataclasses import dataclass
from typing import Any, Optional

# Security definitions for zero-knowledge proofs
zkpSecDefs = Enum('HVZK', 'ZK', 'NIZK', 'SIM')
HVZK, ZK, NIZK, SIM = "HVZK", "ZK", "NIZK", "SIM"


[docs] class ZKProofError(Exception): """Base exception for the ZKP module. All ZKP-related exceptions inherit from this class, allowing for broad exception catching when needed. """ pass
[docs] class ZKParseError(ZKProofError): """Error parsing ZK statements. Raised when a zero-knowledge statement cannot be parsed, typically due to malformed input or invalid syntax. """ pass
[docs] class ZKValidationError(ZKProofError): """Error validating inputs. Raised when inputs to ZKP operations fail validation, such as invalid group elements or malformed witnesses. """ pass
[docs] class ZKProofVerificationError(ZKProofError): """Proof verification failed. Raised when a zero-knowledge proof fails verification, indicating either an invalid proof or mismatched statement. """ pass
[docs] @dataclass class Proof: """Dataclass to hold zero-knowledge proof components. This class encapsulates all components of a zero-knowledge proof, following the standard Sigma protocol structure (commitment, challenge, response). Attributes: commitment: The prover's initial commitment value(s). This is the first message in a Sigma protocol, committing the prover to random values. challenge: The challenge value from the verifier (or derived via Fiat-Shamir for non-interactive proofs). Must be unpredictable to the prover. response: The prover's response computed using the witness and challenge. This allows the verifier to check the proof without learning the witness. proof_type: String identifier for the type of proof (e.g., 'schnorr', 'dleq', 'or', 'and'). Used for deserialization and validation. version: Integer version number for the proof format. Allows for backward compatibility when proof formats evolve. Example: proof = Proof( commitment=g ** r, challenge=hash(commitment, statement), response=r + challenge * secret, proof_type='schnorr', version=1 ) """ commitment: Any challenge: Any response: Any proof_type: str version: int = 1
[docs] class ZKProofBase(SchemeBase): """Base class for zero-knowledge proof schemes. This class provides the foundation for implementing zero-knowledge proof systems in Charm. Concrete implementations should extend this class and implement all abstract methods. A zero-knowledge proof scheme consists of three core algorithms: - setup: Initialize the proof system with group parameters - prove: Generate a proof that a statement is true given a witness - verify: Verify that a proof is valid for a given statement Additionally, serialization methods are provided for proof persistence and network transmission. Security Properties: Implementations should specify their security level using setProperty(): - HVZK: Secure against honest verifiers only - ZK: Secure against malicious verifiers (requires simulation) - NIZK: Non-interactive (typically via Fiat-Shamir transform) - SIM: Simulation soundness (proofs unforgeable even with simulated proofs) Example: class MyZKProof(ZKProofBase): def __init__(self): ZKProofBase.__init__(self) self.setProperty(secDef='NIZK', assumption='DL', secModel='ROM') """ def __init__(self): """Initialize the ZKProof base class. Calls the parent SchemeBase constructor and sets the scheme type to 'ZKProof' for property tracking and type checking. """ SchemeBase.__init__(self) SchemeBase._setProperty(self, scheme='ZKProof')
[docs] def setProperty(self, secDef=None, assumption=None, messageSpace=None, secModel=None, **kwargs): """Set security properties for this ZK proof scheme. Configures the security properties of the proof scheme, including the security definition, hardness assumption, and security model. Args: secDef: Security definition, must be one of: 'HVZK', 'ZK', 'NIZK', 'SIM'. Defines the zero-knowledge security level of the scheme. assumption: The computational hardness assumption (e.g., 'DL', 'DDH'). Should be a string representing the underlying assumption. messageSpace: Description of the valid message/statement space. Can be a type or list of types. secModel: Security model, typically 'SM' (standard), 'ROM' (random oracle), or 'CRS' (common reference string). **kwargs: Additional scheme-specific properties. Returns: bool: True if properties were set successfully. Raises: AssertionError: If secDef is not a valid security definition. """ assert secDef is not None and secDef in zkpSecDefs.getList(), \ "not a valid security definition for this scheme type." SchemeBase._setProperty(self, None, zkpSecDefs[secDef], str(assumption), messageSpace, str(secModel), **kwargs) return True
[docs] def getProperty(self): """Get the security properties of this ZK proof scheme. Returns: dict: A dictionary containing all configured security properties, including scheme type, security definition, assumption, message space, and security model. """ baseProp = SchemeBase._getProperty(self) return baseProp
[docs] def setup(self, group): """Initialize the proof system with group parameters. This method should initialize any scheme-specific parameters needed for proof generation and verification. Args: group: The algebraic group to use for the proof system. Typically a pairing group or integer group from Charm. Returns: Implementation-specific setup parameters (e.g., public parameters). Raises: NotImplementedError: Must be implemented by subclasses. """ raise NotImplementedError
[docs] def prove(self, statement, witness): """Generate a zero-knowledge proof. Creates a proof that the prover knows a witness satisfying the given statement, without revealing the witness itself. Args: statement: The public statement to prove. The format depends on the specific proof type (e.g., public key for Schnorr). witness: The secret witness known only to the prover (e.g., private key for Schnorr). Returns: Proof: A Proof object containing commitment, challenge, and response. Raises: NotImplementedError: Must be implemented by subclasses. ZKValidationError: If statement or witness validation fails. """ raise NotImplementedError
[docs] def verify(self, statement, proof): """Verify a zero-knowledge proof. Checks whether the given proof is valid for the statement, confirming that the prover knows a valid witness. Args: statement: The public statement that was proven. proof: The Proof object to verify. Returns: bool: True if the proof is valid, False otherwise. Raises: NotImplementedError: Must be implemented by subclasses. ZKValidationError: If statement or proof format is invalid. ZKProofVerificationError: If verification fails due to invalid proof. """ raise NotImplementedError
[docs] def serialize(self, proof, group): """Serialize a proof to bytes. Converts a Proof object to a byte representation suitable for storage or network transmission. Args: proof: The Proof object to serialize. group: The algebraic group used in the proof, needed for serializing group elements. Returns: bytes: The serialized proof data. Raises: NotImplementedError: Must be implemented by subclasses. ZKValidationError: If proof format is invalid for serialization. """ raise NotImplementedError
[docs] def deserialize(self, data, group): """Deserialize bytes to a proof. Reconstructs a Proof object from its byte representation. Args: data: The serialized proof bytes. group: The algebraic group used in the proof, needed for deserializing group elements. Returns: Proof: The reconstructed Proof object. Raises: NotImplementedError: Must be implemented by subclasses. ZKParseError: If the data cannot be parsed as a valid proof. """ raise NotImplementedError