A high-performance Go library for pairing-based cryptography operations over elliptic curve groups.
mathlib provides a unified interface for performing cryptographic operations on pairing-friendly elliptic curves. It supports multiple curve implementations and backends, making it suitable for various cryptographic protocols including:
- Zero-knowledge proofs
- Anonymous credentials
The library abstracts the complexity of pairing operations while providing flexibility to choose different curve types and backend implementations based on performance and security requirements.
- Multiple Curve Support: FP256BN, BN254, BLS12-381, BLS12-377, and BBS+ variants
- Pluggable Backends: Support for AMCL, Gurvy, and Kilic implementations
- Type-Safe API: Strongly-typed group elements (G1, G2, Gt, Zr)
- Efficient Operations: Optimized pairing computations and multi-scalar multiplications
- Serialization: Support for both compressed and uncompressed point representations
- Hash-to-Curve: Secure hashing to curve points with optional domain separation
- Modular Arithmetic: Comprehensive scalar field operations
go get github.com/IBM/mathlibRequirements:
- Go 1.25 or higher
package main
import (
"fmt"
"github.com/IBM/mathlib"
)
func main() {
// Select a curve (BLS12-381 in this example)
curve := math.Curves[math.BLS12_381]
// Generate random scalars
rng, _ := curve.Rand()
a := curve.NewRandomZr(rng)
b := curve.NewRandomZr(rng)
// Perform scalar multiplication on G1
P := curve.GenG1.Mul(a)
Q := curve.GenG1.Mul(b)
// Compute pairing
e1 := curve.Pairing(curve.GenG2, P)
e2 := curve.Pairing(curve.GenG2, Q)
// Multiply in target group
e1.Mul(e2)
fmt.Printf("Pairing result: %s\n", e1.String())
}| Curve ID | Description | Backend | Use Case |
|---|---|---|---|
FP256BN_AMCL |
256-bit Barreto-Naehrig curve | AMCL | General-purpose pairing operations |
FP256BN_AMCL_MIRACL |
256-bit BN curve (MIRACL variant) | AMCL | Legacy compatibility |
BN254 |
254-bit Barreto-Naehrig curve | Gurvy | High-performance applications |
BLS12_381 |
BLS12-381 curve | Kilic | Modern protocols, BLS signatures |
BLS12_381_GURVY |
BLS12-381 curve | Gurvy | Performance-optimized BLS12-381 |
BLS12_377_GURVY |
BLS12-377 curve | Gurvy | Recursive proof systems |
BLS12_381_BBS |
BLS12-381 for BBS+ signatures | Kilic | Anonymous credentials |
BLS12_381_BBS_GURVY |
BLS12-381 for BBS+ signatures | Gurvy | High-performance BBS+ |
- BLS12-381: Recommended for new projects, widely standardized, excellent security margins
- BN254: Good performance, but security margins are tighter than BLS12-381
- BLS12-377: Specialized for recursive proof composition (e.g., zk-SNARKs)
- BBS+ variants: Specifically optimized for BBS+ signature schemes
Curve: Main interface for curve operations, provides factory methods for group elementsZr: Elements in the scalar field (integers modulo curve order)G1: Points on the first elliptic curve groupG2: Points on the second elliptic curve group (twisted curve)Gt: Elements in the target group (result of pairing operations)
// Curve selection
curve := math.Curves[math.BLS12_381]
// Scalar operations
a := curve.NewZrFromInt(42)
b := curve.HashToZr([]byte("some data"))
c := a.Plus(b)
// G1 operations
P := curve.GenG1.Mul(a)
Q := curve.HashToG1([]byte("hash to point"))
P.Add(Q)
// G2 operations
R := curve.GenG2.Mul(b)
// Pairing
e := curve.Pairing(R, P)
// Target group operations
e2 := e.Exp(c)curve := math.Curves[math.BLS12_381]
// Create scalars
a := curve.NewZrFromInt(5)
b := curve.NewZrFromInt(7)
// Compute [a]G1 and [b]G2
P := curve.GenG1.Mul(a)
Q := curve.GenG2.Mul(b)
// Compute pairing e([b]G2, [a]G1)
result := curve.Pairing(Q, P)
// Verify bilinearity: e(G2, [ab]G1) == e([b]G2, [a]G1)
ab := a.Mul(b)
expected := curve.Pairing(curve.GenG2, curve.GenG1.Mul(ab))
if result.Equals(expected) {
fmt.Println("Pairing bilinearity verified!")
}curve := math.Curves[math.BLS12_381]
// Create a point
rng, _ := curve.Rand()
scalar := curve.NewRandomZr(rng)
point := curve.GenG1.Mul(scalar)
// Serialize (uncompressed)
bytes := point.Bytes()
// Deserialize
recovered, err := curve.NewG1FromBytes(bytes)
if err != nil {
panic(err)
}
// Serialize (compressed)
compressed := point.Compressed()
recoveredCompressed, err := curve.NewG1FromCompressed(compressed)
if err != nil {
panic(err)
}
fmt.Printf("Original and recovered points match: %v\n",
point.Equals(recovered) && point.Equals(recoveredCompressed))curve := math.Curves[math.BLS12_381]
// Hash to G1 with domain separation
message := []byte("sign this message")
domain := []byte("my-application-v1")
point := curve.HashToG1WithDomain(message, domain)
// Use in signature scheme
rng, _ := curve.Rand()
secretKey := curve.NewRandomZr(rng)
signature := point.Mul(secretKey)
fmt.Printf("Signature: %x\n", signature.Compressed())curve := math.Curves[math.BLS12_381]
// Create multiple points and scalars
points := []*math.G1{
curve.GenG1,
curve.HashToG1([]byte("point2")),
curve.HashToG1([]byte("point3")),
}
scalars := []*math.Zr{
curve.NewZrFromInt(2),
curve.NewZrFromInt(3),
curve.NewZrFromInt(5),
}
// Efficient multi-scalar multiplication: [2]P1 + [3]P2 + [5]P3
result := curve.MultiScalarMul(points, scalars)
fmt.Printf("Multi-scalar multiplication result: %s\n", result.String())mathlib uses a driver pattern to support multiple backend implementations:
┌─────────────────────────────────────┐
│ mathlib (Public API) │
│ Curve, G1, G2, Gt, Zr types │
└─────────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────┐
│ driver (Interface Layer) │
│ Curve, G1, G2, Gt, Zr interfaces │
└─────────────────┬───────────────────┘
│
┌─────────┼─────────┐
▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────┐
│ AMCL │ │Gurvy │ │Kilic │
└──────┘ └──────┘ └──────┘
This design allows:
- Flexibility: Easy addition of new curve implementations
- Performance: Choose the fastest backend for your use case
- Compatibility: Support for different cryptographic libraries
- AMCL (Apache Milagro Crypto Library): Mature, well-tested implementation
- Gurvy: High-performance Go-native implementation with assembly optimizations
- Kilic: Optimized BLS12-381 implementation with focus on BLS signatures
- Use compressed point serialization when bandwidth is limited
- Prefer
Pairing2for double pairings (more efficient than two separate pairings) - Use
MultiScalarMulfor multiple scalar multiplications (faster than individual operations) - Consider
Mul2andMul2InPlacefor combined operations on G1 - BLS12-381 with Gurvy backend offers excellent performance for most applications
Run the test suite:
make unit-testsRun benchmarks:
make perfContributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow Go coding conventions and style guidelines
- Add tests for new functionality
- Update documentation for API changes
- Run
make checksandmake lintbefore committing - Ensure all tests pass and linters are satisfied
- Always use cryptographically secure random number generators
- Validate all deserialized points (the library does this automatically)
- Use appropriate curve parameters for your security requirements
- Consider timing attack mitigations for sensitive operations
- Keep dependencies up to date
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
This library builds upon the excellent work of:
- Apache Milagro Crypto Library (AMCL)
- ConsenSys Gurvy library
- Kilic BLS12-381 implementation