mirror of
https://github.com/luxfi/accel.git
synced 2026-10-30 17:03:45 +00:00
474 lines
12 KiB
Go
474 lines
12 KiB
Go
// Package zk provides GPU-accelerated zero-knowledge proof operations.
|
|
//
|
|
// Supports NTT, MSM, polynomial arithmetic, Poseidon2 hashing, FRI folding,
|
|
// and commitment schemes. All operations use unified accel backend selection
|
|
// with automatic fallback to CPU implementations.
|
|
package zk
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/luxfi/accel"
|
|
)
|
|
|
|
// Errors
|
|
var (
|
|
ErrInvalidInput = errors.New("zk: invalid input")
|
|
ErrInvalidDegree = errors.New("zk: invalid polynomial degree")
|
|
ErrInvalidModulus = errors.New("zk: invalid modulus")
|
|
ErrDimensionMismatch = errors.New("zk: dimension mismatch")
|
|
ErrEmptyBatch = errors.New("zk: empty batch")
|
|
)
|
|
|
|
// CurveType identifies the elliptic curve for MSM operations.
|
|
type CurveType uint8
|
|
|
|
const (
|
|
CurveBN254 CurveType = iota // BN254 (alt_bn128)
|
|
CurveBLS12_381 // BLS12-381
|
|
CurveBLS12_377 // BLS12-377
|
|
CurvePallas // Pallas (Zcash/Halo2)
|
|
CurveVesta // Vesta (Zcash/Halo2)
|
|
)
|
|
|
|
// NTTParams contains parameters for Number Theoretic Transform.
|
|
type NTTParams struct {
|
|
N uint32 // Polynomial degree (power of 2)
|
|
Modulus uint64 // Prime modulus
|
|
Root uint64 // Primitive N-th root of unity mod Modulus
|
|
}
|
|
|
|
// FieldParams contains parameters for finite field operations.
|
|
type FieldParams struct {
|
|
Modulus uint64 // Prime modulus
|
|
}
|
|
|
|
// Poseidon2Params contains parameters for Poseidon2 hash.
|
|
type Poseidon2Params struct {
|
|
T uint32 // State width (t)
|
|
D uint32 // S-box degree (typically 5 or 7)
|
|
RoundsF uint32 // Full rounds
|
|
RoundsP uint32 // Partial rounds
|
|
Modulus uint64 // Field modulus
|
|
RoundConst []uint64 // Round constants
|
|
MDS []uint64 // MDS matrix (t x t)
|
|
}
|
|
|
|
// CommitParams contains parameters for polynomial commitments.
|
|
type CommitParams struct {
|
|
Curve CurveType // Curve for commitment
|
|
Degree uint32 // Maximum polynomial degree
|
|
}
|
|
|
|
// FRIParams contains parameters for FRI folding.
|
|
type FRIParams struct {
|
|
Modulus uint64 // Field modulus
|
|
FoldFactor uint32 // Folding factor (typically 2 or 4)
|
|
BlowupFactor uint32 // Reed-Solomon blowup factor
|
|
}
|
|
|
|
// NTT performs forward Number Theoretic Transform.
|
|
// Transforms polynomial from coefficient to evaluation form.
|
|
func NTT(params NTTParams, coeffs []uint64) ([]uint64, error) {
|
|
if len(coeffs) != int(params.N) {
|
|
return nil, ErrInvalidDegree
|
|
}
|
|
if params.Modulus == 0 {
|
|
return nil, ErrInvalidModulus
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return nttCPU(params, coeffs)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return nttGPU(sess, params, coeffs)
|
|
}
|
|
|
|
// INTT performs inverse Number Theoretic Transform.
|
|
// Transforms polynomial from evaluation to coefficient form.
|
|
func INTT(params NTTParams, evals []uint64) ([]uint64, error) {
|
|
if len(evals) != int(params.N) {
|
|
return nil, ErrInvalidDegree
|
|
}
|
|
if params.Modulus == 0 {
|
|
return nil, ErrInvalidModulus
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return inttCPU(params, evals)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return inttGPU(sess, params, evals)
|
|
}
|
|
|
|
// BatchNTT performs forward NTT on multiple polynomials in parallel.
|
|
func BatchNTT(params NTTParams, polys [][]uint64) ([][]uint64, error) {
|
|
if len(polys) == 0 {
|
|
return nil, ErrEmptyBatch
|
|
}
|
|
for _, p := range polys {
|
|
if len(p) != int(params.N) {
|
|
return nil, ErrInvalidDegree
|
|
}
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return batchNTTCPU(params, polys)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return batchNTTGPU(sess, params, polys)
|
|
}
|
|
|
|
// BatchINTT performs inverse NTT on multiple polynomials in parallel.
|
|
func BatchINTT(params NTTParams, polys [][]uint64) ([][]uint64, error) {
|
|
if len(polys) == 0 {
|
|
return nil, ErrEmptyBatch
|
|
}
|
|
for _, p := range polys {
|
|
if len(p) != int(params.N) {
|
|
return nil, ErrInvalidDegree
|
|
}
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return batchINTTCPU(params, polys)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return batchINTTGPU(sess, params, polys)
|
|
}
|
|
|
|
// MSM performs multi-scalar multiplication.
|
|
// result = sum(scalars[i] * points[i]) for all i
|
|
func MSM(curve CurveType, scalars, points [][]byte) ([]byte, error) {
|
|
if len(scalars) != len(points) {
|
|
return nil, ErrDimensionMismatch
|
|
}
|
|
if len(scalars) == 0 {
|
|
return nil, ErrEmptyBatch
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return msmCPU(curve, scalars, points)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return msmGPU(sess, curve, scalars, points)
|
|
}
|
|
|
|
// MSMBatch performs multiple MSMs in parallel.
|
|
func MSMBatch(curve CurveType, scalars, points [][][]byte) ([][]byte, error) {
|
|
if len(scalars) != len(points) {
|
|
return nil, ErrDimensionMismatch
|
|
}
|
|
if len(scalars) == 0 {
|
|
return nil, ErrEmptyBatch
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return msmBatchCPU(curve, scalars, points)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return msmBatchGPU(sess, curve, scalars, points)
|
|
}
|
|
|
|
// Poseidon2 computes Poseidon2 hash of inputs.
|
|
// Returns field element as uint64 (for fields <= 64 bits) or []byte.
|
|
func Poseidon2(params Poseidon2Params, inputs []uint64) (uint64, error) {
|
|
if len(inputs) == 0 {
|
|
return 0, ErrInvalidInput
|
|
}
|
|
if params.Modulus == 0 {
|
|
return 0, ErrInvalidModulus
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return poseidon2CPU(params, inputs)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return poseidon2GPU(sess, params, inputs)
|
|
}
|
|
|
|
// Poseidon2Hash computes Poseidon2 hash for Merkle trees.
|
|
// left and right are field elements to hash together.
|
|
func Poseidon2Hash(params Poseidon2Params, left, right uint64) (uint64, error) {
|
|
if params.Modulus == 0 {
|
|
return 0, ErrInvalidModulus
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return poseidon2HashCPU(params, left, right)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return poseidon2HashGPU(sess, params, left, right)
|
|
}
|
|
|
|
// BatchPoseidon2Hash computes multiple Poseidon2 hashes in parallel.
|
|
// Used for building Merkle trees efficiently.
|
|
func BatchPoseidon2Hash(params Poseidon2Params, lefts, rights []uint64) ([]uint64, error) {
|
|
if len(lefts) != len(rights) {
|
|
return nil, ErrDimensionMismatch
|
|
}
|
|
if len(lefts) == 0 {
|
|
return nil, ErrEmptyBatch
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return batchPoseidon2HashCPU(params, lefts, rights)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return batchPoseidon2HashGPU(sess, params, lefts, rights)
|
|
}
|
|
|
|
// PolyAdd adds two polynomials coefficient-wise.
|
|
func PolyAdd(params FieldParams, a, b []uint64) ([]uint64, error) {
|
|
if len(a) != len(b) {
|
|
return nil, ErrDimensionMismatch
|
|
}
|
|
if len(a) == 0 {
|
|
return nil, ErrInvalidInput
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return polyAddCPU(params, a, b)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return polyAddGPU(sess, params, a, b)
|
|
}
|
|
|
|
// PolySub subtracts two polynomials coefficient-wise.
|
|
func PolySub(params FieldParams, a, b []uint64) ([]uint64, error) {
|
|
if len(a) != len(b) {
|
|
return nil, ErrDimensionMismatch
|
|
}
|
|
if len(a) == 0 {
|
|
return nil, ErrInvalidInput
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return polySubCPU(params, a, b)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return polySubGPU(sess, params, a, b)
|
|
}
|
|
|
|
// PolyMul multiplies two polynomials using NTT.
|
|
// Result is in coefficient form with degree len(a) + len(b) - 1.
|
|
func PolyMul(params NTTParams, a, b []uint64) ([]uint64, error) {
|
|
if len(a) != int(params.N) || len(b) != int(params.N) {
|
|
return nil, ErrInvalidDegree
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return polyMulCPU(params, a, b)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return polyMulGPU(sess, params, a, b)
|
|
}
|
|
|
|
// PolyMulPointwise multiplies polynomials in NTT domain (pointwise).
|
|
func PolyMulPointwise(params FieldParams, a, b []uint64) ([]uint64, error) {
|
|
if len(a) != len(b) {
|
|
return nil, ErrDimensionMismatch
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return polyMulPointwiseCPU(params, a, b)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return polyMulPointwiseGPU(sess, params, a, b)
|
|
}
|
|
|
|
// PolyEval evaluates polynomial at given points.
|
|
// coeffs: [degree+1] coefficients, points: evaluation points
|
|
// Returns values[i] = poly(points[i])
|
|
func PolyEval(params FieldParams, coeffs, points []uint64) ([]uint64, error) {
|
|
if len(coeffs) == 0 || len(points) == 0 {
|
|
return nil, ErrInvalidInput
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return polyEvalCPU(params, coeffs, points)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return polyEvalGPU(sess, params, coeffs, points)
|
|
}
|
|
|
|
// PolyInterpolate computes polynomial from points using Lagrange interpolation.
|
|
// xs, ys: evaluation points and values
|
|
// Returns polynomial coefficients.
|
|
func PolyInterpolate(params FieldParams, xs, ys []uint64) ([]uint64, error) {
|
|
if len(xs) != len(ys) {
|
|
return nil, ErrDimensionMismatch
|
|
}
|
|
if len(xs) == 0 {
|
|
return nil, ErrInvalidInput
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return polyInterpolateCPU(params, xs, ys)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return polyInterpolateGPU(sess, params, xs, ys)
|
|
}
|
|
|
|
// FRIFold performs FRI folding step.
|
|
// evals: polynomial evaluations at rate-2 LDE
|
|
// alpha: random folding challenge
|
|
// Returns folded polynomial evaluations.
|
|
func FRIFold(params FRIParams, evals []uint64, alpha uint64) ([]uint64, error) {
|
|
if len(evals) == 0 || len(evals)&1 != 0 {
|
|
return nil, ErrInvalidInput
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return friFoldCPU(params, evals, alpha)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return friFoldGPU(sess, params, evals, alpha)
|
|
}
|
|
|
|
// FRIQueryPhase computes query responses for FRI protocol.
|
|
// evals: committed polynomial evaluations
|
|
// indices: query indices
|
|
// Returns query response data.
|
|
func FRIQueryPhase(params FRIParams, evals []uint64, indices []uint32) ([][]uint64, error) {
|
|
if len(evals) == 0 || len(indices) == 0 {
|
|
return nil, ErrInvalidInput
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return friQueryPhaseCPU(params, evals, indices)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return friQueryPhaseGPU(sess, params, evals, indices)
|
|
}
|
|
|
|
// CommitPoly computes a polynomial commitment (KZG).
|
|
// coeffs: polynomial coefficients
|
|
// srs: structured reference string (powers of tau)
|
|
// Returns commitment point in compressed form.
|
|
func CommitPoly(params CommitParams, coeffs [][]byte, srs [][]byte) ([]byte, error) {
|
|
if len(coeffs) == 0 {
|
|
return nil, ErrInvalidInput
|
|
}
|
|
if uint32(len(coeffs)) > params.Degree+1 {
|
|
return nil, ErrInvalidDegree
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return commitPolyCPU(params, coeffs, srs)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return commitPolyGPU(sess, params, coeffs, srs)
|
|
}
|
|
|
|
// BatchCommitPoly computes multiple polynomial commitments in parallel.
|
|
func BatchCommitPoly(params CommitParams, coeffsList [][][]byte, srs [][]byte) ([][]byte, error) {
|
|
if len(coeffsList) == 0 {
|
|
return nil, ErrEmptyBatch
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return batchCommitPolyCPU(params, coeffsList, srs)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return batchCommitPolyGPU(sess, params, coeffsList, srs)
|
|
}
|
|
|
|
// FieldAdd adds field elements.
|
|
func FieldAdd(params FieldParams, a, b []uint64) ([]uint64, error) {
|
|
if len(a) != len(b) {
|
|
return nil, ErrDimensionMismatch
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return fieldAddCPU(params, a, b)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return fieldAddGPU(sess, params, a, b)
|
|
}
|
|
|
|
// FieldMul multiplies field elements.
|
|
func FieldMul(params FieldParams, a, b []uint64) ([]uint64, error) {
|
|
if len(a) != len(b) {
|
|
return nil, ErrDimensionMismatch
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return fieldMulCPU(params, a, b)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return fieldMulGPU(sess, params, a, b)
|
|
}
|
|
|
|
// FieldInv computes modular inverse of field elements.
|
|
func FieldInv(params FieldParams, a []uint64) ([]uint64, error) {
|
|
if len(a) == 0 {
|
|
return nil, ErrInvalidInput
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return fieldInvCPU(params, a)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return fieldInvGPU(sess, params, a)
|
|
}
|
|
|
|
// FieldExp computes a^exp mod modulus for each element.
|
|
func FieldExp(params FieldParams, a []uint64, exp uint64) ([]uint64, error) {
|
|
if len(a) == 0 {
|
|
return nil, ErrInvalidInput
|
|
}
|
|
|
|
sess, err := accel.NewSession()
|
|
if err != nil {
|
|
return fieldExpCPU(params, a, exp)
|
|
}
|
|
defer sess.Close()
|
|
|
|
return fieldExpGPU(sess, params, a, exp)
|
|
}
|