math

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 24, 2026 License: Apache-2.0 Imports: 12 Imported by: 142

README

mathlib

License Go Report Card Go GoDoc

A high-performance Go library for pairing-based cryptography operations over elliptic curve groups.

Overview

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.

Features

  • 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

Installation

go get github.com/IBM/mathlib

Requirements:

  • Go 1.25 or higher

Quick Start

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())
}

Supported Curves

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+
Choosing a Curve
  • 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

API Overview

Core Types
  • Curve: Main interface for curve operations, provides factory methods for group elements
  • Zr: Elements in the scalar field (integers modulo curve order)
  • G1: Points on the first elliptic curve group
  • G2: Points on the second elliptic curve group (twisted curve)
  • Gt: Elements in the target group (result of pairing operations)
Key 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)

Usage Examples

Example 1: Basic Pairing Operation
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!")
}
Example 2: Serialization and Deserialization
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))
Example 3: Hash-to-Curve with Domain Separation
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())
Example 4: Multi-Scalar Multiplication
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())

Architecture

Driver Pattern

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
Backend Implementations
  • 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

Performance Considerations

  • Use compressed point serialization when bandwidth is limited
  • Prefer Pairing2 for double pairings (more efficient than two separate pairings)
  • Use MultiScalarMul for multiple scalar multiplications (faster than individual operations)
  • Consider Mul2 and Mul2InPlace for combined operations on G1
  • BLS12-381 with Gurvy backend offers excellent performance for most applications

Testing

Run the test suite:

make unit-tests

Run benchmarks:

make perf

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request
Development Guidelines
  • Follow Go coding conventions and style guidelines
  • Add tests for new functionality
  • Update documentation for API changes
  • Run make checks and make lint before committing
  • Ensure all tests pass and linters are satisfied

Security Considerations

  • 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

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

References

Acknowledgments

This library builds upon the excellent work of:

  • Apache Milagro Crypto Library (AMCL)
  • ConsenSys Gurvy library
  • Kilic BLS12-381 implementation

Documentation

Overview

Package math provides a high-level interface for pairing-based cryptography operations on elliptic curves. It supports multiple pairing-friendly curves including BN254, BLS12-381, BLS12-377, and FP256BN variants.

Overview

This package implements operations on three main groups used in pairing-based cryptography:

  • G1: Points on the first elliptic curve group
  • G2: Points on the second elliptic curve group (twisted curve)
  • Gt: Elements in the target group (result of pairing operations)
  • Zr: Scalars in the field (integers modulo the curve order)

The library uses a driver pattern to support multiple backend implementations (AMCL, Gurvy, Kilic), allowing users to choose the best performance/compatibility trade-off for their use case.

Basic Usage

Select a curve and perform operations:

curve := math.Curves[math.BLS12_381]
rng, _ := curve.Rand()
scalar := curve.NewRandomZr(rng)
point := curve.GenG1.Mul(scalar)
result := curve.Pairing(curve.GenG2, point)

Supported Curves

The package provides pre-configured curves accessible via the Curves slice:

  • FP256BN_AMCL: 256-bit Barreto-Naehrig curve (AMCL backend)
  • BN254: 254-bit Barreto-Naehrig curve (Gurvy backend)
  • FP256BN_AMCL_MIRACL: 256-bit BN curve MIRACL variant (AMCL backend)
  • BLS12_381: BLS12-381 curve (Kilic backend)
  • BLS12_377_GURVY: BLS12-377 curve (Gurvy backend)
  • BLS12_381_GURVY: BLS12-381 curve (Gurvy backend)
  • BLS12_381_BBS: BLS12-381 optimized for BBS+ signatures (Kilic backend)
  • BLS12_381_BBS_GURVY: BLS12-381 for BBS+ (Gurvy backend)

Thread Safety

The types in this package are not thread-safe. Users should implement their own synchronization when sharing instances across goroutines.

Index

Constants

This section is empty.

Variables

