Sigma Protocols Implementation in C A clean, simple C implementation of Sigma protocols with Fiat-Shamir transformation for non-interactive zero-knowledge proofs. Features Schnorr Protocol: Prove knowledge of discrete logarithm Chaum-Pedersen Protocol: Prove discrete logarithm equality (DLEQ) Non-interactive proofs: Using Fiat-Shamir transformation with SHAKE128 Minimal API: Just 6 functions for complete functionality No abstractions: Direct use of byte arrays, no wrapper types Secure: Built on libsodium's Ristretto255 group operations Quick Start #include "sigma.h" // Initialize sigma_init (); // Prove knowledge of private key uint8_t private_key [ 32 ], public_key [ 32 ], proof [ 64 ]; crypto_core_ristretto255_scalar_random ( private_key ); crypto_scalarmult_ristretto255_base ( public_key , private_key ); schnorr_prove ( proof , private_key , public_key , message , message_len ); bool valid = schnorr_verify ( proof , public_key , message , message_len ); Building Prerequisites: C compiler (clang or gcc) libsodium development libraries # Install libsodium (Ubuntu/Debian) sudo apt-get install libsodium-dev # Install libsodium (macOS) brew install libsodium # Build make # Run tests ./test # Run examples ./example API Reference Initialization int sigma_init ( void ); Initialize the library (wraps sodium_init). Schnorr Protocol Proves knowledge of x where Y = x*G (G is the generator). // Create proof int schnorr_prove ( uint8_t proof [ 64 ], // Output: 64-byte proof const uint8_t witness [ 32 ], // Secret x const uint8_t public_key [ 32 ], // Public Y = x*G const uint8_t * message , // Message to bind size_t message_len ); // Verify proof bool schnorr_verify ( const uint8_t proof [ 64 ], const uint8_t public_key [ 32 ], const uint8_t * message , size_t message_len ); Chaum-Pedersen Protocol Proves that log_g1(h1) = log_g2(h2) without revealing the exponent. // Create proof int chaum_pedersen_prove ( uint8_t proof [ 96 ], // Output: 96-byte proof const uint8_t witness [ 32 ], // Secret x where h1=g1^x, h2=g2^x const uint8_t g1 [ 32 ], const uint8_t h1 [ 32 ], const uint8_t g2 [ 32 ], const uint8_t h2 [ 32 ], const uint8_t * message , size_t message_len ); // Verify proof bool chaum_pedersen_verify ( const uint8_t proof [ 96 ], const uint8_t g1 [ 32 ], const uint8_t h1 [ 32 ], const uint8_t g2 [ 32 ], const uint8_t h2 [ 32 ], const uint8_t * message , size_t message_len ); When to Use Each Protocol Schnorr Protocol What it proves: Knowledge of a secret value (discrete logarithm) without revealing it. Mathematical property: Proves "I know x such that Y = x*G" where G is the generator and Y is public. Use cases: Digital signatures: Prove you own the private key corresponding to a public key Authentication: Log in to a service without transmitting your password Cryptocurrency wallets: Prove ownership of funds without revealing private keys Access control: Demonstrate you have credentials without exposing them Password-authenticated key exchange (PAKE): Establish secure channels based on passwords Example scenario: Alice wants to prove she owns a Bitcoin address. She uses Schnorr to prove she knows the private key corresponding to the public address, without revealing the private key itself. Chaum-Pedersen Protocol What it proves: Two discrete logarithms are equal, without revealing the common exponent. Mathematical property: Proves "log_g1(h1) = log_g2(h2)" or equivalently "h1 = g1^x AND h2 = g2^x" for some secret x. Use cases: Verifiable encryption: Prove a ciphertext encrypts a specific value without decryption Anonymous credentials: Show two credentials belong to the same user without revealing identity Mix networks: Prove correct re-encryption in privacy protocols Cross-chain atomic swaps: Prove same secret is used in multiple transactions Verifiable shuffles: Prove a list was correctly permuted without revealing the permutation Blind signatures: Prove consistency between blinded and unblinded values Example scenario: A voting system needs to prove that an encrypted vote was correctly re-encrypted (same vote, different randomness) during the mixing phase, without revealing the actual vote. Protocol Comparison Aspect Schnorr Chaum-Pedersen Proof size 64 bytes 96 bytes What's proven Knowledge of one secret Equality of two discrete logs Complexity Simpler More complex Computation 2 exponentiations to verify 4 exponentiations to verify Primary use Authentication, signatures Verifiable encryption, DLEQ proofs Implementation Details