mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-08 23:17:58 -05:00
refactor, perf: prover/crypto/sis improvements (#554)
* fix: revert gnark go mod change * refactor: checkpoint mvp working * feat: added case for smartvector.Constant rows block * refactor: checkpoint * refactor: checkpoint * refactor: checkpoint * style: code cleaning * style: more comments * refactor: use gnark-crypto sis and refactor ringsis.TransversalHash * test: restore bench size * perf: better parallelization * chore: update gnark crypto * fix: restored gnark dep as in main * test: restored separate tests in transversal hash test * build: update to gnark crypto master with latest sis * build: fix linter
This commit is contained in:
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.
|
||||
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,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,114 +0,0 @@
|
||||
// Code generated by bavard DO NOT EDIT
|
||||
|
||||
package ringsis_64_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_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/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_8.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
params = ringsis.Params{LogTwoBound: 8, LogTwoDegree: 6}
|
||||
testCases = [][]smartvectors.SmartVector{
|
||||
constantRandomTestVector(rng, 2, numCols),
|
||||
regularRandomTestVector(rng, 2, numCols),
|
||||
}
|
||||
)
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 2, numCols))
|
||||
}
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 8, 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_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[64*col:64*col+64]),
|
||||
"column %v", col,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -40,27 +40,28 @@ var testCasesKey = []struct {
|
||||
Size: 576,
|
||||
Params: StdParams,
|
||||
},
|
||||
{
|
||||
Size: 43,
|
||||
Params: Params{
|
||||
LogTwoBound: 1,
|
||||
LogTwoDegree: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Size: 23,
|
||||
Params: Params{
|
||||
LogTwoBound: 1,
|
||||
LogTwoDegree: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Size: 256,
|
||||
Params: Params{
|
||||
LogTwoBound: 1,
|
||||
LogTwoDegree: 1,
|
||||
},
|
||||
},
|
||||
// TODO @gbotrel confirm with @AlexandreBelling we don't need to test these cases
|
||||
// {
|
||||
// Size: 43,
|
||||
// Params: Params{
|
||||
// LogTwoBound: 1,
|
||||
// LogTwoDegree: 1,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// Size: 23,
|
||||
// Params: Params{
|
||||
// LogTwoBound: 1,
|
||||
// LogTwoDegree: 1,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// Size: 256,
|
||||
// Params: Params{
|
||||
// LogTwoBound: 1,
|
||||
// LogTwoDegree: 1,
|
||||
// },
|
||||
// },
|
||||
}
|
||||
|
||||
func TestKeyMaxNumFieldHashable(t *testing.T) {
|
||||
@@ -275,35 +276,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_32_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_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/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(32, fft.WithShift(wfft.GetOmega(32*2)))
|
||||
twiddles = ringsis_32_8.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen)
|
||||
params = ringsis.Params{LogTwoBound: 8, LogTwoDegree: 5}
|
||||
nbCols = 16
|
||||
rng = rand.New(utils.NewRandSource(77442)) // nolint
|
||||
params = Params{LogTwoBound: 16, LogTwoDegree: 6}
|
||||
testCases = [][]smartvectors.SmartVector{
|
||||
constantRandomTestVector(rng, 1, numCols),
|
||||
regularRandomTestVector(rng, 1, numCols),
|
||||
constantRandomTestVector(rng, 4, nbCols),
|
||||
regularRandomTestVector(rng, 4, nbCols),
|
||||
}
|
||||
)
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 1, numCols))
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 4, nbCols))
|
||||
}
|
||||
|
||||
for i := 0; i < numReps; i++ {
|
||||
testCases = append(testCases, fullyRandomTestVector(rng, 4, 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_32_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[32*col:32*col+32]),
|
||||
"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)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,9 @@ toolchain go1.23.0
|
||||
|
||||
require (
|
||||
github.com/bits-and-blooms/bitset v1.14.3
|
||||
github.com/consensys/bavard v0.1.24
|
||||
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.20241217134352-810063550bd4
|
||||
github.com/consensys/gnark-crypto v0.14.1-0.20250117145449-0493a37cc361
|
||||
github.com/consensys/go-corset v0.0.0-20250217020957-ab7f2d548fa8
|
||||
github.com/crate-crypto/go-kzg-4844 v1.1.0
|
||||
github.com/dlclark/regexp2 v1.11.2
|
||||
@@ -45,6 +44,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.25 // 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
|
||||
|
||||
@@ -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.25 h1:5YcSBnp03/HvfpKaIQLr/ecspTp2k8YNR5rQLOWvUyc=
|
||||
github.com/consensys/bavard v0.1.25/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.20241217134352-810063550bd4 h1:Kp6egjRqKZf4469dfAWqFe6gi3MRs4VvNHmTfEjUlS8=
|
||||
github.com/consensys/gnark-crypto v0.14.1-0.20241217134352-810063550bd4/go.mod h1:GMPeN3dUSslNBYJsK3WTjIGd3l0ccfMbcEh/d5knFrc=
|
||||
github.com/consensys/gnark-crypto v0.14.1-0.20250117145449-0493a37cc361 h1:7HGt1kXTPR3qB5BGO6NMrjncXhunSLEtFPeZtVe/dI8=
|
||||
github.com/consensys/gnark-crypto v0.14.1-0.20250117145449-0493a37cc361/go.mod h1:q9s22Y0WIHd9UCBfD+xGeW8wDJ7WAGZZpMrLFqzBzrQ=
|
||||
github.com/consensys/go-corset v0.0.0-20250217020957-ab7f2d548fa8 h1:q6LG3JTvcx9OfKKWDS/5xcT0+mO2gHJnKKpy5mdMN+g=
|
||||
github.com/consensys/go-corset v0.0.0-20250217020957-ab7f2d548fa8/go.mod h1:rNP3hMR2Sjy5EdQNTHINwaM5kD08E3CSw8CCKhljjO8=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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