View Source
var Curves []*Curve = []*Curve{
	NewCurve(
		amcl.NewFp256bn(),
		NewG1((&amcl.Fp256bn{}).GenG1(), FP256BN_AMCL),
		NewG2((&amcl.Fp256bn{}).GenG2(), FP256BN_AMCL),
		NewGt((&amcl.Fp256bn{}).GenGt(), FP256BN_AMCL),
		NewZr(amcl.NewFp256bn().GroupOrder(), FP256BN_AMCL),
		(&amcl.Fp256bn{}).CoordinateByteSize(),
		(&amcl.Fp256bn{}).G1ByteSize(),
		(&amcl.Fp256bn{}).CompressedG1ByteSize(),
		(&amcl.Fp256bn{}).G2ByteSize(),
		(&amcl.Fp256bn{}).CompressedG2ByteSize(),
		(&amcl.Fp256bn{}).ScalarByteSize(),
		FP256BN_AMCL,
	),
	{

		GenG1:                NewG1((&gurvy.Bn254{}).GenG1(), BN254),
		GenG2:                NewG2((&gurvy.Bn254{}).GenG2(), BN254),
		GenGt:                NewGt((&gurvy.Bn254{}).GenGt(), BN254),
		GroupOrder:           NewZr(gurvy.NewBn254().GroupOrder(), BN254),
		CoordByteSize:        (&gurvy.Bn254{}).CoordinateByteSize(),
		G1ByteSize:           (&gurvy.Bn254{}).G1ByteSize(),
		CompressedG1ByteSize: (&gurvy.Bn254{}).CompressedG1ByteSize(),
		G2ByteSize:           (&gurvy.Bn254{}).G2ByteSize(),
		CompressedG2ByteSize: (&gurvy.Bn254{}).CompressedG2ByteSize(),
		ScalarByteSize:       (&gurvy.Bn254{}).ScalarByteSize(),
		// contains filtered or unexported fields
	},
	{

		GenG1:                NewG1((&amcl.Fp256Miraclbn{}).GenG1(), FP256BN_AMCL_MIRACL),
		GenG2:                NewG2((&amcl.Fp256Miraclbn{}).GenG2(), FP256BN_AMCL_MIRACL),
		GenGt:                NewGt((&amcl.Fp256Miraclbn{}).GenGt(), FP256BN_AMCL_MIRACL),
		GroupOrder:           NewZr(amcl.NewFp256Miraclbn().GroupOrder(), FP256BN_AMCL_MIRACL),
		CoordByteSize:        (&amcl.Fp256Miraclbn{}).CoordinateByteSize(),
		G1ByteSize:           (&amcl.Fp256Miraclbn{}).G1ByteSize(),
		CompressedG1ByteSize: (&amcl.Fp256Miraclbn{}).CompressedG1ByteSize(),
		G2ByteSize:           (&amcl.Fp256Miraclbn{}).G2ByteSize(),
		CompressedG2ByteSize: (&amcl.Fp256Miraclbn{}).CompressedG2ByteSize(),
		ScalarByteSize:       (&amcl.Fp256Miraclbn{}).ScalarByteSize(),
		// contains filtered or unexported fields
	},
	{

		GenG1:                NewG1((&kilic.Bls12_381{}).GenG1(), BLS12_381),
		GenG2:                NewG2((&kilic.Bls12_381{}).GenG2(), BLS12_381),
		GenGt:                NewGt((&kilic.Bls12_381{}).GenGt(), BLS12_381),
		GroupOrder:           NewZr(kilic.NewBls12_381().GroupOrder(), BLS12_381),
		CoordByteSize:        (&kilic.Bls12_381{}).CoordinateByteSize(),
		G1ByteSize:           (&kilic.Bls12_381{}).G1ByteSize(),
		CompressedG1ByteSize: (&kilic.Bls12_381{}).CompressedG1ByteSize(),
		G2ByteSize:           (&kilic.Bls12_381{}).G2ByteSize(),
		CompressedG2ByteSize: (&kilic.Bls12_381{}).CompressedG2ByteSize(),
		ScalarByteSize:       (&kilic.Bls12_381{}).ScalarByteSize(),
		// contains filtered or unexported fields
	},
	{

		GenG1:                NewG1((&gurvy.Bls12_377{}).GenG1(), BLS12_377_GURVY),
		GenG2:                NewG2((&gurvy.Bls12_377{}).GenG2(), BLS12_377_GURVY),
		GenGt:                NewGt((&gurvy.Bls12_377{}).GenGt(), BLS12_377_GURVY),
		GroupOrder:           NewZr(gurvy.NewBls12_377().GroupOrder(), BLS12_377_GURVY),
		CoordByteSize:        (&gurvy.Bls12_377{}).CoordinateByteSize(),
		G1ByteSize:           (&gurvy.Bls12_377{}).G1ByteSize(),
		CompressedG1ByteSize: (&gurvy.Bls12_377{}).CompressedG1ByteSize(),
		G2ByteSize:           (&gurvy.Bls12_377{}).G2ByteSize(),
		CompressedG2ByteSize: (&gurvy.Bls12_377{}).CompressedG2ByteSize(),
		ScalarByteSize:       (&gurvy.Bls12_377{}).ScalarByteSize(),
		// contains filtered or unexported fields
	},
	{

		GenG1:                NewG1((&bls12381.Curve{}).GenG1(), BLS12_381_GURVY),
		GenG2:                NewG2((&bls12381.Curve{}).GenG2(), BLS12_381_GURVY),
		GenGt:                NewGt((&bls12381.Curve{}).GenGt(), BLS12_381_GURVY),
		GroupOrder:           NewZr(bls12381.NewCurve().GroupOrder(), BLS12_381_GURVY),
		CoordByteSize:        (&bls12381.Curve{}).CoordinateByteSize(),
		G1ByteSize:           (&bls12381.Curve{}).G1ByteSize(),
		CompressedG1ByteSize: (&bls12381.Curve{}).CompressedG1ByteSize(),
		G2ByteSize:           (&bls12381.Curve{}).G2ByteSize(),
		CompressedG2ByteSize: (&bls12381.Curve{}).CompressedG2ByteSize(),
		ScalarByteSize:       (&bls12381.Curve{}).ScalarByteSize(),
		// contains filtered or unexported fields
	},
	{

		GenG1:                NewG1(kilic.NewBls12_381BBS().GenG1(), BLS12_381_BBS),
		GenG2:                NewG2(kilic.NewBls12_381BBS().GenG2(), BLS12_381_BBS),
		GenGt:                NewGt(kilic.NewBls12_381BBS().GenGt(), BLS12_381_BBS),
		GroupOrder:           NewZr(kilic.NewBls12_381().GroupOrder(), BLS12_381_BBS),
		CoordByteSize:        kilic.NewBls12_381BBS().CoordinateByteSize(),
		G1ByteSize:           kilic.NewBls12_381BBS().G1ByteSize(),
		CompressedG1ByteSize: kilic.NewBls12_381BBS().CompressedG1ByteSize(),
		G2ByteSize:           kilic.NewBls12_381BBS().G2ByteSize(),
		CompressedG2ByteSize: kilic.NewBls12_381BBS().CompressedG2ByteSize(),
		ScalarByteSize:       kilic.NewBls12_381BBS().ScalarByteSize(),
		// contains filtered or unexported fields
	},
	{

		GenG1:                NewG1(bls12381.NewBBSCurve().GenG1(), BLS12_381_BBS_GURVY),
		GenG2:                NewG2(bls12381.NewBBSCurve().GenG2(), BLS12_381_BBS_GURVY),
		GenGt:                NewGt(bls12381.NewBBSCurve().GenGt(), BLS12_381_BBS_GURVY),
		GroupOrder:           NewZr(bls12381.NewCurve().GroupOrder(), BLS12_381_BBS_GURVY),
		CoordByteSize:        bls12381.NewBBSCurve().CoordinateByteSize(),
		G1ByteSize:           bls12381.NewBBSCurve().G1ByteSize(),
		CompressedG1ByteSize: bls12381.NewBBSCurve().CompressedG1ByteSize(),
		G2ByteSize:           bls12381.NewBBSCurve().G2ByteSize(),
		CompressedG2ByteSize: bls12381.NewBBSCurve().CompressedG2ByteSize(),
		ScalarByteSize:       bls12381.NewBBSCurve().ScalarByteSize(),
		// contains filtered or unexported fields
	},
}

