mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-08 03:43:56 -05:00
refactor: Use new GKR API (#1064)
* use new gkr API
* fix Table pointers
* refactor: remove removed test engine option
* chore: don't initialize struct for interface assertion
* refactor: plonk-in-wizard hardcoded over U64 for now
* refactor: use new gnark-crypto stateless RSis API
* test: disable incompatible tests
* chore: go mod update to PR tip
* chore: dependency against gnark master
* chore: cherry-pick 43141fc13d
* test: cherry pick test from 407d2e25ecfc32f5ed702ab42e5b829d7cabd483
* chore: remove magic values
* chore: update go version in Docker builder to match go.mod
---------
Co-authored-by: Ivo Kubjas <ivo.kubjas@consensys.net>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
# G O + R U S T B U I L D E R
|
||||
#
|
||||
###############################
|
||||
FROM golang:1.22.7-alpine AS go-builder
|
||||
FROM golang:1.23.10-alpine AS go-builder
|
||||
|
||||
RUN apk add --no-cache rust cargo bash make
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ func (c *Circuit) Define(api frontend.API) error {
|
||||
}
|
||||
|
||||
// create a lookup table of actual public inputs
|
||||
actualPI := make([]*logderivlookup.Table, (emFr{}).NbLimbs())
|
||||
actualPI := make([]logderivlookup.Table, (emFr{}).NbLimbs())
|
||||
for i := range actualPI {
|
||||
actualPI[i] = logderivlookup.New(api)
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@ import (
|
||||
// TODO Use std/rangecheck instead
|
||||
type RangeChecker struct {
|
||||
api frontend.API
|
||||
tables map[uint]*logderivlookup.Table
|
||||
tables map[uint]logderivlookup.Table
|
||||
}
|
||||
|
||||
func NewRangeChecker(api frontend.API) *RangeChecker {
|
||||
return &RangeChecker{api: api, tables: make(map[uint]*logderivlookup.Table)}
|
||||
return &RangeChecker{api: api, tables: make(map[uint]logderivlookup.Table)}
|
||||
}
|
||||
|
||||
func (r *RangeChecker) AssertLessThan(bound uint, c ...frontend.Variable) {
|
||||
|
||||
@@ -126,7 +126,7 @@ func Decompress(api frontend.API, c []frontend.Variable, cLength frontend.Variab
|
||||
return dLength, nil
|
||||
}
|
||||
|
||||
func initAddrTable(api frontend.API, bytes, c []frontend.Variable, wordNbBits int, backrefs []lzss.BackrefType) *logderivlookup.Table {
|
||||
func initAddrTable(api frontend.API, bytes, c []frontend.Variable, wordNbBits int, backrefs []lzss.BackrefType) logderivlookup.Table {
|
||||
for i := range backrefs {
|
||||
if backrefs[i].NbBitsLength != backrefs[0].NbBitsLength {
|
||||
panic("all backref types must have the same length size")
|
||||
|
||||
@@ -180,7 +180,7 @@ func CheckBatchesSums(api frontend.API, hasher snarkHash.FieldHasher, nbBatches
|
||||
}
|
||||
|
||||
var (
|
||||
partialSumsT *logderivlookup.Table
|
||||
partialSumsT logderivlookup.Table
|
||||
partialSums []frontend.Variable
|
||||
)
|
||||
// create a table of claimed sums and prove their correctness as we go through the payload
|
||||
|
||||
@@ -40,7 +40,7 @@ func AssertIsLessIf(api frontend.API, cond, a, b frontend.Variable) {
|
||||
api.AssertIsLessOrEqual(a_, b_)
|
||||
}
|
||||
|
||||
func SliceToTable(api frontend.API, slice []frontend.Variable) *logderivlookup.Table {
|
||||
func SliceToTable(api frontend.API, slice []frontend.Variable) logderivlookup.Table {
|
||||
table := logderivlookup.New(api)
|
||||
for i := range slice {
|
||||
table.Insert(slice[i])
|
||||
@@ -271,7 +271,7 @@ func (s VarSlice) Range(api frontend.API) *Range {
|
||||
func Concat(api frontend.API, maxLinearizedLength int, slices ...VarSlice) Slice[frontend.Variable] {
|
||||
|
||||
res := Slice[frontend.Variable]{make([]frontend.Variable, maxLinearizedLength), 0}
|
||||
var outT *logderivlookup.Table
|
||||
var outT logderivlookup.Table
|
||||
{ // hint
|
||||
inLen := 2 * len(slices)
|
||||
for i := range slices {
|
||||
@@ -414,7 +414,7 @@ func ChecksumSubSlices(api frontend.API, hsh snarkHash.FieldHasher, slice []fron
|
||||
lastElems[i] =
|
||||
plonk.EvaluateExpression(api, e, endpointsR.InRange[i], 0, -1-len(slice), 1, len(slice))
|
||||
}
|
||||
var lastElemsT *logderivlookup.Table
|
||||
var lastElemsT logderivlookup.Table
|
||||
if len(slice) > 1 {
|
||||
lastElemsT = SliceToTable(api, lastElems)
|
||||
lastElemsT.Insert(len(slice)) // in case subEndPoints is tight
|
||||
@@ -730,7 +730,7 @@ func PartitionSlice(api frontend.API, s []frontend.Variable, selectors []fronten
|
||||
panic(err)
|
||||
}
|
||||
|
||||
subsT := make([]*logderivlookup.Table, len(subs))
|
||||
subsT := make([]logderivlookup.Table, len(subs))
|
||||
for i := range subs {
|
||||
copy(subs[i], subsGlued[:len(subs[i])])
|
||||
subsGlued = subsGlued[len(subs[i]):]
|
||||
|
||||
@@ -86,7 +86,9 @@ func ProveCheck(setup *Setup, assignment frontend.Circuit, opts ...any) (plonk.P
|
||||
assignment,
|
||||
assignment,
|
||||
setup.Circuit.Field(),
|
||||
test.WithBackendProverOptions(proverOpts...),
|
||||
// the test engine never accounted for passed in prover options, so
|
||||
// we removed the option from gnark.
|
||||
// test.WithBackendProverOptions(proverOpts...),
|
||||
)
|
||||
return nil, fmt.Errorf("while running the plonk prover: %w", errDetail)
|
||||
}
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
package gkrmimc
|
||||
|
||||
import (
|
||||
"github.com/consensys/gnark/frontend"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
)
|
||||
|
||||
// FinalRoundGate represents the last round in a gnark circuit
|
||||
//
|
||||
// It performs all the actions required to complete the compression function of
|
||||
// MiMC; including (1) the last application of the S-box x^17 as in the
|
||||
// intermediate rounds and then adds twice the initial state and once the block
|
||||
// to the result before returning.
|
||||
type FinalRoundGate struct {
|
||||
Ark frontend.Variable
|
||||
}
|
||||
|
||||
// NewFinalRoundGateGnark creates a new FinalRoundGate using the provided
|
||||
// round constant which should correspond to the final rounds's constant of
|
||||
// MiMC.
|
||||
func NewFinalRoundGateGnark(ark field.Element) FinalRoundGate {
|
||||
return FinalRoundGate{
|
||||
Ark: ark,
|
||||
}
|
||||
}
|
||||
|
||||
func (m FinalRoundGate) Evaluate(api frontend.API, input ...frontend.Variable) frontend.Variable {
|
||||
|
||||
if len(input) != 3 {
|
||||
utils.Panic("expected fan-in of 3, got %v", len(input))
|
||||
}
|
||||
|
||||
// Parse the inputs
|
||||
initialState := input[0]
|
||||
block := input[1]
|
||||
currentState := input[2]
|
||||
|
||||
// Compute the S-box function
|
||||
sum := api.Add(currentState, initialState, m.Ark)
|
||||
sumPow16 := api.Mul(sum, sum) // sum^2
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^4
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^8
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^16
|
||||
sum = api.Mul(sumPow16, sum)
|
||||
|
||||
// And add back the last values, following the Miyaguchi-Preneel
|
||||
// construction.
|
||||
return api.Add(sum, initialState, initialState, block)
|
||||
}
|
||||
|
||||
func (m FinalRoundGate) Degree() int {
|
||||
return 17
|
||||
}
|
||||
|
||||
// FinalRoundGateCrypto represents the last round in the GKR circuit for MiMC.
|
||||
//
|
||||
// It performs all the actions required to complete the compression function of
|
||||
// MiMC; including (1) the last application of the S-box x^17 as in the
|
||||
// intermediate rounds and then adds twice the initial state and once the block
|
||||
// to the result before returning.
|
||||
type FinalRoundGateCrypto struct {
|
||||
Ark field.Element
|
||||
}
|
||||
|
||||
// NewFinalRoundGateCrypto creates a new MiMCCipherGate with the given parameters
|
||||
func NewFinalRoundGateCrypto(ark field.Element) FinalRoundGateCrypto {
|
||||
return FinalRoundGateCrypto{
|
||||
Ark: ark,
|
||||
}
|
||||
}
|
||||
|
||||
func (m FinalRoundGateCrypto) Evaluate(input ...field.Element) field.Element {
|
||||
|
||||
if len(input) != 3 {
|
||||
utils.Panic("expected fan-in of 3, got %v", len(input))
|
||||
}
|
||||
|
||||
// Parse the inputs
|
||||
initialState := input[0]
|
||||
block := input[1]
|
||||
curr := input[2]
|
||||
|
||||
// Compute the S-box function
|
||||
var sum, sumPow16 field.Element
|
||||
sum.Add(&initialState, &curr).Add(&sum, &m.Ark)
|
||||
sumPow16.Mul(&sum, &sum)
|
||||
sumPow16.Mul(&sumPow16, &sumPow16)
|
||||
sumPow16.Mul(&sumPow16, &sumPow16)
|
||||
sumPow16.Mul(&sumPow16, &sumPow16)
|
||||
sum.Mul(&sumPow16, &sum)
|
||||
|
||||
// And add back the last values, following the Miyaguchi-Preneel
|
||||
// construction.
|
||||
sum.Add(&sum, &initialState)
|
||||
sum.Add(&sum, &initialState)
|
||||
sum.Add(&sum, &block)
|
||||
return sum
|
||||
}
|
||||
|
||||
func (m FinalRoundGateCrypto) Degree() int {
|
||||
return 17
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
package gkrmimc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
cGkr "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/gkr"
|
||||
"github.com/consensys/gnark/constraint"
|
||||
cs "github.com/consensys/gnark/constraint/bls12-377"
|
||||
"github.com/consensys/gnark-crypto/ecc"
|
||||
"github.com/consensys/gnark/constraint/solver"
|
||||
"github.com/consensys/gnark/constraint/solver/gkrgates"
|
||||
"github.com/consensys/gnark/frontend"
|
||||
gGkr "github.com/consensys/gnark/std/gkr"
|
||||
"github.com/consensys/gnark/std/hash"
|
||||
gmimc "github.com/consensys/gnark/std/hash/mimc"
|
||||
"github.com/consensys/gnark/std/gkrapi"
|
||||
"github.com/consensys/gnark/std/gkrapi/gkr"
|
||||
"github.com/consensys/gnark/std/multicommit"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/mimc"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -21,22 +21,16 @@ import (
|
||||
var (
|
||||
prefetchSize = 4 // all layers before the "actual" MiMc round layers
|
||||
numGates int = prefetchSize + len(mimc.Constants)
|
||||
gateNames []string
|
||||
gateNames []gkr.GateName
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Registers the names of the GKR gates into the global GKR registry.
|
||||
createGateNames()
|
||||
registerGates()
|
||||
if err := registerGates(); err != nil {
|
||||
panic(fmt.Errorf("failed to register gates: %w", err))
|
||||
}
|
||||
|
||||
// Registers the mimc hash function in the hash builder registry.
|
||||
hash.Register("mimc", func(api frontend.API) (hash.FieldHasher, error) {
|
||||
h, err := gmimc.NewMiMC(api)
|
||||
return &h, err
|
||||
})
|
||||
|
||||
// Registers the hasher to be used in the GKR prover
|
||||
cs.RegisterHashBuilder("mimc", mimc.NewMiMC)
|
||||
solver.RegisterHint(mimcHintfunc)
|
||||
}
|
||||
|
||||
@@ -57,7 +51,7 @@ func createGateNames() {
|
||||
nbDigits++
|
||||
}
|
||||
|
||||
gateNames = make([]string, numGates)
|
||||
gateNames = make([]gkr.GateName, numGates)
|
||||
|
||||
gateNames[0] = "input" // no name necessary. will map to nil. this is just for clarity
|
||||
gateNames[1] = "input"
|
||||
@@ -68,23 +62,42 @@ func createGateNames() {
|
||||
var gateNameBuilder strings.Builder
|
||||
gateNameBuilder.WriteString("mimc")
|
||||
writePaddedHex(&gateNameBuilder, i, nbDigits)
|
||||
gateNames[i] = gateNameBuilder.String()
|
||||
gateNames[i] = gkr.GateName(gateNameBuilder.String())
|
||||
}
|
||||
}
|
||||
|
||||
// registerGates instantiates and populates the cGkr and gGkr global variables
|
||||
// registerGates instantiates and populates the cGkr and gkr global variables
|
||||
// which contains the "normal" and the "gnark" version of the GKR gates forming
|
||||
// the MiMC GKR circuit.
|
||||
func registerGates() {
|
||||
func registerGates() error {
|
||||
const (
|
||||
ROUND_GATE_NB_INPUTS = 2 // initial state and current state
|
||||
FINAL_GATE_NB_INPUTS = 3 // initial state, block and current state
|
||||
GATE_DEGREE = 17 // MiMC S-box degree for BLS12-377
|
||||
)
|
||||
for i := 4; i < numGates-1; i++ {
|
||||
name := gateNames[i]
|
||||
gGkr.Gates[name] = NewRoundGateGnark(mimc.Constants[i-prefetchSize])
|
||||
cGkr.Gates[name] = NewRoundGateCrypto(mimc.Constants[i-prefetchSize])
|
||||
if err := gkrgates.Register(
|
||||
RoundGate(mimc.Constants[i-prefetchSize]),
|
||||
ROUND_GATE_NB_INPUTS,
|
||||
gkrgates.WithName(gateNames[i]),
|
||||
gkrgates.WithUnverifiedDegree(GATE_DEGREE),
|
||||
gkrgates.WithCurves(ecc.BLS12_377),
|
||||
); err != nil {
|
||||
return fmt.Errorf("failed to register gate %s: %v", gateNames[i], err)
|
||||
}
|
||||
}
|
||||
|
||||
name := gateNames[numGates-1]
|
||||
gGkr.Gates[name] = NewFinalRoundGateGnark(mimc.Constants[len(mimc.Constants)-1])
|
||||
cGkr.Gates[name] = NewFinalRoundGateCrypto(mimc.Constants[len(mimc.Constants)-1])
|
||||
if err := gkrgates.Register(
|
||||
FinalRoundGate(mimc.Constants[len(mimc.Constants)-1]),
|
||||
FINAL_GATE_NB_INPUTS,
|
||||
gkrgates.WithName(gateNames[numGates-1]),
|
||||
gkrgates.WithUnverifiedDegree(GATE_DEGREE),
|
||||
gkrgates.WithCurves(ecc.BLS12_377),
|
||||
); err != nil {
|
||||
return fmt.Errorf("failed to register gate %s: %v", gateNames[numGates-1], err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// gkrMiMC constructs and return the GKR circuit. The function is concretely
|
||||
@@ -94,25 +107,25 @@ func registerGates() {
|
||||
// The returned object symbolizees the last layer of the GKR circuit and formally
|
||||
// contains the result of the MiMC block compression as computed by the GKR
|
||||
// circuit.
|
||||
func gkrMiMC(gkr *gGkr.API, initStates, blocks []frontend.Variable) (constraint.GkrVariable, error) {
|
||||
func gkrMiMC(gkrapi *gkrapi.API, initStates, blocks []frontend.Variable) (gkr.Variable, error) {
|
||||
|
||||
var err error
|
||||
v := make([]constraint.GkrVariable, numGates-1)
|
||||
if v[0], err = gkr.Import(initStates); err != nil {
|
||||
v := make([]gkr.Variable, numGates-1)
|
||||
if v[0], err = gkrapi.Import(initStates); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if v[1], err = gkr.Import(blocks); err != nil {
|
||||
if v[1], err = gkrapi.Import(blocks); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v[2] = gkr.NamedGate("identity", v[0])
|
||||
v[3] = gkr.NamedGate("identity", v[1])
|
||||
v[2] = gkrapi.NamedGate("identity", v[0])
|
||||
v[3] = gkrapi.NamedGate("identity", v[1])
|
||||
|
||||
for i := 4; i < numGates-1; i++ {
|
||||
v[i] = gkr.NamedGate(gateNames[i], v[2], v[i-1])
|
||||
v[i] = gkrapi.NamedGate(gateNames[i], v[2], v[i-1])
|
||||
}
|
||||
|
||||
res := gkr.NamedGate(gateNames[numGates-1], v[2], v[3], v[numGates-2])
|
||||
res := gkrapi.NamedGate(gateNames[numGates-1], v[2], v[3], v[numGates-2])
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@@ -126,7 +139,7 @@ func gkrMiMC(gkr *gGkr.API, initStates, blocks []frontend.Variable) (constraint.
|
||||
// instances are the inner indexes
|
||||
func checkWithGkr(api frontend.API, initStates, blocks, allegedNewState []frontend.Variable) {
|
||||
|
||||
gkr := gGkr.NewApi()
|
||||
gkr := gkrapi.New()
|
||||
|
||||
D, err := gkrMiMC(gkr, initStates, blocks)
|
||||
if err != nil {
|
||||
@@ -134,7 +147,7 @@ func checkWithGkr(api frontend.API, initStates, blocks, allegedNewState []fronte
|
||||
}
|
||||
|
||||
// This creates a placeholder that will contain the GKR assignment
|
||||
var solution gGkr.Solution
|
||||
var solution gkrapi.Solution
|
||||
if solution, err = gkr.Solve(api); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -150,9 +163,9 @@ func checkWithGkr(api frontend.API, initStates, blocks, allegedNewState []fronte
|
||||
func(api frontend.API, initialChallenge frontend.Variable) error {
|
||||
logrus.Infof("defining the constraints of the GKR verifier")
|
||||
|
||||
// "mimc" means that we are using MiMC hashes to compute the FS challenges
|
||||
// "MIMC" means that we are using MiMC hashes to compute the FS challenges
|
||||
// this part is responsible for verifying the GKR proof.
|
||||
err = solution.Verify("mimc", initialChallenge)
|
||||
err = solution.Verify("MIMC", initialChallenge)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -176,3 +189,61 @@ func checkWithGkr(api frontend.API, initStates, blocks, allegedNewState []fronte
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// RoundGate represents a normal round of gkr (i.e. any round except for the
|
||||
// first and last ones). It represents the computation of the S-box of MiMC
|
||||
//
|
||||
// (curr + init + ark)^17
|
||||
//
|
||||
// This struct is meant to be used to represent the GKR gate within a gnark
|
||||
// circuit and is used for the verifier part of GKR.
|
||||
func RoundGate(ark field.Element) gkr.GateFunction {
|
||||
return func(api gkr.GateAPI, input ...frontend.Variable) frontend.Variable {
|
||||
if len(input) != 2 {
|
||||
panic("mimc has fan-in 2")
|
||||
}
|
||||
|
||||
initialState := input[0]
|
||||
curr := input[1]
|
||||
|
||||
// Compute the s-box (curr + init + ark)^17
|
||||
sum := api.Add(curr, initialState, ark)
|
||||
|
||||
sumPow16 := api.Mul(sum, sum) // sum^2
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^4
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^8
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^16
|
||||
return api.Mul(sumPow16, sum)
|
||||
}
|
||||
}
|
||||
|
||||
// FinalRoundGate represents the last round in a gnark circuit
|
||||
//
|
||||
// It performs all the actions required to complete the compression function of
|
||||
// MiMC; including (1) the last application of the S-box x^17 as in the
|
||||
// intermediate rounds and then adds twice the initial state and once the block
|
||||
// to the result before returning.
|
||||
func FinalRoundGate(ark field.Element) gkr.GateFunction {
|
||||
return func(api gkr.GateAPI, input ...frontend.Variable) frontend.Variable {
|
||||
if len(input) != 3 {
|
||||
utils.Panic("expected fan-in of 3, got %v", len(input))
|
||||
}
|
||||
|
||||
// Parse the inputs
|
||||
initialState := input[0]
|
||||
block := input[1]
|
||||
currentState := input[2]
|
||||
|
||||
// Compute the S-box function
|
||||
sum := api.Add(currentState, initialState, ark)
|
||||
sumPow16 := api.Mul(sum, sum) // sum^2
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^4
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^8
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^16
|
||||
sum = api.Mul(sumPow16, sum)
|
||||
|
||||
// And add back the last values, following the Miyaguchi-Preneel
|
||||
// construction.
|
||||
return api.Add(sum, initialState, initialState, block)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
package gkrmimc
|
||||
|
||||
import (
|
||||
"github.com/consensys/gnark/frontend"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
)
|
||||
|
||||
// RoundGate represents a normal round of gkr (i.e. any round except for the
|
||||
// first and last ones). It represents the computation of the S-box of MiMC
|
||||
//
|
||||
// (curr + init + ark)^17
|
||||
//
|
||||
// This struct is meant to be used to represent the GKR gate within a gnark
|
||||
// circuit and is used for the verifier part of GKR.
|
||||
type RoundGate struct {
|
||||
Ark frontend.Variable
|
||||
}
|
||||
|
||||
// NewRoundGateGnark creates a new RoundGate using the provided round constant
|
||||
func NewRoundGateGnark(ark field.Element) *RoundGate {
|
||||
return &RoundGate{
|
||||
Ark: ark,
|
||||
}
|
||||
}
|
||||
|
||||
func (m RoundGate) Evaluate(api frontend.API, input ...frontend.Variable) frontend.Variable {
|
||||
|
||||
if len(input) != 2 {
|
||||
panic("mimc has fan-in 2")
|
||||
}
|
||||
|
||||
initialState := input[0]
|
||||
curr := input[1]
|
||||
|
||||
// Compute the s-box (curr + init + ark)^17
|
||||
sum := api.Add(curr, initialState, m.Ark)
|
||||
|
||||
sumPow16 := api.Mul(sum, sum) // sum^2
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^4
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^8
|
||||
sumPow16 = api.Mul(sumPow16, sumPow16) // sum^16
|
||||
return api.Mul(sumPow16, sum)
|
||||
}
|
||||
|
||||
func (m RoundGate) Degree() int {
|
||||
return 17
|
||||
}
|
||||
|
||||
// RoundGate represents a normal round of gkr (i.e. any round except for the
|
||||
// first and last ones). It represents the computation of the S-box of MiMC
|
||||
//
|
||||
// (curr + init + ark)^17
|
||||
//
|
||||
// This struct is meant to be used for the prover part of GKR
|
||||
type RoundGateCrypto struct {
|
||||
Ark field.Element
|
||||
}
|
||||
|
||||
// NewRoundGateCrypto construct a new instance of a [RoundGate] with the
|
||||
// caller-supplied round constant `ark`
|
||||
func NewRoundGateCrypto(ark field.Element) *RoundGateCrypto {
|
||||
return &RoundGateCrypto{Ark: ark}
|
||||
}
|
||||
|
||||
func (m RoundGateCrypto) Evaluate(inputs ...field.Element) field.Element {
|
||||
|
||||
if len(inputs) != 2 {
|
||||
panic("mimc has fan-in 2")
|
||||
}
|
||||
|
||||
initialState := inputs[0]
|
||||
curr := inputs[1]
|
||||
|
||||
var sum, sumPow16 field.Element
|
||||
sum.Add(&initialState, &curr).Add(&sum, &m.Ark)
|
||||
sumPow16.Mul(&sum, &sum)
|
||||
sumPow16.Mul(&sumPow16, &sumPow16)
|
||||
sumPow16.Mul(&sumPow16, &sumPow16)
|
||||
sumPow16.Mul(&sumPow16, &sumPow16)
|
||||
sum.Mul(&sumPow16, &sum)
|
||||
|
||||
return sum
|
||||
}
|
||||
|
||||
func (m RoundGateCrypto) Degree() int {
|
||||
return 17
|
||||
}
|
||||
1
prover/crypto/ringsis/.gitignore
vendored
Normal file
1
prover/crypto/ringsis/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
**/*.txt
|
||||
@@ -1,5 +0,0 @@
|
||||
package ringsis
|
||||
|
||||
//go:generate go run ./templates --logTwoBound=16 --modulusDegree=64
|
||||
//go:generate go run ./templates --logTwoBound=8 --modulusDegree=64
|
||||
//go:generate go run ./templates --logTwoBound=8 --modulusDegree=32
|
||||
@@ -1,24 +1,10 @@
|
||||
package ringsis
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"math"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr"
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/sis"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
"github.com/consensys/linea-monorepo/prover/utils/parallel"
|
||||
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis/ringsis_32_8"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis/ringsis_64_16"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis/ringsis_64_8"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -29,21 +15,12 @@ const (
|
||||
// Key encapsulates the public parameters of an instance of the ring-SIS hash
|
||||
// instance.
|
||||
type Key struct {
|
||||
// lock guards the access to the SIS key and prevents the user from hashing
|
||||
// concurrently with the same SIS key.
|
||||
lock *sync.Mutex
|
||||
// gnarkInternal stores the SIS key itself and some precomputed domain
|
||||
// twiddles.
|
||||
gnarkInternal *sis.RSis
|
||||
// Params provides the parameters of the ring-SIS instance (logTwoBound,
|
||||
// degree etc)
|
||||
Params
|
||||
// twiddleCosets stores the list of twiddles that we use to implement the
|
||||
// SIS parameters. The twiddleAreInternally are only used when dealing with
|
||||
// the parameters modulusDegree=64 and logTwoBound=8 and is passed as input
|
||||
// to the specially unrolled [sis.FFT64] function. They are thus optionally
|
||||
// constructed when [GenerateKey] is called.
|
||||
twiddleCosets []field.Element
|
||||
}
|
||||
|
||||
// GenerateKey generates a ring-SIS key from a set of a [Params] and a max
|
||||
@@ -62,33 +39,10 @@ func GenerateKey(params Params, maxNumFieldToHash int) Key {
|
||||
}
|
||||
|
||||
res := Key{
|
||||
lock: &sync.Mutex{},
|
||||
gnarkInternal: rsis,
|
||||
Params: params,
|
||||
}
|
||||
|
||||
// Optimization for these specific parameters
|
||||
if params.LogTwoBound == 8 && 1<<params.LogTwoDegree == 64 {
|
||||
res.twiddleCosets = ringsis_64_8.PrecomputeTwiddlesCoset(
|
||||
rsis.Domain.Generator,
|
||||
rsis.Domain.FrMultiplicativeGen,
|
||||
)
|
||||
}
|
||||
|
||||
if params.LogTwoBound == 16 && 1<<params.LogTwoDegree == 64 {
|
||||
res.twiddleCosets = ringsis_64_16.PrecomputeTwiddlesCoset(
|
||||
rsis.Domain.Generator,
|
||||
rsis.Domain.FrMultiplicativeGen,
|
||||
)
|
||||
}
|
||||
|
||||
if params.LogTwoBound == 8 && 1<<params.LogTwoDegree == 32 {
|
||||
res.twiddleCosets = ringsis_32_8.PrecomputeTwiddlesCoset(
|
||||
rsis.Domain.Generator,
|
||||
rsis.Domain.FrMultiplicativeGen,
|
||||
)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -104,55 +58,32 @@ func (s *Key) Ag() [][]field.Element {
|
||||
// It is equivalent to calling r.Write(element.Marshal()); outBytes = r.Sum(nil);
|
||||
func (s *Key) Hash(v []field.Element) []field.Element {
|
||||
|
||||
// since hashing writes into internal buffers
|
||||
// we need to guard against races conditions.
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
// write the input as byte
|
||||
s.gnarkInternal.Reset()
|
||||
for i := range v {
|
||||
_, err := s.gnarkInternal.Write(v[i].Marshal())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
sum := s.gnarkInternal.Sum(make([]byte, 0, field.Bytes*s.OutputSize()))
|
||||
|
||||
// unmarshal the result
|
||||
var rlen [4]byte
|
||||
if len(sum) > math.MaxUint32*fr.Bytes {
|
||||
panic("slice too long")
|
||||
}
|
||||
binary.BigEndian.PutUint32(rlen[:], uint32(len(sum)/fr.Bytes)) // #nosec G115 -- Overflow checked
|
||||
reader := io.MultiReader(bytes.NewReader(rlen[:]), bytes.NewReader(sum))
|
||||
var result fr.Vector
|
||||
_, err := result.ReadFrom(reader)
|
||||
if err != nil {
|
||||
sum := make([]field.Element, s.OutputSize())
|
||||
if err := s.gnarkInternal.Hash(v, sum); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return result
|
||||
return sum
|
||||
}
|
||||
|
||||
// LimbSplit breaks down the entries of `v` into short limbs representing
|
||||
// `LogTwoBound` bits each. The function then flatten and flatten them in a
|
||||
// vector, casted as field elements in Montgommery form.
|
||||
// vector, casted as field elements in Montgomery form.
|
||||
func (s *Key) LimbSplit(vReg []field.Element) []field.Element {
|
||||
|
||||
writer := bytes.Buffer{}
|
||||
for i := range vReg {
|
||||
b := vReg[i].Bytes() // big endian serialization
|
||||
writer.Write(b[:])
|
||||
}
|
||||
|
||||
buf := writer.Bytes()
|
||||
m := make([]field.Element, len(vReg)*s.NumLimbs())
|
||||
sis.LimbDecomposeBytes(buf, m, s.LogTwoBound)
|
||||
|
||||
it := sis.NewLimbIterator(sis.NewVectorIterator(vReg), s.LogTwoBound/8)
|
||||
|
||||
// The limbs are in regular form, we reconvert them back into montgommery
|
||||
// form
|
||||
var ok bool
|
||||
for i := range m {
|
||||
m[i][0], ok = it.NextLimb()
|
||||
if !ok {
|
||||
// the rest is 0 we can stop (note that if we change the padding
|
||||
// policy we may need to change this)
|
||||
break
|
||||
}
|
||||
m[i] = field.MulR(m[i])
|
||||
}
|
||||
|
||||
@@ -256,111 +187,3 @@ func (s *Key) FlattenedKey() []field.Element {
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// TransversalHash evaluates SIS hashes transversally over a list of smart-vectors.
|
||||
// Each smart-vector is seen as the row of a matrix. All rows must have the same
|
||||
// size or panic. The function returns the hash of the columns. The column hashes
|
||||
// are concatenated into a single array.
|
||||
//
|
||||
// The function is optimize to deal with the ring-SIS instances parametrized by
|
||||
//
|
||||
// - modulus degree: 64 log2(bound): 8
|
||||
// - modulus degree: 64 log2(bound): 16
|
||||
// - modulus degree: 32 log2(bound): 8
|
||||
func (s *Key) TransversalHash(v []smartvectors.SmartVector) []field.Element {
|
||||
|
||||
// numRows stores the number of rows in the matrix to hash it must be
|
||||
// strictly positive and be within the bounds of MaxNumFieldHashable.
|
||||
numRows := len(v)
|
||||
|
||||
if numRows == 0 {
|
||||
utils.Panic("Attempted to transversally hash a matrix with no rows")
|
||||
}
|
||||
|
||||
if numRows > s.MaxNumFieldHashable() {
|
||||
utils.Panic("Attempted to hash %v rows, but the limit is %v", numRows, s.MaxNumFieldHashable())
|
||||
}
|
||||
|
||||
// numCols stores the number of columns in the matrix to hash et must be
|
||||
// positive and all the rows must have the same size.
|
||||
numCols := v[0].Len()
|
||||
|
||||
if numCols == 0 {
|
||||
utils.Panic("Provided a 0-colums matrix")
|
||||
}
|
||||
|
||||
for i := range v {
|
||||
if v[i].Len() != numCols {
|
||||
utils.Panic("Unexpected : all inputs smart-vectors should have the same length the first one has length %v, but #%v has length %v",
|
||||
numCols, i, v[i].Len())
|
||||
}
|
||||
}
|
||||
|
||||
if s.LogTwoBound == 8 && s.LogTwoDegree == 6 {
|
||||
return ringsis_64_8.TransversalHash(
|
||||
s.gnarkInternal.Ag,
|
||||
v,
|
||||
s.twiddleCosets,
|
||||
s.gnarkInternal.Domain,
|
||||
)
|
||||
}
|
||||
|
||||
if s.LogTwoBound == 16 && s.LogTwoDegree == 6 {
|
||||
return ringsis_64_16.TransversalHash(
|
||||
s.gnarkInternal.Ag,
|
||||
v,
|
||||
s.twiddleCosets,
|
||||
s.gnarkInternal.Domain,
|
||||
)
|
||||
}
|
||||
|
||||
if s.LogTwoBound == 8 && s.LogTwoDegree == 5 {
|
||||
return ringsis_32_8.TransversalHash(
|
||||
s.gnarkInternal.Ag,
|
||||
v,
|
||||
s.twiddleCosets,
|
||||
s.gnarkInternal.Domain,
|
||||
)
|
||||
}
|
||||
|
||||
res := make([]field.Element, numCols*s.OutputSize())
|
||||
|
||||
// Will contain keys per threads
|
||||
keys := make([]*Key, runtime.GOMAXPROCS(0))
|
||||
buffers := make([][]field.Element, runtime.GOMAXPROCS(0))
|
||||
|
||||
parallel.ExecuteThreadAware(
|
||||
numCols,
|
||||
func(threadID int) {
|
||||
keys[threadID] = s.CopyWithFreshBuffer()
|
||||
buffers[threadID] = make([]field.Element, numRows)
|
||||
},
|
||||
func(col, threadID int) {
|
||||
buffer := buffers[threadID]
|
||||
key := keys[threadID]
|
||||
for row := 0; row < numRows; row++ {
|
||||
buffer[row] = v[row].Get(col)
|
||||
}
|
||||
copy(res[col*key.OutputSize():(col+1)*key.OutputSize()], key.Hash(buffer))
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// CopyWithFreshBuffer creates a copy of the key with fresh buffers. Shallow
|
||||
// copies the the key itself.
|
||||
func (s *Key) CopyWithFreshBuffer() *Key {
|
||||
|
||||
// Since hashing consumes and mutates the buffer stored internally in
|
||||
// `gnarkInternal` go race had figured there might be a race condition
|
||||
// possibility.
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
clonedRsis := s.gnarkInternal.CopyWithFreshBuffer()
|
||||
return &Key{
|
||||
lock: &sync.Mutex{},
|
||||
gnarkInternal: &clonedRsis,
|
||||
Params: s.Params,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_32_8
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLimbDecompose(t *testing.T) {
|
||||
|
||||
var (
|
||||
limbs = make([]int64, 32)
|
||||
rng = rand.New(rand.NewChaCha8([32]byte{}))
|
||||
inputs = make([]field.Element, 1)
|
||||
obtainedLimbs = make([]field.Element, 32)
|
||||
)
|
||||
|
||||
for i := range limbs {
|
||||
if i%32 > 31 {
|
||||
limbs[i] = int64(rng.IntN(1 << 8))
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 1; i++ {
|
||||
buf := &big.Int{}
|
||||
for j := 30; j >= 0; j-- {
|
||||
buf.Mul(buf, big.NewInt(1<<8))
|
||||
tmp := new(big.Int).SetInt64(limbs[32*i+j])
|
||||
buf.Add(buf, tmp)
|
||||
}
|
||||
inputs[i].SetBigInt(buf)
|
||||
}
|
||||
|
||||
limbDecompose(obtainedLimbs, inputs)
|
||||
|
||||
for i := range obtainedLimbs {
|
||||
assert.Equal(t, uint64(limbs[i]), obtainedLimbs[i][0])
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_32_8
|
||||
|
||||
import (
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
)
|
||||
|
||||
var partialFFT = []func(a, twiddles []field.Element){
|
||||
partialFFT_0,
|
||||
partialFFT_1,
|
||||
}
|
||||
|
||||
func partialFFT_0(a, twiddles []field.Element) {
|
||||
}
|
||||
|
||||
func partialFFT_1(a, twiddles []field.Element) {
|
||||
a[16].Mul(&a[16], &twiddles[0])
|
||||
a[17].Mul(&a[17], &twiddles[0])
|
||||
a[18].Mul(&a[18], &twiddles[0])
|
||||
a[19].Mul(&a[19], &twiddles[0])
|
||||
a[20].Mul(&a[20], &twiddles[0])
|
||||
a[21].Mul(&a[21], &twiddles[0])
|
||||
a[22].Mul(&a[22], &twiddles[0])
|
||||
a[23].Mul(&a[23], &twiddles[0])
|
||||
a[24].Mul(&a[24], &twiddles[0])
|
||||
a[25].Mul(&a[25], &twiddles[0])
|
||||
a[26].Mul(&a[26], &twiddles[0])
|
||||
a[27].Mul(&a[27], &twiddles[0])
|
||||
a[28].Mul(&a[28], &twiddles[0])
|
||||
a[29].Mul(&a[29], &twiddles[0])
|
||||
a[30].Mul(&a[30], &twiddles[0])
|
||||
a[31].Mul(&a[31], &twiddles[0])
|
||||
field.Butterfly(&a[0], &a[16])
|
||||
field.Butterfly(&a[1], &a[17])
|
||||
field.Butterfly(&a[2], &a[18])
|
||||
field.Butterfly(&a[3], &a[19])
|
||||
field.Butterfly(&a[4], &a[20])
|
||||
field.Butterfly(&a[5], &a[21])
|
||||
field.Butterfly(&a[6], &a[22])
|
||||
field.Butterfly(&a[7], &a[23])
|
||||
field.Butterfly(&a[8], &a[24])
|
||||
field.Butterfly(&a[9], &a[25])
|
||||
field.Butterfly(&a[10], &a[26])
|
||||
field.Butterfly(&a[11], &a[27])
|
||||
field.Butterfly(&a[12], &a[28])
|
||||
field.Butterfly(&a[13], &a[29])
|
||||
field.Butterfly(&a[14], &a[30])
|
||||
field.Butterfly(&a[15], &a[31])
|
||||
a[8].Mul(&a[8], &twiddles[1])
|
||||
a[9].Mul(&a[9], &twiddles[1])
|
||||
a[10].Mul(&a[10], &twiddles[1])
|
||||
a[11].Mul(&a[11], &twiddles[1])
|
||||
a[12].Mul(&a[12], &twiddles[1])
|
||||
a[13].Mul(&a[13], &twiddles[1])
|
||||
a[14].Mul(&a[14], &twiddles[1])
|
||||
a[15].Mul(&a[15], &twiddles[1])
|
||||
a[24].Mul(&a[24], &twiddles[2])
|
||||
a[25].Mul(&a[25], &twiddles[2])
|
||||
a[26].Mul(&a[26], &twiddles[2])
|
||||
a[27].Mul(&a[27], &twiddles[2])
|
||||
a[28].Mul(&a[28], &twiddles[2])
|
||||
a[29].Mul(&a[29], &twiddles[2])
|
||||
a[30].Mul(&a[30], &twiddles[2])
|
||||
a[31].Mul(&a[31], &twiddles[2])
|
||||
field.Butterfly(&a[0], &a[8])
|
||||
field.Butterfly(&a[1], &a[9])
|
||||
field.Butterfly(&a[2], &a[10])
|
||||
field.Butterfly(&a[3], &a[11])
|
||||
field.Butterfly(&a[4], &a[12])
|
||||
field.Butterfly(&a[5], &a[13])
|
||||
field.Butterfly(&a[6], &a[14])
|
||||
field.Butterfly(&a[7], &a[15])
|
||||
field.Butterfly(&a[16], &a[24])
|
||||
field.Butterfly(&a[17], &a[25])
|
||||
field.Butterfly(&a[18], &a[26])
|
||||
field.Butterfly(&a[19], &a[27])
|
||||
field.Butterfly(&a[20], &a[28])
|
||||
field.Butterfly(&a[21], &a[29])
|
||||
field.Butterfly(&a[22], &a[30])
|
||||
field.Butterfly(&a[23], &a[31])
|
||||
a[4].Mul(&a[4], &twiddles[3])
|
||||
a[5].Mul(&a[5], &twiddles[3])
|
||||
a[6].Mul(&a[6], &twiddles[3])
|
||||
a[7].Mul(&a[7], &twiddles[3])
|
||||
a[12].Mul(&a[12], &twiddles[4])
|
||||
a[13].Mul(&a[13], &twiddles[4])
|
||||
a[14].Mul(&a[14], &twiddles[4])
|
||||
a[15].Mul(&a[15], &twiddles[4])
|
||||
a[20].Mul(&a[20], &twiddles[5])
|
||||
a[21].Mul(&a[21], &twiddles[5])
|
||||
a[22].Mul(&a[22], &twiddles[5])
|
||||
a[23].Mul(&a[23], &twiddles[5])
|
||||
a[28].Mul(&a[28], &twiddles[6])
|
||||
a[29].Mul(&a[29], &twiddles[6])
|
||||
a[30].Mul(&a[30], &twiddles[6])
|
||||
a[31].Mul(&a[31], &twiddles[6])
|
||||
field.Butterfly(&a[0], &a[4])
|
||||
field.Butterfly(&a[1], &a[5])
|
||||
field.Butterfly(&a[2], &a[6])
|
||||
field.Butterfly(&a[3], &a[7])
|
||||
field.Butterfly(&a[8], &a[12])
|
||||
field.Butterfly(&a[9], &a[13])
|
||||
field.Butterfly(&a[10], &a[14])
|
||||
field.Butterfly(&a[11], &a[15])
|
||||
field.Butterfly(&a[16], &a[20])
|
||||
field.Butterfly(&a[17], &a[21])
|
||||
field.Butterfly(&a[18], &a[22])
|
||||
field.Butterfly(&a[19], &a[23])
|
||||
field.Butterfly(&a[24], &a[28])
|
||||
field.Butterfly(&a[25], &a[29])
|
||||
field.Butterfly(&a[26], &a[30])
|
||||
field.Butterfly(&a[27], &a[31])
|
||||
a[2].Mul(&a[2], &twiddles[7])
|
||||
a[3].Mul(&a[3], &twiddles[7])
|
||||
a[6].Mul(&a[6], &twiddles[8])
|
||||
a[7].Mul(&a[7], &twiddles[8])
|
||||
a[10].Mul(&a[10], &twiddles[9])
|
||||
a[11].Mul(&a[11], &twiddles[9])
|
||||
a[14].Mul(&a[14], &twiddles[10])
|
||||
a[15].Mul(&a[15], &twiddles[10])
|
||||
a[18].Mul(&a[18], &twiddles[11])
|
||||
a[19].Mul(&a[19], &twiddles[11])
|
||||
a[22].Mul(&a[22], &twiddles[12])
|
||||
a[23].Mul(&a[23], &twiddles[12])
|
||||
a[26].Mul(&a[26], &twiddles[13])
|
||||
a[27].Mul(&a[27], &twiddles[13])
|
||||
a[30].Mul(&a[30], &twiddles[14])
|
||||
a[31].Mul(&a[31], &twiddles[14])
|
||||
field.Butterfly(&a[0], &a[2])
|
||||
field.Butterfly(&a[1], &a[3])
|
||||
field.Butterfly(&a[4], &a[6])
|
||||
field.Butterfly(&a[5], &a[7])
|
||||
field.Butterfly(&a[8], &a[10])
|
||||
field.Butterfly(&a[9], &a[11])
|
||||
field.Butterfly(&a[12], &a[14])
|
||||
field.Butterfly(&a[13], &a[15])
|
||||
field.Butterfly(&a[16], &a[18])
|
||||
field.Butterfly(&a[17], &a[19])
|
||||
field.Butterfly(&a[20], &a[22])
|
||||
field.Butterfly(&a[21], &a[23])
|
||||
field.Butterfly(&a[24], &a[26])
|
||||
field.Butterfly(&a[25], &a[27])
|
||||
field.Butterfly(&a[28], &a[30])
|
||||
field.Butterfly(&a[29], &a[31])
|
||||
a[1].Mul(&a[1], &twiddles[15])
|
||||
a[3].Mul(&a[3], &twiddles[16])
|
||||
a[5].Mul(&a[5], &twiddles[17])
|
||||
a[7].Mul(&a[7], &twiddles[18])
|
||||
a[9].Mul(&a[9], &twiddles[19])
|
||||
a[11].Mul(&a[11], &twiddles[20])
|
||||
a[13].Mul(&a[13], &twiddles[21])
|
||||
a[15].Mul(&a[15], &twiddles[22])
|
||||
a[17].Mul(&a[17], &twiddles[23])
|
||||
a[19].Mul(&a[19], &twiddles[24])
|
||||
a[21].Mul(&a[21], &twiddles[25])
|
||||
a[23].Mul(&a[23], &twiddles[26])
|
||||
a[25].Mul(&a[25], &twiddles[27])
|
||||
a[27].Mul(&a[27], &twiddles[28])
|
||||
a[29].Mul(&a[29], &twiddles[29])
|
||||
a[31].Mul(&a[31], &twiddles[30])
|
||||
field.Butterfly(&a[0], &a[1])
|
||||
field.Butterfly(&a[2], &a[3])
|
||||
field.Butterfly(&a[4], &a[5])
|
||||
field.Butterfly(&a[6], &a[7])
|
||||
field.Butterfly(&a[8], &a[9])
|
||||
field.Butterfly(&a[10], &a[11])
|
||||
field.Butterfly(&a[12], &a[13])
|
||||
field.Butterfly(&a[14], &a[15])
|
||||
field.Butterfly(&a[16], &a[17])
|
||||
field.Butterfly(&a[18], &a[19])
|
||||
field.Butterfly(&a[20], &a[21])
|
||||
field.Butterfly(&a[22], &a[23])
|
||||
field.Butterfly(&a[24], &a[25])
|
||||
field.Butterfly(&a[26], &a[27])
|
||||
field.Butterfly(&a[28], &a[29])
|
||||
field.Butterfly(&a[30], &a[31])
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_32_8
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPartialFFT(t *testing.T) {
|
||||
|
||||
var (
|
||||
domain = fft.NewDomain(32)
|
||||
twiddles = PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
)
|
||||
|
||||
for mask := 0; mask < 2; mask++ {
|
||||
|
||||
var (
|
||||
a = vec123456()
|
||||
b = vec123456()
|
||||
)
|
||||
|
||||
zeroizeWithMask(a, mask)
|
||||
zeroizeWithMask(b, mask)
|
||||
|
||||
domain.FFT(a, fft.DIF, fft.OnCoset())
|
||||
partialFFT[mask](b, twiddles)
|
||||
assert.Equal(t, a, b)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func vec123456() []field.Element {
|
||||
vec := make([]field.Element, 32)
|
||||
for i := range vec {
|
||||
vec[i].SetInt64(int64(i))
|
||||
}
|
||||
return vec
|
||||
}
|
||||
|
||||
func zeroizeWithMask(v []field.Element, mask int) {
|
||||
for i := 0; i < 1; i++ {
|
||||
if (mask>>i)&1 == 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
for j := 0; j < 32; j++ {
|
||||
v[32*i+j].SetZero()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_32_8
|
||||
|
||||
import (
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/vector"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
"github.com/consensys/linea-monorepo/prover/utils/parallel"
|
||||
ppool "github.com/consensys/linea-monorepo/prover/utils/parallel/pool"
|
||||
)
|
||||
|
||||
func TransversalHash(
|
||||
// the Ag for ring-sis
|
||||
ag [][]field.Element,
|
||||
// A non-transposed list of columns
|
||||
// All of the same length
|
||||
pols []smartvectors.SmartVector,
|
||||
// The precomputed twiddle cosets for the forward FFT
|
||||
twiddleCosets []field.Element,
|
||||
// The domain for the final inverse-FFT
|
||||
domain *fft.Domain,
|
||||
) []field.Element {
|
||||
|
||||
var (
|
||||
// Each field element is encoded in 32 limbs but the degree is 32. So, each
|
||||
// polynomial multiplication "hashes" 1 field elements at once. This is
|
||||
// important to know for parallelization.
|
||||
resultSize = pols[0].Len() * 32
|
||||
|
||||
// To optimize memory usage, we limit ourself to hash only 16 columns per
|
||||
// iteration.
|
||||
numColumnPerJob int = 16
|
||||
|
||||
// In theory, it should be a div ceil. But in practice we only process power's
|
||||
// of two number of columns. If that's not the case, then the function will panic
|
||||
// but we can always change that if this is needed. The rational for the current
|
||||
// design is simplicity.
|
||||
numJobs = utils.DivExact(pols[0].Len(), numColumnPerJob) // we make blocks of 16 columns
|
||||
|
||||
// Main result of the hashing
|
||||
mainResults = make([]field.Element, resultSize)
|
||||
// When we encounter a const row, it will have the same additive contribution
|
||||
// to the result on every column. So we compute the contribution only once and
|
||||
// accumulate it with the other "constant column contributions". And it is only
|
||||
// performed by the first thread.
|
||||
constResults = make([]field.Element, 32)
|
||||
)
|
||||
|
||||
ppool.ExecutePoolChunky(numJobs, func(i int) {
|
||||
// We process the columns per segment of `numColumnPerJob`
|
||||
var (
|
||||
localResult = make([]field.Element, numColumnPerJob*32)
|
||||
limbs = make([]field.Element, 32)
|
||||
|
||||
// Each segment is processed by packet of `numFieldPerPoly=1` rows
|
||||
startFromCol = i * numColumnPerJob
|
||||
stopAtCol = (i + 1) * numColumnPerJob
|
||||
)
|
||||
|
||||
for row := 0; row < len(pols); row += 1 {
|
||||
|
||||
var (
|
||||
chunksFull = make([][]field.Element, 1)
|
||||
mask = 0
|
||||
)
|
||||
|
||||
for j := 0; j < 1; j++ {
|
||||
if row+j >= len(pols) {
|
||||
continue
|
||||
}
|
||||
|
||||
pReg, pIsReg := pols[row+j].(*smartvectors.Regular)
|
||||
if pIsReg {
|
||||
chunksFull[j] = (*pReg)[startFromCol:stopAtCol]
|
||||
mask |= (1 << j)
|
||||
continue
|
||||
}
|
||||
|
||||
pPool, pIsPool := pols[row+j].(*smartvectors.Pooled)
|
||||
if pIsPool {
|
||||
chunksFull[j] = pPool.Regular[startFromCol:stopAtCol]
|
||||
mask |= (1 << j)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if mask > 0 {
|
||||
for col := 0; col < (stopAtCol - startFromCol); col++ {
|
||||
colChunk := [1]field.Element{}
|
||||
for j := 0; j < 1; j++ {
|
||||
if chunksFull[j] != nil {
|
||||
colChunk[j] = chunksFull[j][col]
|
||||
}
|
||||
}
|
||||
|
||||
limbDecompose(limbs, colChunk[:])
|
||||
partialFFT[mask](limbs, twiddleCosets)
|
||||
mulModAcc(localResult[col*32:(col+1)*32], limbs, ag[row/1])
|
||||
}
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
|
||||
var (
|
||||
cMask = ((1 << 1) - 1) ^ mask
|
||||
chunkConst = make([]field.Element, 1)
|
||||
)
|
||||
|
||||
if cMask > 0 {
|
||||
for j := 0; j < 1; j++ {
|
||||
if row+j >= len(pols) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (cMask>>j)&1 == 1 {
|
||||
chunkConst[j] = pols[row+j].(*smartvectors.Constant).Get(0)
|
||||
}
|
||||
}
|
||||
|
||||
limbDecompose(limbs, chunkConst)
|
||||
partialFFT[cMask](limbs, twiddleCosets)
|
||||
mulModAcc(constResults, limbs, ag[row/1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy the segment into the main result at the end
|
||||
copy(mainResults[startFromCol*32:stopAtCol*32], localResult)
|
||||
})
|
||||
|
||||
// Now, we need to reconciliate the results of the buffer with
|
||||
// the result for each thread
|
||||
parallel.Execute(pols[0].Len(), func(start, stop int) {
|
||||
for col := start; col < stop; col++ {
|
||||
// Accumulate the const
|
||||
vector.Add(mainResults[col*32:(col+1)*32], mainResults[col*32:(col+1)*32], constResults)
|
||||
// And run the reverse FFT
|
||||
domain.FFTInverse(mainResults[col*32:(col+1)*32], fft.DIT, fft.OnCoset(), fft.WithNbTasks(1))
|
||||
}
|
||||
})
|
||||
|
||||
return mainResults
|
||||
}
|
||||
|
||||
var _zeroes []field.Element = make([]field.Element, 32)
|
||||
|
||||
// zeroize fills `buf` with zeroes.
|
||||
func zeroize(buf []field.Element) {
|
||||
copy(buf, _zeroes)
|
||||
}
|
||||
|
||||
// mulModAdd increments each entry `i` of `res` as `res[i] = a[i] * b[i]`. The
|
||||
// input vectors are trusted to all have the same length.
|
||||
func mulModAcc(res, a, b []field.Element) {
|
||||
var tmp field.Element
|
||||
for i := range res {
|
||||
tmp.Mul(&a[i], &b[i])
|
||||
res[i].Add(&res[i], &tmp)
|
||||
}
|
||||
}
|
||||
|
||||
func limbDecompose(result []field.Element, x []field.Element) {
|
||||
|
||||
zeroize(result)
|
||||
var bytesBuffer = [32]byte{}
|
||||
|
||||
bytesBuffer = x[0].Bytes()
|
||||
|
||||
result[31][0] = uint64(bytesBuffer[0])
|
||||
result[30][0] = uint64(bytesBuffer[1])
|
||||
result[29][0] = uint64(bytesBuffer[2])
|
||||
result[28][0] = uint64(bytesBuffer[3])
|
||||
result[27][0] = uint64(bytesBuffer[4])
|
||||
result[26][0] = uint64(bytesBuffer[5])
|
||||
result[25][0] = uint64(bytesBuffer[6])
|
||||
result[24][0] = uint64(bytesBuffer[7])
|
||||
result[23][0] = uint64(bytesBuffer[8])
|
||||
result[22][0] = uint64(bytesBuffer[9])
|
||||
result[21][0] = uint64(bytesBuffer[10])
|
||||
result[20][0] = uint64(bytesBuffer[11])
|
||||
result[19][0] = uint64(bytesBuffer[12])
|
||||
result[18][0] = uint64(bytesBuffer[13])
|
||||
result[17][0] = uint64(bytesBuffer[14])
|
||||
result[16][0] = uint64(bytesBuffer[15])
|
||||
result[15][0] = uint64(bytesBuffer[16])
|
||||
result[14][0] = uint64(bytesBuffer[17])
|
||||
result[13][0] = uint64(bytesBuffer[18])
|
||||
result[12][0] = uint64(bytesBuffer[19])
|
||||
result[11][0] = uint64(bytesBuffer[20])
|
||||
result[10][0] = uint64(bytesBuffer[21])
|
||||
result[9][0] = uint64(bytesBuffer[22])
|
||||
result[8][0] = uint64(bytesBuffer[23])
|
||||
result[7][0] = uint64(bytesBuffer[24])
|
||||
result[6][0] = uint64(bytesBuffer[25])
|
||||
result[5][0] = uint64(bytesBuffer[26])
|
||||
result[4][0] = uint64(bytesBuffer[27])
|
||||
result[3][0] = uint64(bytesBuffer[28])
|
||||
result[2][0] = uint64(bytesBuffer[29])
|
||||
result[1][0] = uint64(bytesBuffer[30])
|
||||
result[0][0] = uint64(bytesBuffer[31])
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_32_8_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis/ringsis_32_8"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/vector"
|
||||
wfft "github.com/consensys/linea-monorepo/prover/maths/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// randomConstRow generates a random constant smart-vector
|
||||
func randomConstRow(rng *rand.Rand, size int) smartvectors.SmartVector {
|
||||
return smartvectors.NewConstant(field.PseudoRand(rng), size)
|
||||
}
|
||||
|
||||
// randomRegularRow generates a random regular smart-vector
|
||||
func randomRegularRow(rng *rand.Rand, size int) smartvectors.SmartVector {
|
||||
return smartvectors.PseudoRand(rng, size)
|
||||
}
|
||||
|
||||
// generate a smartvector row-matrix by using randomly constant or regular smart-vectors
|
||||
func fullyRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector {
|
||||
list := make([]smartvectors.SmartVector, numRow)
|
||||
for i := range list {
|
||||
coin := rng.IntN(2)
|
||||
switch {
|
||||
case coin == 0:
|
||||
list[i] = randomConstRow(rng, numCols)
|
||||
case coin == 1:
|
||||
list[i] = randomRegularRow(rng, numCols)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func constantRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector {
|
||||
list := make([]smartvectors.SmartVector, numRow)
|
||||
for i := range list {
|
||||
list[i] = randomConstRow(rng, numCols)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func regularRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector {
|
||||
list := make([]smartvectors.SmartVector, numRow)
|
||||
for i := range list {
|
||||
list[i] = randomConstRow(rng, numCols)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func TestSmartVectorTransversalSisHash(t *testing.T) {
|
||||
|
||||
var (
|
||||
numReps = 64
|
||||
numCols = 16
|
||||
rng = rand.New(rand.NewChaCha8([32]byte{}))
|
||||
domain = fft.NewDomain(32, fft.WithShift(wfft.GetOmega(32*2)))
|
||||
twiddles = ringsis_32_8.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
params = ringsis.Params{LogTwoBound: 8, LogTwoDegree: 5}
|
||||
testCases = [][]smartvectors.SmartVector{
|
||||
constantRandomTestVector(rng, 1, numCols),
|
||||
regularRandomTestVector(rng, 1, numCols),
|
||||
}
|
||||
)
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 1, numCols))
|
||||
}
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 4, 2*numCols))
|
||||
}
|
||||
|
||||
for i, c := range testCases {
|
||||
t.Run(fmt.Sprintf("testcase-%v", i), func(t *testing.T) {
|
||||
|
||||
var (
|
||||
numRow = len(c)
|
||||
key = ringsis.GenerateKey(params, numRow)
|
||||
result = ringsis_32_8.TransversalHash(
|
||||
key.Ag(),
|
||||
c,
|
||||
twiddles,
|
||||
domain,
|
||||
)
|
||||
)
|
||||
|
||||
for col := 0; col < numCols; col++ {
|
||||
column := make([]field.Element, numRow)
|
||||
for r := 0; r < numRow; r++ {
|
||||
column[r] = c[r].Get(col)
|
||||
}
|
||||
|
||||
colHash := key.Hash(column)
|
||||
require.Equalf(
|
||||
t,
|
||||
vector.Prettify(colHash),
|
||||
vector.Prettify(result[32*col:32*col+32]),
|
||||
"column %v", col,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_32_8
|
||||
|
||||
import (
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// PrecomputeTwiddlesCoset precomputes twiddlesCoset from twiddles and coset table
|
||||
// it then return all elements in the correct order for the unrolled FFT.
|
||||
func PrecomputeTwiddlesCoset(generator, shifter field.Element) []field.Element {
|
||||
toReturn := make([]field.Element, 31)
|
||||
var r, s field.Element
|
||||
e := new(big.Int)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 4; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[0] = s
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 3; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[1] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<3*1)))
|
||||
toReturn[2].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 2; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[3] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*2)))
|
||||
toReturn[4].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*1)))
|
||||
toReturn[5].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*3)))
|
||||
toReturn[6].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 1; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[7] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*4)))
|
||||
toReturn[8].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*2)))
|
||||
toReturn[9].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*6)))
|
||||
toReturn[10].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*1)))
|
||||
toReturn[11].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*5)))
|
||||
toReturn[12].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*3)))
|
||||
toReturn[13].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*7)))
|
||||
toReturn[14].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 0; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[15] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*8)))
|
||||
toReturn[16].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*4)))
|
||||
toReturn[17].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*12)))
|
||||
toReturn[18].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*2)))
|
||||
toReturn[19].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*10)))
|
||||
toReturn[20].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*6)))
|
||||
toReturn[21].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*14)))
|
||||
toReturn[22].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*1)))
|
||||
toReturn[23].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*9)))
|
||||
toReturn[24].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*5)))
|
||||
toReturn[25].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*13)))
|
||||
toReturn[26].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*3)))
|
||||
toReturn[27].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*11)))
|
||||
toReturn[28].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*7)))
|
||||
toReturn[29].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*15)))
|
||||
toReturn[30].Mul(&r, &s)
|
||||
|
||||
return toReturn
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_16
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLimbDecompose(t *testing.T) {
|
||||
|
||||
var (
|
||||
limbs = make([]int64, 64)
|
||||
rng = rand.New(rand.NewChaCha8([32]byte{}))
|
||||
inputs = make([]field.Element, 4)
|
||||
obtainedLimbs = make([]field.Element, 64)
|
||||
)
|
||||
|
||||
for i := range limbs {
|
||||
if i%16 > 15 {
|
||||
limbs[i] = int64(rng.IntN(1 << 16))
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
buf := &big.Int{}
|
||||
for j := 14; j >= 0; j-- {
|
||||
buf.Mul(buf, big.NewInt(1<<16))
|
||||
tmp := new(big.Int).SetInt64(limbs[16*i+j])
|
||||
buf.Add(buf, tmp)
|
||||
}
|
||||
inputs[i].SetBigInt(buf)
|
||||
}
|
||||
|
||||
limbDecompose(obtainedLimbs, inputs)
|
||||
|
||||
for i := range obtainedLimbs {
|
||||
assert.Equal(t, uint64(limbs[i]), obtainedLimbs[i][0])
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,55 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_16
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPartialFFT(t *testing.T) {
|
||||
|
||||
var (
|
||||
domain = fft.NewDomain(64)
|
||||
twiddles = PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
)
|
||||
|
||||
for mask := 0; mask < 16; mask++ {
|
||||
|
||||
var (
|
||||
a = vec123456()
|
||||
b = vec123456()
|
||||
)
|
||||
|
||||
zeroizeWithMask(a, mask)
|
||||
zeroizeWithMask(b, mask)
|
||||
|
||||
domain.FFT(a, fft.DIF, fft.OnCoset())
|
||||
partialFFT[mask](b, twiddles)
|
||||
assert.Equal(t, a, b)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func vec123456() []field.Element {
|
||||
vec := make([]field.Element, 64)
|
||||
for i := range vec {
|
||||
vec[i].SetInt64(int64(i))
|
||||
}
|
||||
return vec
|
||||
}
|
||||
|
||||
func zeroizeWithMask(v []field.Element, mask int) {
|
||||
for i := 0; i < 4; i++ {
|
||||
if (mask>>i)&1 == 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
for j := 0; j < 16; j++ {
|
||||
v[16*i+j].SetZero()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package ringsis_64_16_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis/ringsis_64_16"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
wfft "github.com/consensys/linea-monorepo/prover/maths/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
)
|
||||
|
||||
func BenchmarkTransversalHash(b *testing.B) {
|
||||
|
||||
var (
|
||||
numRow = 1024
|
||||
numCols = 1024
|
||||
rng = rand.New(utils.NewRandSource(786868)) // nolint
|
||||
domain = fft.NewDomain(64, fft.WithShift(wfft.GetOmega(64*2)))
|
||||
twiddles = ringsis_64_16.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
params = ringsis.Params{LogTwoBound: 16, LogTwoDegree: 6}
|
||||
numInputPerPoly = params.OutputSize() / (field.Bytes * 8 / params.LogTwoBound)
|
||||
key = ringsis.GenerateKey(params, numRow)
|
||||
numTestCases = 1 << numInputPerPoly
|
||||
numPoly = numRow / numInputPerPoly
|
||||
)
|
||||
|
||||
for tc := 0; tc < numTestCases; tc++ {
|
||||
|
||||
b.Run(fmt.Sprintf("testcase-%b", tc), func(b *testing.B) {
|
||||
|
||||
inputs := make([]smartvectors.SmartVector, 0, numPoly*numInputPerPoly)
|
||||
|
||||
for p := 0; p < numPoly; p++ {
|
||||
for i := 0; i < numInputPerPoly; i++ {
|
||||
if (tc>>i)&1 == 0 {
|
||||
inputs = append(inputs, randomConstRow(rng, numCols))
|
||||
} else {
|
||||
inputs = append(inputs, randomRegularRow(rng, numCols))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for c := 0; c < b.N; c++ {
|
||||
_ = ringsis_64_16.TransversalHash(key.Ag(), inputs, twiddles, domain)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_16
|
||||
|
||||
import (
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/vector"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
"github.com/consensys/linea-monorepo/prover/utils/parallel"
|
||||
ppool "github.com/consensys/linea-monorepo/prover/utils/parallel/pool"
|
||||
)
|
||||
|
||||
func TransversalHash(
|
||||
// the Ag for ring-sis
|
||||
ag [][]field.Element,
|
||||
// A non-transposed list of columns
|
||||
// All of the same length
|
||||
pols []smartvectors.SmartVector,
|
||||
// The precomputed twiddle cosets for the forward FFT
|
||||
twiddleCosets []field.Element,
|
||||
// The domain for the final inverse-FFT
|
||||
domain *fft.Domain,
|
||||
) []field.Element {
|
||||
|
||||
var (
|
||||
// Each field element is encoded in 16 limbs but the degree is 64. So, each
|
||||
// polynomial multiplication "hashes" 4 field elements at once. This is
|
||||
// important to know for parallelization.
|
||||
resultSize = pols[0].Len() * 64
|
||||
|
||||
// To optimize memory usage, we limit ourself to hash only 16 columns per
|
||||
// iteration.
|
||||
numColumnPerJob int = 16
|
||||
|
||||
// In theory, it should be a div ceil. But in practice we only process power's
|
||||
// of two number of columns. If that's not the case, then the function will panic
|
||||
// but we can always change that if this is needed. The rational for the current
|
||||
// design is simplicity.
|
||||
numJobs = utils.DivExact(pols[0].Len(), numColumnPerJob) // we make blocks of 16 columns
|
||||
|
||||
// Main result of the hashing
|
||||
mainResults = make([]field.Element, resultSize)
|
||||
// When we encounter a const row, it will have the same additive contribution
|
||||
// to the result on every column. So we compute the contribution only once and
|
||||
// accumulate it with the other "constant column contributions". And it is only
|
||||
// performed by the first thread.
|
||||
constResults = make([]field.Element, 64)
|
||||
)
|
||||
|
||||
ppool.ExecutePoolChunky(numJobs, func(i int) {
|
||||
// We process the columns per segment of `numColumnPerJob`
|
||||
var (
|
||||
localResult = make([]field.Element, numColumnPerJob*64)
|
||||
limbs = make([]field.Element, 64)
|
||||
|
||||
// Each segment is processed by packet of `numFieldPerPoly=4` rows
|
||||
startFromCol = i * numColumnPerJob
|
||||
stopAtCol = (i + 1) * numColumnPerJob
|
||||
)
|
||||
|
||||
for row := 0; row < len(pols); row += 4 {
|
||||
|
||||
var (
|
||||
chunksFull = make([][]field.Element, 4)
|
||||
mask = 0
|
||||
)
|
||||
|
||||
for j := 0; j < 4; j++ {
|
||||
if row+j >= len(pols) {
|
||||
continue
|
||||
}
|
||||
|
||||
pReg, pIsReg := pols[row+j].(*smartvectors.Regular)
|
||||
if pIsReg {
|
||||
chunksFull[j] = (*pReg)[startFromCol:stopAtCol]
|
||||
mask |= (1 << j)
|
||||
continue
|
||||
}
|
||||
|
||||
pPool, pIsPool := pols[row+j].(*smartvectors.Pooled)
|
||||
if pIsPool {
|
||||
chunksFull[j] = pPool.Regular[startFromCol:stopAtCol]
|
||||
mask |= (1 << j)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if mask > 0 {
|
||||
for col := 0; col < (stopAtCol - startFromCol); col++ {
|
||||
colChunk := [4]field.Element{}
|
||||
for j := 0; j < 4; j++ {
|
||||
if chunksFull[j] != nil {
|
||||
colChunk[j] = chunksFull[j][col]
|
||||
}
|
||||
}
|
||||
|
||||
limbDecompose(limbs, colChunk[:])
|
||||
partialFFT[mask](limbs, twiddleCosets)
|
||||
mulModAcc(localResult[col*64:(col+1)*64], limbs, ag[row/4])
|
||||
}
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
|
||||
var (
|
||||
cMask = ((1 << 4) - 1) ^ mask
|
||||
chunkConst = make([]field.Element, 4)
|
||||
)
|
||||
|
||||
if cMask > 0 {
|
||||
for j := 0; j < 4; j++ {
|
||||
if row+j >= len(pols) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (cMask>>j)&1 == 1 {
|
||||
chunkConst[j] = pols[row+j].(*smartvectors.Constant).Get(0)
|
||||
}
|
||||
}
|
||||
|
||||
limbDecompose(limbs, chunkConst)
|
||||
partialFFT[cMask](limbs, twiddleCosets)
|
||||
mulModAcc(constResults, limbs, ag[row/4])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy the segment into the main result at the end
|
||||
copy(mainResults[startFromCol*64:stopAtCol*64], localResult)
|
||||
})
|
||||
|
||||
// Now, we need to reconciliate the results of the buffer with
|
||||
// the result for each thread
|
||||
parallel.Execute(pols[0].Len(), func(start, stop int) {
|
||||
for col := start; col < stop; col++ {
|
||||
// Accumulate the const
|
||||
vector.Add(mainResults[col*64:(col+1)*64], mainResults[col*64:(col+1)*64], constResults)
|
||||
// And run the reverse FFT
|
||||
domain.FFTInverse(mainResults[col*64:(col+1)*64], fft.DIT, fft.OnCoset(), fft.WithNbTasks(1))
|
||||
}
|
||||
})
|
||||
|
||||
return mainResults
|
||||
}
|
||||
|
||||
var _zeroes []field.Element = make([]field.Element, 64)
|
||||
|
||||
// zeroize fills `buf` with zeroes.
|
||||
func zeroize(buf []field.Element) {
|
||||
copy(buf, _zeroes)
|
||||
}
|
||||
|
||||
// mulModAdd increments each entry `i` of `res` as `res[i] = a[i] * b[i]`. The
|
||||
// input vectors are trusted to all have the same length.
|
||||
func mulModAcc(res, a, b []field.Element) {
|
||||
var tmp field.Element
|
||||
for i := range res {
|
||||
tmp.Mul(&a[i], &b[i])
|
||||
res[i].Add(&res[i], &tmp)
|
||||
}
|
||||
}
|
||||
|
||||
func limbDecompose(result []field.Element, x []field.Element) {
|
||||
|
||||
zeroize(result)
|
||||
var bytesBuffer = [32]byte{}
|
||||
|
||||
bytesBuffer = x[0].Bytes()
|
||||
|
||||
result[15][0] = uint64(bytesBuffer[1]) | (uint64(bytesBuffer[0]) << 8)
|
||||
result[14][0] = uint64(bytesBuffer[3]) | (uint64(bytesBuffer[2]) << 8)
|
||||
result[13][0] = uint64(bytesBuffer[5]) | (uint64(bytesBuffer[4]) << 8)
|
||||
result[12][0] = uint64(bytesBuffer[7]) | (uint64(bytesBuffer[6]) << 8)
|
||||
result[11][0] = uint64(bytesBuffer[9]) | (uint64(bytesBuffer[8]) << 8)
|
||||
result[10][0] = uint64(bytesBuffer[11]) | (uint64(bytesBuffer[10]) << 8)
|
||||
result[9][0] = uint64(bytesBuffer[13]) | (uint64(bytesBuffer[12]) << 8)
|
||||
result[8][0] = uint64(bytesBuffer[15]) | (uint64(bytesBuffer[14]) << 8)
|
||||
result[7][0] = uint64(bytesBuffer[17]) | (uint64(bytesBuffer[16]) << 8)
|
||||
result[6][0] = uint64(bytesBuffer[19]) | (uint64(bytesBuffer[18]) << 8)
|
||||
result[5][0] = uint64(bytesBuffer[21]) | (uint64(bytesBuffer[20]) << 8)
|
||||
result[4][0] = uint64(bytesBuffer[23]) | (uint64(bytesBuffer[22]) << 8)
|
||||
result[3][0] = uint64(bytesBuffer[25]) | (uint64(bytesBuffer[24]) << 8)
|
||||
result[2][0] = uint64(bytesBuffer[27]) | (uint64(bytesBuffer[26]) << 8)
|
||||
result[1][0] = uint64(bytesBuffer[29]) | (uint64(bytesBuffer[28]) << 8)
|
||||
result[0][0] = uint64(bytesBuffer[31]) | (uint64(bytesBuffer[30]) << 8)
|
||||
|
||||
bytesBuffer = x[1].Bytes()
|
||||
|
||||
result[31][0] = uint64(bytesBuffer[1]) | (uint64(bytesBuffer[0]) << 8)
|
||||
result[30][0] = uint64(bytesBuffer[3]) | (uint64(bytesBuffer[2]) << 8)
|
||||
result[29][0] = uint64(bytesBuffer[5]) | (uint64(bytesBuffer[4]) << 8)
|
||||
result[28][0] = uint64(bytesBuffer[7]) | (uint64(bytesBuffer[6]) << 8)
|
||||
result[27][0] = uint64(bytesBuffer[9]) | (uint64(bytesBuffer[8]) << 8)
|
||||
result[26][0] = uint64(bytesBuffer[11]) | (uint64(bytesBuffer[10]) << 8)
|
||||
result[25][0] = uint64(bytesBuffer[13]) | (uint64(bytesBuffer[12]) << 8)
|
||||
result[24][0] = uint64(bytesBuffer[15]) | (uint64(bytesBuffer[14]) << 8)
|
||||
result[23][0] = uint64(bytesBuffer[17]) | (uint64(bytesBuffer[16]) << 8)
|
||||
result[22][0] = uint64(bytesBuffer[19]) | (uint64(bytesBuffer[18]) << 8)
|
||||
result[21][0] = uint64(bytesBuffer[21]) | (uint64(bytesBuffer[20]) << 8)
|
||||
result[20][0] = uint64(bytesBuffer[23]) | (uint64(bytesBuffer[22]) << 8)
|
||||
result[19][0] = uint64(bytesBuffer[25]) | (uint64(bytesBuffer[24]) << 8)
|
||||
result[18][0] = uint64(bytesBuffer[27]) | (uint64(bytesBuffer[26]) << 8)
|
||||
result[17][0] = uint64(bytesBuffer[29]) | (uint64(bytesBuffer[28]) << 8)
|
||||
result[16][0] = uint64(bytesBuffer[31]) | (uint64(bytesBuffer[30]) << 8)
|
||||
|
||||
bytesBuffer = x[2].Bytes()
|
||||
|
||||
result[47][0] = uint64(bytesBuffer[1]) | (uint64(bytesBuffer[0]) << 8)
|
||||
result[46][0] = uint64(bytesBuffer[3]) | (uint64(bytesBuffer[2]) << 8)
|
||||
result[45][0] = uint64(bytesBuffer[5]) | (uint64(bytesBuffer[4]) << 8)
|
||||
result[44][0] = uint64(bytesBuffer[7]) | (uint64(bytesBuffer[6]) << 8)
|
||||
result[43][0] = uint64(bytesBuffer[9]) | (uint64(bytesBuffer[8]) << 8)
|
||||
result[42][0] = uint64(bytesBuffer[11]) | (uint64(bytesBuffer[10]) << 8)
|
||||
result[41][0] = uint64(bytesBuffer[13]) | (uint64(bytesBuffer[12]) << 8)
|
||||
result[40][0] = uint64(bytesBuffer[15]) | (uint64(bytesBuffer[14]) << 8)
|
||||
result[39][0] = uint64(bytesBuffer[17]) | (uint64(bytesBuffer[16]) << 8)
|
||||
result[38][0] = uint64(bytesBuffer[19]) | (uint64(bytesBuffer[18]) << 8)
|
||||
result[37][0] = uint64(bytesBuffer[21]) | (uint64(bytesBuffer[20]) << 8)
|
||||
result[36][0] = uint64(bytesBuffer[23]) | (uint64(bytesBuffer[22]) << 8)
|
||||
result[35][0] = uint64(bytesBuffer[25]) | (uint64(bytesBuffer[24]) << 8)
|
||||
result[34][0] = uint64(bytesBuffer[27]) | (uint64(bytesBuffer[26]) << 8)
|
||||
result[33][0] = uint64(bytesBuffer[29]) | (uint64(bytesBuffer[28]) << 8)
|
||||
result[32][0] = uint64(bytesBuffer[31]) | (uint64(bytesBuffer[30]) << 8)
|
||||
|
||||
bytesBuffer = x[3].Bytes()
|
||||
|
||||
result[63][0] = uint64(bytesBuffer[1]) | (uint64(bytesBuffer[0]) << 8)
|
||||
result[62][0] = uint64(bytesBuffer[3]) | (uint64(bytesBuffer[2]) << 8)
|
||||
result[61][0] = uint64(bytesBuffer[5]) | (uint64(bytesBuffer[4]) << 8)
|
||||
result[60][0] = uint64(bytesBuffer[7]) | (uint64(bytesBuffer[6]) << 8)
|
||||
result[59][0] = uint64(bytesBuffer[9]) | (uint64(bytesBuffer[8]) << 8)
|
||||
result[58][0] = uint64(bytesBuffer[11]) | (uint64(bytesBuffer[10]) << 8)
|
||||
result[57][0] = uint64(bytesBuffer[13]) | (uint64(bytesBuffer[12]) << 8)
|
||||
result[56][0] = uint64(bytesBuffer[15]) | (uint64(bytesBuffer[14]) << 8)
|
||||
result[55][0] = uint64(bytesBuffer[17]) | (uint64(bytesBuffer[16]) << 8)
|
||||
result[54][0] = uint64(bytesBuffer[19]) | (uint64(bytesBuffer[18]) << 8)
|
||||
result[53][0] = uint64(bytesBuffer[21]) | (uint64(bytesBuffer[20]) << 8)
|
||||
result[52][0] = uint64(bytesBuffer[23]) | (uint64(bytesBuffer[22]) << 8)
|
||||
result[51][0] = uint64(bytesBuffer[25]) | (uint64(bytesBuffer[24]) << 8)
|
||||
result[50][0] = uint64(bytesBuffer[27]) | (uint64(bytesBuffer[26]) << 8)
|
||||
result[49][0] = uint64(bytesBuffer[29]) | (uint64(bytesBuffer[28]) << 8)
|
||||
result[48][0] = uint64(bytesBuffer[31]) | (uint64(bytesBuffer[30]) << 8)
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_16_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis/ringsis_64_16"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/vector"
|
||||
wfft "github.com/consensys/linea-monorepo/prover/maths/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// randomConstRow generates a random constant smart-vector
|
||||
func randomConstRow(rng *rand.Rand, size int) smartvectors.SmartVector {
|
||||
return smartvectors.NewConstant(field.PseudoRand(rng), size)
|
||||
}
|
||||
|
||||
// randomRegularRow generates a random regular smart-vector
|
||||
func randomRegularRow(rng *rand.Rand, size int) smartvectors.SmartVector {
|
||||
return smartvectors.PseudoRand(rng, size)
|
||||
}
|
||||
|
||||
// generate a smartvector row-matrix by using randomly constant or regular smart-vectors
|
||||
func fullyRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector {
|
||||
list := make([]smartvectors.SmartVector, numRow)
|
||||
for i := range list {
|
||||
coin := rng.IntN(2)
|
||||
switch {
|
||||
case coin == 0:
|
||||
list[i] = randomConstRow(rng, numCols)
|
||||
case coin == 1:
|
||||
list[i] = randomRegularRow(rng, numCols)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func constantRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector {
|
||||
list := make([]smartvectors.SmartVector, numRow)
|
||||
for i := range list {
|
||||
list[i] = randomConstRow(rng, numCols)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func regularRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector {
|
||||
list := make([]smartvectors.SmartVector, numRow)
|
||||
for i := range list {
|
||||
list[i] = randomConstRow(rng, numCols)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func TestSmartVectorTransversalSisHash(t *testing.T) {
|
||||
|
||||
var (
|
||||
numReps = 64
|
||||
numCols = 16
|
||||
rng = rand.New(rand.NewChaCha8([32]byte{}))
|
||||
domain = fft.NewDomain(64, fft.WithShift(wfft.GetOmega(64*2)))
|
||||
twiddles = ringsis_64_16.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
params = ringsis.Params{LogTwoBound: 16, LogTwoDegree: 6}
|
||||
testCases = [][]smartvectors.SmartVector{
|
||||
constantRandomTestVector(rng, 4, numCols),
|
||||
regularRandomTestVector(rng, 4, numCols),
|
||||
}
|
||||
)
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 4, numCols))
|
||||
}
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 16, 2*numCols))
|
||||
}
|
||||
|
||||
for i, c := range testCases {
|
||||
t.Run(fmt.Sprintf("testcase-%v", i), func(t *testing.T) {
|
||||
|
||||
var (
|
||||
numRow = len(c)
|
||||
key = ringsis.GenerateKey(params, numRow)
|
||||
result = ringsis_64_16.TransversalHash(
|
||||
key.Ag(),
|
||||
c,
|
||||
twiddles,
|
||||
domain,
|
||||
)
|
||||
)
|
||||
|
||||
for col := 0; col < numCols; col++ {
|
||||
column := make([]field.Element, numRow)
|
||||
for r := 0; r < numRow; r++ {
|
||||
column[r] = c[r].Get(col)
|
||||
}
|
||||
|
||||
colHash := key.Hash(column)
|
||||
require.Equalf(
|
||||
t,
|
||||
vector.Prettify(colHash),
|
||||
vector.Prettify(result[64*col:64*col+64]),
|
||||
"column %v", col,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_16
|
||||
|
||||
import (
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// PrecomputeTwiddlesCoset precomputes twiddlesCoset from twiddles and coset table
|
||||
// it then return all elements in the correct order for the unrolled FFT.
|
||||
func PrecomputeTwiddlesCoset(generator, shifter field.Element) []field.Element {
|
||||
toReturn := make([]field.Element, 63)
|
||||
var r, s field.Element
|
||||
e := new(big.Int)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 5; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[0] = s
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 4; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[1] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<4*1)))
|
||||
toReturn[2].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 3; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[3] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<3*2)))
|
||||
toReturn[4].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<3*1)))
|
||||
toReturn[5].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<3*3)))
|
||||
toReturn[6].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 2; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[7] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*4)))
|
||||
toReturn[8].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*2)))
|
||||
toReturn[9].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*6)))
|
||||
toReturn[10].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*1)))
|
||||
toReturn[11].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*5)))
|
||||
toReturn[12].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*3)))
|
||||
toReturn[13].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*7)))
|
||||
toReturn[14].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 1; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[15] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*8)))
|
||||
toReturn[16].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*4)))
|
||||
toReturn[17].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*12)))
|
||||
toReturn[18].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*2)))
|
||||
toReturn[19].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*10)))
|
||||
toReturn[20].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*6)))
|
||||
toReturn[21].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*14)))
|
||||
toReturn[22].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*1)))
|
||||
toReturn[23].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*9)))
|
||||
toReturn[24].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*5)))
|
||||
toReturn[25].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*13)))
|
||||
toReturn[26].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*3)))
|
||||
toReturn[27].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*11)))
|
||||
toReturn[28].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*7)))
|
||||
toReturn[29].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*15)))
|
||||
toReturn[30].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 0; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[31] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*16)))
|
||||
toReturn[32].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*8)))
|
||||
toReturn[33].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*24)))
|
||||
toReturn[34].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*4)))
|
||||
toReturn[35].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*20)))
|
||||
toReturn[36].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*12)))
|
||||
toReturn[37].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*28)))
|
||||
toReturn[38].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*2)))
|
||||
toReturn[39].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*18)))
|
||||
toReturn[40].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*10)))
|
||||
toReturn[41].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*26)))
|
||||
toReturn[42].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*6)))
|
||||
toReturn[43].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*22)))
|
||||
toReturn[44].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*14)))
|
||||
toReturn[45].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*30)))
|
||||
toReturn[46].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*1)))
|
||||
toReturn[47].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*17)))
|
||||
toReturn[48].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*9)))
|
||||
toReturn[49].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*25)))
|
||||
toReturn[50].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*5)))
|
||||
toReturn[51].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*21)))
|
||||
toReturn[52].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*13)))
|
||||
toReturn[53].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*29)))
|
||||
toReturn[54].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*3)))
|
||||
toReturn[55].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*19)))
|
||||
toReturn[56].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*11)))
|
||||
toReturn[57].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*27)))
|
||||
toReturn[58].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*7)))
|
||||
toReturn[59].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*23)))
|
||||
toReturn[60].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*15)))
|
||||
toReturn[61].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*31)))
|
||||
toReturn[62].Mul(&r, &s)
|
||||
|
||||
return toReturn
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_8
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLimbDecompose(t *testing.T) {
|
||||
|
||||
var (
|
||||
limbs = make([]int64, 64)
|
||||
rng = rand.New(rand.NewChaCha8([32]byte{}))
|
||||
inputs = make([]field.Element, 2)
|
||||
obtainedLimbs = make([]field.Element, 64)
|
||||
)
|
||||
|
||||
for i := range limbs {
|
||||
if i%32 > 31 {
|
||||
limbs[i] = int64(rng.IntN(1 << 8))
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
buf := &big.Int{}
|
||||
for j := 30; j >= 0; j-- {
|
||||
buf.Mul(buf, big.NewInt(1<<8))
|
||||
tmp := new(big.Int).SetInt64(limbs[32*i+j])
|
||||
buf.Add(buf, tmp)
|
||||
}
|
||||
inputs[i].SetBigInt(buf)
|
||||
}
|
||||
|
||||
limbDecompose(obtainedLimbs, inputs)
|
||||
|
||||
for i := range obtainedLimbs {
|
||||
assert.Equal(t, uint64(limbs[i]), obtainedLimbs[i][0])
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,55 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_8
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPartialFFT(t *testing.T) {
|
||||
|
||||
var (
|
||||
domain = fft.NewDomain(64)
|
||||
twiddles = PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
)
|
||||
|
||||
for mask := 0; mask < 4; mask++ {
|
||||
|
||||
var (
|
||||
a = vec123456()
|
||||
b = vec123456()
|
||||
)
|
||||
|
||||
zeroizeWithMask(a, mask)
|
||||
zeroizeWithMask(b, mask)
|
||||
|
||||
domain.FFT(a, fft.DIF, fft.OnCoset())
|
||||
partialFFT[mask](b, twiddles)
|
||||
assert.Equal(t, a, b)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func vec123456() []field.Element {
|
||||
vec := make([]field.Element, 64)
|
||||
for i := range vec {
|
||||
vec[i].SetInt64(int64(i))
|
||||
}
|
||||
return vec
|
||||
}
|
||||
|
||||
func zeroizeWithMask(v []field.Element, mask int) {
|
||||
for i := 0; i < 2; i++ {
|
||||
if (mask>>i)&1 == 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
for j := 0; j < 32; j++ {
|
||||
v[32*i+j].SetZero()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_8
|
||||
|
||||
import (
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/vector"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
"github.com/consensys/linea-monorepo/prover/utils/parallel"
|
||||
ppool "github.com/consensys/linea-monorepo/prover/utils/parallel/pool"
|
||||
)
|
||||
|
||||
func TransversalHash(
|
||||
// the Ag for ring-sis
|
||||
ag [][]field.Element,
|
||||
// A non-transposed list of columns
|
||||
// All of the same length
|
||||
pols []smartvectors.SmartVector,
|
||||
// The precomputed twiddle cosets for the forward FFT
|
||||
twiddleCosets []field.Element,
|
||||
// The domain for the final inverse-FFT
|
||||
domain *fft.Domain,
|
||||
) []field.Element {
|
||||
|
||||
var (
|
||||
// Each field element is encoded in 32 limbs but the degree is 64. So, each
|
||||
// polynomial multiplication "hashes" 2 field elements at once. This is
|
||||
// important to know for parallelization.
|
||||
resultSize = pols[0].Len() * 64
|
||||
|
||||
// To optimize memory usage, we limit ourself to hash only 16 columns per
|
||||
// iteration.
|
||||
numColumnPerJob int = 16
|
||||
|
||||
// In theory, it should be a div ceil. But in practice we only process power's
|
||||
// of two number of columns. If that's not the case, then the function will panic
|
||||
// but we can always change that if this is needed. The rational for the current
|
||||
// design is simplicity.
|
||||
numJobs = utils.DivExact(pols[0].Len(), numColumnPerJob) // we make blocks of 16 columns
|
||||
|
||||
// Main result of the hashing
|
||||
mainResults = make([]field.Element, resultSize)
|
||||
// When we encounter a const row, it will have the same additive contribution
|
||||
// to the result on every column. So we compute the contribution only once and
|
||||
// accumulate it with the other "constant column contributions". And it is only
|
||||
// performed by the first thread.
|
||||
constResults = make([]field.Element, 64)
|
||||
)
|
||||
|
||||
ppool.ExecutePoolChunky(numJobs, func(i int) {
|
||||
// We process the columns per segment of `numColumnPerJob`
|
||||
var (
|
||||
localResult = make([]field.Element, numColumnPerJob*64)
|
||||
limbs = make([]field.Element, 64)
|
||||
|
||||
// Each segment is processed by packet of `numFieldPerPoly=2` rows
|
||||
startFromCol = i * numColumnPerJob
|
||||
stopAtCol = (i + 1) * numColumnPerJob
|
||||
)
|
||||
|
||||
for row := 0; row < len(pols); row += 2 {
|
||||
|
||||
var (
|
||||
chunksFull = make([][]field.Element, 2)
|
||||
mask = 0
|
||||
)
|
||||
|
||||
for j := 0; j < 2; j++ {
|
||||
if row+j >= len(pols) {
|
||||
continue
|
||||
}
|
||||
|
||||
pReg, pIsReg := pols[row+j].(*smartvectors.Regular)
|
||||
if pIsReg {
|
||||
chunksFull[j] = (*pReg)[startFromCol:stopAtCol]
|
||||
mask |= (1 << j)
|
||||
continue
|
||||
}
|
||||
|
||||
pPool, pIsPool := pols[row+j].(*smartvectors.Pooled)
|
||||
if pIsPool {
|
||||
chunksFull[j] = pPool.Regular[startFromCol:stopAtCol]
|
||||
mask |= (1 << j)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if mask > 0 {
|
||||
for col := 0; col < (stopAtCol - startFromCol); col++ {
|
||||
colChunk := [2]field.Element{}
|
||||
for j := 0; j < 2; j++ {
|
||||
if chunksFull[j] != nil {
|
||||
colChunk[j] = chunksFull[j][col]
|
||||
}
|
||||
}
|
||||
|
||||
limbDecompose(limbs, colChunk[:])
|
||||
partialFFT[mask](limbs, twiddleCosets)
|
||||
mulModAcc(localResult[col*64:(col+1)*64], limbs, ag[row/2])
|
||||
}
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
|
||||
var (
|
||||
cMask = ((1 << 2) - 1) ^ mask
|
||||
chunkConst = make([]field.Element, 2)
|
||||
)
|
||||
|
||||
if cMask > 0 {
|
||||
for j := 0; j < 2; j++ {
|
||||
if row+j >= len(pols) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (cMask>>j)&1 == 1 {
|
||||
chunkConst[j] = pols[row+j].(*smartvectors.Constant).Get(0)
|
||||
}
|
||||
}
|
||||
|
||||
limbDecompose(limbs, chunkConst)
|
||||
partialFFT[cMask](limbs, twiddleCosets)
|
||||
mulModAcc(constResults, limbs, ag[row/2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy the segment into the main result at the end
|
||||
copy(mainResults[startFromCol*64:stopAtCol*64], localResult)
|
||||
})
|
||||
|
||||
// Now, we need to reconciliate the results of the buffer with
|
||||
// the result for each thread
|
||||
parallel.Execute(pols[0].Len(), func(start, stop int) {
|
||||
for col := start; col < stop; col++ {
|
||||
// Accumulate the const
|
||||
vector.Add(mainResults[col*64:(col+1)*64], mainResults[col*64:(col+1)*64], constResults)
|
||||
// And run the reverse FFT
|
||||
domain.FFTInverse(mainResults[col*64:(col+1)*64], fft.DIT, fft.OnCoset(), fft.WithNbTasks(1))
|
||||
}
|
||||
})
|
||||
|
||||
return mainResults
|
||||
}
|
||||
|
||||
var _zeroes []field.Element = make([]field.Element, 64)
|
||||
|
||||
// zeroize fills `buf` with zeroes.
|
||||
func zeroize(buf []field.Element) {
|
||||
copy(buf, _zeroes)
|
||||
}
|
||||
|
||||
// mulModAdd increments each entry `i` of `res` as `res[i] = a[i] * b[i]`. The
|
||||
// input vectors are trusted to all have the same length.
|
||||
func mulModAcc(res, a, b []field.Element) {
|
||||
var tmp field.Element
|
||||
for i := range res {
|
||||
tmp.Mul(&a[i], &b[i])
|
||||
res[i].Add(&res[i], &tmp)
|
||||
}
|
||||
}
|
||||
|
||||
func limbDecompose(result []field.Element, x []field.Element) {
|
||||
|
||||
zeroize(result)
|
||||
var bytesBuffer = [32]byte{}
|
||||
|
||||
bytesBuffer = x[0].Bytes()
|
||||
|
||||
result[31][0] = uint64(bytesBuffer[0])
|
||||
result[30][0] = uint64(bytesBuffer[1])
|
||||
result[29][0] = uint64(bytesBuffer[2])
|
||||
result[28][0] = uint64(bytesBuffer[3])
|
||||
result[27][0] = uint64(bytesBuffer[4])
|
||||
result[26][0] = uint64(bytesBuffer[5])
|
||||
result[25][0] = uint64(bytesBuffer[6])
|
||||
result[24][0] = uint64(bytesBuffer[7])
|
||||
result[23][0] = uint64(bytesBuffer[8])
|
||||
result[22][0] = uint64(bytesBuffer[9])
|
||||
result[21][0] = uint64(bytesBuffer[10])
|
||||
result[20][0] = uint64(bytesBuffer[11])
|
||||
result[19][0] = uint64(bytesBuffer[12])
|
||||
result[18][0] = uint64(bytesBuffer[13])
|
||||
result[17][0] = uint64(bytesBuffer[14])
|
||||
result[16][0] = uint64(bytesBuffer[15])
|
||||
result[15][0] = uint64(bytesBuffer[16])
|
||||
result[14][0] = uint64(bytesBuffer[17])
|
||||
result[13][0] = uint64(bytesBuffer[18])
|
||||
result[12][0] = uint64(bytesBuffer[19])
|
||||
result[11][0] = uint64(bytesBuffer[20])
|
||||
result[10][0] = uint64(bytesBuffer[21])
|
||||
result[9][0] = uint64(bytesBuffer[22])
|
||||
result[8][0] = uint64(bytesBuffer[23])
|
||||
result[7][0] = uint64(bytesBuffer[24])
|
||||
result[6][0] = uint64(bytesBuffer[25])
|
||||
result[5][0] = uint64(bytesBuffer[26])
|
||||
result[4][0] = uint64(bytesBuffer[27])
|
||||
result[3][0] = uint64(bytesBuffer[28])
|
||||
result[2][0] = uint64(bytesBuffer[29])
|
||||
result[1][0] = uint64(bytesBuffer[30])
|
||||
result[0][0] = uint64(bytesBuffer[31])
|
||||
|
||||
bytesBuffer = x[1].Bytes()
|
||||
|
||||
result[63][0] = uint64(bytesBuffer[0])
|
||||
result[62][0] = uint64(bytesBuffer[1])
|
||||
result[61][0] = uint64(bytesBuffer[2])
|
||||
result[60][0] = uint64(bytesBuffer[3])
|
||||
result[59][0] = uint64(bytesBuffer[4])
|
||||
result[58][0] = uint64(bytesBuffer[5])
|
||||
result[57][0] = uint64(bytesBuffer[6])
|
||||
result[56][0] = uint64(bytesBuffer[7])
|
||||
result[55][0] = uint64(bytesBuffer[8])
|
||||
result[54][0] = uint64(bytesBuffer[9])
|
||||
result[53][0] = uint64(bytesBuffer[10])
|
||||
result[52][0] = uint64(bytesBuffer[11])
|
||||
result[51][0] = uint64(bytesBuffer[12])
|
||||
result[50][0] = uint64(bytesBuffer[13])
|
||||
result[49][0] = uint64(bytesBuffer[14])
|
||||
result[48][0] = uint64(bytesBuffer[15])
|
||||
result[47][0] = uint64(bytesBuffer[16])
|
||||
result[46][0] = uint64(bytesBuffer[17])
|
||||
result[45][0] = uint64(bytesBuffer[18])
|
||||
result[44][0] = uint64(bytesBuffer[19])
|
||||
result[43][0] = uint64(bytesBuffer[20])
|
||||
result[42][0] = uint64(bytesBuffer[21])
|
||||
result[41][0] = uint64(bytesBuffer[22])
|
||||
result[40][0] = uint64(bytesBuffer[23])
|
||||
result[39][0] = uint64(bytesBuffer[24])
|
||||
result[38][0] = uint64(bytesBuffer[25])
|
||||
result[37][0] = uint64(bytesBuffer[26])
|
||||
result[36][0] = uint64(bytesBuffer[27])
|
||||
result[35][0] = uint64(bytesBuffer[28])
|
||||
result[34][0] = uint64(bytesBuffer[29])
|
||||
result[33][0] = uint64(bytesBuffer[30])
|
||||
result[32][0] = uint64(bytesBuffer[31])
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_8
|
||||
|
||||
import (
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// PrecomputeTwiddlesCoset precomputes twiddlesCoset from twiddles and coset table
|
||||
// it then return all elements in the correct order for the unrolled FFT.
|
||||
func PrecomputeTwiddlesCoset(generator, shifter field.Element) []field.Element {
|
||||
toReturn := make([]field.Element, 63)
|
||||
var r, s field.Element
|
||||
e := new(big.Int)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 5; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[0] = s
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 4; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[1] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<4*1)))
|
||||
toReturn[2].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 3; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[3] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<3*2)))
|
||||
toReturn[4].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<3*1)))
|
||||
toReturn[5].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<3*3)))
|
||||
toReturn[6].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 2; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[7] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*4)))
|
||||
toReturn[8].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*2)))
|
||||
toReturn[9].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*6)))
|
||||
toReturn[10].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*1)))
|
||||
toReturn[11].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*5)))
|
||||
toReturn[12].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*3)))
|
||||
toReturn[13].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<2*7)))
|
||||
toReturn[14].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 1; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[15] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*8)))
|
||||
toReturn[16].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*4)))
|
||||
toReturn[17].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*12)))
|
||||
toReturn[18].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*2)))
|
||||
toReturn[19].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*10)))
|
||||
toReturn[20].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*6)))
|
||||
toReturn[21].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*14)))
|
||||
toReturn[22].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*1)))
|
||||
toReturn[23].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*9)))
|
||||
toReturn[24].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*5)))
|
||||
toReturn[25].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*13)))
|
||||
toReturn[26].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*3)))
|
||||
toReturn[27].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*11)))
|
||||
toReturn[28].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*7)))
|
||||
toReturn[29].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<1*15)))
|
||||
toReturn[30].Mul(&r, &s)
|
||||
|
||||
s = shifter
|
||||
|
||||
for k := 0; k < 0; k++ {
|
||||
s.Square(&s)
|
||||
}
|
||||
|
||||
toReturn[31] = s
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*16)))
|
||||
toReturn[32].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*8)))
|
||||
toReturn[33].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*24)))
|
||||
toReturn[34].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*4)))
|
||||
toReturn[35].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*20)))
|
||||
toReturn[36].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*12)))
|
||||
toReturn[37].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*28)))
|
||||
toReturn[38].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*2)))
|
||||
toReturn[39].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*18)))
|
||||
toReturn[40].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*10)))
|
||||
toReturn[41].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*26)))
|
||||
toReturn[42].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*6)))
|
||||
toReturn[43].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*22)))
|
||||
toReturn[44].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*14)))
|
||||
toReturn[45].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*30)))
|
||||
toReturn[46].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*1)))
|
||||
toReturn[47].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*17)))
|
||||
toReturn[48].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*9)))
|
||||
toReturn[49].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*25)))
|
||||
toReturn[50].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*5)))
|
||||
toReturn[51].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*21)))
|
||||
toReturn[52].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*13)))
|
||||
toReturn[53].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*29)))
|
||||
toReturn[54].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*3)))
|
||||
toReturn[55].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*19)))
|
||||
toReturn[56].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*11)))
|
||||
toReturn[57].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*27)))
|
||||
toReturn[58].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*7)))
|
||||
toReturn[59].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*23)))
|
||||
toReturn[60].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*15)))
|
||||
toReturn[61].Mul(&r, &s)
|
||||
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<0*31)))
|
||||
toReturn[62].Mul(&r, &s)
|
||||
|
||||
return toReturn
|
||||
}
|
||||
@@ -43,22 +43,8 @@ var testCasesKey = []struct {
|
||||
{
|
||||
Size: 43,
|
||||
Params: Params{
|
||||
LogTwoBound: 1,
|
||||
LogTwoDegree: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Size: 23,
|
||||
Params: Params{
|
||||
LogTwoBound: 1,
|
||||
LogTwoDegree: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Size: 256,
|
||||
Params: Params{
|
||||
LogTwoBound: 1,
|
||||
LogTwoDegree: 1,
|
||||
LogTwoBound: 8,
|
||||
LogTwoDegree: 6,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -275,35 +261,40 @@ func TestTransveralHashFromLimbs(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for pId, tcKeyParams := range testCasesKey {
|
||||
for _, tcKeyParams := range testCasesKey {
|
||||
for _, tcDim := range testCaseDimensions {
|
||||
t.Run(
|
||||
fmt.Sprintf("params-%v-numRow=%v-nCols=%v", pId, tcDim.NumRows, tcDim.NumCols),
|
||||
func(t *testing.T) {
|
||||
t.Logf("params-%v-numRow=%v-nCols=%v", tcKeyParams.Size, tcDim.NumRows, tcDim.NumCols)
|
||||
// t.Run(
|
||||
// fmt.Sprintf("params-%v-numRow=%v-nCols=%v", pId, tcDim.NumRows, tcDim.NumCols),
|
||||
// func(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
|
||||
key := GenerateKey(tcKeyParams.Params, tcDim.NumRows)
|
||||
key := GenerateKey(tcKeyParams.Params, tcDim.NumRows)
|
||||
|
||||
inputs := make([]smartvectors.SmartVector, 4)
|
||||
for i := range inputs {
|
||||
inputs[i] = smartvectors.Rand(16)
|
||||
}
|
||||
inputs := make([]smartvectors.SmartVector, 4)
|
||||
for i := range inputs {
|
||||
inputs[i] = smartvectors.Rand(16)
|
||||
}
|
||||
|
||||
transposed := make([][]field.Element, 16)
|
||||
for i := range transposed {
|
||||
transposed[i] = make([]fr.Element, 4)
|
||||
for j := range transposed[i] {
|
||||
transposed[i][j] = inputs[j].Get(i)
|
||||
}
|
||||
}
|
||||
transposed := make([][]field.Element, 16)
|
||||
for i := range transposed {
|
||||
transposed[i] = make([]fr.Element, 4)
|
||||
for j := range transposed[i] {
|
||||
transposed[i][j] = inputs[j].Get(i)
|
||||
}
|
||||
}
|
||||
|
||||
res := key.TransversalHash(inputs)
|
||||
for i := range transposed {
|
||||
baseline := key.Hash(transposed[i])
|
||||
assert.Equal(t, baseline, res[i*key.OutputSize():(i+1)*key.OutputSize()])
|
||||
}
|
||||
|
||||
},
|
||||
)
|
||||
res := key.TransversalHash(inputs)
|
||||
for i := range transposed {
|
||||
baseline := key.Hash(transposed[i])
|
||||
for j := range baseline {
|
||||
assert.Equal(baseline[j], res[i*key.OutputSize()+j], "transversal hash does not match col hash at %d %d", i, j)
|
||||
}
|
||||
// assert.Equal(baseline, res[i*key.OutputSize():(i+1)*key.OutputSize()])
|
||||
}
|
||||
// t.FailNow()
|
||||
// },
|
||||
// )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/bits"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/consensys/bavard"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
)
|
||||
|
||||
// Config stores the template generation parameters for the optimized ring-SIS
|
||||
type Config struct {
|
||||
ModulusDegree int64
|
||||
LogTwoBound int64
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
cfg := Config{}
|
||||
flag.Int64Var(&cfg.LogTwoBound, "logTwoBound", 0, "")
|
||||
flag.Int64Var(&cfg.ModulusDegree, "modulusDegree", 0, "")
|
||||
flag.Parse()
|
||||
|
||||
filesList := []string{
|
||||
"transversal_hash.go",
|
||||
"transversal_hash_test.go",
|
||||
"partial_fft.go",
|
||||
"twiddles.go",
|
||||
"partial_fft_test.go",
|
||||
"limb_decompose_test.go",
|
||||
}
|
||||
|
||||
for _, file := range filesList {
|
||||
var (
|
||||
source = "./templates/" + file + ".tmpl"
|
||||
target = fmt.Sprintf("./ringsis_%v_%v/%v", cfg.ModulusDegree, cfg.LogTwoBound, file)
|
||||
)
|
||||
|
||||
err := bavard.GenerateFromFiles(
|
||||
target,
|
||||
[]string{source},
|
||||
cfg,
|
||||
bavard.Funcs(template.FuncMap{
|
||||
"partialFFT": partialFFT,
|
||||
"pow": pow,
|
||||
"bitReverse": bitReverse,
|
||||
"log2": log2,
|
||||
}),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("err = %v\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pow(base, pow int64) int64 {
|
||||
var (
|
||||
b = new(big.Int).SetInt64(base)
|
||||
p = new(big.Int).SetInt64(pow)
|
||||
)
|
||||
b.Exp(b, p, nil)
|
||||
|
||||
if !b.IsInt64() {
|
||||
utils.Panic("could not cast big.Int %v to int64 as it overflows", b.String())
|
||||
}
|
||||
|
||||
return b.Int64()
|
||||
}
|
||||
|
||||
func log2(n int64) int64 {
|
||||
return int64(utils.Log2Floor(int(n)))
|
||||
}
|
||||
|
||||
func bitReverse(n, i int64) uint64 {
|
||||
nn := uint64(64 - bits.TrailingZeros64(uint64(n)))
|
||||
r := make([]uint64, n)
|
||||
for i := 0; i < len(r); i++ {
|
||||
r[i] = uint64(i)
|
||||
}
|
||||
for i := 0; i < len(r); i++ {
|
||||
irev := bits.Reverse64(r[i]) >> nn
|
||||
if irev > uint64(i) {
|
||||
r[i], r[irev] = r[irev], r[i]
|
||||
}
|
||||
}
|
||||
return r[i]
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
{{- $bitPerField := 256}}
|
||||
{{- $limbPerField := div $bitPerField .LogTwoBound}}
|
||||
{{- $fieldPerPoly := div .ModulusDegree $limbPerField}}
|
||||
{{- $numMask := pow 2 $fieldPerPoly}}
|
||||
|
||||
func TestLimbDecompose(t *testing.T) {
|
||||
|
||||
var (
|
||||
limbs = make([]int64, {{.ModulusDegree}})
|
||||
rng = rand.New(rand.NewChaCha8([32]byte{}))
|
||||
inputs = make([]field.Element, {{$fieldPerPoly}})
|
||||
obtainedLimbs = make([]field.Element, {{.ModulusDegree}})
|
||||
)
|
||||
|
||||
for i := range limbs {
|
||||
if i%{{$limbPerField}} > {{sub $limbPerField 1}} {
|
||||
limbs[i] = int64(rng.IntN(1 << {{.LogTwoBound}}))
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < {{$fieldPerPoly}}; i++ {
|
||||
buf := &big.Int{}
|
||||
for j := {{sub $limbPerField 2}}; j >= 0; j-- {
|
||||
buf.Mul(buf, big.NewInt(1<<{{.LogTwoBound}}))
|
||||
tmp := new(big.Int).SetInt64(limbs[{{$limbPerField}}*i+j])
|
||||
buf.Add(buf, tmp)
|
||||
}
|
||||
inputs[i].SetBigInt(buf)
|
||||
}
|
||||
|
||||
limbDecompose(obtainedLimbs, inputs)
|
||||
|
||||
for i := range obtainedLimbs {
|
||||
assert.Equal(t, uint64(limbs[i]), obtainedLimbs[i][0])
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
)
|
||||
|
||||
func partialFFT(domainSize, numField, mask int64) string {
|
||||
|
||||
gen := initializePartialFFTCodeGen(domainSize, numField, mask)
|
||||
|
||||
gen.header()
|
||||
gen.indent()
|
||||
|
||||
var (
|
||||
numStages int = utils.Log2Ceil(int(domainSize))
|
||||
numSplits int = 1
|
||||
splitSize int = int(domainSize)
|
||||
)
|
||||
|
||||
for level := 0; level < numStages; level++ {
|
||||
for s := 0; s < numSplits; s++ {
|
||||
for k := 0; k < splitSize/2; k++ {
|
||||
gen.twiddleMulLine(s*splitSize+splitSize/2+k, numSplits-1+s)
|
||||
}
|
||||
}
|
||||
|
||||
for s := 0; s < numSplits; s++ {
|
||||
for k := 0; k < splitSize/2; k++ {
|
||||
gen.butterFlyLine(s*splitSize+k, s*splitSize+splitSize/2+k)
|
||||
}
|
||||
}
|
||||
|
||||
splitSize /= 2
|
||||
numSplits *= 2
|
||||
}
|
||||
|
||||
gen.desindent()
|
||||
gen.tail()
|
||||
return gen.Builder.String()
|
||||
}
|
||||
|
||||
func initializePartialFFTCodeGen(domainSize, numField, mask int64) PartialFFTCodeGen {
|
||||
res := PartialFFTCodeGen{
|
||||
DomainSize: int(domainSize),
|
||||
NumField: int(numField),
|
||||
Mask: int(mask),
|
||||
IsZero: make([]bool, domainSize),
|
||||
Builder: &strings.Builder{},
|
||||
NumIndent: 0,
|
||||
}
|
||||
|
||||
for i := range res.IsZero {
|
||||
var (
|
||||
fieldSize = domainSize / numField
|
||||
bit = i / int(fieldSize)
|
||||
isZero = ((mask >> bit) & 1) == 0
|
||||
)
|
||||
|
||||
res.IsZero[i] = isZero
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
type PartialFFTCodeGen struct {
|
||||
DomainSize int
|
||||
NumField int
|
||||
Mask int
|
||||
Builder *strings.Builder
|
||||
NumIndent int
|
||||
IsZero []bool
|
||||
}
|
||||
|
||||
func (p *PartialFFTCodeGen) header() {
|
||||
writeIndent(p.Builder, p.NumIndent)
|
||||
line := fmt.Sprintf("func partialFFT_%v(a, twiddles []field.Element) {\n", p.Mask)
|
||||
p.Builder.WriteString(line)
|
||||
}
|
||||
|
||||
func (p *PartialFFTCodeGen) tail() {
|
||||
writeIndent(p.Builder, p.NumIndent)
|
||||
p.Builder.WriteString("}\n")
|
||||
}
|
||||
|
||||
func (p *PartialFFTCodeGen) butterFlyLine(i, j int) {
|
||||
allZeroes := p.IsZero[i] && p.IsZero[j]
|
||||
if allZeroes {
|
||||
return
|
||||
}
|
||||
|
||||
p.IsZero[i] = false
|
||||
p.IsZero[j] = false
|
||||
|
||||
writeIndent(p.Builder, p.NumIndent)
|
||||
|
||||
line := fmt.Sprintf("field.Butterfly(&a[%v], &a[%v])\n", i, j)
|
||||
if _, err := p.Builder.WriteString(line); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PartialFFTCodeGen) twiddleMulLine(i, twidPos int) {
|
||||
if p.IsZero[i] {
|
||||
return
|
||||
}
|
||||
|
||||
writeIndent(p.Builder, p.NumIndent)
|
||||
|
||||
line := fmt.Sprintf("a[%v].Mul(&a[%v], &twiddles[%v])\n", i, i, twidPos)
|
||||
if _, err := p.Builder.WriteString(line); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PartialFFTCodeGen) desindent() {
|
||||
p.NumIndent--
|
||||
}
|
||||
|
||||
func (p *PartialFFTCodeGen) indent() {
|
||||
p.NumIndent++
|
||||
}
|
||||
|
||||
func writeIndent(w *strings.Builder, n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
w.WriteString("\t")
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}
|
||||
|
||||
import (
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
)
|
||||
|
||||
{{- $bitPerField := 256}}
|
||||
{{- $limbPerField := div $bitPerField .LogTwoBound}}
|
||||
{{- $fieldPerPoly := div .ModulusDegree $limbPerField}}
|
||||
{{- $numMask := pow 2 $fieldPerPoly}}
|
||||
|
||||
var partialFFT = []func(a, twiddles []field.Element){
|
||||
{{- range $i := iterate 0 $numMask}}
|
||||
partialFFT_{{$i}},
|
||||
{{- end}}
|
||||
}
|
||||
{{range $mask := iterate 0 $numMask}}
|
||||
{{partialFFT $.ModulusDegree $fieldPerPoly $mask}}
|
||||
{{- end}}
|
||||
@@ -1,18 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed testcases/partial_fft_64_3_2.txt
|
||||
case_64_3_2 string
|
||||
)
|
||||
|
||||
func TestPartialFFT(t *testing.T) {
|
||||
str := partialFFT(64, 2, 3)
|
||||
assert.Equal(t, case_64_3_2, str)
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
{{- $bitPerField := 256}}
|
||||
{{- $limbPerField := div $bitPerField .LogTwoBound}}
|
||||
{{- $fieldPerPoly := div .ModulusDegree $limbPerField}}
|
||||
{{- $numMask := pow 2 $fieldPerPoly}}
|
||||
|
||||
func TestPartialFFT(t *testing.T) {
|
||||
|
||||
var (
|
||||
domain = fft.NewDomain({{.ModulusDegree}})
|
||||
twiddles = PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
)
|
||||
|
||||
for mask := 0; mask < {{$numMask}}; mask++ {
|
||||
|
||||
var (
|
||||
a = vec123456()
|
||||
b = vec123456()
|
||||
)
|
||||
|
||||
zeroizeWithMask(a, mask)
|
||||
zeroizeWithMask(b, mask)
|
||||
|
||||
domain.FFT(a, fft.DIF, fft.OnCoset())
|
||||
partialFFT[mask](b, twiddles)
|
||||
assert.Equal(t, a, b)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func vec123456() []field.Element {
|
||||
vec := make([]field.Element, {{.ModulusDegree}})
|
||||
for i := range vec {
|
||||
vec[i].SetInt64(int64(i))
|
||||
}
|
||||
return vec
|
||||
}
|
||||
|
||||
func zeroizeWithMask(v []field.Element, mask int) {
|
||||
for i := 0; i < {{$fieldPerPoly}}; i++ {
|
||||
if (mask>>i)&1 == 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
for j := 0; j < {{$limbPerField}}; j++ {
|
||||
v[{{$limbPerField}}*i+j].SetZero()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,386 +0,0 @@
|
||||
func partialFFT_3(a, twiddles []field.Element) {
|
||||
a[32].Mul(&a[32], &twiddles[0])
|
||||
a[33].Mul(&a[33], &twiddles[0])
|
||||
a[34].Mul(&a[34], &twiddles[0])
|
||||
a[35].Mul(&a[35], &twiddles[0])
|
||||
a[36].Mul(&a[36], &twiddles[0])
|
||||
a[37].Mul(&a[37], &twiddles[0])
|
||||
a[38].Mul(&a[38], &twiddles[0])
|
||||
a[39].Mul(&a[39], &twiddles[0])
|
||||
a[40].Mul(&a[40], &twiddles[0])
|
||||
a[41].Mul(&a[41], &twiddles[0])
|
||||
a[42].Mul(&a[42], &twiddles[0])
|
||||
a[43].Mul(&a[43], &twiddles[0])
|
||||
a[44].Mul(&a[44], &twiddles[0])
|
||||
a[45].Mul(&a[45], &twiddles[0])
|
||||
a[46].Mul(&a[46], &twiddles[0])
|
||||
a[47].Mul(&a[47], &twiddles[0])
|
||||
a[48].Mul(&a[48], &twiddles[0])
|
||||
a[49].Mul(&a[49], &twiddles[0])
|
||||
a[50].Mul(&a[50], &twiddles[0])
|
||||
a[51].Mul(&a[51], &twiddles[0])
|
||||
a[52].Mul(&a[52], &twiddles[0])
|
||||
a[53].Mul(&a[53], &twiddles[0])
|
||||
a[54].Mul(&a[54], &twiddles[0])
|
||||
a[55].Mul(&a[55], &twiddles[0])
|
||||
a[56].Mul(&a[56], &twiddles[0])
|
||||
a[57].Mul(&a[57], &twiddles[0])
|
||||
a[58].Mul(&a[58], &twiddles[0])
|
||||
a[59].Mul(&a[59], &twiddles[0])
|
||||
a[60].Mul(&a[60], &twiddles[0])
|
||||
a[61].Mul(&a[61], &twiddles[0])
|
||||
a[62].Mul(&a[62], &twiddles[0])
|
||||
a[63].Mul(&a[63], &twiddles[0])
|
||||
field.Butterfly(&a[0], &a[32])
|
||||
field.Butterfly(&a[1], &a[33])
|
||||
field.Butterfly(&a[2], &a[34])
|
||||
field.Butterfly(&a[3], &a[35])
|
||||
field.Butterfly(&a[4], &a[36])
|
||||
field.Butterfly(&a[5], &a[37])
|
||||
field.Butterfly(&a[6], &a[38])
|
||||
field.Butterfly(&a[7], &a[39])
|
||||
field.Butterfly(&a[8], &a[40])
|
||||
field.Butterfly(&a[9], &a[41])
|
||||
field.Butterfly(&a[10], &a[42])
|
||||
field.Butterfly(&a[11], &a[43])
|
||||
field.Butterfly(&a[12], &a[44])
|
||||
field.Butterfly(&a[13], &a[45])
|
||||
field.Butterfly(&a[14], &a[46])
|
||||
field.Butterfly(&a[15], &a[47])
|
||||
field.Butterfly(&a[16], &a[48])
|
||||
field.Butterfly(&a[17], &a[49])
|
||||
field.Butterfly(&a[18], &a[50])
|
||||
field.Butterfly(&a[19], &a[51])
|
||||
field.Butterfly(&a[20], &a[52])
|
||||
field.Butterfly(&a[21], &a[53])
|
||||
field.Butterfly(&a[22], &a[54])
|
||||
field.Butterfly(&a[23], &a[55])
|
||||
field.Butterfly(&a[24], &a[56])
|
||||
field.Butterfly(&a[25], &a[57])
|
||||
field.Butterfly(&a[26], &a[58])
|
||||
field.Butterfly(&a[27], &a[59])
|
||||
field.Butterfly(&a[28], &a[60])
|
||||
field.Butterfly(&a[29], &a[61])
|
||||
field.Butterfly(&a[30], &a[62])
|
||||
field.Butterfly(&a[31], &a[63])
|
||||
a[16].Mul(&a[16], &twiddles[1])
|
||||
a[17].Mul(&a[17], &twiddles[1])
|
||||
a[18].Mul(&a[18], &twiddles[1])
|
||||
a[19].Mul(&a[19], &twiddles[1])
|
||||
a[20].Mul(&a[20], &twiddles[1])
|
||||
a[21].Mul(&a[21], &twiddles[1])
|
||||
a[22].Mul(&a[22], &twiddles[1])
|
||||
a[23].Mul(&a[23], &twiddles[1])
|
||||
a[24].Mul(&a[24], &twiddles[1])
|
||||
a[25].Mul(&a[25], &twiddles[1])
|
||||
a[26].Mul(&a[26], &twiddles[1])
|
||||
a[27].Mul(&a[27], &twiddles[1])
|
||||
a[28].Mul(&a[28], &twiddles[1])
|
||||
a[29].Mul(&a[29], &twiddles[1])
|
||||
a[30].Mul(&a[30], &twiddles[1])
|
||||
a[31].Mul(&a[31], &twiddles[1])
|
||||
a[48].Mul(&a[48], &twiddles[2])
|
||||
a[49].Mul(&a[49], &twiddles[2])
|
||||
a[50].Mul(&a[50], &twiddles[2])
|
||||
a[51].Mul(&a[51], &twiddles[2])
|
||||
a[52].Mul(&a[52], &twiddles[2])
|
||||
a[53].Mul(&a[53], &twiddles[2])
|
||||
a[54].Mul(&a[54], &twiddles[2])
|
||||
a[55].Mul(&a[55], &twiddles[2])
|
||||
a[56].Mul(&a[56], &twiddles[2])
|
||||
a[57].Mul(&a[57], &twiddles[2])
|
||||
a[58].Mul(&a[58], &twiddles[2])
|
||||
a[59].Mul(&a[59], &twiddles[2])
|
||||
a[60].Mul(&a[60], &twiddles[2])
|
||||
a[61].Mul(&a[61], &twiddles[2])
|
||||
a[62].Mul(&a[62], &twiddles[2])
|
||||
a[63].Mul(&a[63], &twiddles[2])
|
||||
field.Butterfly(&a[0], &a[16])
|
||||
field.Butterfly(&a[1], &a[17])
|
||||
field.Butterfly(&a[2], &a[18])
|
||||
field.Butterfly(&a[3], &a[19])
|
||||
field.Butterfly(&a[4], &a[20])
|
||||
field.Butterfly(&a[5], &a[21])
|
||||
field.Butterfly(&a[6], &a[22])
|
||||
field.Butterfly(&a[7], &a[23])
|
||||
field.Butterfly(&a[8], &a[24])
|
||||
field.Butterfly(&a[9], &a[25])
|
||||
field.Butterfly(&a[10], &a[26])
|
||||
field.Butterfly(&a[11], &a[27])
|
||||
field.Butterfly(&a[12], &a[28])
|
||||
field.Butterfly(&a[13], &a[29])
|
||||
field.Butterfly(&a[14], &a[30])
|
||||
field.Butterfly(&a[15], &a[31])
|
||||
field.Butterfly(&a[32], &a[48])
|
||||
field.Butterfly(&a[33], &a[49])
|
||||
field.Butterfly(&a[34], &a[50])
|
||||
field.Butterfly(&a[35], &a[51])
|
||||
field.Butterfly(&a[36], &a[52])
|
||||
field.Butterfly(&a[37], &a[53])
|
||||
field.Butterfly(&a[38], &a[54])
|
||||
field.Butterfly(&a[39], &a[55])
|
||||
field.Butterfly(&a[40], &a[56])
|
||||
field.Butterfly(&a[41], &a[57])
|
||||
field.Butterfly(&a[42], &a[58])
|
||||
field.Butterfly(&a[43], &a[59])
|
||||
field.Butterfly(&a[44], &a[60])
|
||||
field.Butterfly(&a[45], &a[61])
|
||||
field.Butterfly(&a[46], &a[62])
|
||||
field.Butterfly(&a[47], &a[63])
|
||||
a[8].Mul(&a[8], &twiddles[3])
|
||||
a[9].Mul(&a[9], &twiddles[3])
|
||||
a[10].Mul(&a[10], &twiddles[3])
|
||||
a[11].Mul(&a[11], &twiddles[3])
|
||||
a[12].Mul(&a[12], &twiddles[3])
|
||||
a[13].Mul(&a[13], &twiddles[3])
|
||||
a[14].Mul(&a[14], &twiddles[3])
|
||||
a[15].Mul(&a[15], &twiddles[3])
|
||||
a[24].Mul(&a[24], &twiddles[4])
|
||||
a[25].Mul(&a[25], &twiddles[4])
|
||||
a[26].Mul(&a[26], &twiddles[4])
|
||||
a[27].Mul(&a[27], &twiddles[4])
|
||||
a[28].Mul(&a[28], &twiddles[4])
|
||||
a[29].Mul(&a[29], &twiddles[4])
|
||||
a[30].Mul(&a[30], &twiddles[4])
|
||||
a[31].Mul(&a[31], &twiddles[4])
|
||||
a[40].Mul(&a[40], &twiddles[5])
|
||||
a[41].Mul(&a[41], &twiddles[5])
|
||||
a[42].Mul(&a[42], &twiddles[5])
|
||||
a[43].Mul(&a[43], &twiddles[5])
|
||||
a[44].Mul(&a[44], &twiddles[5])
|
||||
a[45].Mul(&a[45], &twiddles[5])
|
||||
a[46].Mul(&a[46], &twiddles[5])
|
||||
a[47].Mul(&a[47], &twiddles[5])
|
||||
a[56].Mul(&a[56], &twiddles[6])
|
||||
a[57].Mul(&a[57], &twiddles[6])
|
||||
a[58].Mul(&a[58], &twiddles[6])
|
||||
a[59].Mul(&a[59], &twiddles[6])
|
||||
a[60].Mul(&a[60], &twiddles[6])
|
||||
a[61].Mul(&a[61], &twiddles[6])
|
||||
a[62].Mul(&a[62], &twiddles[6])
|
||||
a[63].Mul(&a[63], &twiddles[6])
|
||||
field.Butterfly(&a[0], &a[8])
|
||||
field.Butterfly(&a[1], &a[9])
|
||||
field.Butterfly(&a[2], &a[10])
|
||||
field.Butterfly(&a[3], &a[11])
|
||||
field.Butterfly(&a[4], &a[12])
|
||||
field.Butterfly(&a[5], &a[13])
|
||||
field.Butterfly(&a[6], &a[14])
|
||||
field.Butterfly(&a[7], &a[15])
|
||||
field.Butterfly(&a[16], &a[24])
|
||||
field.Butterfly(&a[17], &a[25])
|
||||
field.Butterfly(&a[18], &a[26])
|
||||
field.Butterfly(&a[19], &a[27])
|
||||
field.Butterfly(&a[20], &a[28])
|
||||
field.Butterfly(&a[21], &a[29])
|
||||
field.Butterfly(&a[22], &a[30])
|
||||
field.Butterfly(&a[23], &a[31])
|
||||
field.Butterfly(&a[32], &a[40])
|
||||
field.Butterfly(&a[33], &a[41])
|
||||
field.Butterfly(&a[34], &a[42])
|
||||
field.Butterfly(&a[35], &a[43])
|
||||
field.Butterfly(&a[36], &a[44])
|
||||
field.Butterfly(&a[37], &a[45])
|
||||
field.Butterfly(&a[38], &a[46])
|
||||
field.Butterfly(&a[39], &a[47])
|
||||
field.Butterfly(&a[48], &a[56])
|
||||
field.Butterfly(&a[49], &a[57])
|
||||
field.Butterfly(&a[50], &a[58])
|
||||
field.Butterfly(&a[51], &a[59])
|
||||
field.Butterfly(&a[52], &a[60])
|
||||
field.Butterfly(&a[53], &a[61])
|
||||
field.Butterfly(&a[54], &a[62])
|
||||
field.Butterfly(&a[55], &a[63])
|
||||
a[4].Mul(&a[4], &twiddles[7])
|
||||
a[5].Mul(&a[5], &twiddles[7])
|
||||
a[6].Mul(&a[6], &twiddles[7])
|
||||
a[7].Mul(&a[7], &twiddles[7])
|
||||
a[12].Mul(&a[12], &twiddles[8])
|
||||
a[13].Mul(&a[13], &twiddles[8])
|
||||
a[14].Mul(&a[14], &twiddles[8])
|
||||
a[15].Mul(&a[15], &twiddles[8])
|
||||
a[20].Mul(&a[20], &twiddles[9])
|
||||
a[21].Mul(&a[21], &twiddles[9])
|
||||
a[22].Mul(&a[22], &twiddles[9])
|
||||
a[23].Mul(&a[23], &twiddles[9])
|
||||
a[28].Mul(&a[28], &twiddles[10])
|
||||
a[29].Mul(&a[29], &twiddles[10])
|
||||
a[30].Mul(&a[30], &twiddles[10])
|
||||
a[31].Mul(&a[31], &twiddles[10])
|
||||
a[36].Mul(&a[36], &twiddles[11])
|
||||
a[37].Mul(&a[37], &twiddles[11])
|
||||
a[38].Mul(&a[38], &twiddles[11])
|
||||
a[39].Mul(&a[39], &twiddles[11])
|
||||
a[44].Mul(&a[44], &twiddles[12])
|
||||
a[45].Mul(&a[45], &twiddles[12])
|
||||
a[46].Mul(&a[46], &twiddles[12])
|
||||
a[47].Mul(&a[47], &twiddles[12])
|
||||
a[52].Mul(&a[52], &twiddles[13])
|
||||
a[53].Mul(&a[53], &twiddles[13])
|
||||
a[54].Mul(&a[54], &twiddles[13])
|
||||
a[55].Mul(&a[55], &twiddles[13])
|
||||
a[60].Mul(&a[60], &twiddles[14])
|
||||
a[61].Mul(&a[61], &twiddles[14])
|
||||
a[62].Mul(&a[62], &twiddles[14])
|
||||
a[63].Mul(&a[63], &twiddles[14])
|
||||
field.Butterfly(&a[0], &a[4])
|
||||
field.Butterfly(&a[1], &a[5])
|
||||
field.Butterfly(&a[2], &a[6])
|
||||
field.Butterfly(&a[3], &a[7])
|
||||
field.Butterfly(&a[8], &a[12])
|
||||
field.Butterfly(&a[9], &a[13])
|
||||
field.Butterfly(&a[10], &a[14])
|
||||
field.Butterfly(&a[11], &a[15])
|
||||
field.Butterfly(&a[16], &a[20])
|
||||
field.Butterfly(&a[17], &a[21])
|
||||
field.Butterfly(&a[18], &a[22])
|
||||
field.Butterfly(&a[19], &a[23])
|
||||
field.Butterfly(&a[24], &a[28])
|
||||
field.Butterfly(&a[25], &a[29])
|
||||
field.Butterfly(&a[26], &a[30])
|
||||
field.Butterfly(&a[27], &a[31])
|
||||
field.Butterfly(&a[32], &a[36])
|
||||
field.Butterfly(&a[33], &a[37])
|
||||
field.Butterfly(&a[34], &a[38])
|
||||
field.Butterfly(&a[35], &a[39])
|
||||
field.Butterfly(&a[40], &a[44])
|
||||
field.Butterfly(&a[41], &a[45])
|
||||
field.Butterfly(&a[42], &a[46])
|
||||
field.Butterfly(&a[43], &a[47])
|
||||
field.Butterfly(&a[48], &a[52])
|
||||
field.Butterfly(&a[49], &a[53])
|
||||
field.Butterfly(&a[50], &a[54])
|
||||
field.Butterfly(&a[51], &a[55])
|
||||
field.Butterfly(&a[56], &a[60])
|
||||
field.Butterfly(&a[57], &a[61])
|
||||
field.Butterfly(&a[58], &a[62])
|
||||
field.Butterfly(&a[59], &a[63])
|
||||
a[2].Mul(&a[2], &twiddles[15])
|
||||
a[3].Mul(&a[3], &twiddles[15])
|
||||
a[6].Mul(&a[6], &twiddles[16])
|
||||
a[7].Mul(&a[7], &twiddles[16])
|
||||
a[10].Mul(&a[10], &twiddles[17])
|
||||
a[11].Mul(&a[11], &twiddles[17])
|
||||
a[14].Mul(&a[14], &twiddles[18])
|
||||
a[15].Mul(&a[15], &twiddles[18])
|
||||
a[18].Mul(&a[18], &twiddles[19])
|
||||
a[19].Mul(&a[19], &twiddles[19])
|
||||
a[22].Mul(&a[22], &twiddles[20])
|
||||
a[23].Mul(&a[23], &twiddles[20])
|
||||
a[26].Mul(&a[26], &twiddles[21])
|
||||
a[27].Mul(&a[27], &twiddles[21])
|
||||
a[30].Mul(&a[30], &twiddles[22])
|
||||
a[31].Mul(&a[31], &twiddles[22])
|
||||
a[34].Mul(&a[34], &twiddles[23])
|
||||
a[35].Mul(&a[35], &twiddles[23])
|
||||
a[38].Mul(&a[38], &twiddles[24])
|
||||
a[39].Mul(&a[39], &twiddles[24])
|
||||
a[42].Mul(&a[42], &twiddles[25])
|
||||
a[43].Mul(&a[43], &twiddles[25])
|
||||
a[46].Mul(&a[46], &twiddles[26])
|
||||
a[47].Mul(&a[47], &twiddles[26])
|
||||
a[50].Mul(&a[50], &twiddles[27])
|
||||
a[51].Mul(&a[51], &twiddles[27])
|
||||
a[54].Mul(&a[54], &twiddles[28])
|
||||
a[55].Mul(&a[55], &twiddles[28])
|
||||
a[58].Mul(&a[58], &twiddles[29])
|
||||
a[59].Mul(&a[59], &twiddles[29])
|
||||
a[62].Mul(&a[62], &twiddles[30])
|
||||
a[63].Mul(&a[63], &twiddles[30])
|
||||
field.Butterfly(&a[0], &a[2])
|
||||
field.Butterfly(&a[1], &a[3])
|
||||
field.Butterfly(&a[4], &a[6])
|
||||
field.Butterfly(&a[5], &a[7])
|
||||
field.Butterfly(&a[8], &a[10])
|
||||
field.Butterfly(&a[9], &a[11])
|
||||
field.Butterfly(&a[12], &a[14])
|
||||
field.Butterfly(&a[13], &a[15])
|
||||
field.Butterfly(&a[16], &a[18])
|
||||
field.Butterfly(&a[17], &a[19])
|
||||
field.Butterfly(&a[20], &a[22])
|
||||
field.Butterfly(&a[21], &a[23])
|
||||
field.Butterfly(&a[24], &a[26])
|
||||
field.Butterfly(&a[25], &a[27])
|
||||
field.Butterfly(&a[28], &a[30])
|
||||
field.Butterfly(&a[29], &a[31])
|
||||
field.Butterfly(&a[32], &a[34])
|
||||
field.Butterfly(&a[33], &a[35])
|
||||
field.Butterfly(&a[36], &a[38])
|
||||
field.Butterfly(&a[37], &a[39])
|
||||
field.Butterfly(&a[40], &a[42])
|
||||
field.Butterfly(&a[41], &a[43])
|
||||
field.Butterfly(&a[44], &a[46])
|
||||
field.Butterfly(&a[45], &a[47])
|
||||
field.Butterfly(&a[48], &a[50])
|
||||
field.Butterfly(&a[49], &a[51])
|
||||
field.Butterfly(&a[52], &a[54])
|
||||
field.Butterfly(&a[53], &a[55])
|
||||
field.Butterfly(&a[56], &a[58])
|
||||
field.Butterfly(&a[57], &a[59])
|
||||
field.Butterfly(&a[60], &a[62])
|
||||
field.Butterfly(&a[61], &a[63])
|
||||
a[1].Mul(&a[1], &twiddles[31])
|
||||
a[3].Mul(&a[3], &twiddles[32])
|
||||
a[5].Mul(&a[5], &twiddles[33])
|
||||
a[7].Mul(&a[7], &twiddles[34])
|
||||
a[9].Mul(&a[9], &twiddles[35])
|
||||
a[11].Mul(&a[11], &twiddles[36])
|
||||
a[13].Mul(&a[13], &twiddles[37])
|
||||
a[15].Mul(&a[15], &twiddles[38])
|
||||
a[17].Mul(&a[17], &twiddles[39])
|
||||
a[19].Mul(&a[19], &twiddles[40])
|
||||
a[21].Mul(&a[21], &twiddles[41])
|
||||
a[23].Mul(&a[23], &twiddles[42])
|
||||
a[25].Mul(&a[25], &twiddles[43])
|
||||
a[27].Mul(&a[27], &twiddles[44])
|
||||
a[29].Mul(&a[29], &twiddles[45])
|
||||
a[31].Mul(&a[31], &twiddles[46])
|
||||
a[33].Mul(&a[33], &twiddles[47])
|
||||
a[35].Mul(&a[35], &twiddles[48])
|
||||
a[37].Mul(&a[37], &twiddles[49])
|
||||
a[39].Mul(&a[39], &twiddles[50])
|
||||
a[41].Mul(&a[41], &twiddles[51])
|
||||
a[43].Mul(&a[43], &twiddles[52])
|
||||
a[45].Mul(&a[45], &twiddles[53])
|
||||
a[47].Mul(&a[47], &twiddles[54])
|
||||
a[49].Mul(&a[49], &twiddles[55])
|
||||
a[51].Mul(&a[51], &twiddles[56])
|
||||
a[53].Mul(&a[53], &twiddles[57])
|
||||
a[55].Mul(&a[55], &twiddles[58])
|
||||
a[57].Mul(&a[57], &twiddles[59])
|
||||
a[59].Mul(&a[59], &twiddles[60])
|
||||
a[61].Mul(&a[61], &twiddles[61])
|
||||
a[63].Mul(&a[63], &twiddles[62])
|
||||
field.Butterfly(&a[0], &a[1])
|
||||
field.Butterfly(&a[2], &a[3])
|
||||
field.Butterfly(&a[4], &a[5])
|
||||
field.Butterfly(&a[6], &a[7])
|
||||
field.Butterfly(&a[8], &a[9])
|
||||
field.Butterfly(&a[10], &a[11])
|
||||
field.Butterfly(&a[12], &a[13])
|
||||
field.Butterfly(&a[14], &a[15])
|
||||
field.Butterfly(&a[16], &a[17])
|
||||
field.Butterfly(&a[18], &a[19])
|
||||
field.Butterfly(&a[20], &a[21])
|
||||
field.Butterfly(&a[22], &a[23])
|
||||
field.Butterfly(&a[24], &a[25])
|
||||
field.Butterfly(&a[26], &a[27])
|
||||
field.Butterfly(&a[28], &a[29])
|
||||
field.Butterfly(&a[30], &a[31])
|
||||
field.Butterfly(&a[32], &a[33])
|
||||
field.Butterfly(&a[34], &a[35])
|
||||
field.Butterfly(&a[36], &a[37])
|
||||
field.Butterfly(&a[38], &a[39])
|
||||
field.Butterfly(&a[40], &a[41])
|
||||
field.Butterfly(&a[42], &a[43])
|
||||
field.Butterfly(&a[44], &a[45])
|
||||
field.Butterfly(&a[46], &a[47])
|
||||
field.Butterfly(&a[48], &a[49])
|
||||
field.Butterfly(&a[50], &a[51])
|
||||
field.Butterfly(&a[52], &a[53])
|
||||
field.Butterfly(&a[54], &a[55])
|
||||
field.Butterfly(&a[56], &a[57])
|
||||
field.Butterfly(&a[58], &a[59])
|
||||
field.Butterfly(&a[60], &a[61])
|
||||
field.Butterfly(&a[62], &a[63])
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
package ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}
|
||||
|
||||
import (
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/vector"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
"github.com/consensys/linea-monorepo/prover/utils/parallel"
|
||||
ppool "github.com/consensys/linea-monorepo/prover/utils/parallel/pool"
|
||||
)
|
||||
|
||||
{{- $bitPerField := 256}}
|
||||
{{- $limbPerField := div $bitPerField .LogTwoBound}}
|
||||
{{- $fieldPerPoly := div .ModulusDegree $limbPerField}}
|
||||
{{- $numMask := pow 2 $fieldPerPoly}}
|
||||
|
||||
func TransversalHash(
|
||||
// the Ag for ring-sis
|
||||
ag [][]field.Element,
|
||||
// A non-transposed list of columns
|
||||
// All of the same length
|
||||
pols []smartvectors.SmartVector,
|
||||
// The precomputed twiddle cosets for the forward FFT
|
||||
twiddleCosets []field.Element,
|
||||
// The domain for the final inverse-FFT
|
||||
domain *fft.Domain,
|
||||
) []field.Element {
|
||||
|
||||
var (
|
||||
// Each field element is encoded in {{$limbPerField}} limbs but the degree is {{.ModulusDegree}}. So, each
|
||||
// polynomial multiplication "hashes" {{$fieldPerPoly}} field elements at once. This is
|
||||
// important to know for parallelization.
|
||||
resultSize = pols[0].Len() * {{.ModulusDegree}}
|
||||
|
||||
// To optimize memory usage, we limit ourself to hash only 16 columns per
|
||||
// iteration.
|
||||
numColumnPerJob int = 16
|
||||
|
||||
// In theory, it should be a div ceil. But in practice we only process power's
|
||||
// of two number of columns. If that's not the case, then the function will panic
|
||||
// but we can always change that if this is needed. The rational for the current
|
||||
// design is simplicity.
|
||||
numJobs = utils.DivExact(pols[0].Len(), numColumnPerJob) // we make blocks of 16 columns
|
||||
|
||||
// Main result of the hashing
|
||||
mainResults = make([]field.Element, resultSize)
|
||||
// When we encounter a const row, it will have the same additive contribution
|
||||
// to the result on every column. So we compute the contribution only once and
|
||||
// accumulate it with the other "constant column contributions". And it is only
|
||||
// performed by the first thread.
|
||||
constResults = make([]field.Element, {{.ModulusDegree}})
|
||||
)
|
||||
|
||||
ppool.ExecutePoolChunky(numJobs, func(i int) {
|
||||
// We process the columns per segment of `numColumnPerJob`
|
||||
var (
|
||||
localResult = make([]field.Element, numColumnPerJob*{{.ModulusDegree}})
|
||||
limbs = make([]field.Element, {{.ModulusDegree}})
|
||||
|
||||
// Each segment is processed by packet of `numFieldPerPoly={{$fieldPerPoly}}` rows
|
||||
startFromCol = i * numColumnPerJob
|
||||
stopAtCol = (i + 1) * numColumnPerJob
|
||||
)
|
||||
|
||||
for row := 0; row < len(pols); row += {{$fieldPerPoly}} {
|
||||
|
||||
var (
|
||||
chunksFull = make([][]field.Element, {{$fieldPerPoly}})
|
||||
mask = 0
|
||||
)
|
||||
|
||||
for j := 0; j < {{$fieldPerPoly}}; j++ {
|
||||
if row+j >= len(pols) {
|
||||
continue
|
||||
}
|
||||
|
||||
pReg, pIsReg := pols[row+j].(*smartvectors.Regular)
|
||||
if pIsReg {
|
||||
chunksFull[j] = (*pReg)[startFromCol:stopAtCol]
|
||||
mask |= (1 << j)
|
||||
continue
|
||||
}
|
||||
|
||||
pPool, pIsPool := pols[row+j].(*smartvectors.Pooled)
|
||||
if pIsPool {
|
||||
chunksFull[j] = pPool.Regular[startFromCol:stopAtCol]
|
||||
mask |= (1 << j)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if mask > 0 {
|
||||
for col := 0; col < (stopAtCol - startFromCol); col++ {
|
||||
colChunk := [{{$fieldPerPoly}}]field.Element{}
|
||||
for j := 0; j < {{$fieldPerPoly}}; j++ {
|
||||
if chunksFull[j] != nil {
|
||||
colChunk[j] = chunksFull[j][col]
|
||||
}
|
||||
}
|
||||
|
||||
limbDecompose(limbs, colChunk[:])
|
||||
partialFFT[mask](limbs, twiddleCosets)
|
||||
mulModAcc(localResult[col*{{.ModulusDegree}}:(col+1)*{{$.ModulusDegree}}], limbs, ag[row/{{$fieldPerPoly}}])
|
||||
}
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
|
||||
var (
|
||||
cMask = ((1 << {{$fieldPerPoly}}) - 1) ^ mask
|
||||
chunkConst = make([]field.Element, {{$fieldPerPoly}})
|
||||
)
|
||||
|
||||
if cMask > 0 {
|
||||
for j := 0; j < {{$fieldPerPoly}}; j++ {
|
||||
if row+j >= len(pols) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (cMask>>j)&1 == 1 {
|
||||
chunkConst[j] = pols[row+j].(*smartvectors.Constant).Get(0)
|
||||
}
|
||||
}
|
||||
|
||||
limbDecompose(limbs, chunkConst)
|
||||
partialFFT[cMask](limbs, twiddleCosets)
|
||||
mulModAcc(constResults, limbs, ag[row/{{$fieldPerPoly}}])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy the segment into the main result at the end
|
||||
copy(mainResults[startFromCol*{{.ModulusDegree}}:stopAtCol*{{.ModulusDegree}}], localResult)
|
||||
})
|
||||
|
||||
// Now, we need to reconciliate the results of the buffer with
|
||||
// the result for each thread
|
||||
parallel.Execute(pols[0].Len(), func(start, stop int) {
|
||||
for col := start; col < stop; col++ {
|
||||
// Accumulate the const
|
||||
vector.Add(mainResults[col*{{.ModulusDegree}}:(col+1)*{{.ModulusDegree}}], mainResults[col*{{.ModulusDegree}}:(col+1)*{{.ModulusDegree}}], constResults)
|
||||
// And run the reverse FFT
|
||||
domain.FFTInverse(mainResults[col*{{.ModulusDegree}}:(col+1)*{{.ModulusDegree}}], fft.DIT, fft.OnCoset(), fft.WithNbTasks(1))
|
||||
}
|
||||
})
|
||||
|
||||
return mainResults
|
||||
}
|
||||
|
||||
var _zeroes []field.Element = make([]field.Element, {{.ModulusDegree}})
|
||||
|
||||
// zeroize fills `buf` with zeroes.
|
||||
func zeroize(buf []field.Element) {
|
||||
copy(buf, _zeroes)
|
||||
}
|
||||
|
||||
// mulModAdd increments each entry `i` of `res` as `res[i] = a[i] * b[i]`. The
|
||||
// input vectors are trusted to all have the same length.
|
||||
func mulModAcc(res, a, b []field.Element) {
|
||||
var tmp field.Element
|
||||
for i := range res {
|
||||
tmp.Mul(&a[i], &b[i])
|
||||
res[i].Add(&res[i], &tmp)
|
||||
}
|
||||
}
|
||||
|
||||
func limbDecompose(result []field.Element, x []field.Element) {
|
||||
|
||||
zeroize(result)
|
||||
var bytesBuffer = [32]byte{}{{"\n"}}
|
||||
{{- range $k := iterate 0 $fieldPerPoly}}
|
||||
{{- $pos := mul (add $k 1) $limbPerField -}}
|
||||
{{- "\n\t"}}bytesBuffer = x[{{$k}}].Bytes(){{"\n\n"}}
|
||||
{{- range $i := iterate 0 $limbPerField }}
|
||||
{{- $resPos := sub (sub $pos $i) 1 }}
|
||||
{{- if eq $.LogTwoBound 8 -}}
|
||||
{{- $inpPos0 := $i -}}
|
||||
{{"\t"}}result[{{$resPos}}][0] = uint64(bytesBuffer[{{$inpPos0}}]){{"\n"}}
|
||||
{{- else if eq $.LogTwoBound 16 }}
|
||||
{{- $inpPos0 := mul $i 2 }}
|
||||
{{- $inpPos1 := add $inpPos0 1 -}}
|
||||
{{"\t"}}result[{{$resPos}}][0] = uint64(bytesBuffer[{{$inpPos1}}]) | (uint64(bytesBuffer[{{$inpPos0}}]) << 8){{"\n"}}
|
||||
{{- end}}
|
||||
{{- end}}{{end}}
|
||||
{{- "}\n" -}}
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
package ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis/ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/vector"
|
||||
wfft "github.com/consensys/linea-monorepo/prover/maths/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
{{- $bitPerField := 256}}
|
||||
{{- $limbPerField := div $bitPerField .LogTwoBound}}
|
||||
{{- $fieldPerPoly := div .ModulusDegree $limbPerField}}
|
||||
|
||||
// randomConstRow generates a random constant smart-vector
|
||||
func randomConstRow(rng *rand.Rand, size int) smartvectors.SmartVector {
|
||||
return smartvectors.NewConstant(field.PseudoRand(rng), size)
|
||||
}
|
||||
|
||||
// randomRegularRow generates a random regular smart-vector
|
||||
func randomRegularRow(rng *rand.Rand, size int) smartvectors.SmartVector {
|
||||
return smartvectors.PseudoRand(rng, size)
|
||||
}
|
||||
|
||||
// generate a smartvector row-matrix by using randomly constant or regular smart-vectors
|
||||
func fullyRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector {
|
||||
list := make([]smartvectors.SmartVector, numRow)
|
||||
for i := range list {
|
||||
coin := rng.IntN(2)
|
||||
switch {
|
||||
case coin == 0:
|
||||
list[i] = randomConstRow(rng, numCols)
|
||||
case coin == 1:
|
||||
list[i] = randomRegularRow(rng, numCols)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func constantRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector {
|
||||
list := make([]smartvectors.SmartVector, numRow)
|
||||
for i := range list {
|
||||
list[i] = randomConstRow(rng, numCols)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func regularRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector {
|
||||
list := make([]smartvectors.SmartVector, numRow)
|
||||
for i := range list {
|
||||
list[i] = randomConstRow(rng, numCols)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func TestSmartVectorTransversalSisHash(t *testing.T) {
|
||||
|
||||
var (
|
||||
numReps = 64
|
||||
numCols = 16
|
||||
rng = rand.New(rand.NewChaCha8([32]byte{}))
|
||||
domain = fft.NewDomain({{.ModulusDegree}}, fft.WithShift(wfft.GetOmega({{.ModulusDegree}}*2)))
|
||||
twiddles = ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
params = ringsis.Params{LogTwoBound: {{.LogTwoBound}}, LogTwoDegree: {{log2 .ModulusDegree}}}
|
||||
testCases = [][]smartvectors.SmartVector{
|
||||
constantRandomTestVector(rng, {{$fieldPerPoly}}, numCols),
|
||||
regularRandomTestVector(rng, {{$fieldPerPoly}}, numCols),
|
||||
}
|
||||
)
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, {{$fieldPerPoly}}, numCols))
|
||||
}
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, {{mul 4 $fieldPerPoly}}, 2*numCols))
|
||||
}
|
||||
|
||||
for i, c := range testCases {
|
||||
t.Run(fmt.Sprintf("testcase-%v", i), func(t *testing.T) {
|
||||
|
||||
var (
|
||||
numRow = len(c)
|
||||
key = ringsis.GenerateKey(params, numRow)
|
||||
result = ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}.TransversalHash(
|
||||
key.Ag(),
|
||||
c,
|
||||
twiddles,
|
||||
domain,
|
||||
)
|
||||
)
|
||||
|
||||
for col := 0; col < numCols; col++ {
|
||||
column := make([]field.Element, numRow)
|
||||
for r := 0; r < numRow; r++ {
|
||||
column[r] = c[r].Get(col)
|
||||
}
|
||||
|
||||
colHash := key.Hash(column)
|
||||
require.Equalf(
|
||||
t,
|
||||
vector.Prettify(colHash),
|
||||
vector.Prettify(result[{{.ModulusDegree}}*col:{{.ModulusDegree}}*col+{{.ModulusDegree}}]),
|
||||
"column %v", col,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}
|
||||
|
||||
import (
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// PrecomputeTwiddlesCoset precomputes twiddlesCoset from twiddles and coset table
|
||||
// it then return all elements in the correct order for the unrolled FFT.
|
||||
func PrecomputeTwiddlesCoset(generator, shifter field.Element) []field.Element {
|
||||
toReturn := make([]field.Element, {{sub .ModulusDegree 1}})
|
||||
var r, s field.Element
|
||||
e := new(big.Int){{"\n"}}
|
||||
{{- $n := .ModulusDegree}}
|
||||
{{- $m := div $n 2}}
|
||||
{{- $split := 1}}
|
||||
{{- $split = div $split 1}}
|
||||
{{- $j := 0}}
|
||||
{{- range $step := reverse (iterate 0 (log2 .ModulusDegree))}}
|
||||
s = shifter{{"\n"}}
|
||||
for k := 0; k < {{$step}}; k++ {
|
||||
s.Square(&s)
|
||||
}{{"\n"}}
|
||||
{{- $offset := 0}}
|
||||
{{- range $s := iterate 0 $split}}
|
||||
{{- $exp := bitReverse $split $s}}
|
||||
{{- if eq $exp 0}}
|
||||
toReturn[{{$j}}] = s{{"\n"}}
|
||||
{{- else}}
|
||||
r.Exp(generator, e.SetUint64(uint64(1<<{{$step}}*{{$exp}})))
|
||||
toReturn[{{$j}}].Mul(&r, &s){{"\n"}}
|
||||
{{- end}}
|
||||
{{- $j = add $j 1}}
|
||||
{{- end}}
|
||||
|
||||
{{- $split = mul $split 2}}
|
||||
{{- end}}
|
||||
return toReturn
|
||||
}
|
||||
242
prover/crypto/ringsis/transversal_hash.go
Normal file
242
prover/crypto/ringsis/transversal_hash.go
Normal file
@@ -0,0 +1,242 @@
|
||||
package ringsis
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/sis"
|
||||
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
"github.com/consensys/linea-monorepo/prover/utils/parallel"
|
||||
"github.com/consensys/linea-monorepo/prover/utils/parallel/pool"
|
||||
)
|
||||
|
||||
// TransversalHash evaluates SIS hashes transversally over a list of smart-vectors.
|
||||
// Each smart-vector is seen as the row of a matrix. All rows must have the same
|
||||
// size or panic. The function returns the hash of the columns. The column hashes
|
||||
// are concatenated into a single array.
|
||||
func (s *Key) TransversalHash(v []smartvectors.SmartVector) []field.Element {
|
||||
|
||||
// nbRows stores the number of rows in the matrix to hash it must be
|
||||
// strictly positive and be within the bounds of MaxNumFieldHashable.
|
||||
nbRows := len(v)
|
||||
|
||||
if nbRows == 0 || nbRows > s.MaxNumFieldHashable() {
|
||||
utils.Panic("Attempted to hash %v rows, must be in [1:%v]", nbRows, s.MaxNumFieldHashable())
|
||||
}
|
||||
|
||||
// nbCols stores the number of columns in the matrix to hash et must be
|
||||
// positive and all the rows must have the same size.
|
||||
nbCols := v[0].Len()
|
||||
|
||||
if nbCols == 0 {
|
||||
utils.Panic("Provided a 0-column matrix")
|
||||
}
|
||||
|
||||
for i := range v {
|
||||
if v[i].Len() != nbCols {
|
||||
utils.Panic("Unexpected : all inputs smart-vectors should have the same length the first one has length %v, but #%v has length %v",
|
||||
nbCols, i, v[i].Len())
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
v contains a list of rows. We want to hash the columns, in a cache-friendly
|
||||
manner.
|
||||
|
||||
|
||||
for example, if we consider the matrix
|
||||
v[0] -> [ 1 2 3 4 ]
|
||||
v[1] -> [ 5 6 7 8 ]
|
||||
v[2] -> [ 9 10 11 12 ]
|
||||
v[3] -> [ 13 14 15 16 ]
|
||||
|
||||
we want to compute
|
||||
res = [ H(1,5,9,13) H(2,6,10,14) H(3,7,11,15) H(4,8,12,16) ]
|
||||
|
||||
note that the output size of the hash is s.OutputSize() (i.e it's a slice)
|
||||
and that we will decompose the columns in "Limbs" of size s.LogTwoBound;
|
||||
this limbs are then interpreted as a slice of coefficients of
|
||||
a polynomial of size s.OutputSize()
|
||||
|
||||
that is, we can decompose H(1,5,9,13) as;
|
||||
k0 := limbs(1,5) = [a b c d e f g h]
|
||||
k1 := limbs(9,13) = [i j k l m n o p]
|
||||
|
||||
In practice, s.OutputSize() is a reasonable size (< 1024) so we can slide our tiles
|
||||
over the partial columns and compute the hash of the columns in parallel.
|
||||
|
||||
*/
|
||||
|
||||
nbBytePerLimb := s.LogTwoBound / 8
|
||||
nbLimbsPerField := field.Bytes / nbBytePerLimb
|
||||
nbFieldPerPoly := s.modulusDegree() / nbLimbsPerField
|
||||
|
||||
N := s.OutputSize()
|
||||
|
||||
nbPolys := utils.DivCeil(len(v), nbFieldPerPoly)
|
||||
res := make(field.Vector, nbCols*N)
|
||||
|
||||
// First we take care of the constant rows;
|
||||
// since they repeat the same value, we can compute them once for the matrix (instead of once per column)
|
||||
// and accumulate in res
|
||||
|
||||
// indicates if a block of N rows is constant: in that case we can skip the computation
|
||||
// of all the columns sub-hashes in that block.
|
||||
// more over; we set the bit of a mask if the row is NOT constant, and exploit the mask
|
||||
// to minimize the number of operations we do (partial FFT)
|
||||
masks := make([]uint64, nbPolys)
|
||||
|
||||
// we will accumulate the constant rows in a separate vector
|
||||
constPoly := make(field.Vector, N)
|
||||
constLock := sync.Mutex{}
|
||||
|
||||
// we parallelize by the "height" of the matrix here, since we only care about the constants
|
||||
// and don't iterate over the columns.
|
||||
parallel.Execute(nbPolys, func(start, stop int) {
|
||||
startRow := start * nbFieldPerPoly
|
||||
stopRow := stop * nbFieldPerPoly
|
||||
if stopRow > len(v) {
|
||||
stopRow = len(v)
|
||||
}
|
||||
localRes := make([]field.Element, N)
|
||||
|
||||
itM := s.newMatrixIterator(v)
|
||||
|
||||
k := make([]field.Element, N)
|
||||
kz := make([]field.Element, N)
|
||||
|
||||
for polID := start; polID < stop; polID++ {
|
||||
mConst := uint64(0)
|
||||
for row := startRow; row < stopRow; row++ {
|
||||
if _, ok := v[row].(*smartvectors.Constant); !ok {
|
||||
// mark the row as non-constant in the mask for this poly
|
||||
masks[polID] |= 1 << (row % nbFieldPerPoly)
|
||||
} else {
|
||||
// mark the row as constant
|
||||
mConst |= 1 << (row % nbFieldPerPoly)
|
||||
}
|
||||
}
|
||||
|
||||
itM.reset(startRow, stopRow, 0, true)
|
||||
s.gnarkInternal.InnerHash(itM.lit, localRes, k, kz, polID, mConst)
|
||||
}
|
||||
|
||||
constLock.Lock()
|
||||
constPoly.Add(constPoly, localRes)
|
||||
constLock.Unlock()
|
||||
})
|
||||
|
||||
nbCpus := runtime.NumCPU()
|
||||
|
||||
nbColPerTile := 16
|
||||
nbJobs := utils.DivCeil(nbCols, nbColPerTile)
|
||||
|
||||
if nbCols < nbCpus {
|
||||
nbJobs = nbCols
|
||||
nbColPerTile = 1
|
||||
}
|
||||
|
||||
for nbJobs < nbCpus && nbColPerTile > 1 {
|
||||
nbColPerTile--
|
||||
nbJobs = utils.DivCeil(nbCols, nbColPerTile)
|
||||
}
|
||||
|
||||
pool.ExecutePoolChunky(nbJobs, func(jobID int) {
|
||||
startCol := jobID * nbColPerTile
|
||||
stopCol := startCol + nbColPerTile
|
||||
stopCol = min(stopCol, nbCols)
|
||||
|
||||
// each go routine will iterate over a range of columns; we will hash the columns in parallel
|
||||
// and accumulate the result in res (no conflict since each go routine writes to a different range of res)
|
||||
|
||||
// init res with const poly
|
||||
for colID := startCol; colID < stopCol; colID++ {
|
||||
copy(res[colID*N:(colID+1)*N], constPoly)
|
||||
}
|
||||
|
||||
itM := s.newMatrixIterator(v)
|
||||
k := make([]field.Element, N)
|
||||
kz := make([]field.Element, N)
|
||||
|
||||
for startRow := 0; startRow < len(v); startRow += nbFieldPerPoly {
|
||||
polID := startRow / nbFieldPerPoly
|
||||
|
||||
// if it's a constant block, we can skip.
|
||||
if masks[polID] == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
stopRow := startRow + nbFieldPerPoly
|
||||
stopRow = min(stopRow, len(v))
|
||||
|
||||
// hash the subcolumns.
|
||||
for colID := startCol; colID < stopCol; colID++ {
|
||||
itM.reset(startRow, stopRow, colID, false)
|
||||
s.gnarkInternal.InnerHash(itM.lit, res[colID*N:colID*N+N], k, kz, polID, masks[polID])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// mod X^n - 1
|
||||
for colID := startCol; colID < stopCol; colID++ {
|
||||
s.gnarkInternal.Domain.FFTInverse(res[colID*N:(colID+1)*N], fft.DIT, fft.OnCoset(), fft.WithNbTasks(1))
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// matrixIterator helps allocate resources per go routine
|
||||
// and iterate over the columns of a matrix (defined by a list of rows: smart-vectors)
|
||||
type matrixIterator struct {
|
||||
it columnIterator
|
||||
lit *sis.LimbIterator
|
||||
}
|
||||
|
||||
func (s *Key) newMatrixIterator(v []smartvectors.SmartVector) matrixIterator {
|
||||
w := matrixIterator{
|
||||
it: columnIterator{
|
||||
v: v,
|
||||
},
|
||||
}
|
||||
w.lit = sis.NewLimbIterator(&w.it, s.LogTwoBound/8)
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *matrixIterator) reset(startRow, stopRow, colIndex int, constIT bool) {
|
||||
w.it.startRow = startRow
|
||||
w.it.endRow = stopRow
|
||||
w.it.colIndex = colIndex
|
||||
w.it.isConstIT = constIT
|
||||
w.lit.Reset(&w.it)
|
||||
}
|
||||
|
||||
// columnIterator is a helper struct to iterate over the columns of a matrix
|
||||
// it implements the sis.ElementIterator interface
|
||||
type columnIterator struct {
|
||||
v []smartvectors.SmartVector
|
||||
startRow, endRow int
|
||||
colIndex int
|
||||
isConstIT bool
|
||||
}
|
||||
|
||||
func (it *columnIterator) Next() (field.Element, bool) {
|
||||
if it.endRow == it.startRow {
|
||||
return field.Element{}, false
|
||||
}
|
||||
row := it.v[it.startRow]
|
||||
_, constRow := row.(*smartvectors.Constant)
|
||||
it.startRow++
|
||||
|
||||
// for a const iterator; we only return constant rows.
|
||||
// for a non-const iterator; we filter out constant rows.
|
||||
if (it.isConstIT && constRow) || (!it.isConstIT && !constRow) {
|
||||
return row.Get(it.colIndex), true
|
||||
}
|
||||
return field.Element{}, true
|
||||
}
|
||||
@@ -1,19 +1,13 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_8_test
|
||||
package ringsis
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis"
|
||||
"github.com/consensys/linea-monorepo/prover/crypto/ringsis/ringsis_64_8"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/common/vector"
|
||||
wfft "github.com/consensys/linea-monorepo/prover/maths/fft"
|
||||
"github.com/consensys/linea-monorepo/prover/maths/field"
|
||||
"github.com/consensys/linea-monorepo/prover/utils"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -59,56 +53,88 @@ func regularRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors
|
||||
}
|
||||
|
||||
func TestSmartVectorTransversalSisHash(t *testing.T) {
|
||||
|
||||
var (
|
||||
numReps = 64
|
||||
numCols = 16
|
||||
rng = rand.New(rand.NewChaCha8([32]byte{}))
|
||||
domain = fft.NewDomain(64, fft.WithShift(wfft.GetOmega(64*2)))
|
||||
twiddles = ringsis_64_8.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
params = ringsis.Params{LogTwoBound: 8, LogTwoDegree: 6}
|
||||
nbCols = 16
|
||||
rng = rand.New(utils.NewRandSource(77442)) // nolint
|
||||
params = Params{LogTwoBound: 16, LogTwoDegree: 6}
|
||||
testCases = [][]smartvectors.SmartVector{
|
||||
constantRandomTestVector(rng, 2, numCols),
|
||||
regularRandomTestVector(rng, 2, numCols),
|
||||
constantRandomTestVector(rng, 4, nbCols),
|
||||
regularRandomTestVector(rng, 4, nbCols),
|
||||
}
|
||||
)
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 2, numCols))
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 4, nbCols))
|
||||
}
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 8, 2*numCols))
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 8, nbCols))
|
||||
}
|
||||
|
||||
for i, c := range testCases {
|
||||
t.Run(fmt.Sprintf("testcase-%v", i), func(t *testing.T) {
|
||||
|
||||
assert := require.New(t)
|
||||
var (
|
||||
numRow = len(c)
|
||||
key = ringsis.GenerateKey(params, numRow)
|
||||
result = ringsis_64_8.TransversalHash(
|
||||
key.Ag(),
|
||||
c,
|
||||
twiddles,
|
||||
domain,
|
||||
)
|
||||
nbRows = len(c)
|
||||
nbCols = c[0].Len()
|
||||
key = GenerateKey(params, nbRows)
|
||||
result = key.TransversalHash(c)
|
||||
)
|
||||
|
||||
for col := 0; col < numCols; col++ {
|
||||
column := make([]field.Element, numRow)
|
||||
for r := 0; r < numRow; r++ {
|
||||
offset := key.modulusDegree()
|
||||
|
||||
for col := 0; col < nbCols; col++ {
|
||||
column := make([]field.Element, nbRows)
|
||||
for r := 0; r < nbRows; r++ {
|
||||
column[r] = c[r].Get(col)
|
||||
}
|
||||
|
||||
colHash := key.Hash(column)
|
||||
require.Equalf(
|
||||
t,
|
||||
vector.Prettify(colHash),
|
||||
vector.Prettify(result[64*col:64*col+64]),
|
||||
"column %v", col,
|
||||
)
|
||||
for j := 0; j < len(colHash); j++ {
|
||||
assert.True(colHash[j].Equal(&result[offset*col+j]), "transversal hash does not match col hash")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTransversalHash(b *testing.B) {
|
||||
|
||||
var (
|
||||
numRow = 1024
|
||||
numCols = 1024
|
||||
rng = rand.New(utils.NewRandSource(77442)) // nolint
|
||||
params = Params{LogTwoBound: 16, LogTwoDegree: 6}
|
||||
numInputPerPoly = params.OutputSize() / (field.Bytes * 8 / params.LogTwoBound)
|
||||
key = GenerateKey(params, numRow)
|
||||
numTestCases = 1 << numInputPerPoly
|
||||
numPoly = numRow / numInputPerPoly
|
||||
)
|
||||
|
||||
for tc := 0; tc < numTestCases; tc++ {
|
||||
|
||||
b.Run(fmt.Sprintf("testcase-%b", tc), func(b *testing.B) {
|
||||
|
||||
inputs := make([]smartvectors.SmartVector, 0, numPoly*numInputPerPoly)
|
||||
|
||||
for p := 0; p < numPoly; p++ {
|
||||
for i := 0; i < numInputPerPoly; i++ {
|
||||
if (tc>>i)&1 == 0 {
|
||||
inputs = append(inputs, randomConstRow(rng, numCols))
|
||||
} else {
|
||||
inputs = append(inputs, randomRegularRow(rng, numCols))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for c := 0; c < b.N; c++ {
|
||||
_ = key.TransversalHash(inputs)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,12 @@
|
||||
module github.com/consensys/linea-monorepo/prover
|
||||
|
||||
go 1.22.7
|
||||
|
||||
toolchain go1.23.0
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/bits-and-blooms/bitset v1.14.3
|
||||
github.com/consensys/bavard v0.1.24
|
||||
github.com/bits-and-blooms/bitset v1.20.0
|
||||
github.com/consensys/compress v0.2.5
|
||||
github.com/consensys/gnark v0.11.1-0.20250107100237-2cb190338a01
|
||||
github.com/consensys/gnark-crypto v0.14.1-0.20250515163241-5b554443cce2
|
||||
github.com/consensys/gnark v0.12.1-0.20250604132941-716710f02181
|
||||
github.com/consensys/gnark-crypto v0.17.1-0.20250528013212-404f8e5110fa
|
||||
github.com/consensys/go-corset v1.0.7
|
||||
github.com/crate-crypto/go-kzg-4844 v1.1.0
|
||||
github.com/dlclark/regexp2 v1.11.2
|
||||
@@ -26,10 +23,10 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golang.org/x/crypto v0.31.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/crypto v0.35.0
|
||||
golang.org/x/net v0.27.0
|
||||
golang.org/x/sync v0.10.0
|
||||
golang.org/x/sync v0.11.0
|
||||
golang.org/x/time v0.5.0
|
||||
)
|
||||
|
||||
@@ -46,6 +43,7 @@ require (
|
||||
github.com/cockroachdb/pebble v1.1.1 // indirect
|
||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
|
||||
github.com/consensys/bavard v0.1.31-0.20250406004941-2db259e4b582 // indirect
|
||||
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
||||
github.com/ethereum/c-kzg-4844 v1.0.3 // indirect
|
||||
@@ -65,7 +63,7 @@ require (
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.3.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b // indirect
|
||||
github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2 // indirect
|
||||
github.com/klauspost/compress v1.17.7 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
@@ -89,7 +87,7 @@ require (
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/supranational/blst v0.3.12 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
@@ -99,7 +97,7 @@ require (
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/term v0.29.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
|
||||
@@ -52,8 +52,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA=
|
||||
github.com/bits-and-blooms/bitset v1.14.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU=
|
||||
github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
@@ -92,14 +92,14 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP
|
||||
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||
github.com/consensys/bavard v0.1.24 h1:Lfe+bjYbpaoT7K5JTFoMi5wo9V4REGLvQQbHmatoN2I=
|
||||
github.com/consensys/bavard v0.1.24/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
|
||||
github.com/consensys/bavard v0.1.31-0.20250406004941-2db259e4b582 h1:dTlIwEdFQmldzFf5F6bbTcYWhvnAgZai2g8eq3Wwxqg=
|
||||
github.com/consensys/bavard v0.1.31-0.20250406004941-2db259e4b582/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
|
||||
github.com/consensys/compress v0.2.5 h1:gJr1hKzbOD36JFsF1AN8lfXz1yevnJi1YolffY19Ntk=
|
||||
github.com/consensys/compress v0.2.5/go.mod h1:pyM+ZXiNUh7/0+AUjUf9RKUM6vSH7T/fsn5LLS0j1Tk=
|
||||
github.com/consensys/gnark v0.11.1-0.20250107100237-2cb190338a01 h1:YCHI04nMKFC60P78x+05QR3jxgBFlDXzJq+7bQOmbfs=
|
||||
github.com/consensys/gnark v0.11.1-0.20250107100237-2cb190338a01/go.mod h1:8YNyW/+XsYiLRzROLaj/PSktYO4VAdv6YW1b1P3UsZk=
|
||||
github.com/consensys/gnark-crypto v0.14.1-0.20250515163241-5b554443cce2 h1:N3OCv+VoCn4CEvhRc3vKXyE3S1Si7OSoFTO3bv6ZEgQ=
|
||||
github.com/consensys/gnark-crypto v0.14.1-0.20250515163241-5b554443cce2/go.mod h1:ePFa23CZLMRMHxQpY5nMaiAZ3yuEIayaB8ElEvlwLEs=
|
||||
github.com/consensys/gnark v0.12.1-0.20250604132941-716710f02181 h1:FXHYtmqRsLWruPo/+v57JaOVipKb9glGjQMfrX4vQ7g=
|
||||
github.com/consensys/gnark v0.12.1-0.20250604132941-716710f02181/go.mod h1:Q3mkMtUVaujW6RVYxclHkQa1EiAMfXdCBL7W055rjEk=
|
||||
github.com/consensys/gnark-crypto v0.17.1-0.20250528013212-404f8e5110fa h1:Sb+sRLftvPWQlqXBW+6EjGmW28Yfk/9eRvLQcRkfp20=
|
||||
github.com/consensys/gnark-crypto v0.17.1-0.20250528013212-404f8e5110fa/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c=
|
||||
github.com/consensys/go-corset v1.0.7 h1:Ym3vjHtVSk59/q7p9/VFvwQkIqyCy1m61DgkNcKlyg4=
|
||||
github.com/consensys/go-corset v1.0.7/go.mod h1:JKJTywyjBE0Goco4DokW4BAkF6R+jtoo3XgkICwxrcw=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
@@ -290,8 +290,8 @@ github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBD
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b h1:AvQTK7l0PTHODD06PVQX1Tn2o29sRIaKIDOvTJmKurY=
|
||||
github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b/go.mod h1:e0JHb27/P6WorCJS3YolbY5XffS4PGBuoW38OthLkDs=
|
||||
github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2 h1:B+aWVgAx+GlFLhtYjIaF0uGjU3rzpl99Wf9wZWt+Mq8=
|
||||
github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2/go.mod h1:CH/cwcr21pPWH+9GtK/PFaa4OGTv4CtfkCKro6GpbRE=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
@@ -437,8 +437,9 @@ github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t6
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
@@ -455,8 +456,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
@@ -502,8 +504,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -613,8 +615,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -694,8 +696,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
||||
@@ -18,6 +18,9 @@ import (
|
||||
// `field.Element(1, 0, 0, 0)` represent valid field elements.
|
||||
type Element = fr.Element
|
||||
|
||||
// Vector aliases [fr.Vector] and represents a slice of field elements.
|
||||
type Vector = fr.Vector
|
||||
|
||||
const (
|
||||
// RootOfUnityOrder is the smallest integer such that
|
||||
// [RootOfUnity] ** (2 ** RootOfUnityOrder) == 1
|
||||
@@ -148,3 +151,7 @@ func PseudoRandTruncated(rng *rand.Rand, sizeByte int) Element {
|
||||
res.SetBigInt(bigInt)
|
||||
return res
|
||||
}
|
||||
|
||||
func Generator(m uint64) (Element, error) {
|
||||
return fr.Generator(m)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
|
||||
// Compile-time sanity check the satisfaction of the interface RangeChecker by
|
||||
// externalRangeChecker
|
||||
var _ frontend.Rangechecker = &externalRangeChecker{}
|
||||
var _ frontend.Rangechecker = (*externalRangeChecker)(nil)
|
||||
|
||||
// externalRangeChecker wraps the frontend.Builder. We require that the builder
|
||||
// also implements [frontend.Committer].
|
||||
@@ -49,7 +49,7 @@ type externalRangeChecker struct {
|
||||
// storeCommitBuilder implements [frontend.Builder], [frontend.Committer] and
|
||||
// [kvstore.Store].
|
||||
type storeCommitBuilder interface {
|
||||
frontend.Builder
|
||||
frontend.Builder[constraint.U64]
|
||||
frontend.Committer
|
||||
SetKeyValue(key, value any)
|
||||
GetKeyValue(key any) (value any)
|
||||
@@ -78,8 +78,8 @@ type storeCommitBuilder interface {
|
||||
// ```
|
||||
func newExternalRangeChecker(comp *wizard.CompiledIOP, addGateForRangeCheck bool) (frontend.NewBuilder, func() [][2]int) {
|
||||
rcCols := make(chan [][2]int)
|
||||
return func(field *big.Int, config frontend.CompileConfig) (frontend.Builder, error) {
|
||||
b, err := scs.NewBuilder(field, config)
|
||||
return func(field *big.Int, config frontend.CompileConfig) (frontend.Builder[constraint.U64], error) {
|
||||
b, err := scs.NewBuilder[constraint.U64](field, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create new native builder: %w", err)
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func DivCeil(a, b int) int {
|
||||
func DivExact(a, b int) int {
|
||||
res := a / b
|
||||
if res*b != a {
|
||||
panic("inexact division")
|
||||
Panic("inexact division %d/%d", a, b)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user