Files
mev-beta/vendor/github.com/crate-crypto/go-eth-kzg/trusted_setup.go

202 lines
6.1 KiB
Go

package goethkzg
import (
"bytes"
_ "embed"
"encoding/hex"
"sync"
bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
)
// This library will not :
// - Check that the points are in the correct subgroup.
// - Check that setupG1Lagrange is the lagrange version of setupG1.
//
// Note: There is an embedded (via a //go:embed - compiler instruction) setup
// testKzgSetupStr, to which we do check those properties in a test function.
// JSONTrustedSetup is a struct used for serializing the trusted setup from/to JSON format.
//
// The intended use-case is that library users store the trusted setup in a JSON file and we provide such a file
// as part of the package.
type JSONTrustedSetup struct {
SetupG2 []G2CompressedHexStr `json:"g2_monomial"`
SetupG1Lagrange [ScalarsPerBlob]G1CompressedHexStr `json:"g1_lagrange"`
SetupG1Monomial [ScalarsPerBlob]G1CompressedHexStr `json:"g1_monomial"`
}
// G1CompressedHexStr is a hex-string (with the 0x prefix) of a compressed G1 point.
type G1CompressedHexStr = string
// G2CompressedHexStr is a hex-string (with the 0x prefix) of a compressed G2 point.
type G2CompressedHexStr = string
// This is the test trusted setup, which SHOULD NOT BE USED IN PRODUCTION.
// The secret for this 1337.
//
//go:embed trusted_setup.json
var testKzgSetupStr string
// CheckTrustedSetupIsWellFormed checks whether the trusted setup is well-formed.
//
// To be specific, this checks that:
// - All elements are in the correct subgroup.
func CheckTrustedSetupIsWellFormed(trustedSetup *JSONTrustedSetup) error {
for i := 0; i < len(trustedSetup.SetupG1Lagrange); i++ {
var point bls12381.G1Affine
byts, err := hex.DecodeString(trim0xPrefix(trustedSetup.SetupG1Lagrange[i]))
if err != nil {
return err
}
_, err = point.SetBytes(byts)
if err != nil {
return err
}
}
for i := 0; i < len(trustedSetup.SetupG1Monomial); i++ {
var point bls12381.G1Affine
byts, err := hex.DecodeString(trim0xPrefix(trustedSetup.SetupG1Monomial[i]))
if err != nil {
return err
}
_, err = point.SetBytes(byts)
if err != nil {
return err
}
}
for i := 0; i < len(trustedSetup.SetupG2); i++ {
var point bls12381.G2Affine
byts, err := hex.DecodeString(trim0xPrefix(trustedSetup.SetupG2[i]))
if err != nil {
return err
}
_, err = point.SetBytes(byts)
if err != nil {
return err
}
}
return nil
}
// parseTrustedSetup parses the trusted setup in `JSONTrustedSetup` format
// which contains hex encoded strings to corresponding group elements.
// Elements are assumed to be well-formed.
//
// This method wil panic if the points have not been serialized correctly.
func parseTrustedSetup(trustedSetup *JSONTrustedSetup) (bls12381.G1Affine, []bls12381.G1Affine, []bls12381.G1Affine, []bls12381.G2Affine) {
// The G1 generator is the first element of the monomial G1 points.
// We do not have that and so we use the fact that the setup started at
// the canonical generator point.
_, _, genG1, _ := bls12381.Generators()
setupLagrangeG1Points := parseG1PointsNoSubgroupCheck(trustedSetup.SetupG1Lagrange[:])
setupMonomialG1Points := parseG1PointsNoSubgroupCheck(trustedSetup.SetupG1Monomial[:])
g2Points := parseG2PointsNoSubgroupCheck(trustedSetup.SetupG2)
return genG1, setupMonomialG1Points, setupLagrangeG1Points, g2Points
}
// parseG1PointNoSubgroupCheck parses a hex-string (with the 0x prefix) into a G1 point.
//
// This function performs no (expensive) subgroup checks, and should only be used
// for trusted inputs.
func parseG1PointNoSubgroupCheck(hexString string) (bls12381.G1Affine, error) {
byts, err := hex.DecodeString(trim0xPrefix(hexString))
if err != nil {
return bls12381.G1Affine{}, err
}
var point bls12381.G1Affine
noSubgroupCheck := bls12381.NoSubgroupChecks()
d := bls12381.NewDecoder(bytes.NewReader(byts), noSubgroupCheck)
return point, d.Decode(&point)
}
// parseG2PointNoSubgroupCheck parses a hex-string (with the 0x prefix) into a G2 point.
//
// This function performs no (expensive) subgroup checks, and should only be used
// for trusted inputs.
func parseG2PointNoSubgroupCheck(hexString string) (bls12381.G2Affine, error) {
byts, err := hex.DecodeString(trim0xPrefix(hexString))
if err != nil {
return bls12381.G2Affine{}, err
}
var point bls12381.G2Affine
noSubgroupCheck := bls12381.NoSubgroupChecks()
d := bls12381.NewDecoder(bytes.NewReader(byts), noSubgroupCheck)
return point, d.Decode(&point)
}
// parseG1PointsNoSubgroupCheck parses a slice hex-string (with the 0x prefix) into a
// slice of G1 points.
//
// This is essentially a parallelized version of calling [parseG1PointNoSubgroupCheck]
// on each element of the slice individually.
//
// This function performs no (expensive) subgroup checks, and should only be used
// for trusted inputs.
func parseG1PointsNoSubgroupCheck(hexStrings []string) []bls12381.G1Affine {
numG1 := len(hexStrings)
g1Points := make([]bls12381.G1Affine, numG1)
var wg sync.WaitGroup
wg.Add(numG1)
for i := 0; i < numG1; i++ {
go func(j int) {
g1Point, err := parseG1PointNoSubgroupCheck(hexStrings[j])
if err != nil {
panic(err)
}
g1Points[j] = g1Point
wg.Done()
}(i)
}
wg.Wait()
return g1Points
}
// parseG2PointsNoSubgroupCheck parses a slice hex-string (with the 0x prefix) into a
// slice of G2 points.
//
// This is essentially a parallelized version of calling [parseG2PointNoSubgroupCheck]
// on each element of the slice individually.
//
// This function performs no (expensive) subgroup checks, and should only be used
// for trusted inputs.
func parseG2PointsNoSubgroupCheck(hexStrings []string) []bls12381.G2Affine {
numG2 := len(hexStrings)
g2Points := make([]bls12381.G2Affine, numG2)
var wg sync.WaitGroup
wg.Add(numG2)
for i := 0; i < numG2; i++ {
go func(_i int) {
g2Point, err := parseG2PointNoSubgroupCheck(hexStrings[_i])
if err != nil {
panic(err)
}
g2Points[_i] = g2Point
wg.Done()
}(i)
}
wg.Wait()
return g2Points
}
// trim0xPrefix removes the "0x" from a hex-string.
func trim0xPrefix(hexString string) string {
// Check that we are trimming off 0x
if hexString[0:2] != "0x" {
panic("hex string is not prefixed with 0x")
}
return hexString[2:]
}