Curves provides pre-configured instances of all supported elliptic curves. Each curve is fully initialized and ready to use. Access curves by their index using the CurveID constants (e.g., Curves[BLS12_381]).

Example:

curve := math.Curves[math.BLS12_381]
point := curve.GenG1.Mul(curve.NewZrFromInt(42))

The curves are instantiated at package initialization and can be used directly or via the NewCurve function for custom configurations.

Functions

func CurveIDToString added in v0.1.0

func CurveIDToString(id CurveID) string

CurveIDToString converts a CurveID to its string representation. Returns a human-readable name for the curve, useful for logging and debugging. Panics if the curve ID is unknown.

Types

type Curve

type Curve struct {
	GenG1                *G1 // Generator point for the G1 group
	GenG2                *G2 // Generator point for the G2 group
	GenGt                *Gt // Generator (identity) element for the Gt group
	GroupOrder           *Zr // Order of the curve groups
	CoordByteSize        int // Size of a single coordinate in bytes
	G1ByteSize           int // Size of uncompressed G1 point in bytes
	CompressedG1ByteSize int // Size of compressed G1 point in bytes
	G2ByteSize           int // Size of uncompressed G2 point in bytes
	CompressedG2ByteSize int // Size of compressed G2 point in bytes
	ScalarByteSize       int // Size of scalar (Zr) in bytes
	// contains filtered or unexported fields
}

Curve represents a pairing-friendly elliptic curve and provides the main interface for cryptographic operations. It encapsulates the curve parameters, generator points, and factory methods for creating group elements.

