Files
mev-beta/vendor/github.com/crate-crypto/go-ipa/ipa/config.go

210 lines
5.9 KiB
Go

package ipa
import (
"crypto/sha256"
"encoding/binary"
"fmt"
"math"
"runtime"
"github.com/crate-crypto/go-ipa/bandersnatch/fp"
"github.com/crate-crypto/go-ipa/bandersnatch/fr"
"github.com/crate-crypto/go-ipa/banderwagon"
"github.com/crate-crypto/go-ipa/common"
)
// IPAConfig contains all the necessary information to create an IPA related proofs,
// such as the SRS, Q, and precomputed weights for the barycentric formula.
type IPAConfig struct {
SRS []banderwagon.Element
Q banderwagon.Element
PrecompMSM banderwagon.MSMPrecomp
PrecomputedWeights *PrecomputedWeights
// The number of rounds the prover and verifier must complete
// in the IPA argument, this will be log2 of the size of the input vectors
// since the vector is halved on each round
numRounds uint32
}
// NewIPASettings generates the SRS, Q and precomputed weights for the barycentric formula.
// The SRS is generated as common.VectorLength random points where the relative discrete log is
// not known between each generator.
func NewIPASettings() (*IPAConfig, error) {
srs := GenerateRandomPoints(common.VectorLength)
precompMSM, err := banderwagon.NewPrecompMSM(srs)
if err != nil {
return nil, fmt.Errorf("creating precomputed MSM: %s", err)
}
return &IPAConfig{
SRS: srs,
Q: banderwagon.Generator,
PrecompMSM: precompMSM,
PrecomputedWeights: NewPrecomputedWeights(),
numRounds: computeNumRounds(common.VectorLength),
}, nil
}
// MultiScalar computes the multi scalar multiplication of points and scalars.
func MultiScalar(points []banderwagon.Element, scalars []fr.Element) (banderwagon.Element, error) {
var result banderwagon.Element
result.SetIdentity()
res, err := result.MultiExp(points, scalars, banderwagon.MultiExpConfig{NbTasks: runtime.NumCPU(), ScalarsMont: true})
if err != nil {
return banderwagon.Element{}, fmt.Errorf("mult exponentiation was not successful: %w", err)
}
return *res, nil
}
// Commit calculates the Pedersen Commitment of a polynomial polynomial
// in evaluation form using the SRS.
func (ic *IPAConfig) Commit(polynomial []fr.Element) banderwagon.Element {
return ic.PrecompMSM.MSM(polynomial)
}
// commit commits to a polynomial using the input group elements
func commit(groupElements []banderwagon.Element, polynomial []fr.Element) (banderwagon.Element, error) {
if len(groupElements) != len(polynomial) {
return banderwagon.Element{}, fmt.Errorf("group elements and polynomial are different sizes, %d != %d", len(groupElements), len(polynomial))
}
return MultiScalar(groupElements, polynomial)
}
// InnerProd computes the inner product of a and b.
func InnerProd(a []fr.Element, b []fr.Element) (fr.Element, error) {
if len(a) != len(b) {
return fr.Element{}, fmt.Errorf("a and b are different sizes, %d != %d", len(a), len(b))
}
result := fr.Zero()
for i := 0; i < len(a); i++ {
var tmp fr.Element
tmp.Mul(&a[i], &b[i])
result.Add(&result, &tmp)
}
return result, nil
}
// Computes c[i] =a[i] + b[i] * x
// returns c
func foldScalars(a []fr.Element, b []fr.Element, x fr.Element) ([]fr.Element, error) {
if len(a) != len(b) {
return nil, fmt.Errorf("slices not equal length")
}
result := make([]fr.Element, len(a))
for i := 0; i < len(a); i++ {
var bx fr.Element
bx.Mul(&x, &b[i])
result[i].Add(&bx, &a[i])
}
return result, nil
}
// Computes c[i] =a[i] + b[i] * x
// returns c
func foldPoints(a []banderwagon.Element, b []banderwagon.Element, x fr.Element) ([]banderwagon.Element, error) {
if len(a) != len(b) {
return nil, fmt.Errorf("slices not equal length")
}
result := make([]banderwagon.Element, len(a))
for i := 0; i < len(a); i++ {
var bx banderwagon.Element
bx.ScalarMul(&b[i], &x)
result[i].Add(&bx, &a[i])
}
return result, nil
}
// Splits a slice of scalars into two slices of equal length
// Eg [S1,S2,S3,S4] becomes [S1,S2] , [S3,S4]
func splitScalars(x []fr.Element) ([]fr.Element, []fr.Element, error) {
if len(x)%2 != 0 {
return nil, nil, fmt.Errorf("slice should have an even length")
}
mid := len(x) / 2
return x[:mid], x[mid:], nil
}
// Splits a slice of points into two slices of equal length
// Eg [P1,P2,P3,P4,P5,P6] becomes [P1,P2,P3] , [P4,P5,P6]
func splitPoints(x []banderwagon.Element) ([]banderwagon.Element, []banderwagon.Element, error) {
if len(x)%2 != 0 {
return nil, nil, fmt.Errorf("slice should have an even length")
}
mid := len(x) / 2
return x[:mid], x[mid:], nil
}
// This function does log2(vector_size)
//
// Since we do not allow for 0 size vectors, this is checked
// since we also do not allow for vectors which are not powers of 2, this is also checked
//
// It is okay to panic here, because the input is a constant, so it will panic before
// any proofs are made.
func computeNumRounds(vectorSize uint32) uint32 {
// Check if this number is 0
// zero is not a valid input to this function for our usecase
if vectorSize == 0 {
panic("zero is not a valid input")
}
// See: https://stackoverflow.com/a/600306
isPow2 := (vectorSize & (vectorSize - 1)) == 0
if !isPow2 {
panic("non power of 2 numbers are not valid inputs")
}
res := math.Log2(float64(vectorSize))
return uint32(res)
}
// GenerateRandomPoints generates numPoints random points on the curve using
// hardcoded seed.
func GenerateRandomPoints(numPoints uint64) []banderwagon.Element {
seed := "eth_verkle_oct_2021"
points := []banderwagon.Element{}
var increment uint64 = 0
for uint64(len(points)) != numPoints {
digest := sha256.New()
digest.Write([]byte(seed))
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, increment)
digest.Write(b)
hash := digest.Sum(nil)
var x fp.Element
x.SetBytes(hash)
increment++
x_as_bytes := x.Bytes()
var point_found banderwagon.Element
err := point_found.SetBytes(x_as_bytes[:])
if err != nil {
// This point is not in the correct subgroup or on the curve
continue
}
points = append(points, point_found)
}
return points
}