- Go 99%
- Nix 1%
| auth | ||
| curves | ||
| examples/http_auth | ||
| schnorr | ||
| .envrc | ||
| .gitignore | ||
| flake.lock | ||
| flake.nix | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| README.md | ||
go-zkp-schnorr
A modular Go library for zero-knowledge proofs focused on Schnorr proofs for authentication.
Sources
https://en.wikipedia.org/wiki/Schnorr_signature
https://crypto.stanford.edu/cs355/19sp/lec5.pdf
https://eprint.iacr.org/2021/1375.pdf
https://asecuritysite.com/golang/ecc_zkp
RFC 8235 - https://datatracker.ietf.org/doc/html/rfc8235
Installation
go get github.com/cedev-1/go-zkp-schnorr
Quick Start
Basic Schnorr Proof
package main
import (
"fmt"
"math/big"
"github.com/cedev-1/go-zkp-schnorr/curves"
"github.com/cedev-1/go-zkp-schnorr/schnorr"
)
func main() {
// Use secp256k1 curve (compatible with Bitcoin/Ethereum)
curve := curves.NewSecp256k1()
// Create a secret key
secret := big.NewInt(12345) // In production, use cryptographically secure random
// Create prover
prover, _ := schnorr.NewProver(curve, secret)
fmt.Printf("Public Key: %x\n", prover.PublicKey().Bytes())
// Generate a non-interactive proof
message := []byte("authentication challenge")
proof, _ := prover.ProveNonInteractive(message)
// Verify the proof
verifier := schnorr.NewVerifier(curve, prover.PublicKey())
valid := verifier.VerifyNonInteractive(proof, message)
fmt.Printf("Proof valid: %v\n", valid)
}
HTTP Authentication
// Server side
server := auth.NewServer(curves.NewSecp256k1())
// Generate challenge for client
sessionID, challenge, _ := server.GenerateChallenge()
// ... client generates proof ...
// Verify authentication
valid, _ := server.VerifyAuthWithSession(sessionID, authRequest)
// Client side
client, _ := auth.NewClientFromBytes(curves.NewSecp256k1(), secretKey)
// Generate proof for challenge
authRequest, _ := client.Authenticate(challenge)
Packages
| Package | Description |
|---|---|
curves |
Elliptic curve abstractions (secp256k1, ed25519) |
schnorr |
Schnorr identification protocol implementation |
auth |
High-level authentication helpers |
Mathematical Background
Discrete Logarithm Assumption
The security of this library relies on the hardness of the Discrete Logarithm Problem (DLP) in elliptic curve groups.
Given:
- A generator point
Gof a group of prime ordern - A scalar
x(private key) - A point
Y = x \cdot G(public key)
It is computationally infeasible to determine x given G and Y.
Schnorr Identification Protocol
The Schnorr protocol is a Sigma protocol ($\Sigma$-protocol) that proves knowledge of a discrete logarithm without revealing it. It consists of three moves:
- Commitment: The prover generates a random nonce
k \in [1, n-1]and computes the commitmentR = k \cdot G.- The prover sends
Rto the verifier.
- The prover sends
- Challenge: The verifier chooses a random challenge
e \in [1, n-1].- The verifier sends
eto the prover.
- The verifier sends
- Response: The prover computes
s = k + e \cdot x \pmod n.- The prover sends
sto the verifier.
- The prover sends
Verification: The verifier accepts the proof if and only if:
s \cdot G \stackrel{?}{=} R + e \cdot Y
Proof of Correctness
s \cdot G = (k + e \cdot x) \cdot G = k \cdot G + e \cdot (x \cdot G) = R + e \cdot Y
Non-Interactive Zero-Knowledge (NIZK)
To make the protocol non-interactive (e.g., for use in an HTTP API or blockchain), we apply the Fiat-Shamir heuristic.
Instead of receiving a random challenge from an interactive verifier, the prover computes the challenge as a cryptographic hash of the public parameters and the commitment:
e = \mathcal{H}(G \parallel R \parallel Y \parallel m)
Where:
\mathcal{H}is a cryptographic hash function (e.g., SHA-256)Gis the generator pointmis an optional message bound to the proof (context)\paralleldenotes concatenation
This transforms the interactive identification scheme into a digital signature scheme (Schnorr signature) or a non-interactive zero-knowledge proof (NIZK).
Security Properties
- Completeness: An honest prover can always convince the verifier.
- Special Soundness: A cheating prover without knowledge of
xcannot convince the verifier (with probability1/n). - Honest Verifier Zero-Knowledge (HVZK): The transcript
(R, e, s)reveals no information about the secretx.
Security
This library implements several security best practices:
- Constant-time comparisons: Uses
crypto/subtle.ConstantTimeCompareto prevent timing attacks - Domain separation: Hash includes curve name to prevent cross-curve attacks
- Generator binding: Fiat-Shamir hash includes
Gto prevent generator substitution attacks - Replay protection: Session-based challenges with single-use enforcement and TTL expiration
- Cryptographically secure randomness: Uses
crypto/randfor all random values
Examples
See the examples directory for complete working examples:
- HTTP Authentication - Full client/server auth flow
Future
- Ring Signatures
- MuSig Aggregation
License
MIT License