A Curve instance provides:

  • Generator points (GenG1, GenG2, GenGt) for each group
  • The group order (GroupOrder) as a Zr element
  • Size information for serialization
  • Factory methods for creating and deserializing group elements
  • Pairing operations
  • Hash-to-curve operations
  • Modular arithmetic operations

Example:

curve := math.Curves[math.BLS12_381]
rng, _ := curve.Rand()
secretKey := curve.NewRandomZr(rng)
publicKey := curve.GenG1.Mul(secretKey)
message := []byte("sign this")
signature := curve.HashToG1(message).Mul(secretKey)

func NewCurve added in v0.1.0

func NewCurve(
	c driver.Curve,
	genG1 *G1,
	genG2 *G2,
	genGt *Gt,
	groupOrder *Zr,
	coordByteSize int,
	g1ByteSize int,
	compressedG1ByteSize int,
	g2ByteSize int,
	compressedG2ByteSize int,
	scalarByteSize int,
	curveID CurveID,
) *Curve

NewCurve creates a new Curve instance with the specified parameters. This is typically used internally during package initialization to create the pre-configured curves in the Curves slice. Most users should use the pre-configured curves rather than creating custom instances.

Parameters:

  • c: The underlying driver implementation
  • genG1, genG2, genGt: Generator points for each group
  • groupOrder: The order of the curve groups
  • coordByteSize: Size of a coordinate in bytes
  • g1ByteSize, compressedG1ByteSize: Sizes for G1 serialization
  • g2ByteSize, compressedG2ByteSize: Sizes for G2 serialization
  • scalarByteSize: Size of scalars in bytes
  • curveID: Identifier for this curve configuration

func (*Curve) FExp

func (c *Curve) FExp(a *Gt) *Gt

FExp performs the final exponentiation in the pairing computation. This is typically used internally but exposed for advanced use cases.

func (*Curve) HashToG1

func (c *Curve) HashToG1(data []byte) *G1

HashToG1 hashes arbitrary data to a point in G1 using a hash-to-curve algorithm. This is useful for creating deterministic points from messages.

func (*Curve) HashToG1WithDomain added in v0.1.0

func (c *Curve) HashToG1WithDomain(data, domain []byte) *G1

HashToG1WithDomain hashes data to a G1 point with domain separation. The domain parameter prevents hash collisions across different protocols or contexts.

func (*Curve) HashToG2 added in v0.1.0

func (c *Curve) HashToG2(data []byte) *G2

HashToG2 hashes arbitrary data to a point in G2 using a hash-to-curve algorithm.

func (*Curve) HashToG2WithDomain added in v0.1.0

func (c *Curve) HashToG2WithDomain(data, domain []byte) *G2

HashToG2WithDomain hashes data to a G2 point with domain separation. The domain parameter prevents hash collisions across different protocols or contexts.

func (*Curve) HashToZr

func (c *Curve) HashToZr(data []byte) *Zr

HashToZr hashes arbitrary data to a scalar in Zr using a cryptographic hash function. The output is uniformly distributed in the scalar field.

func (*Curve) ID added in v0.1.0

func (c *Curve) ID() CurveID

ID returns the curve identifier for this curve.

func (*Curve) ModAdd

func (c *Curve) ModAdd(a, b, m *Zr) *Zr

ModAdd computes (a + b) mod m.

func (*Curve) ModAddMul added in v0.1.0

func (c *Curve) ModAddMul(a1, b1 []*Zr, m *Zr) *Zr

ModAddMul computes the sum of products: (a1[0]*b1[0] + a1[1]*b1[1] + ... + a1[n]*b1[n]) mod m. This is more efficient than computing each product separately. The slices a1 and b1 must have the same length.

func (*Curve) ModAddMul2 added in v0.1.0

func (c *Curve) ModAddMul2(a1, a2, b1, b2 *Zr, m *Zr) *Zr

ModAddMul2 computes (a1*a2 + b1*b2) mod m. This is more efficient than computing the products separately.

func (*Curve) ModAddMul2InPlace added in v0.1.0

func (c *Curve) ModAddMul2InPlace(result, a1, c1, b1, c2, m *Zr)

ModAddMul2InPlace computes (a1*c1 + b1*c2) mod m and stores the result in result. This avoids allocating a new Zr for the result.

func (*Curve) ModAddMul3 added in v0.1.0

func (c *Curve) ModAddMul3(a1, a2, b1, b2, c1, c2 *Zr, m *Zr) *Zr

ModAddMul3 computes (a1*a2 + b1*b2 + c1*c2) mod m. This is more efficient than computing the products separately.

func (*Curve) ModAddMul3InPlace added in v0.1.0

func (c *Curve) ModAddMul3InPlace(result, a1, a2, b1, b2, c1, c2, m *Zr)

ModAddMul3InPlace computes (a1*a2 + b1*b2 + c1*c2) mod m and stores the result in result. This avoids allocating a new Zr for the result.

func (*Curve) ModMul

func (c *Curve) ModMul(a1, b1, m *Zr) *Zr

ModMul computes (a1 * b1) mod m.

func (*Curve) ModMulInPlace added in v0.1.0

func (c *Curve) ModMulInPlace(result, a, b, m *Zr)

ModMulInPlace computes (a * b) mod m and stores the result in result. This avoids allocating a new Zr for the result.

func (*Curve) ModNeg

func (c *Curve) ModNeg(a1, m *Zr) *Zr

ModNeg computes (-a1) mod m.

func (*Curve) ModSub

func (c *Curve) ModSub(a, b, m *Zr) *Zr

ModSub computes (a - b) mod m.

func (*Curve) MultiScalarMul added in v0.1.0

func (c *Curve) MultiScalarMul(a []*G1, b []*Zr) *G1

MultiScalarMul computes a multi-scalar multiplication: [b[0]]a[0] + [b[1]]a[1] + ... + [b[n]]a[n]. This is significantly more efficient than computing each scalar multiplication separately. The slices a and b must have the same length.

func (*Curve) NewG1

func (c *Curve) NewG1() *G1

NewG1 creates a new G1 point initialized to the identity element (point at infinity).

func (*Curve) NewG1FromBytes

func (c *Curve) NewG1FromBytes(b []byte) (p *G1, err error)

NewG1FromBytes deserializes a G1 point from its uncompressed byte representation. Returns an error if the bytes are invalid or don't represent a valid point.

func (*Curve) NewG1FromCompressed added in v0.1.0

func (c *Curve) NewG1FromCompressed(b []byte) (p *G1, err error)

NewG1FromCompressed deserializes a G1 point from its compressed byte representation. Returns an error if the bytes are invalid or don't represent a valid point.

func (*Curve) NewG2

func (c *Curve) NewG2() *G2

NewG2 creates a new G2 point initialized to the identity element (point at infinity).

func (*Curve) NewG2FromBytes

func (c *Curve) NewG2FromBytes(b []byte) (p *G2, err error)

NewG2FromBytes deserializes a G2 point from its uncompressed byte representation. Returns an error if the bytes are invalid or don't represent a valid point.

func (*Curve) NewG2FromCompressed added in v0.1.0

func (c *Curve) NewG2FromCompressed(b []byte) (p *G2, err error)

NewG2FromCompressed deserializes a G2 point from its compressed byte representation. Returns an error if the bytes are invalid or don't represent a valid point.

func (*Curve) NewGtFromBytes

func (c *Curve) NewGtFromBytes(b []byte) (p *Gt, err error)

NewGtFromBytes deserializes a Gt element from its byte representation. Returns an error if the bytes are invalid or don't represent a valid element.

func (*Curve) NewRandomZr

func (c *Curve) NewRandomZr(rng io.Reader) *Zr

NewRandomZr generates a random scalar using the provided random number generator. The scalar is uniformly distributed in the range [0, group order).

func (*Curve) NewZrFromBigInt added in v0.1.0

func (c *Curve) NewZrFromBigInt(i *big.Int) *Zr

NewZrFromBigInt creates a Zr scalar from a *big.Int value. The value is reduced modulo the curve order.

func (*Curve) NewZrFromBytes

func (c *Curve) NewZrFromBytes(b []byte) *Zr

NewZrFromBytes creates a Zr scalar from its byte representation. The byte slice should be in the format produced by Zr.Bytes().

func (*Curve) NewZrFromInt

func (c *Curve) NewZrFromInt(i int64) *Zr

NewZrFromInt creates a Zr scalar from an int64 value.

func (*Curve) NewZrFromUint64 added in v0.1.0

func (c *Curve) NewZrFromUint64(i uint64) *Zr

NewZrFromUint64 creates a Zr scalar from a uint64 value.

func (*Curve) Pairing

func (c *Curve) Pairing(a *G2, b *G1) *Gt

Pairing computes the bilinear pairing e(a, b) where a ∈ G2 and b ∈ G1. The result is an element in the target group Gt. The pairing satisfies the bilinearity property: e([x]a, [y]b) = e(a, b)^(xy).

func (*Curve) Pairing2

func (c *Curve) Pairing2(p *G2, q *G1, r *G2, s *G1) *Gt

Pairing2 efficiently computes e(p, q) * e(r, s) where p, r ∈ G2 and q, s ∈ G1. This is more efficient than computing two separate pairings and multiplying them.

func (*Curve) Rand

func (c *Curve) Rand() (io.Reader, error)

Rand returns a cryptographically secure random number generator. Returns an error if the RNG cannot be initialized.

type CurveID

type CurveID int

CurveID identifies a specific elliptic curve configuration and its backend implementation. Each curve ID represents a unique combination of curve parameters and the underlying cryptographic library used for operations.

const (
	// FP256BN_AMCL represents a 256-bit Barreto-Naehrig curve using the AMCL backend.
	// Suitable for general-purpose pairing operations with good performance.
	FP256BN_AMCL CurveID = iota

	// BN254 represents a 254-bit Barreto-Naehrig curve using the Gurvy backend.
	// Offers high performance but has tighter security margins than BLS12-381.
	BN254

	// FP256BN_AMCL_MIRACL represents a 256-bit BN curve MIRACL variant using AMCL.
	// Provided for legacy compatibility with MIRACL-based systems.
	FP256BN_AMCL_MIRACL

	// BLS12_381 represents the BLS12-381 curve using the Kilic backend.
	// Recommended for new projects due to excellent security margins and wide adoption.
	// Suitable for BLS signatures and modern cryptographic protocols.
	BLS12_381

	// BLS12_377_GURVY represents the BLS12-377 curve using the Gurvy backend.
	// Optimized for recursive proof composition in zk-SNARK systems.
	BLS12_377_GURVY

	// BLS12_381_GURVY represents the BLS12-381 curve using the Gurvy backend.
	// Performance-optimized implementation of BLS12-381 with assembly optimizations.
	BLS12_381_GURVY

	// BLS12_381_BBS is equivalent to BLS12_381 up to HashToG1 and HashToG2.
	// Those functions follow the rules of the standard draft.
	BLS12_381_BBS

	// BLS12_381_BBS_GURVY is equivalent to BLS12_381_GURVY up to HashToG1 and HashToG2.
	// Those functions follow the rules of the standard draft.
	BLS12_381_BBS_GURVY
)

type G1

type G1 struct {
	// contains filtered or unexported fields
}

G1 represents a point on the first elliptic curve group in pairing-based cryptography. G1 is typically the "smaller" group in terms of representation size and is used for signatures, commitments, and as the first argument in pairing operations.

G1 points support group operations (addition, scalar multiplication) and can be serialized in both compressed and uncompressed formats.

Example:

curve := math.Curves[math.BLS12_381]
scalar := curve.NewZrFromInt(42)
point := curve.GenG1.Mul(scalar)  // [42]G1
point.Add(curve.GenG1)            // [43]G1

func NewG1 added in v0.1.0

func NewG1(g1 driver.G1, curveID CurveID) *G1

NewG1 creates a new G1 point from a driver.G1 implementation and curve ID. This is typically used internally; users should use Curve methods like NewG1, NewG1FromBytes, or HashToG1 instead.

func (*G1) Add

func (g *G1) Add(a *G1)

Add adds point a to g in place (g = g + a).

func (*G1) Bytes

func (g *G1) Bytes() []byte

Bytes returns the uncompressed byte representation of this G1 point. The format is backend-specific but typically includes both coordinates.

func (*G1) Clone

func (g *G1) Clone(a *G1)

Clone copies the value of a into g.

func (*G1) Compressed added in v0.1.0

func (g *G1) Compressed() []byte

Compressed returns the compressed byte representation of this G1 point. Compressed format uses roughly half the space of uncompressed format.

func (*G1) Copy

func (g *G1) Copy() *G1

Copy returns a deep copy of this G1 point.

func (*G1) CurveID added in v0.1.0

func (g *G1) CurveID() CurveID

CurveID returns the curve identifier for this G1 point.

func (*G1) Equals

func (g *G1) Equals(a *G1) bool

Equals returns true if g and a represent the same point.

func (*G1) IsInfinity

func (g *G1) IsInfinity() bool

IsInfinity returns true if this point is the point at infinity (identity element).

func (*G1) MarshalJSON

func (g *G1) MarshalJSON() ([]byte, error)

func (*G1) Mul

func (g *G1) Mul(a *Zr) *G1

Mul returns a new G1 point representing scalar multiplication [a]g.

func (*G1) Mul2

func (g *G1) Mul2(e *Zr, Q *G1, f *Zr) *G1

Mul2 computes [e]g + [f]Q and returns the result as a new G1 point. This is more efficient than computing the two scalar multiplications separately.

func (*G1) Mul2InPlace added in v0.1.0

func (g *G1) Mul2InPlace(e *Zr, Q *G1, f *Zr)

Mul2InPlace computes [e]g + [f]Q and stores the result in g. This is more efficient than Mul2 when the result can overwrite g.

func (*G1) Neg added in v0.1.0

func (g *G1) Neg()

Neg negates g in place (g = -g).

func (*G1) String

func (g *G1) String() string

String returns a string representation of this G1 point.

func (*G1) Sub

func (g *G1) Sub(a *G1)

Sub subtracts point a from g in place (g = g - a).

func (*G1) UnmarshalJSON

func (g *G1) UnmarshalJSON(raw []byte) error

type G2

type G2 struct {
	// contains filtered or unexported fields
}

G2 represents a point on the second elliptic curve group in pairing-based cryptography. G2 is typically the "larger" group (on a twisted curve) and is used as the second argument in pairing operations. In many protocols, public keys reside in G2 while signatures are in G1.

G2 points support group operations (addition, scalar multiplication) and can be serialized in both compressed and uncompressed formats.

Example:

curve := math.Curves[math.BLS12_381]
scalar := curve.NewZrFromInt(42)
point := curve.GenG2.Mul(scalar)  // [42]G2

func NewG2 added in v0.1.0

func NewG2(g2 driver.G2, curveID CurveID) *G2

NewG2 creates a new G2 point from a driver.G2 implementation and curve ID. This is typically used internally; users should use Curve methods like NewG2, NewG2FromBytes, or HashToG2 instead.

func (*G2) Add

func (g *G2) Add(a *G2)

Add adds point a to g in place (g = g + a).

func (*G2) Affine

func (g *G2) Affine()

Affine converts g to affine coordinates in place. This may be required by some operations or for serialization.

func (*G2) Bytes

func (g *G2) Bytes() []byte

Bytes returns the uncompressed byte representation of this G2 point. The format is backend-specific but typically includes all coordinates.

func (*G2) Clone

func (g *G2) Clone(a *G2)

Clone copies the value of a into g.

func (*G2) Compressed added in v0.1.0

func (g *G2) Compressed() []byte

Compressed returns the compressed byte representation of this G2 point. Compressed format uses roughly half the space of uncompressed format.

func (*G2) Copy

func (g *G2) Copy() *G2

Copy returns a deep copy of this G2 point.

func (*G2) CurveID added in v0.1.0

func (g *G2) CurveID() CurveID

CurveID returns the curve identifier for this G2 point.

func (*G2) Equals

func (g *G2) Equals(a *G2) bool

Equals returns true if g and a represent the same point.

func (*G2) MarshalJSON

func (g *G2) MarshalJSON() ([]byte, error)

func (*G2) Mul

func (g *G2) Mul(a *Zr) *G2

Mul returns a new G2 point representing scalar multiplication [a]g.

func (*G2) String

func (g *G2) String() string

String returns a string representation of this G2 point.

func (*G2) Sub

func (g *G2) Sub(a *G2)

Sub subtracts point a from g in place (g = g - a).

func (*G2) UnmarshalJSON

func (g *G2) UnmarshalJSON(raw []byte) error

type Gt

type Gt struct {
	// contains filtered or unexported fields
}

Gt represents an element in the target group of a pairing operation. Gt is the multiplicative group that results from pairing G1 and G2 elements. In pairing-based cryptography, the pairing function e: G2 × G1 → Gt has the bilinearity property: e([a]G2, [b]G1) = e(G2, G1)^(ab).

Gt elements support multiplication, exponentiation, and inversion operations.

Example:

curve := math.Curves[math.BLS12_381]
gt1 := curve.Pairing(curve.GenG2, curve.GenG1)
scalar := curve.NewZrFromInt(5)
gt2 := gt1.Exp(scalar)  // gt1^5

func NewGt added in v0.1.0

func NewGt(gt driver.Gt, curveID CurveID) *Gt

NewGt creates a new Gt element from a driver.Gt implementation and curve ID. This is typically used internally; users should use Curve.Pairing or Curve.NewGtFromBytes instead.

func (*Gt) Bytes

func (g *Gt) Bytes() []byte

Bytes returns the byte representation of this Gt element. The format is backend-specific.

func (*Gt) CurveID added in v0.1.0

func (g *Gt) CurveID() CurveID

CurveID returns the curve identifier for this Gt element.

func (*Gt) Equals

func (g *Gt) Equals(a *Gt) bool

Equals returns true if g and a represent the same target group element.

func (*Gt) Exp

func (g *Gt) Exp(z *Zr) *Gt

Exp returns a new Gt element representing g^z (exponentiation).

func (*Gt) Inverse

func (g *Gt) Inverse()

Inverse computes the multiplicative inverse of g in place (g = g^-1).

func (*Gt) IsUnity

func (g *Gt) IsUnity() bool

IsUnity returns true if g is the identity element (unity) in Gt.

func (*Gt) MarshalJSON

func (g *Gt) MarshalJSON() ([]byte, error)

func (*Gt) Mul

func (g *Gt) Mul(a *Gt)

Mul multiplies g by a in place (g = g * a).

func (*Gt) String

func (g *Gt) String() string

String returns a string representation of this Gt element.

func (*Gt) UnmarshalJSON

func (g *Gt) UnmarshalJSON(raw []byte) error

type Zr

type Zr struct {
	// contains filtered or unexported fields
}

Zr represents an element in the scalar field of an elliptic curve. These are integers modulo the curve's group order, used for scalar multiplication and other arithmetic operations in pairing-based cryptography.

Zr elements support standard arithmetic operations (addition, subtraction, multiplication) as well as modular operations and conversions to/from various numeric types.

Example:

curve := math.Curves[math.BLS12_381]
a := curve.NewZrFromInt(5)
b := curve.NewZrFromInt(7)
c := a.Plus(b)  // c = 12 (mod curve order)

func NewZr added in v0.1.0

func NewZr(zr driver.Zr, curveID CurveID) *Zr

NewZr creates a new Zr element from a driver.Zr implementation and curve ID. This is typically used internally; users should use Curve methods like NewZrFromInt, NewZrFromBytes, or NewRandomZr instead.

func (*Zr) BigInt added in v0.1.0

func (z *Zr) BigInt() *big.Int

BigInt returns the scalar as a *big.Int. BigInt assumes that its output will not be altered by the caller. It responsibility of the caller to clone the output of BigInt if needed.

func (*Zr) Bytes

func (z *Zr) Bytes() []byte

Bytes returns the byte representation of this scalar. The format is backend-specific but typically big-endian.

func (*Zr) Clone

func (z *Zr) Clone(a *Zr)

Clone copies the value of a into z.

func (*Zr) Copy

func (z *Zr) Copy() *Zr

Copy returns a deep copy of this scalar.

func (*Zr) CurveID added in v0.1.0

func (z *Zr) CurveID() CurveID

CurveID returns the curve identifier for this scalar.

func (*Zr) Equals

func (z *Zr) Equals(a *Zr) bool

Equals returns true if z and a represent the same scalar value.

func (*Zr) Int

func (z *Zr) Int() (int64, error)

Int converts the scalar to an int64. Returns an error if the value is out of the int64 range.

func (*Zr) InvModOrder added in v0.1.0

func (z *Zr) InvModOrder()

InvModOrder sets z to its modular inverse modulo the curve order in place.

func (*Zr) InvModP

func (z *Zr) InvModP(a *Zr)

InvModP sets z to its modular inverse modulo a in place.

func (*Zr) IsOne added in v0.1.0

func (z *Zr) IsOne() bool

IsOne returns true if this scalar is one.

func (*Zr) IsZero added in v0.1.0

func (z *Zr) IsZero() bool

IsZero returns true if this scalar is zero.

func (*Zr) MarshalJSON

func (z *Zr) MarshalJSON() ([]byte, error)

func (*Zr) Minus added in v0.1.0

func (z *Zr) Minus(a *Zr) *Zr

Minus returns a new Zr representing (z - a) mod order.

func (*Zr) Mod

func (z *Zr) Mod(a *Zr)

Mod sets z to z mod a in place.

func (*Zr) Mul

func (z *Zr) Mul(a *Zr) *Zr

Mul returns a new Zr representing (z * a) mod order.

func (*Zr) Neg added in v0.1.0

func (z *Zr) Neg()

Neg negates z in place (z = -z mod order).

func (*Zr) Plus

func (z *Zr) Plus(a *Zr) *Zr

Plus returns a new Zr representing (z + a) mod order.

func (*Zr) PowMod

func (z *Zr) PowMod(a *Zr) *Zr

PowMod returns a new Zr representing z^a mod order.

func (*Zr) String

func (z *Zr) String() string

String returns a string representation of this scalar.

func (*Zr) Uint added in v0.1.0

func (z *Zr) Uint() (uint64, error)

Uint converts the scalar to a uint64. Returns an error if the value is out of the uint64 range.

func (*Zr) UnmarshalJSON

func (z *Zr) UnmarshalJSON(raw []byte) error

Directories

Path Synopsis
Package driver defines the interface layer for pairing-based cryptography implementations.
Package driver defines the interface layer for pairing-based cryptography implementations.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL