From 8794e7e06034a9b6140c519d2b73c14b315c7c41 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 26 May 2023 20:15:34 -0700 Subject: [PATCH 1/7] Switch to data as coefficients --- pkg/encoding/encoder/decode.go | 151 ++-------------------- pkg/encoding/encoder/encode.go | 113 +++------------- pkg/encoding/encoder/encode_test.go | 6 +- pkg/encoding/encoder/encoder_fuzz_test.go | 2 +- pkg/encoding/encoder/interpolation.go | 56 -------- pkg/encoding/encoder/params.go | 12 +- pkg/encoding/encoder/utils_test.go | 1 - pkg/encoding/kzgEncoder/encoder.go | 134 +------------------ pkg/encoding/main.go | 2 +- 9 files changed, 40 insertions(+), 437 deletions(-) diff --git a/pkg/encoding/encoder/decode.go b/pkg/encoding/encoder/decode.go index 850a56144d..47baf09986 100644 --- a/pkg/encoding/encoder/decode.go +++ b/pkg/encoding/encoder/decode.go @@ -4,88 +4,22 @@ import ( "errors" "log" - rb "github.com/Layr-Labs/eigenda/pkg/encoding/utils/reverseBits" bls "github.com/Layr-Labs/eigenda/pkg/kzg/bn254" ) // Decode data when some chunks from systematic nodes are lost. It first uses FFT to recover // the whole polynomial. Then it extracts only the systematic chunks -func (g *Encoder) Decode(samples []Frame, indices []uint64, inputSize uint64) ([]bls.Fr, error) { - if g.verbose { - log.Println("Entering Decode function") - defer log.Println("Exiting Decode function") - } - - reconSysEval, err := g.RecoverPolyEval(samples, indices) - if err != nil { - return nil, err - } - - concatFr := make([]bls.Fr, 0) - for j := 0; j < int(g.NumSysE); j++ { - dataFr := make([]bls.Fr, g.ChunkLen) - for i := 0; i < int(g.ChunkLen); i++ { - dataFr[i] = reconSysEval[i*int(g.NumSysE)+j] - } - - z := rb.ReverseBitsLimited(uint32(g.NumNodeE), uint32(j)) - coeffs, err := g.GetInterpolationPolyCoeff(dataFr, z) - if err != nil { - return nil, err - } - concatFr = append(concatFr, coeffs...) - } - - return concatFr[:inputSize], nil -} - -// Decode Original data if chunks from all systematic node are received. No need to do erasure recovery -func (g *Encoder) DecodeSys(frames []Frame, indices []uint64, inputSize uint64) ([]bls.Fr, error) { - if g.verbose { - log.Println("Entering DecodeSys function") - defer log.Println("Exiting DecodeSys function") - } - - codedDataFr := make([]bls.Fr, g.PaddedSysGroupSize) - - num := 0 - numFrame := uint64(0) - for i, d := range indices { - if uint64(d) < g.NumSys { - f := frames[i] - for j := uint64(0); j < g.ChunkLen; j++ { - p := j*g.NumSysE + d - bls.CopyFr(&codedDataFr[p], &f.Coeffs[j]) - num += 1 - } - numFrame += 1 - } - } - if numFrame != g.NumSys { - return nil, errors.New("does not contain sufficient chunks from systematic nodes") - } - - concatFr := make([]bls.Fr, 0) - for j := 0; j < int(g.NumSysE); j++ { - dataFr := make([]bls.Fr, g.ChunkLen) - for i := 0; i < int(g.ChunkLen); i++ { - dataFr[i] = codedDataFr[i*int(g.NumSysE)+j] - } - concatFr = append(concatFr, dataFr...) - } - - return concatFr[:inputSize], nil -} // This function takes a list of available frame, and return the original encoded data // storing the evaluation points, since it is where RS is applied. The input frame contains // the coefficient of the interpolating polynomina, hence interpolation is needed before -// recovery. The code autmomatic padded the systematic chunk (numSys <= chunk id < numSysE) -// which consists of zeros bls.Fr -func (g *Encoder) RecoverPolyEval(frames []Frame, indices []uint64) ([]bls.Fr, error) { +// recovery. + +func (g *Encoder) Decode(frames []Frame, indices []uint64, inputSize uint64) ([]byte, error) { + if g.verbose { - log.Println("Entering RecoverPolyEval function") - defer log.Println("Exiting RecoverPolyEval function") + log.Println("Entering Decode function") + defer log.Println("Exiting Decode function") } if uint64(len(frames)) < g.NumSys { @@ -114,27 +48,7 @@ func (g *Encoder) RecoverPolyEval(frames []Frame, indices []uint64) ([]bls.Fr, e } } - // padded zero chunks - zeroChunk := make([]bls.Fr, g.ChunkLen) - for i := uint64(0); i < g.ChunkLen; i++ { - bls.CopyFr(&zeroChunk[i], &bls.ZERO) - } - // copy evals based on frame zero coeffs padded NumSys dimension - for d := g.NumSys; d < g.NumSysE; d++ { - e := rb.ReverseBitsLimited(uint32(g.NumNodeE), uint32(d)) - evals, err := g.GetInterpolationPolyEval(zeroChunk, uint32(e)) - if err != nil { - return nil, err - } - - for j := uint64(0); j < g.ChunkLen; j++ { - p := j*g.NumNodeE + uint64(e) - samples[p] = new(bls.Fr) - bls.CopyFr(samples[p], &evals[j]) - } - } - - recovered, err := g.Fs.RecoverPolyFromSamples( + reconstructedData, err := g.Fs.RecoverPolyFromSamples( samples, g.Fs.ZeroPolyViaMultiplication, ) @@ -142,55 +56,12 @@ func (g *Encoder) RecoverPolyEval(frames []Frame, indices []uint64) ([]bls.Fr, e return nil, err } - // extract only systematic data evals from full recovered eval poly - polyOrder := g.NumSysE * g.ChunkLen - orderRatio := uint64(len(recovered)) / (polyOrder) - dataFr := make([]bls.Fr, polyOrder) - - k := uint64(0) - for j := uint64(0); j < polyOrder; j++ { - bls.CopyFr(&dataFr[k], &recovered[j*orderRatio]) - k++ - } - - for j := uint64(0); j < g.ChunkLen; j++ { - err = rb.ReverseBitOrderFr(dataFr[j*g.NumSysE : (j+1)*g.NumSysE]) - if err != nil { - return nil, err - } - } - - return dataFr, nil -} - -func (g *Encoder) DecodeSafe(frames []Frame, indices []uint64, inputSize uint64) ([]byte, error) { - if g.verbose { - log.Println("Entering DecodeSafe function") - defer log.Println("Exiting DecodeSafe function") + reconstructedPoly, err := g.Fs.FFT(reconstructedData, true) + if err != nil { + return nil, err } - numFr := GetNumElement(inputSize, bls.BYTES_PER_COEFFICIENT) - mpFrames := make([]Frame, len(frames)) - - copy(mpFrames, frames) + data := ToByteArray(reconstructedPoly, inputSize) - var data []byte - - // TODO optimize that if num sys is sufficient - if g.EncodingParams.NumSys+g.EncodingParams.NumPar > uint64(len(frames)) { - dataFr, err := g.Decode(mpFrames[:], indices[:], numFr) - if err != nil { - return nil, err - } - - data = ToByteArray(dataFr, inputSize) - } else { - - dataFr, err := g.DecodeSys(mpFrames, indices, numFr) - if err != nil { - return nil, err - } - data = ToByteArray(dataFr, inputSize) - } return data, nil } diff --git a/pkg/encoding/encoder/encode.go b/pkg/encoding/encoder/encode.go index 29c5fa1e39..1361551cdf 100644 --- a/pkg/encoding/encoder/encode.go +++ b/pkg/encoding/encoder/encode.go @@ -1,7 +1,6 @@ package encoder import ( - "errors" "log" "time" @@ -40,46 +39,17 @@ func (g *Encoder) Encode(inputFr []bls.Fr) (*GlobalPoly, []Frame, []uint32, erro defer log.Println("Exiting Encode function") } - // treating input as coeff of the interpolating poly - interpolatingCoeffs := g.PadToRequiredSymbols(inputFr) - - if g.verbose { - log.Printf(" Pad takes %v\n", time.Since(intermediate)) - intermediate = time.Now() - } - - // divide the data into chunks, treat a chunk data as coeff of poly and get its eval - evalChunks, err := g.CreateSysEvalChunks(interpolatingCoeffs) - if err != nil { - return nil, nil, nil, err - } - - // butterfly reorder the chunks to make it digestible for erasure code (polynomial extension) - splicedPolyEvals := g.SpliceEvalChunks(evalChunks) - - // compute polynomial coefficient. Note this interpolates the full poly, which is not - // the original data. We want the interpolating poly in the frame coset to be the data - fullCoeffsPoly, err := g.ConvertEvalsToCoeffs(splicedPolyEvals) - if err != nil { - return nil, nil, nil, err - } - - if g.verbose { - log.Printf(" Chunk and Splice take %v\n", time.Since(intermediate)) - log.Printf(" eval %v\n", time.Since(intermediate)) - log.Printf(" coeff %v\n", time.Since(intermediate)) - intermediate = time.Now() - } + polyCoeffs := inputFr // extend data based on Sys, Par ratio. The returned fullCoeffsPoly is padded with 0 to ease proof - fullPolyEvals, fullCoeffsPoly, err := g.ExtendPolyEval(fullCoeffsPoly) + polyEvals, _, err := g.ExtendPolyEval(polyCoeffs) if err != nil { return nil, nil, nil, err } poly := &GlobalPoly{ - Values: fullPolyEvals, - Coeffs: fullCoeffsPoly, + Values: polyEvals, + Coeffs: polyEvals, } if g.verbose { @@ -87,25 +57,23 @@ func (g *Encoder) Encode(inputFr []bls.Fr) (*GlobalPoly, []Frame, []uint32, erro } // create frames to group relevant info - frames, indices, err := g.MakeFrames(fullPolyEvals, interpolatingCoeffs) + frames, indices, err := g.MakeFrames(polyEvals) if err != nil { return nil, nil, nil, err } if g.verbose { log.Printf(" SUMMARY: Encode %v byte among %v numNode out of %v extended numNode takes %v\n", - len(inputFr)*bls.BYTES_PER_COEFFICIENT, g.NumSys+g.NumPar, g.NumSysE, time.Since(start)) + len(inputFr)*bls.BYTES_PER_COEFFICIENT, g.NumSys+g.NumPar, g.NumNodeE, time.Since(start)) } return poly, frames, indices, nil } // This Function takes extended evaluation data and bundles relevant information into Frame. -// Every frame is verifiable to the commitment. It returns only first numSys frame, and the -// first numSysE to numSysE + numPar chunks +// Every frame is verifiable to the commitment. func (g *Encoder) MakeFrames( - encodedEvalFr []bls.Fr, - coeffs []bls.Fr, + polyEvals []bls.Fr, ) ([]Frame, []uint32, error) { if g.verbose { log.Println("Entering MakeFrames function") @@ -113,13 +81,9 @@ func (g *Encoder) MakeFrames( } numFrame := g.NumSys + g.NumPar - numPadSys := g.NumSysE - g.NumSys - if numFrame > g.NumNodeE-numPadSys { - return nil, nil, errors.New("cannot create number of frame higher than possible") - } // reverse dataFr making easier to sample points - err := rb.ReverseBitOrderFr(encodedEvalFr) + err := rb.ReverseBitOrderFr(polyEvals) if err != nil { return nil, nil, err } @@ -130,10 +94,6 @@ func (g *Encoder) MakeFrames( for i := uint64(0); i < uint64(g.NumNodeE); i++ { - // skip padded chunk and its coding - if i >= g.NumSys && i < g.NumSysE { - continue - } // if collect sufficient chunks if k == numFrame { return frames, indices, nil @@ -146,24 +106,18 @@ func (g *Encoder) MakeFrames( frame := Frame{} indices = append(indices, j) - // since coeff of interpolating poly for the coset is data itself, avoid taking FFT - if i < g.NumSys { - frame.Coeffs = coeffs[g.ChunkLen*i : g.ChunkLen*(i+1)] - } else { - ys := encodedEvalFr[g.ChunkLen*i : g.ChunkLen*(i+1)] - err := rb.ReverseBitOrderFr(ys) - if err != nil { - return nil, nil, err - } - coeffs, err := g.GetInterpolationPolyCoeff(ys, uint32(j)) - if err != nil { - return nil, nil, err - } - - frame.Coeffs = coeffs - + ys := polyEvals[g.ChunkLen*i : g.ChunkLen*(i+1)] + err := rb.ReverseBitOrderFr(ys) + if err != nil { + return nil, nil, err + } + coeffs, err := g.GetInterpolationPolyCoeff(ys, uint32(j)) + if err != nil { + return nil, nil, err } + frame.Coeffs = coeffs + frames[k] = frame k++ } @@ -193,32 +147,3 @@ func (g *Encoder) ExtendPolyEval(coeffs []bls.Fr) ([]bls.Fr, []bls.Fr, error) { return evals, pdCoeffs, nil } - -// get coeff from data -func (g *Encoder) ConvertEvalsToCoeffs(coeffs []bls.Fr) ([]bls.Fr, error) { - if g.verbose { - log.Println("Entering ConvertEvalsToCoeffs function") - defer log.Println("Exiting ConvertEvalsToCoeffs function") - } - - evals, err := g.Fs.FFT(coeffs, true) - if err != nil { - return nil, err - } - return evals, nil -} - -// Pad 0 to input to reach the closest power of 2 -func (g *Encoder) PadToRequiredSymbols(dataFr []bls.Fr) []bls.Fr { - if g.verbose { - log.Println("Entering PadToRequiredSymbols function") - defer log.Println("Exiting PadToRequiredSymbols function") - } - - outFr := make([]bls.Fr, g.PaddedSysGroupSize) - copy(outFr, dataFr) - for i := len(dataFr); i < len(outFr); i++ { - bls.CopyFr(&outFr[i], &bls.ZERO) - } - return outFr -} diff --git a/pkg/encoding/encoder/encode_test.go b/pkg/encoding/encoder/encode_test.go index e5a083ed64..9d143f48c5 100644 --- a/pkg/encoding/encoder/encode_test.go +++ b/pkg/encoding/encoder/encode_test.go @@ -21,7 +21,7 @@ func TestEncodeDecode_InvertsWhenSamplingAllFrames(t *testing.T) { // sample some frames samples, indices := sampleFrames(frames, uint64(len(frames))) - data, err := enc.DecodeSafe(samples, indices, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + data, err := enc.Decode(samples, indices, uint64(len(GETTYSBURG_ADDRESS_BYTES))) require.Nil(t, err) require.NotNil(t, data) @@ -41,7 +41,7 @@ func TestEncodeDecode_InvertsWhenSamplingMissingFrame(t *testing.T) { // sample some frames samples, indices := sampleFrames(frames, uint64(len(frames)-1)) - data, err := enc.DecodeSafe(samples, indices, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + data, err := enc.Decode(samples, indices, uint64(len(GETTYSBURG_ADDRESS_BYTES))) require.Nil(t, err) require.NotNil(t, data) @@ -61,7 +61,7 @@ func TestEncodeDecode_ErrorsWhenNotEnoughSampledFrames(t *testing.T) { // sample some frames samples, indices := sampleFrames(frames, uint64(len(frames)-2)) - data, err := enc.DecodeSafe(samples, indices, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + data, err := enc.Decode(samples, indices, uint64(len(GETTYSBURG_ADDRESS_BYTES))) require.Nil(t, data) require.NotNil(t, err) diff --git a/pkg/encoding/encoder/encoder_fuzz_test.go b/pkg/encoding/encoder/encoder_fuzz_test.go index 5de849db59..60e067652f 100644 --- a/pkg/encoding/encoder/encoder_fuzz_test.go +++ b/pkg/encoding/encoder/encoder_fuzz_test.go @@ -25,7 +25,7 @@ func FuzzOnlySystematic(f *testing.F) { //sample the correct systematic frames samples, indices := sampleFrames(frames, uint64(len(frames))) - data, err := enc.DecodeSafe(samples, indices, uint64(len(input))) + data, err := enc.Decode(samples, indices, uint64(len(input))) if err != nil { t.Errorf("Error Decoding:\n Data:\n %q \n Err: %q", input, err) } diff --git a/pkg/encoding/encoder/interpolation.go b/pkg/encoding/encoder/interpolation.go index 725c988a1b..8ee54d4c56 100644 --- a/pkg/encoding/encoder/interpolation.go +++ b/pkg/encoding/encoder/interpolation.go @@ -1,7 +1,6 @@ package encoder import ( - rb "github.com/Layr-Labs/eigenda/pkg/encoding/utils/reverseBits" bls "github.com/Layr-Labs/eigenda/pkg/kzg/bn254" ) @@ -85,58 +84,3 @@ func (g *Encoder) GetInterpolationPolyCoeff(chunk []bls.Fr, k uint32) ([]bls.Fr, } return coeffs, nil } - -// Create evaluation using coeff based on systematic data chunk -func (g *Encoder) CreateSysEvalChunks(interpolatingCoeff []bls.Fr) ([][]bls.Fr, error) { - chunks := make([][]bls.Fr, g.NumSysE) - for i := uint64(0); i < g.NumSysE; i++ { - chunks[i] = make([]bls.Fr, g.ChunkLen) - // evaluate each ChunkLen of the data as a interpolating poly to get the evals - // where to evaluate at depends on index - j := rb.ReverseBitsLimited(uint32(g.NumNodeE), uint32(i)) - evals, err := g.GetInterpolationPolyEval( - interpolatingCoeff[g.ChunkLen*i:g.ChunkLen*(i+1)], - j, - ) - chunks[i] = evals - - if err != nil { - return nil, err - } - } - return chunks, nil -} - -// suppose the original data are [1,2,3,o,4,5..,n], represented as a matrix -// [1, 2, 3, o] -// [4, 5, 6, p] -// [7, 8, 9, m] -// [a, b, c, n] -// where each row is the coeff for the smaller poly. -// last GetInterpolationPolyEval step applied F W to every row of the matrix -// to transfer coeffs to evaluations, such that we want every entry in the matrix -// corresponds to distinct evaluation index for the full polynomial, -// whose indices are [1, w, w^2, w^3, φ, wφ, w^2φ, ...] -// But since our data undergo a butterfly operation -// [1, 7, 4, a, 2, 8, 5, b, 3, 9, 6, c, o, m, p, n] -// those number are symbolic, but they should gives a assending order -// [1, w, w^2, w^3, φ, wφ, w^2φ, ...] -// hence chunk 0 has a coset of [1, 2, 3, o] <=> [1, φ, φ^2, φ^3] <=> F W0 [1, 2, 3, o] -// hence chunk 2 has a coset of [7, 8, 9, m] <=> [w, wφ, wφ^2, wφ^3] <=> F W2 [7, 8, 9, m] -// hence chunk 1 has a coset of [4, 5, 6, p] <=> [w^2, w^2φ, w^2φ^2, w^2φ^3] <=> F W1 [4, 5, 6, p] -// hence chunk 3 has a coset of [a, b, c, n] <=> [w^3, w^3φ, w^3φ^2, w^3φ^3] <=> F W3 [a, b, c, n] -// W_i are different diaganol matrices -func (g *Encoder) SpliceEvalChunks(chunks [][]bls.Fr) []bls.Fr { - dataFr := make([]bls.Fr, g.PaddedSysGroupSize) - indices := make([]int, 0) - for i := 0; i < len(chunks); i++ { - indices = append(indices, int(rb.ReverseBitsLimited(uint32(g.NumSysE), uint32(i)))) - } - - for i := 0; i < int(g.ChunkLen); i++ { - for j, k := range indices { - dataFr[i*len(chunks)+k] = chunks[j][i] - } - } - return dataFr -} diff --git a/pkg/encoding/encoder/params.go b/pkg/encoding/encoder/params.go index 73a1621e2d..84cf4bb025 100644 --- a/pkg/encoding/encoder/params.go +++ b/pkg/encoding/encoder/params.go @@ -8,11 +8,9 @@ type EncodingParams struct { // num chunk meta NumSys uint64 // number of systematic nodes that are storing data NumPar uint64 // number of parity nodes that are storing data - NumSysE uint64 // number of systematic chunks that are padded to power of 2 NumNodeE uint64 // number of total chunks that are padded to power of 2 ChunkLen uint64 // number of Fr symbol stored inside a chunk ChunkDegree uint64 // degree of the polynomial interpolating a chunk. ChunkDegree = ChunkLen-1 - PaddedSysGroupSize uint64 // the size of the group (power of 2) used to construct the global polynomial which interpolates numSysE padded systematic chunks. PaddedSysGroupSize = NumSysE*ChunkLen PaddedNodeGroupSize uint64 // the size of the group (power of 2) on which the global polynomial is evaluted in order to extend to NumPar chunks PaddedNodeGroupSize = NumNodeE*ChunkLen GlobalPolyDegree uint64 // degree of the PaddedSymPoly. GlobalPolyDegree = PaddedSysGroupSize - 1 } @@ -26,32 +24,26 @@ type EncodingKey struct { func GetEncodingParams(numSys, numPar, dataByteLen uint64) EncodingParams { - // Extended number of systematic symbols - numSysE := NextPowerOf2(numSys) - // Extended number of nodes numNode := numSys + numPar ratio := RoundUpDivision(numNode, numSys) - numNodeE := NextPowerOf2(numSysE * ratio) + numNodeE := NextPowerOf2(numSys * ratio) // chunk/coset size to fit into FFT for multi-reveal dataLen := RoundUpDivision(dataByteLen, bls.BYTES_PER_COEFFICIENT) chunkLen := NextPowerOf2(RoundUpDivision(dataLen, numSys)) // Order of the global polynomial + 1 - paddedSysGroupSize := numSysE * chunkLen // This will always be a power of 2, since both factors are powers of 2. paddedNodeGroupSize := numNodeE * chunkLen // This will always be a power of 2, since both factors are powers of 2. params := EncodingParams{ NumSys: numSys, NumPar: numPar, - NumSysE: numSysE, NumNodeE: numNodeE, ChunkLen: chunkLen, ChunkDegree: chunkLen - 1, - PaddedSysGroupSize: paddedSysGroupSize, PaddedNodeGroupSize: paddedNodeGroupSize, - GlobalPolyDegree: paddedSysGroupSize - 1, + GlobalPolyDegree: dataLen - 1, } return params diff --git a/pkg/encoding/encoder/utils_test.go b/pkg/encoding/encoder/utils_test.go index 3489ab2f58..5ef8e763e3 100644 --- a/pkg/encoding/encoder/utils_test.go +++ b/pkg/encoding/encoder/utils_test.go @@ -18,7 +18,6 @@ func TestGetEncodingParams(t *testing.T) { assert.Equal(t, params.NumNodeE, uint64(8)) assert.Equal(t, params.NumPar, uint64(4)) assert.Equal(t, params.NumSys, uint64(1)) - assert.Equal(t, params.NumSysE, uint64(1)) assert.Equal(t, params.PaddedNodeGroupSize, uint64(512)) } diff --git a/pkg/encoding/kzgEncoder/encoder.go b/pkg/encoding/kzgEncoder/encoder.go index 1ff7544146..de71ec33cd 100644 --- a/pkg/encoding/kzgEncoder/encoder.go +++ b/pkg/encoding/kzgEncoder/encoder.go @@ -9,7 +9,6 @@ import ( rs "github.com/Layr-Labs/eigenda/pkg/encoding/encoder" "github.com/Layr-Labs/eigenda/pkg/encoding/utils" - rb "github.com/Layr-Labs/eigenda/pkg/encoding/utils/reverseBits" kzg "github.com/Layr-Labs/eigenda/pkg/kzg" "github.com/ethereum/go-ethereum/crypto" @@ -160,15 +159,15 @@ func (g *KzgEncoder) Encode(inputFr []bls.Fr) (*bls.G1Point, *bls.G1Point, []Fra log.Printf(" Commiting takes %v\n", time.Since(intermediate)) intermediate = time.Now() - log.Printf("shift %v\n", g.SRSOrder-g.PaddedSysGroupSize) + log.Printf("shift %v\n", g.SRSOrder-g.GlobalPolyDegree-1) log.Printf("order %v\n", len(g.Srs.G2)) log.Println("low degree verification info") } - shiftedSecret := g.Srs.G1[g.SRSOrder-g.PaddedSysGroupSize:] + shiftedSecret := g.Srs.G1[g.SRSOrder-g.GlobalPolyDegree-1:] //The proof of low degree is commitment of the polynomial shifted to the largest srs degree - lowDegreeProof := bls.LinCombG1(shiftedSecret, poly.Coeffs[:g.PaddedSysGroupSize]) + lowDegreeProof := bls.LinCombG1(shiftedSecret, poly.Coeffs[:g.GlobalPolyDegree+1]) //fmt.Println("kzgFFT lowDegreeProof", lowDegreeProof, "poly len ", len(fullCoeffsPoly), "order", len(g.Ks.SecretG2) ) ok := VerifyLowDegreeProof(&commit, lowDegreeProof, g.GlobalPolyDegree, g.SRSOrder, g.Srs.G2) if !ok { @@ -201,20 +200,6 @@ func (g *KzgEncoder) Encode(inputFr []bls.Fr) (*bls.G1Point, *bls.G1Point, []Fra } } - // Perform zero padding only if NumSys is not a power of 2 - // TODO: Disabling zero padding proof due to CPU issues - // if g.NumSys != g.NumSysE { - // paddingproof, paddingQuotientPolyCommit, _ := g.ProveZeroPadding(poly.Coeffs, commit) - // verificationFlag := g.VerifyZeroPadding(paddingproof, paddingQuotientPolyCommit, &commit) - // if !verificationFlag { - // log.Printf("Kzg FFT Cannot Verify zero padding proof %v\n", paddingproof) - // return nil, nil, nil, nil, errors.New("cannot verify zero padding proof") - // } else { - // log.Printf("Kzg FFT can verify zero padding proof PPPASSS %v\n", lowDegreeProof) - // log.Printf("Verification flag is %v\n", verificationFlag) - // } - // } - return &commit, lowDegreeProof, kzgFrames, indices, nil } @@ -229,98 +214,6 @@ func (g *KzgEncoder) Commit(polyFr []bls.Fr) bls.G1Point { return *commit } -// This function is called for generating the proof for zero padding. -func (g *KzgEncoder) ProveZeroPadding(metaPoly []bls.Fr, metaPolyCommit bls.G1Point) (*bls.G1Point, *bls.G1Point, error) { - if g.Verbose { - log.Println("Entering ProveZeroPadding function") - defer log.Println("Exiting ProveZeroPadding function") - } - - // construct the polynomial vanishingPoly(x) - // start by initalizing it first to a constant poly - vanishingPoly := make([]bls.Fr, g.ChunkLen*(g.NumSysE-g.NumSys)+1) - vanishingPoly[0] = bls.ToFr("1") - for i := g.NumSys; i < g.NumSysE; i++ { - - // multiplying the zero poly with the running product - prod := g.ZeroPolyMul(vanishingPoly[:int(g.ChunkLen*(i-g.NumSys)+1)], i) - - copy(vanishingPoly[:len(prod)], prod) - } - - // getting the polynomial: quotientPoly(x) - quotientPoly := kzg.PolyLongDiv(metaPoly, vanishingPoly[:]) - - // getting commitment at G1: [quotientPoly(x)]_1 - quotientPolyCommit := g.Commit(quotientPoly) - - // getting random challenge as part of Fiat-Shamir heurestic - byteArray := [][32]byte{quotientPolyCommit.X.Bytes(), - quotientPolyCommit.Y.Bytes(), - metaPolyCommit.X.Bytes(), - metaPolyCommit.Y.Bytes(), - } - alpha := createFiatShamirChallenge(byteArray) - - // evaluate vanishing polynomial vanishingPoly(x) at the challenge alpha - var vanishingPolyEval bls.Fr - bls.EvalPolyAt(&vanishingPolyEval, vanishingPoly, alpha) - - // construct the numerator polynomial metaPoly(x) - vanishingPoly(alpha)*quotientPoly(x) - // we are storing the numerator polynomial in metaPoly itself - var tmp2 bls.Fr - for i := 0; i < len(quotientPoly); i++ { - bls.MulModFr(&tmp2, &vanishingPolyEval, "ientPoly[i]) - bls.SubModFr(&metaPoly[i], &metaPoly[i], &tmp2) - } - - // evaluate proof for zero padding - zeroPaddingProof := g.Ks.ComputeProofSingleAtFr(metaPoly, *alpha) - return zeroPaddingProof, "ientPolyCommit, nil -} - -// This function verifies that the proof generated for zero padding is correct. -func (g *KzgEncoder) VerifyZeroPadding(zeroPaddingProof *bls.G1Point, quotientPolyCommit *bls.G1Point, metaPolyCommit *bls.G1Point) bool { - if g.Verbose { - log.Println("Entering VerifyZeroPadding function") - defer log.Println("Exiting VerifyZeroPadding function") - } - - // getting random challenge alpha as part of Fiat-Shamir heurestic - byteArray := [][32]byte{quotientPolyCommit.X.Bytes(), - quotientPolyCommit.Y.Bytes(), - metaPolyCommit.X.Bytes(), - metaPolyCommit.Y.Bytes(), - } - alpha := createFiatShamirChallenge(byteArray) - - // construct the big vanishing poly vanishingPoly(x) and initalizing it to first zero poly - vanishingPoly := make([]bls.Fr, g.ChunkLen*(g.NumSysE-g.NumSys)+1) - vanishingPoly[0] = bls.ToFr("1") - for i := g.NumSys; i < g.NumSysE; i++ { - // multiplying the zero poly with the running product - prod := g.ZeroPolyMul(vanishingPoly[:int(g.ChunkLen*(i-g.NumSys)+1)], i) - copy(vanishingPoly[:len(prod)], prod) - - } - - // evaluate vanishing polynomial at alpha: vanishingPoly(alpha) - var vanishingPolyEval bls.Fr - bls.EvalPolyAt(&vanishingPolyEval, vanishingPoly, alpha) - - // pairing check - // compute alpha[zeroPaddingProof]_1 + [metaPoly(X)]_1 - vanishingPolyEval[quotientPolyCommit]_1 - var summand bls.G1Point - bls.MulG1(&summand, zeroPaddingProof, alpha) - bls.AddG1(&summand, metaPolyCommit, &summand) - var zMulPiG1 bls.G1Point - bls.MulG1(&zMulPiG1, quotientPolyCommit, &vanishingPolyEval) - bls.SubG1(&summand, &summand, &zMulPiG1) - - return bls.PairingsVerify(&summand, &bls.GenG2, zeroPaddingProof, &g.Srs.G2[1]) - -} - // The function verify low degree proof against a poly commitment // We wish to show x^shift poly = shiftedPoly, with // With shift = SRSOrder-1 - claimedDegree and @@ -353,24 +246,3 @@ func polyFactorDiv(dst *bls.Fr, a *bls.Fr, b *bls.Fr) { bls.InvModFr(&tmp, b) bls.MulModFr(dst, &tmp, a) } - -// Multiplying the zero polynomial -func (g *KzgEncoder) ZeroPolyMul(f []bls.Fr, index uint64) []bls.Fr { - prod := make([]bls.Fr, len(f)+int(g.ChunkLen)) - copy(prod[int(g.ChunkLen):], f) - - // Observe that we can write (⍵^i * φ)^{ChunkLenE} = (⍵^i * ⍵^{NumSysE})^{ChunkLenE} = ⍵^{(i+NumSysE)*ChunkLenE} - // ATTENTION: Due to butterfly algorithm used in FFT, we need to put - // i = rb.ReverseBitsLimited(uint32(g.NumNodeE), uint32(index)) instead of index to evaluate the - // corresponding power of ⍵. - // TRIVIA: The root of this zero polynomial is given by g.Fs.ExpandedRootsOfUnity[(rb.ReverseBitsLimited(uint32(g.NumNodeE), uint32(index)))] - constcoeff := g.Ks.ExpandedRootsOfUnity[uint32(g.ChunkLen)*(rb.ReverseBitsLimited(uint32(g.NumNodeE), uint32(index)))] - - for i := 0; i < len(f); i++ { - bls.MulModFr(&f[i], &f[i], &constcoeff) - bls.SubModFr(&prod[i], &prod[i], &f[i]) - } - - return prod - -} diff --git a/pkg/encoding/main.go b/pkg/encoding/main.go index 07eef57650..cf57f4d757 100644 --- a/pkg/encoding/main.go +++ b/pkg/encoding/main.go @@ -99,7 +99,7 @@ func TestKzgRs() { //fmt.Printf("* Sampled %v frames\n", numSys) //// Decode data from samples - dataFr, err := enc.DecodeSafe(samples, indices, inputSize) + dataFr, err := enc.Decode(samples, indices, inputSize) if err != nil { log.Fatal(err) } From fe3b8515f318a8e95e342dd5e789387ee5170a0c Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 26 May 2023 20:43:38 -0700 Subject: [PATCH 2/7] initial refactor encoding params --- pkg/encoding/encoder/decode.go | 10 +++--- pkg/encoding/encoder/encode.go | 12 +++---- pkg/encoding/encoder/encoder.go | 2 +- pkg/encoding/encoder/params.go | 36 ++++++++----------- pkg/encoding/encoder/utils_test.go | 6 ++-- pkg/encoding/kzgEncoder/decode.go | 4 +-- pkg/encoding/kzgEncoder/encoder.go | 18 +++++----- pkg/encoding/kzgEncoder/encoder_fuzz_test.go | 2 +- pkg/encoding/kzgEncoder/frame_test.go | 2 +- pkg/encoding/kzgEncoder/precomputeSRS_test.go | 4 +-- pkg/encoding/kzgEncoder/verifier.go | 4 +-- 11 files changed, 47 insertions(+), 53 deletions(-) diff --git a/pkg/encoding/encoder/decode.go b/pkg/encoding/encoder/decode.go index 47baf09986..5be424c328 100644 --- a/pkg/encoding/encoder/decode.go +++ b/pkg/encoding/encoder/decode.go @@ -22,15 +22,17 @@ func (g *Encoder) Decode(frames []Frame, indices []uint64, inputSize uint64) ([] defer log.Println("Exiting Decode function") } - if uint64(len(frames)) < g.NumSys { + numSys := GetNumSys(inputSize, g.ChunkLen) + + if uint64(len(frames)) < numSys { return nil, errors.New("number of frame must be sufficient") } - samples := make([]*bls.Fr, g.NumNodeE*g.ChunkLen) + samples := make([]*bls.Fr, g.NumEvaluations) // copy evals based on frame coeffs into samples for i, d := range indices { f := frames[i] - e, err := GetLeadingCosetIndex(d, g.NumSys, g.NumPar) + e, err := GetLeadingCosetIndex(d, numSys, g.NumChunks-numSys) if err != nil { return nil, err } @@ -42,7 +44,7 @@ func (g *Encoder) Decode(frames []Frame, indices []uint64, inputSize uint64) ([] // Some pattern i butterfly swap. Find the leading coset, then increment by number of coset for j := uint64(0); j < g.ChunkLen; j++ { - p := j*g.NumNodeE + uint64(e) + p := j*g.NumChunks + uint64(e) samples[p] = new(bls.Fr) bls.CopyFr(samples[p], &evals[j]) } diff --git a/pkg/encoding/encoder/encode.go b/pkg/encoding/encoder/encode.go index 1361551cdf..494e40edd8 100644 --- a/pkg/encoding/encoder/encode.go +++ b/pkg/encoding/encoder/encode.go @@ -63,8 +63,8 @@ func (g *Encoder) Encode(inputFr []bls.Fr) (*GlobalPoly, []Frame, []uint32, erro } if g.verbose { - log.Printf(" SUMMARY: Encode %v byte among %v numNode out of %v extended numNode takes %v\n", - len(inputFr)*bls.BYTES_PER_COEFFICIENT, g.NumSys+g.NumPar, g.NumNodeE, time.Since(start)) + log.Printf(" SUMMARY: Encode %v byte among %v numNode takes %v\n", + len(inputFr)*bls.BYTES_PER_COEFFICIENT, g.NumChunks, time.Since(start)) } return poly, frames, indices, nil @@ -80,7 +80,7 @@ func (g *Encoder) MakeFrames( defer log.Println("Exiting MakeFrames function") } - numFrame := g.NumSys + g.NumPar + numFrame := g.NumChunks // reverse dataFr making easier to sample points err := rb.ReverseBitOrderFr(polyEvals) @@ -92,7 +92,7 @@ func (g *Encoder) MakeFrames( indices := make([]uint32, 0) frames := make([]Frame, numFrame) - for i := uint64(0); i < uint64(g.NumNodeE); i++ { + for i := uint64(0); i < uint64(g.NumChunks); i++ { // if collect sufficient chunks if k == numFrame { @@ -100,7 +100,7 @@ func (g *Encoder) MakeFrames( } // finds out which coset leader i-th node is having - j := rb.ReverseBitsLimited(uint32(g.NumNodeE), uint32(i)) + j := rb.ReverseBitsLimited(uint32(g.NumChunks), uint32(i)) // mutltiprover return proof in butterfly order frame := Frame{} @@ -132,7 +132,7 @@ func (g *Encoder) ExtendPolyEval(coeffs []bls.Fr) ([]bls.Fr, []bls.Fr, error) { defer log.Println("Exiting ExtendPolyEval function") } - pdCoeffs := make([]bls.Fr, g.PaddedNodeGroupSize) + pdCoeffs := make([]bls.Fr, g.NumEvaluations) for i := 0; i < len(coeffs); i++ { bls.CopyFr(&pdCoeffs[i], &coeffs[i]) } diff --git a/pkg/encoding/encoder/encoder.go b/pkg/encoding/encoder/encoder.go index b62853a0cb..ca01e81895 100644 --- a/pkg/encoding/encoder/encoder.go +++ b/pkg/encoding/encoder/encoder.go @@ -30,7 +30,7 @@ func NewEncoder(numSys, numPar, dataByteLen uint64, verbose bool) (*Encoder, err params := GetEncodingParams(numSys, numPar, dataByteLen) - n := uint8(math.Log2(float64(params.PaddedNodeGroupSize))) + n := uint8(math.Log2(float64(params.NumEvaluations))) fs := kzg.NewFFTSettings(n) return &Encoder{ diff --git a/pkg/encoding/encoder/params.go b/pkg/encoding/encoder/params.go index 84cf4bb025..df47c37e33 100644 --- a/pkg/encoding/encoder/params.go +++ b/pkg/encoding/encoder/params.go @@ -5,21 +5,16 @@ import ( ) type EncodingParams struct { - // num chunk meta - NumSys uint64 // number of systematic nodes that are storing data - NumPar uint64 // number of parity nodes that are storing data - NumNodeE uint64 // number of total chunks that are padded to power of 2 - ChunkLen uint64 // number of Fr symbol stored inside a chunk - ChunkDegree uint64 // degree of the polynomial interpolating a chunk. ChunkDegree = ChunkLen-1 - PaddedNodeGroupSize uint64 // the size of the group (power of 2) on which the global polynomial is evaluted in order to extend to NumPar chunks PaddedNodeGroupSize = NumNodeE*ChunkLen - GlobalPolyDegree uint64 // degree of the PaddedSymPoly. GlobalPolyDegree = PaddedSysGroupSize - 1 + NumChunks uint64 // number of total chunks that are padded to power of 2 + ChunkLen uint64 // number of Fr symbol stored inside a chunk + ChunkDegree uint64 // degree of the polynomial interpolating a chunk. ChunkDegree = ChunkLen-1 + NumEvaluations uint64 // the size of the group (power of 2) on which the global polynomial is evaluted in order to extend to NumPar chunks PaddedNodeGroupSize = NumNodeE*ChunkLen } -// Used to save only the Encoding Parameters which are key degrees of freedom which which other params can be reconstructed -type EncodingKey struct { - NumSys uint64 - NumPar uint64 - ChunkLen uint64 +func GetNumSys(dataByteLen uint64, chunkLen uint64) uint64 { + dataLen := RoundUpDivision(dataByteLen, bls.BYTES_PER_COEFFICIENT) + numSys := dataLen / chunkLen + return numSys } func GetEncodingParams(numSys, numPar, dataByteLen uint64) EncodingParams { @@ -27,23 +22,20 @@ func GetEncodingParams(numSys, numPar, dataByteLen uint64) EncodingParams { // Extended number of nodes numNode := numSys + numPar ratio := RoundUpDivision(numNode, numSys) - numNodeE := NextPowerOf2(numSys * ratio) + numChunks := NextPowerOf2(numSys * ratio) // chunk/coset size to fit into FFT for multi-reveal dataLen := RoundUpDivision(dataByteLen, bls.BYTES_PER_COEFFICIENT) chunkLen := NextPowerOf2(RoundUpDivision(dataLen, numSys)) // Order of the global polynomial + 1 - paddedNodeGroupSize := numNodeE * chunkLen // This will always be a power of 2, since both factors are powers of 2. + numEvaluations := numChunks * chunkLen // This will always be a power of 2, since both factors are powers of 2. params := EncodingParams{ - NumSys: numSys, - NumPar: numPar, - NumNodeE: numNodeE, - ChunkLen: chunkLen, - ChunkDegree: chunkLen - 1, - PaddedNodeGroupSize: paddedNodeGroupSize, - GlobalPolyDegree: dataLen - 1, + NumChunks: numChunks, + ChunkLen: chunkLen, + ChunkDegree: chunkLen - 1, + NumEvaluations: numEvaluations, } return params diff --git a/pkg/encoding/encoder/utils_test.go b/pkg/encoding/encoder/utils_test.go index 5ef8e763e3..e2865a2522 100644 --- a/pkg/encoding/encoder/utils_test.go +++ b/pkg/encoding/encoder/utils_test.go @@ -15,10 +15,8 @@ func TestGetEncodingParams(t *testing.T) { require.NotNil(t, params) assert.Equal(t, params.ChunkLen, uint64(64)) // assert.Equal(t, params.DataLen, uint64(1000)) - assert.Equal(t, params.NumNodeE, uint64(8)) - assert.Equal(t, params.NumPar, uint64(4)) - assert.Equal(t, params.NumSys, uint64(1)) - assert.Equal(t, params.PaddedNodeGroupSize, uint64(512)) + assert.Equal(t, params.NumChunks, uint64(8)) + assert.Equal(t, params.NumEvaluations, uint64(512)) } func TestGetLeadingCoset(t *testing.T) { diff --git a/pkg/encoding/kzgEncoder/decode.go b/pkg/encoding/kzgEncoder/decode.go index 468c74dc3e..52a46771db 100644 --- a/pkg/encoding/kzgEncoder/decode.go +++ b/pkg/encoding/kzgEncoder/decode.go @@ -6,7 +6,7 @@ import ( rs "github.com/Layr-Labs/eigenda/pkg/encoding/encoder" ) -func (g *KzgEncoder) DecodeSafe(frames []Frame, indices []uint64, inputSize uint64) ([]byte, error) { +func (g *KzgEncoder) Decode(frames []Frame, indices []uint64, inputSize uint64) ([]byte, error) { if g.Verbose { log.Println("Entering DecodeSafe function") defer log.Println("Exiting DecodeSafe function") @@ -17,5 +17,5 @@ func (g *KzgEncoder) DecodeSafe(frames []Frame, indices []uint64, inputSize uint rsFrames[ind] = rs.Frame{Coeffs: frame.Coeffs} } - return g.Encoder.DecodeSafe(rsFrames, indices, inputSize) + return g.Encoder.Decode(rsFrames, indices, inputSize) } diff --git a/pkg/encoding/kzgEncoder/encoder.go b/pkg/encoding/kzgEncoder/encoder.go index de71ec33cd..241a07ebf2 100644 --- a/pkg/encoding/kzgEncoder/encoder.go +++ b/pkg/encoding/kzgEncoder/encoder.go @@ -100,13 +100,13 @@ func (g *KzgEncoderGroup) NewKzgEncoder(numSys, numPar, dataByteLen uint64) (*Kz return nil, err } - fftPoints, err := subTable.GetSubTables(encoder.NumNodeE, encoder.ChunkLen) + fftPoints, err := subTable.GetSubTables(encoder.NumChunks, encoder.ChunkLen) if err != nil { log.Println("could not get sub tables", err) return nil, err } - n := uint8(math.Log2(float64(encoder.PaddedNodeGroupSize))) + n := uint8(math.Log2(float64(encoder.NumEvaluations))) fs := kzg.NewFFTSettings(n) ks, err := kzg.NewKZGSettings(fs, g.Srs) @@ -114,7 +114,7 @@ func (g *KzgEncoderGroup) NewKzgEncoder(numSys, numPar, dataByteLen uint64) (*Kz return nil, err } - t := uint8(math.Log2(float64(2 * encoder.NumNodeE))) + t := uint8(math.Log2(float64(2 * encoder.NumChunks))) sfs := kzg.NewFFTSettings(t) return &KzgEncoder{ @@ -155,21 +155,23 @@ func (g *KzgEncoder) Encode(inputFr []bls.Fr) (*bls.G1Point, *bls.G1Point, []Fra intermediate := time.Now() + polyDegreePlus1 := uint64(len(inputFr)) + if g.Verbose { log.Printf(" Commiting takes %v\n", time.Since(intermediate)) intermediate = time.Now() - log.Printf("shift %v\n", g.SRSOrder-g.GlobalPolyDegree-1) + log.Printf("shift %v\n", g.SRSOrder-polyDegreePlus1) log.Printf("order %v\n", len(g.Srs.G2)) log.Println("low degree verification info") } - shiftedSecret := g.Srs.G1[g.SRSOrder-g.GlobalPolyDegree-1:] + shiftedSecret := g.Srs.G1[g.SRSOrder-polyDegreePlus1:] //The proof of low degree is commitment of the polynomial shifted to the largest srs degree - lowDegreeProof := bls.LinCombG1(shiftedSecret, poly.Coeffs[:g.GlobalPolyDegree+1]) + lowDegreeProof := bls.LinCombG1(shiftedSecret, poly.Coeffs[:polyDegreePlus1]) //fmt.Println("kzgFFT lowDegreeProof", lowDegreeProof, "poly len ", len(fullCoeffsPoly), "order", len(g.Ks.SecretG2) ) - ok := VerifyLowDegreeProof(&commit, lowDegreeProof, g.GlobalPolyDegree, g.SRSOrder, g.Srs.G2) + ok := VerifyLowDegreeProof(&commit, lowDegreeProof, polyDegreePlus1-1, g.SRSOrder, g.Srs.G2) if !ok { log.Printf("Kzg FFT Cannot Verify low degree proof %v", lowDegreeProof) return nil, nil, nil, nil, errors.New("cannot verify low degree proof") @@ -183,7 +185,7 @@ func (g *KzgEncoder) Encode(inputFr []bls.Fr) (*bls.G1Point, *bls.G1Point, []Fra } // compute proofs - proofs, err := g.ProveAllCosetThreads(poly.Coeffs, g.NumNodeE, g.ChunkLen, g.NumWorker) + proofs, err := g.ProveAllCosetThreads(poly.Coeffs, g.NumChunks, g.ChunkLen, g.NumWorker) if err != nil { return nil, nil, nil, nil, err } diff --git a/pkg/encoding/kzgEncoder/encoder_fuzz_test.go b/pkg/encoding/kzgEncoder/encoder_fuzz_test.go index a1a72f6c33..56bb0ce5e6 100644 --- a/pkg/encoding/kzgEncoder/encoder_fuzz_test.go +++ b/pkg/encoding/kzgEncoder/encoder_fuzz_test.go @@ -33,7 +33,7 @@ func FuzzOnlySystematic(f *testing.F) { //sample the correct systematic frames samples, indices := sampleFrames(frames, uint64(len(frames))) - data, err := enc.DecodeSafe(samples, indices, uint64(len(input))) + data, err := enc.Decode(samples, indices, uint64(len(input))) if err != nil { t.Errorf("Error Decoding:\n Data:\n %q \n Err: %q", input, err) } diff --git a/pkg/encoding/kzgEncoder/frame_test.go b/pkg/encoding/kzgEncoder/frame_test.go index 53ced37e7a..28fdb4251f 100644 --- a/pkg/encoding/kzgEncoder/frame_test.go +++ b/pkg/encoding/kzgEncoder/frame_test.go @@ -54,7 +54,7 @@ func TestVerify(t *testing.T) { params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) require.NotNil(t, params) - n := uint8(math.Log2(float64(params.PaddedNodeGroupSize))) + n := uint8(math.Log2(float64(params.NumEvaluations))) fs := kzg.NewFFTSettings(n) require.NotNil(t, fs) diff --git a/pkg/encoding/kzgEncoder/precomputeSRS_test.go b/pkg/encoding/kzgEncoder/precomputeSRS_test.go index 46e50031e6..5520fdef51 100644 --- a/pkg/encoding/kzgEncoder/precomputeSRS_test.go +++ b/pkg/encoding/kzgEncoder/precomputeSRS_test.go @@ -30,7 +30,7 @@ func TestNewSRSTable_PreComputeWorks(t *testing.T) { require.Nil(t, err) require.NotNil(t, subTable1) - fftPoints1, err := subTable1.GetSubTables(params.NumNodeE, params.ChunkLen) + fftPoints1, err := subTable1.GetSubTables(params.NumChunks, params.ChunkLen) require.Nil(t, err) require.NotNil(t, fftPoints1) @@ -38,7 +38,7 @@ func TestNewSRSTable_PreComputeWorks(t *testing.T) { require.Nil(t, err) require.NotNil(t, subTable2) - fftPoints2, err := subTable2.GetSubTables(params.NumNodeE, params.ChunkLen) + fftPoints2, err := subTable2.GetSubTables(params.NumChunks, params.ChunkLen) require.Nil(t, err) require.NotNil(t, fftPoints2) diff --git a/pkg/encoding/kzgEncoder/verifier.go b/pkg/encoding/kzgEncoder/verifier.go index e01e7a600e..879f8df43c 100644 --- a/pkg/encoding/kzgEncoder/verifier.go +++ b/pkg/encoding/kzgEncoder/verifier.go @@ -41,7 +41,7 @@ func (g *KzgEncoderGroup) NewKzgVerifier(numSys, numPar, dataByteLen uint64) (*K params := rs.GetEncodingParams(numSys, numPar, dataByteLen) - n := uint8(math.Log2(float64(params.PaddedNodeGroupSize))) + n := uint8(math.Log2(float64(params.NumEvaluations))) fs := kzg.NewFFTSettings(n) ks, err := kzg.NewKZGSettings(fs, g.Srs) @@ -60,7 +60,7 @@ func (g *KzgEncoderGroup) NewKzgVerifier(numSys, numPar, dataByteLen uint64) (*K func (v *KzgVerifier) VerifyCommit(commit, lowDegreeProof *wbls.G1Point) error { - if !VerifyLowDegreeProof(commit, lowDegreeProof, v.GlobalPolyDegree, v.SRSOrder, v.Srs.G2) { + if !VerifyLowDegreeProof(commit, lowDegreeProof, v.PolyDegree, v.SRSOrder, v.Srs.G2) { return errors.New("low degree proof fails") } return nil From eff1389167476e91ccb5c47004191caa164d801e Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 29 May 2023 11:11:49 -0700 Subject: [PATCH 3/7] Encoder tests pass --- pkg/encoding/encoder/decode.go | 27 +++++++++++++++------ pkg/encoding/encoder/encode_test.go | 3 +++ pkg/encoding/encoder/params.go | 3 +-- pkg/encoding/encoder/utils.go | 17 ++++--------- pkg/encoding/encoder/utils_test.go | 2 +- pkg/encoding/kzgEncoder/multiprover_test.go | 2 +- pkg/encoding/kzgEncoder/verifier.go | 11 ++++----- pkg/encoding/main.go | 2 +- 8 files changed, 37 insertions(+), 30 deletions(-) diff --git a/pkg/encoding/encoder/decode.go b/pkg/encoding/encoder/decode.go index 5be424c328..257cd6a6ea 100644 --- a/pkg/encoding/encoder/decode.go +++ b/pkg/encoding/encoder/decode.go @@ -32,7 +32,7 @@ func (g *Encoder) Decode(frames []Frame, indices []uint64, inputSize uint64) ([] // copy evals based on frame coeffs into samples for i, d := range indices { f := frames[i] - e, err := GetLeadingCosetIndex(d, numSys, g.NumChunks-numSys) + e, err := GetLeadingCosetIndex(d, g.NumChunks) if err != nil { return nil, err } @@ -50,12 +50,25 @@ func (g *Encoder) Decode(frames []Frame, indices []uint64, inputSize uint64) ([] } } - reconstructedData, err := g.Fs.RecoverPolyFromSamples( - samples, - g.Fs.ZeroPolyViaMultiplication, - ) - if err != nil { - return nil, err + reconstructedData := make([]bls.Fr, g.NumEvaluations) + missingIndices := false + for i, s := range samples { + if s == nil { + missingIndices = true + break + } + reconstructedData[i] = *s + } + + if missingIndices { + var err error + reconstructedData, err = g.Fs.RecoverPolyFromSamples( + samples, + g.Fs.ZeroPolyViaMultiplication, + ) + if err != nil { + return nil, err + } } reconstructedPoly, err := g.Fs.FFT(reconstructedData, true) diff --git a/pkg/encoding/encoder/encode_test.go b/pkg/encoding/encoder/encode_test.go index 9d143f48c5..d30a7f8cb8 100644 --- a/pkg/encoding/encoder/encode_test.go +++ b/pkg/encoding/encoder/encode_test.go @@ -1,6 +1,7 @@ package encoder_test import ( + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -56,6 +57,8 @@ func TestEncodeDecode_ErrorsWhenNotEnoughSampledFrames(t *testing.T) { enc, _ := rs.NewEncoder(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES)), true) require.NotNil(t, enc) + fmt.Println("Num Chunks: ", enc.NumChunks) + inputFr := rs.ToFrArray(GETTYSBURG_ADDRESS_BYTES) _, frames, _, err := enc.Encode(inputFr) diff --git a/pkg/encoding/encoder/params.go b/pkg/encoding/encoder/params.go index df47c37e33..dddcde85f4 100644 --- a/pkg/encoding/encoder/params.go +++ b/pkg/encoding/encoder/params.go @@ -21,8 +21,7 @@ func GetEncodingParams(numSys, numPar, dataByteLen uint64) EncodingParams { // Extended number of nodes numNode := numSys + numPar - ratio := RoundUpDivision(numNode, numSys) - numChunks := NextPowerOf2(numSys * ratio) + numChunks := NextPowerOf2(numNode) // chunk/coset size to fit into FFT for multi-reveal dataLen := RoundUpDivision(dataByteLen, bls.BYTES_PER_COEFFICIENT) diff --git a/pkg/encoding/encoder/utils.go b/pkg/encoding/encoder/utils.go index c548f3e758..84460aed7f 100644 --- a/pkg/encoding/encoder/utils.go +++ b/pkg/encoding/encoder/utils.go @@ -39,8 +39,8 @@ func ToByteArray(dataFr []bls.Fr, num uint64) []byte { end := (i + 1) * bls.BYTES_PER_COEFFICIENT if uint64(end) > num { - t := num - uint64(start) + 1 - copy(data[start:num], v[1:t]) + copy(data[start:num], v[1:]) + break } else { copy(data[start:end], v[1:]) } @@ -65,17 +65,10 @@ func NextPowerOf2(d uint64) uint64 { } // This function is used by user to get the leading coset for a frame, where i is frame index -func GetLeadingCosetIndex(i uint64, numSys, numPar uint64) (uint32, error) { - numNode := numSys + numPar - numSysE := NextPowerOf2(numSys) - ratio := RoundUpDivision(numNode, numSys) - numNodeE := NextPowerOf2(numSysE * ratio) +func GetLeadingCosetIndex(i uint64, numChunks uint64) (uint32, error) { - if i < numSys { - j := rb.ReverseBitsLimited(uint32(numNodeE), uint32(i)) - return j, nil - } else if i < numNodeE-(numSysE-numSys) { - j := rb.ReverseBitsLimited(uint32(numNodeE), uint32((i-numSys)+numSysE)) + if i < numChunks { + j := rb.ReverseBitsLimited(uint32(numChunks), uint32(i)) return j, nil } else { return 0, errors.New("Cannot create number of frame higher than possible") diff --git a/pkg/encoding/encoder/utils_test.go b/pkg/encoding/encoder/utils_test.go index e2865a2522..68453dd0e0 100644 --- a/pkg/encoding/encoder/utils_test.go +++ b/pkg/encoding/encoder/utils_test.go @@ -20,7 +20,7 @@ func TestGetEncodingParams(t *testing.T) { } func TestGetLeadingCoset(t *testing.T) { - a, err := rs.GetLeadingCosetIndex(0, 10, 0) + a, err := rs.GetLeadingCosetIndex(0, 10) require.Nil(t, err, "err not nil") assert.Equal(t, a, uint32(0)) } diff --git a/pkg/encoding/kzgEncoder/multiprover_test.go b/pkg/encoding/kzgEncoder/multiprover_test.go index b3bded5163..9f054028b5 100644 --- a/pkg/encoding/kzgEncoder/multiprover_test.go +++ b/pkg/encoding/kzgEncoder/multiprover_test.go @@ -27,7 +27,7 @@ func TestProveAllCosetThreads(t *testing.T) { f := frames[i] j := fIndices[i] - q, err := rs.GetLeadingCosetIndex(uint64(i), numSys, numPar) + q, err := rs.GetLeadingCosetIndex(uint64(i), numSys+numPar) require.Nil(t, err) assert.Equal(t, j, q, "leading coset inconsistency") diff --git a/pkg/encoding/kzgEncoder/verifier.go b/pkg/encoding/kzgEncoder/verifier.go index 879f8df43c..eaba679e48 100644 --- a/pkg/encoding/kzgEncoder/verifier.go +++ b/pkg/encoding/kzgEncoder/verifier.go @@ -58,9 +58,9 @@ func (g *KzgEncoderGroup) NewKzgVerifier(numSys, numPar, dataByteLen uint64) (*K }, nil } -func (v *KzgVerifier) VerifyCommit(commit, lowDegreeProof *wbls.G1Point) error { +func (v *KzgVerifier) VerifyCommit(commit, lowDegreeProof *wbls.G1Point, degree uint64) error { - if !VerifyLowDegreeProof(commit, lowDegreeProof, v.PolyDegree, v.SRSOrder, v.Srs.G2) { + if !VerifyLowDegreeProof(commit, lowDegreeProof, degree, v.SRSOrder, v.Srs.G2) { return errors.New("low degree proof fails") } return nil @@ -71,8 +71,7 @@ func (v *KzgVerifier) VerifyFrame(commit *wbls.G1Point, f *Frame, index uint64) j, err := rs.GetLeadingCosetIndex( uint64(index), - v.NumSys, - v.NumPar, + v.NumChunks, ) if err != nil { return err @@ -87,9 +86,9 @@ func (v *KzgVerifier) VerifyFrame(commit *wbls.G1Point, f *Frame, index uint64) } // A single thread verifier -func (v *KzgVerifier) Verify(commit, lowDegreeProof *wbls.G1Point, f *Frame, index uint64) error { +func (v *KzgVerifier) Verify(commit, lowDegreeProof *wbls.G1Point, f *Frame, index, degree uint64) error { - if err := v.VerifyCommit(commit, lowDegreeProof); err != nil { + if err := v.VerifyCommit(commit, lowDegreeProof, degree); err != nil { return err } diff --git a/pkg/encoding/main.go b/pkg/encoding/main.go index cf57f4d757..9a71374f16 100644 --- a/pkg/encoding/main.go +++ b/pkg/encoding/main.go @@ -75,7 +75,7 @@ func TestKzgRs() { //for i, f := range frames { f := frames[i] j := fIndices[i] - q, err := rs.GetLeadingCosetIndex(uint64(i), numSys, numPar) + q, err := rs.GetLeadingCosetIndex(uint64(i), numSys+numPar) if err != nil { log.Fatalf("%v", err) } From a6b985313e16ad7267f0a085ce89a231844e2aae Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 29 May 2023 11:34:06 -0700 Subject: [PATCH 4/7] kzgEncoder tests pass --- go.mod | 6 ++---- go.sum | 12 ++++-------- pkg/encoding/encoder/encode.go | 2 +- pkg/encoding/kzgEncoder/data/SRSTable/dimE32.coset8 | 8 -------- pkg/encoding/kzgEncoder/encoder.go | 9 ++++++++- pkg/encoding/kzgEncoder/encoder_suite_test.go | 6 +++--- 6 files changed, 18 insertions(+), 25 deletions(-) delete mode 100644 pkg/encoding/kzgEncoder/data/SRSTable/dimE32.coset8 diff --git a/go.mod b/go.mod index 5adb2dd476..08dcc30625 100644 --- a/go.mod +++ b/go.mod @@ -3,18 +3,16 @@ module github.com/Layr-Labs/eigenda go 1.19 require ( - github.com/consensys/gnark-crypto v0.11.0 - github.com/ethereum/go-ethereum v1.12.0 + github.com/consensys/gnark-crypto v0.8.0 + github.com/ethereum/go-ethereum v1.10.26 github.com/stretchr/testify v1.8.3 ) require ( - github.com/bits-and-blooms/bitset v1.7.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect - github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/crypto v0.1.0 // indirect diff --git a/go.sum b/go.sum index 246b38c732..d6be6ca94a 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,19 @@ -github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= -github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.11.0 h1:QqzHQlwEqlQr5jfWblGDkwlKHpT+4QodYqqExkAtyks= -github.com/consensys/gnark-crypto v0.11.0/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.8.0 h1:HHmhTEzHq6k/fJroPGzq8Biafn2X2IFKlKDhaL5gMHU= +github.com/consensys/gnark-crypto v0.8.0/go.mod h1:ZTnSzNlt98CpwYIJyk6q/KVcshYWr3fOXXFrrY8a0QQ= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= -github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= +github.com/ethereum/go-ethereum v1.10.26 h1:i/7d9RBBwiXCEuyduBQzJw/mKmnvzsN14jqBmytw72s= +github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= -github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= diff --git a/pkg/encoding/encoder/encode.go b/pkg/encoding/encoder/encode.go index 494e40edd8..c47e0d0057 100644 --- a/pkg/encoding/encoder/encode.go +++ b/pkg/encoding/encoder/encode.go @@ -49,7 +49,7 @@ func (g *Encoder) Encode(inputFr []bls.Fr) (*GlobalPoly, []Frame, []uint32, erro poly := &GlobalPoly{ Values: polyEvals, - Coeffs: polyEvals, + Coeffs: polyCoeffs, } if g.verbose { diff --git a/pkg/encoding/kzgEncoder/data/SRSTable/dimE32.coset8 b/pkg/encoding/kzgEncoder/data/SRSTable/dimE32.coset8 deleted file mode 100644 index 28b88ec50e..0000000000 --- a/pkg/encoding/kzgEncoder/data/SRSTable/dimE32.coset8 +++ /dev/null @@ -1,8 +0,0 @@ -c68eede15b1b87692a19448ddc7ef1e78338c5cedf44c62c008802a97d73d3dfac2716110a1ca381149601688443a43d75c9220475dd338f20be0d72b68514b8dbbba8ea97963a52ee517b89135631163140e9c9405c66b1cb6d5a41d36ce04da9e727bceb6a2946d807c0af143128318d7c7e9ab18c8b4335efbc8626014408dd027f825bf8e230393bcc0dd6b34d58d50a2bfd96ffddf4fe6f7fce4f1cf19cecf1a46a79d0bd4e843bb66b6219d585a62aee59ba800820783942d4f9b1d4c0cb9fc311c2d5057fb65e0bb905a0106ac9029a94002dd12f677c271717f12c0688002c8a25e7297ec9b43532474ae37fc97a90c354168102bf538e50e0d79b43eeb3a11079b2188e663d9902865edbafd20b7d80627e06dd34d05b5dec84a694ef7012f22657815b06c8e042f2ac7226653d2e414df069f69a9e17547a70ca6ca3e868a7232e8aba30b0b4b300e0a7eb6f8fe7cd9089f0688df78d69a767037588e076d9321c9a2cd141057313a879977a7eb10849bdf51a3b068f4ab683ded6890c43592033a06a4fa184636885c51b658fb8c551988f5cae5d8d6f8b46d30d9a5f17b424304d1b95787165c1d31c8766007976770e2f892bf0368b31c0592f92af3f4b057fd84ed6eb159feaa405d60355a85bfc4deb050cda859dc77ca35aab84807666bb977c7a6e9436089e9973d20d3144eeb754687a4b26fc2c1893c1d1115208732e60b2c449cc888eee48929750aaf011dbe13c498f6f4fd32451fb9341b05fef893521aeae46a8f3d929f1a338ae9e085cd355f1b7868ce6dec57acad92eace022d6bc822ea05b5834528737c7f3e3ba10e4d89878b3c321d5cfb6a7776ea59c00b844c741376f32e76e957297bcca37a04269e8321c307fd325e2acbd5de582c459809010daea39e382180c5c2394e99d04106b70dac7593cc07a80a82229ec628ac52a8d54d4d745b6aa4275eed45aaf0edf04045b44b3671a169cb5eb29ccffda263895c256589ebfa7c1fddf0bfb2cf4a59ccd827dc1b151f6dfaed083a6aaaad98105ea69ad5b431f94b8919fae84317cff7713475ec02e42ca9969534ae3201ee24b526322197542c72b4077831f131a91505fd41fb0a486a72f6e0a5a11cff946a4a603dad1f6d2898e68a58164d5c2fe2bf0630a0c765dd1d79fa43acc24e42748623e49b1849c6807c51d503e593abdec6d48b1914c3eecd3270e29a09c62a1a44e7695d5ca68d82c5cbb6abb1b7d29cfc5571c846e3ece0d8b22942e1e3b81df3a024918b0f1eac32cbdbdf7e5be94590c9c2c8122b9c72f1574cd14e036176334cfa22c9275d419be699d824c7afe1641efd00c28bad0d20e71487823ba69fafa191b2019cbfe7807ceeaddf224fb4100371f941b1e97bf771fc20480902df7636517404ccae16c8248889ea311a5d7daf092cfaf56d36476df662e9db04901169b5d08823d413a1bc2f3b0785fabbf24eeb7d095d5a0e2a22178d9bc8fa8a8bd349842eed7a6bb56ccc984a20d31800d69e883726892f721250c35c896186d924b8234392442bcb4fb7711facf60b41172757d38e38cabee5e4fc87ff800df81063974638e66fe146b719a0da2b1793096ff37536ee9016e7017576c8f1bafcd2c4bf4bb5c6fefc724932c08e3fa5129b074c8b33eef7b18735589389240b0419b2631d307ac94335b2ecacc468225969aabe529958c6bbbc5c6c1b4dc18296024f2ad6fe32af098cb80ee3690ce65af589334b52584bfef9a1a1be412de4c6dbdb686b98488f751e2c222fb22849d030a9f39c64192c6b93a041600c0f81c734007b1d19ceae1c39d45d7c57cbb7953ccce651237a8234c88dd813a37a1c6e71f02271859044a871c5b8c7fb80f54564033aa50318004c8856b936658dcd835bd91c51fda34d7961096d8ec47d14bcb3542f86883d2d20aa17df357da75bfd06174d03206a97cee4455c7a41ff0dde9acd6ce6478d0f0f441c3747f31c6141b94263e051c0db34cc4ae0cbc8402e33c60ee57f4eea0454618fda94decdfdd5072426051d4566b9bf6c5dfd56173340455eea1d3c0e4c0deffae98b5871d8641c9cc707841895bedb79a5909826a0ee2a87c0fa61c9222bee22cc6a002e000a41aa15204e864a1b5d45e25cb5d0a8b431482bc69198979afa1c9d88e384843015bc115766faa7c07af35141eb7876ee912b8fa5b99922112a2b544a1d6fa44643e71a0c2d7506562207d3713924c9b2dea87924b79e8a4caa125663765904989eb906e483d7edb906bd9cac89111b4c726a2d0661c99525e1daa73d589b24dfb7a1c9081e79a100342da89277d512c2a492f442156cc566e18919a5c38d15417d67451039f1054f02f27e3251276bcfc63c8a2b924ce11a0bfaf386c8c07df2f8f51ebed30a635b2cdc24ad4972e9354daf08d6e55dfa74ac7bc0e8f9079d51c40bf04952e797186b1345e0fb5275ff30fde61e72391d0fbe4986b5ee0bf9d7ab38236364d5fd4412d62702330edad87d4ae87b4618e1db04220687c35902e4ee835d6dc47c584392770007f6539ee80bba0d9184faa1e27f2d6131d8950f7a83f4b32b2a84fbe7e2796e981b98f4862b8669ccfddeae0d7e447cf536be3b4e8e4541825d3ebee4852a00de38736a7f79f4ef9a7dce2922cc0135e1b28e54fd71ffaee96fac6f2cc19fdd8783a29815327fc621aa69ae93cf655e822289a37f0b3453cb9b6db0066c1b70dcb6678f7afda8c8c51c4868c8f24e2c972b3b122532fc8d880440cbea140dcf714d79352a6aa0028b941e79f2580ff043af9ab90de4877224cae13c348991f6f51aa1dc5902dea877b8e90868450e0229bb8d2cb1e3172aa69f157367c771911d3b60400eed2f958b9d1 -ad4ac604b73cb7448c8509ca8cc2ca1b7e84e798356ca0cceb306aee4b9fbdc3acca09df96f555100d7a297019ef38ec6e0178c1f6f1ae84299e0753e215d4629ccbcbf480789391769483698e1f2582c23c4729e7b3efba785f6704ad93ceaea09cfd5a091799504673c31f2b66bd01f6fc688c970dae1c96d2520ffda1d4d9d2b715d3a24498863e737bfc10c32165a6399f3962ccd2c538bdf720273694e796c87df06e9a979b26626dcca19facd71ec208e8a696e67c873abe06ea98a99e9cdfd2c4fd7a71563afd5a6f55a0b3ba690cbfd7253c32ae609ce9f3af0c12c685096de245b0fc4c59d72bf99d13298b557856a04b5ea0b5ef140dec204f71298a2a7bd24263c7737f4ab46a19cb8cd49d79d1d41507dc537d6aeb6ad284050d99d8e5890d20017d61f429de40432d433459a2b2c634c69cef34f3680e28b22ca5cc80291054006ffd7bed642f500f797a9c1dde29461450a464a57cd94fda37a2133de8f2335b2c7c44d64376b733665ef7e0042daf54d134bef1871a2f1e25af8485eb09cc61df9edfc682477f549ad729c69aeaa404cd60ee24bad36d78099fdbba1fcb0148efdad3e01d6e907bfa69362c491add5ec924b5e21b3c92bd56ae051798a58ac52c7903a88b7ba897360233ae430fb63620f0c59e7438fb7fb3d7224b830d39e2e649bea1d87c2dd97360f96dcd5fb79b0eb2d1c9931f95eec2ad87139f25d40efb61350a4fe27df6601ac5492894ea7950753be10657836b83a7ffdbb96e4a313466b6f01aba148350f35697daae1fe1cf26cbababaea11f749023459921678ec1bd9bafe8fa44533c2240035d7e6c19193cd990daf0bfa28edc44b436faa54d7eded9584c8bb03c1ba482a04769d6c078b8856780e5fffd1392c409a14805b6015480d1484de143a26885c367defaa1339216bd826e8a895cc93c8fbb297a517f6823f5a64aff0f2616bc6ebc4ae571211cccdab8289b9858c1117863db8b3e1aa28efbe0d22fb40189b952d8a0776f2afa24301c3c5a3458a5049d715fd11e5bd49afd80c7152b431b506710a61f43a9e40902a984c02eb5a750dfaba5c3b54efe8e14b45ac2368a2a32c74b72cd200b777041b8bd9293ab8d1d36e6bf726710eab8d8fcee818d16ada04adb7d4d4904c0dce0a40aafaf8de284c19b7efd86a56a5b9688fed79f29b99714cdd301b23ec58285f029179b34dec6e62a6a13e969ad8efb44baed4e477db377e5d44c399b1a3f4b31f04f88d7a796a2951139f11642c30014f4abdbd6105f828a39359bc19023afc66048c9409607c637d483746b8f68702c69d6a2518b366fe5265b560cdddeba985b8b6272ec1a1d250a7d1b6fe317a34d74e1ea9c59e4f0b2d8368eb5c7c7d17405d78079c510b4a96d25f494c6fd9ff4c9ebf67ffa503a079b8b1ce7bfe5b44a74a5706bd63d2f32297902a99d3ce9788362a1060bdb378276684abace3863170d7c2b99cb79cfdf5ea19197a9ec8339e760682fe2a88d099cf6e3e7c72157bfa27b31a2ae1c05614b2c560a0f8edca2d8ceec54e6bb37c70a8c5a71bc930719ba31d77ed55ddc7a2a8480be9b7ff2481c70df9c933fc20f0f3d214f95ac12e6a5241756e899b47704b015fd9b443bced625961d729596fbdaa9e32685172d9c0a13a3868ca8162eb5621396bb865c9c1c3f023eca03f52e6a348a643039f5e9c8fd1eb6c9f0ad33d9cb6dafd01608a678e87e7fe9bedebd6e72246abb26ece3dac9f650c65c8ffe9399d1e6ff2bab94c42912ea862a20729488c0b8ef2994716f115afa8272f83d8ad98e512ae9a1b872f4c39ee7e4907a35fd0d36a7130f5c497ffe86ef0b3d92369f627da3a6cd0ca50b124a9dc8dcbfcdef7ebed0af4db2f77d0846c89645788b9a39ceb6566e98d79f0bcfff4901060617e60b2e3838f64c79e6a1c0cddce3361be163fcb1878634ed0a0dc7c42b8384be81d97eeb2ccd3e1d57588383edff4c68e425689ffc5a53173941c25d86afa8ce71caecc52686e06a0b978367fb601769974df9ad25410966be28432d63288704eaf5d213b27926884ad9c5b76f7ae448670fc783023f3072f8c1e9a1335519c3488f6db853ff8bd2d4c4c113f9fda29910089593501484cfac57b10f54042e4a721e544fb9c7d5d78791a038e2605c7586c640b775e98f60bc22f8a26713edb9c6812eac0c1108a049c0c92ff876b12b86ecc698a325f842debaf93135886d88c53726f43cf4fd95d8fc813312ddeee9e139cccfd615129bc81c81d17ddc44063058efdcdfbe2c89776da606376ddb38f4484b430e55180a224ca22065e0c8dbdc1cd8cab18c7639c47da4b0b88bed6739cc8fe2a667cdebeffdf006cd78de39feb45114ee7b58bfe5bae7a8c30a0913d30013faf7196de3100a23966d3d0e471bca2267f77dc6e1749a85f0f35099faa295c0fa4631e8d483d88b91afc22993b676b50e08f3e4e5f8f2c0c575cc30d1be34dd9d9e90f5fda709a2f578cc1031fed81110bd86b4099b7ac497532ce472c8c8377aaea4e8d28d09c7df4b42e961e7b53562b0b3749ce1e5e60cee28893ca5ff76b355070b70ae267421bcc0d263140d9a6c31348c2ae7ef8a535afb8e99d8e03e157d37ca67028b09d7f15bbb687304849c6501d5931776cbfa94ca29ab214383a83329e322a514141257d1b7734f26c6bf28d489e65b52ab52da2c8efb37b4d9081361ef0f56afeb4f831bf2b6170e8c343532bce9d7bb8aae033754ab4dbb949f27cb8e0af0f85f0f245c4afe531a1998ef455793833aa99aa8b542311224a2e4a654741df676a955c7ad1a5b20456b34c866c5c54eb59de8826acd5827a200aadf2a5400e50cdbb958c2216c784b6fa6c0da7ec4d529 -8098de534a60568bcdb2433502d3e46a062a22c3f688a3c6fc5089e78929c776883c2dfbe70ec7d25b90e27eff70be131c0a2c7fbc29bd018167f43c51b2a643e02d15d0d92ea7bd77bce8b1fd44183eca159a58012f3309aaf9bf1acb16a4a1dda2a61a3fda9eb7bfb9db2d4348595195e9ed23808600f28ce12dfaa1310ee5e98cc00189f7e40adb773b79990ddeb830ea4777c58c0837c16c27bfe124e135de622565325399b1748d40bc8eae8734c89160ae17b2f9cc772ec49a1e410044d20016a9915591143e6493162caafa8761af8a910a02db02bf0a05b26a57fa8be58ad34a274f91d6f20b555971693dac849c673ce7c34702bc14d78daf32e534c56ba5e8daec7d9886fff5b5b89ba10c64087b8490f23af58ddb67898555c360dc2187d7ee7029e23ad9ab09c25de0c59cdba8f5bb15726ed6d67e9b2ce5e8c3dcfdcb5eecbc409b6ce95b54a6f2977634985446103054ba22d92402069f53d2ac7db9215f9a18d54abfc4251448f1f2fc1b1f56a4e050916e83d47c6565ea2dea836f15310294100a9fd9d6a0ff53ad919de7f874cb872defdd74adefbfbaa9c1e38ec16eef65eb7c25d5060d5c9207f3b527b5ca050f470846f7ac8f4d80afd6e5e3c6beece4ffba78408e3d563ffc164112d36454669bd5aeb642ee33d78c9fabad1449ac7a6e8fab4c7c35cea4dfce3f98faa736d4c6299839a88139bb1d84232eca4d977bcc5992be4e84f11d774e21b150c6fc1c584e1b4c8d49f51ccba365fce005220e94275e8ec6125987d51e6c3174d72cd1a0693499decac82b02d3373e93cbe51db643136220c69a1bac4fb24faaa728cda1b94526ecec7a8a6b9fc0a2b6345f832cf2de97034326c01cd22229d06b4735723ad46e3359a834a399c0ab8adc6fe2089eac69cf6fe4bb65dc71c8d8a7b128b2f90e8cff83937144912fbcb7eab2c32d061d60fc91c5fcd0347eaba4fac1b270cf62b007f776bc3dea43d114d762e43b03f78197f1ae5f234bb8c06bcaeaa3cf7a0c129a131d247ddeaf82d92daf83877c90911a550db6c41aff4ee125b5e3c9dc26432433148951d132f50bf42624fe83a829ca7ce8d7bad9537cd80372e7549fcde9fcb673868ad707aafdedc7d102ad60225561837e34ce882e0428e46499b3e7bb86295c78b68599a50f6ab3fb04eb438666b0293f577d6df83c9ceffea770a2a093d4124935a600dcee3a454c584b77b34e49d5a4800d050ab06854861d7d01e063579b2745e562b3d5fab74157f4d05187892e334633fb323dc8d68baf2b6eec56b37e40b7d44b8b59c19b7fa98f7ff23307fc68acdb5fcf6cb5fcd88facf86b340beac763efa1fa4405da3d6e14a20aafd0f1213f420aed878a013b7d62e3dc0066af5cfed61339e36920516c82ea8f472f26f4612b7c9ad58980c544810cde213024b616962466f5f5545e37c57ab779daff2ed9cc2fc8260764cae55acf5e143dcecf1a8b3abf23855e4d6ad72d29c7cdc6b94f9e93972671ada19f2a7af67e22773248f0507b4eb1a97ee44746873c8b1ae007b878ae727515790815970fb1a16ae07aa388019158143558546ad1131eb79d7a3d34e80a92c6f01b6cd2eb0fb84e9bbca2411d6642e8d9185d563b8a50c8bbab26cdb903cb1c74be36eba15c4723425d8c6ce85e3b51bae754bf7fb490554dd2ef8227f72ea1eaf305b413aa45ce4c73dcbd1f58890523e520aad0ccb0e92ae78cdfe8780472581374cf12da0c87480ac58659c9cea2cdb7dd6d031d06a83fafc0c18e4f79f2d65734496c46dc44b211d4947574c16f646deaadf0b0c28a23714ef2d7409141a5305c4a06f46d942775c8fbe366655f54ec209880dc66b43ea18d2ed68256319555a8654332833ee8d4c6e42520f5be9aae7341f15e537ddc6ece66b2c8454c20a8c9fa743004074bfbc5dacc1778288ffe5e274108d4bb7ea78760c763e1eb00757f80b904058080d590a55568da267d79d196b02116dc0b085edd6fca29015f0cffb3d4560c2f773dc4991dddaf97058f2f40039c921c7331945280a4d3c56260768ffbacb245cc1dd3d8dbaf71f4d58095361bc5c638a54652c65b521a4820dd1ed4a52681f35d8eea290eee6eb9839ab44b28f0125c9f716a336f4fa7c5276aecdeb354e638b250a35b4de158683181ed59518fdb414668f9232cf6d0c2d918ebe233bef25cbad3d442593d4ba9f139ee571b7b3f75b2d858f03a733860f43415949550d3806f7ae75ff21dfed8669e785b9e1058bcbee4bedf63b815952e1dd90a73b8c58c9999ecf8a0d3c55b56a0545d9cb2ff9e88058a3a40538a13b257391498212ccf07b6a502bfadad52126acda9f338db6b429142d3480ca6e6b34e3c55c7b70b0ceea5ea1ac69b8328a2b2d794734246ae1611e7b8e922731efe3afd58d5a9e8acd41fa1e41b5446b3ee7cccc3452ae8701aa650346db23e3d2e903840760a3f67c4cb96aad395428c4407a971b26ae0e12ca797cc623a4e67481184d9c25217e98b15c460f4584db236e5a72d602b46ed5c8ce307da08aa0ada39465812f6462438d0cf26dd1947faae4d957ef37249fdc7063f53cd85e6305db5ad061c750bb1cd5a896d9d7851f4bf1ed8e2cbb2d9097bd24d00c83ce863ad76d97d812041d9ea63cf26d8443e9ccc240b911d0739feaeb34f0ef3c13fc4d843ef785e2bf0862a34e091075207957b4dc29e69b1ee96d20748c81c4204feca12ac0592a6c8881b8e8683ca83c67c582e9bece556dc515a9676f70bb1972c30fa07a70517816853e597edee69a2a5b9a6f37bb2b0dcef1f66e564ffd47e5c8384e74c7fc15279a257d92c6b3b7839c4fea002d2852582d3b00ab71eb522e9cdf6b887958e408fd546 -d7791c16ffebce4d03acf0413c229c3e600753ba9d6ee781761316045efb4bec813318d8024f9e968dec113b19fb31b545304d09b31cea0ffebb083df46d7b4b808656b4a130025f111f37957bea256b1dfda00b16dd4b91e886a4a9d6bf5156d77dea70934bcce1733ed43b12139dd302c853352140be60ae06646f1b69f44691abe45398c9b90fd845d330aee2b08bab2269dcfecfc9978d6c3801db2bb399a7f246b49ac031d746519d8bc2a3cc81339f6c931e6e1055890ec7bb147bea7ede0d109998f752592b5a378c275910188f4f47cca639eadfa4c137167e99607f95451fb3c0526c33ccb1387e392b95dda57a588812542b0c783c1865442096edd619277f4621404b1e6b94160d776cc78bad280e7dd2f794739496edd4a293abd91d3e0c9c3fa1b04a49dd83870392cc1ee01b75b7d4b1b7e0f3626b5d2c1c509c4ca49cb614b51fa27e4d85c484caa4d342895c6626a58791252a4d9890232aa9af92ee05e1330cd692f6ed6e61e59e7d716bc13b80f1213aa22c83094c0415984bd4b2b4a638249a8c79c2b4e7dbff53c629f0fa08fe1cb26ac377a65c8481e0edb8d026f8a9abfb854b40b1934488ad8d6d503dce65c24b638e67fc2ce479830adf7eb8ad2fda0cc938276b6d6edd6259ac92ca2ebbfd5bc2fa4a9fc337af82750aace4da56cb5b79ca441dbbebeb8c0b80fda5bbc2af09bcd3b666115c06c0b8486464bc6d305be66d3efd0a88e6877a22ce8ddf931dc2311f3bc6ce0e908836d0c22558312e784fa485c569b0f92c8d7ab936d015e130b10b6733338d1f9a9c90f1d1cd6d3d226cad88e97e597133d0578b68cd5e14bd22cba9b57ab20fd96755961d6b16864ab9582967ba85ae99e565662f9c48316a7218b796731d19c4b787e03244f506fb6177fe7e130d655e3336dc1cdda578ba257fe8eb2c7840ef7b6421f6faa932c33eca0a9bce9a33aaca330f70a08c0279505ee45ea6eba3888e69541c999fbc2030af88c572e6e5a0a86d3b7cbe1e653c66108c3fb496258f598b1f9558d1ead1ced20ad153f21560cb2652a00fd963aafa00d3cfd85a6a9c971b2e0b1d00f47361ed508b71f39a88623e02edb956cc4d8fb3bd6328c7c591a120b68dd2864a93f5e9b5cd7721d748acc794b1ebe34151e1d98e56c12240cc5cbf019468f2018ef9d21b35872882e1f513526ca6ada67ad30f36f3775629c23251956a98d46d96936748b1dcf5f6a5877b2df15a4e120949e54651136513e6e4799aa472ecec59121013c3f2e5198fff9752d612f3f4d2422c233e58c7cb9c913f878a88383e46bae91c0a6c11ffeb614854a73355f0b2f4980ffce24e76ab549c37322f72870e1e585a22e265471a279377e75202a867b7dd056db3afe4e2c84ce82290b8f5ca7ba4268b664dab3bc96f461cc9080ad333ff213ed04998e1550feb7dcf458fbe0f322628de1a484bedc0443702a5db009bcadb6b98b9a2dea19f5e033f98caf5dafdb937b96207da6f801308dbf4f073cad87af819ce2896adc7e9948bc47854f87a0b98800e702b08d47fefc605c967666219b81273ccaeb4a11aff9f71d48ca4cd8f87cec94e305a185eb6e6d88621cba312ea79bab2e88a0eb1cf8e92fef0b46c9a5a5d4a43658ed3e8d847fa07b4623795643a38c797cec153f5fbe843341f71b612853f7a6c11371fc76fc20641f558f743a7ac4def3795617a58d69a36a56c6077070bf85bb5987f5acf27dfe535095120a73289e55360c52861ea2a13b88555ec4015c88c632dcc53e2beffb89baa1388f7487185b37005f7f0bc6f40e654675de2cbd246cdc9d3b82a6f1c000a24e45b1e1415800d28e5dad7c9e7acb74a733be1d0341f160f3cd184bc164f53644a3f79ff25a7c5a40f0ae926d426b115eeb8f42ab20f16c77b828fe86c6b062818596330e8dd8b94347ec76e5acd34b5b258aef457fa6f8ce4fcb6c2eef1e3ee57e0ff86f8cf1729eede14d154adfd33b25f4756861f89185efc7daedca8dae4c6ad45259dc7b7572ca74c6c9f336c6bb5c71d2346271ec5f8df85754278b8da7c6143bda795a83a11dbe0a4758765bbb567d72bb60a4f9b77ade67fda6e47bb4da1ebbaabcc83098b917af6bcf9a0e62fed93040e50a2622eb4b04626bec3e7d7a88f00bdd2855619b7237e75aaec0524122073fc2a3cfceaa2858c483c895f1fe4d6eeb581d76d09230557a94768181082d268005cef97a3eaed631c5ac202c35137b37bae4fb541cc0a913225e45a14607725dd4adb85e25b29efd6685bbadaac140274cbadd49e2a3deeff58d6f7ebc80995b702b7e2ccb34d052084f49f586953a0c3e9a03b3c27ad879bc5869ae9ba8580fbefc1b9843fe84625b9f6a8a5a5122b9de68a8178c21ef17d9bb6655a060e724a8d688b975d5d813f2dfbb5af31ff26c2dcf15410751d7ce00c4507402411d485ea3c64fb0ad5b218944021f7cc0dd1a8dbfffc31a0f32ae8f104827c0b54b4833e08f312301ef0e3d2296dc14094d484a80c64beccd67ed6ca5fa0629b571879d5e47bb0e3421e22158db7feef0f31ddde2708d16dd5dca4f62f748a5656139e5b10c1648b2b0635e456591baf7340619e131768826736db729a473399ac57b584893fcd74d8e2367ae34b379fcb6940c167c02e2cf970badc58ae153610b90f4e4d7febcd5d354d5c835411663c847fe2a82147132eeb1dc73d31ed994994bd055490fddc5e3f7b03515cee61bc2106cac0f1ecdd158c304dac32c57f64be65775703a5810a6b1adaf81fe830b648d1c9b30e3e86c15fa69c531726f6d8e1a1a5299a63b1361cde9ff06750bc1c1633d2d584a6e338e1abfc0010b8bc47223260fbbca07104bb531132ad0cf549ca3f -93749f0b9b8210e62e18a84b518e9609be161c091a1930ec954913f74c2d5605ea4c1cef1e46aa33c4ed62b3659c67d0bdb64f90222f70e0b82e77f10965ae4cee41a9ce7e44fdb436dbef60ec543457618fb4f8891df4ca1d76b792f786ec64c1c1a842e49f28bea092cfefcb2ac8f47b86b590cec397d8d09e04f56bf78238963ddd9264943dce282a27a30db4a1f3be8e8c9ffb40bc33ab2743900ef1d6cda1bb8842ce35fbb1dd50292e98ec2d5091ba5334acf1ce84c36502c8f3c9a1f5821843ce3a298633c7e8969967f3cd28bfba459466588b77ecd6aadc8e431192d2979498e8429274ccb864d3799ed0551897106c6b2a4cb15d449a704f344511c4d57ace789cd73999ca39245d195977122c1ffcfe1eefcfdc25715066198236c3afe9178780ed6702f7b3e22db1832c1a77ccfeaee38d9b169afe78493fed59853091b7f48ab2463df19bc078eec63f029df4da13e783cb5789b21cb2a25350c84b18041f69ce5ff5971fcd9c2d5926835b5146fb8a1cdcdaae26ad69cf5d90ad87c47ac105af1ba34408384588b323e3900354afc7fd503e64ebfdb5e6132998357a74fb58b874766efb79dd9bda23378dfd399b4ae0d273bf76bb31cb1f1cc1937c5ed84a940dfab325ca9b4bc8ec280bf6c47aca6cf2041afbad9d4ad808acd4991600a1e0df97ef8208027422deaaf875b372060b9849d3542ad5e65642a1b0d167b1b34243229a899cefc2f81bfa9a5f0759c78507c7423fa3cb3afa52acdb5e7a4095f53f384a6296009e531b3d7c49c194cd0630efd17b3f55d648108a8f60f46107607b14b19e8e841d7662974b1c5433d5295ea5de18f74418bfc489785c3bed2d7f06c446d586f30c5842d2cf56dcf59a8b1f665901e466737d38917f80f5041de39a093b362ac9d588659b5895903e43ebcc0b2295acbee2f7f584de6b3697713f5930ec97c879987617d0dbbd2d8657cc73b3c49297ed73b2f5efc1ff8a40c89fd9497578f0e22f82c11ad1dae478c69675d04ec21739c6e8518c151b7f1bd05105d4227c66b087f625bc645654c0fca51ba01a1e2118886932e684d6c96f6ee147c228eceb8f5c8b2c52d670e6317061d693047b92cf49ade78df1577a6ea4bdce2db020c64c6aefefac00a6bc07fde75fb20ed0bfb86223f0a801e84d6490727c0b3735026775dd21c32896c1c78ef5f5cf1c6591e7bdcab0efeff2a86c65f5d941d708684148e89a9df3515959786b5aa0050fac57dee5ea891b9e397fc66c325f32732ee5d48e869bfa1874192fefe737a1b060010975308d77434a2cd624e907a2e81372980a250a16aeef334935463a65d375c8f0b849ca7de07efcb06dc07b379e33ca37b09702ea774095c672d3185e3fca1c1fa35da9e2f2c27abbc80338e6a889159c76b2be3307afa23b7905d3121379df3040f58346216642a929396e3ba38a9bb76e4e663a988ef5e8302908201f4e688801afe5dd2f12346ecb1b729f1aa7adcfc7926415a3f48d061b050d8ba9138fd28a0499a801466957503f701279d8386d53da4a9d35d18b397ca8e4f06d030ccf794dac804e032eab5f9d454845474e12ddfddbc1a46675087cc3010f21b919be2e51ae0d2ebd3c1378eec6a9017c24f076c69754b3518f88b04c96694b299d9eae548dce34a22aace548bda4b20e027e04bab326516acea6b88dc52dabe2c93ea8add14a7e870ad172704ca7ff1f7a274073f888e66ae04fe3315b16458669d0d013a9727d6e5285f9421233317780814ffa71998003ed07ead41debefdcffa02df9988f10d3210cd3fb28c8f504d5946718e96401c0631f93d1a16ce42594f73aa2807790ed5a203824916250af5c4ccae293d4efa24bf3ec77c75c318db3cdcfe3c9977450a80cb1d9b5265eae71ca8bb5856fda8c1f7ee6c0498cade165b8b3ebe0b19a347754b2857c0f26e4761dbbac26939dfd3e23bef6aae1ed79507089a9c6a8665eec98acf17daa3fa719f57c0a6264a12b43f2390655161a76e7a76ca5d872ff3074f894c256c0ab4d47ddd0870c2bdde877a213f494c359e5b4a2f84c9ee9ed6e29fd0be37f4f3a5e55021b736ab8eb6cc95561328e9d5499eb25990ca1f0e2aa07660bfcacbc8f7742bed71802262cc39a1eda2b5e3da6e485116d13a8b17ad7ea05ccb46ce99573449d9a7d0563a722522e8a2ca6554c09bd312746d5ea72ea4410eb8ee54b5c18dd2e03dddf6ab59311d0818ebd53cdbf1ce18861c13044c26583bbcb3c30b2493024ce7799ae6a2abf0e7516df73f931da4d6fac91362591eefbd5ca35ba8929e1b024948f12720b0e4544285f657dfb7ade26d6998d0c4e2badcf4fbea5a9f57233930d93267ec96d4c7213fd789f57aa40399483e13220fa30d8bdb6c63f4986626ef01e00f181d6f20634da9da1ab5e0b2aaae2080407b016b6cf20d5afe693b2177820d84a81e3b00170c025cf64d9472211e982b189ff44fe3df94da0804c2da40d07c360d2d13e0f430b7d5fdac442e253a1cb8d00eb6ac7838472874e032d1132cc6ecaf37d590d12a476264b545f12478a1cfdfe61cd320ce3880709fd49acd53841b27c91b3aa5ea4738c520008e7e8ed4c51b34ec84156b9953bb598bb5a9831caec456afba0ec63b869197ef64357db2b2f1c840a1cd4cec9b777c149066e0426c90b659cde0486ccdf06a55aa3cfaad927369dbefdeafbcc16b002fc96d52cc6e055a940d4b58323b7fff35bb387ebaab500aac8e5f3e929d9a30ecfc6ef5c931d7424a50dde47e285e859ad2b8786da967a74c3bde2d108d234cc724991be37d695f0154daeedd48bc3f71935b5d5b550a9b6e2f1fc3fa0c2bd608c2c347f822ebc671ecb1e05fb8954f0a7e8a3 -d7ea2600cb4cd90d27d6a789ffcaf6656f2c99db58908c2df0e2980730b933b68301d74e75fbacedbffb9c83d260558ecfbe5d9300ddd67003dee154e606d50388aa37f3c09944d2b2b3d5407923f88438bbd0fb3cbaaf06dc4e0afe4375bf25d7ff34d68be7e79d66b01e5b7fcf3cdb361160ca15f6d6647786509ae83ea7e6ae623f2cf672c79e00719734d48a89921f9b3aa9413ec2ce9f7bb1cd50b25865e90a4c110985be4894491927c0c69e7fe10e2d3974d56d15a57771d86d8d31f3af8ea608a0bb61b972efcf66ac8466a217405a24c085587adaf4fa9f2b579cabd5505d07abcbb19f7f202ad366c482955c9aa6356952949a6f24279b0b5c38fdae9cdf88eab30d8220158206a4531bd99a2ad991fd807dc6f053dd617fd260889e935aab4ef9740095d12ff0694e752aa53eb4bc952a49e13834239fcc6efe06a81d94d00157b2edce8e01253238cd4b3b81a970774f94ccc7a11bb7dd90a4d2e7b98f5d9f281c0147c686ac5de1b7247016c95257367af0d78e9a8bc448378285d6ef6a8229fa5896aeeacaec505666b2c2c0fdb48ed87ad533528731da1622ec35144977d31ac79749a8e08b742ba168b98e4fd73597a5b5f768f3c56fc0bc996d78d2f0bee7b090d9d9535fdbd8373cc7444a182a0bfbfb92a93dccf51ddecdf8c45444e2d1e6fcf2cbe6c1a43f14ea38219ad9eaf293d904f3e9424664d3eacb7943e1d1ebf4e7c53e7207fe2534b9dc40d0979e857ec9e51dda44c1595388a5ddfcb89000195fb41ff6e93268016ac2e8931c5690fd87c20c3915a33c90d327602da83def4d678dbdb43b773213b648c182e3360af903e7dc29e6e82ad3abb4850303537c0d4aced5667d42e46029f3fa01c7abae6f1e1657ec0af355bfd4524694a46d61285417a4bfed663c05066fa3aa928e8401a221497e4145bba9dfd564ba1e2f0890628808e0c2c9ba34135539c3a90ae37c1593c92626a4e612a4cb58371d6d183f8a1d12fcda173950aed156f0339071f670cfa388e799bbee84dfacceafc53f0c2e90f0a81e7bc506651580b68352ed04264ffb5ccd44c548d9420a0797af6d085956aef8de2bcd752bc777e9ce9330cef5eb9a64181b0ef2c41ae5ccc8d53aa5c01f5db45991e18f24cc2c777e07215c2388233c453bd2fec7dd7ec652f370c76954b1483b24ffeb8729d1707b531bf4e7d0b25a15387880dd69ef52e0a70e41c65ca8e7838a8ce665f37d62e80a1770dffd11f7210a1865da819d543a93decb75ada07ee3e14fa505ee7c723d2d5dfefe000a9f9d168e6e9a99e3e08b11b4594d7370a68b0051b9870acace9e515e484e082bcd642e6e52dee5df11e9324ceacfb8da70d7691e68f20aa32d3cf3a5a3d61da84ef632d614da811d70fdc973b87fb282636ff6f0cfed66e350b2c3d933c17aee88ecee2b20d4b358a1531c046de55b2e3afe72a2256750c5c83bca1b7febf0191b2a1282a8e31e4b00a7cc7106aa38b06289084656f36c30f6662664a3968f046f89f15a4ad18a2bd5aeec5b69d578c2e2955f5776903bf3460dedfe5dd854e4eb4f48bef49eaaad04e37993f9b44df3c50f13dacdb4fea0411dbda5d4583adc91215f398797b47243a8f99815ed2afa3bafdec4cc9c4f91a0b35c472c9acef027141f5dd1e61c1b98bbc407f2c906a4c9215fa6aa9fb4a5fe60c8ab4e1ae06f2ae383536da2195937e3fc388f7102a962fca7d677dbd70b1997363f14264c861375ee852683e1138777e16d5fafad081e696f7e2acfe9f755fbd88448153c58b8f30927dac24bbd705005d76896136cb600c874b5d7ec7201ede87863ea6d6f7573365c6cafb7a0c4be099be981e3dc5f1217ba0611a23f88a8b302201ef2ce45a51d75d4d96ce358e0c93e3a31c3fe980ec66a5d58f8bcd5c04e27526dd275d2931e0005adb43530070d03e8b048f4fe0dbd86442cb6204097c869925bcee39ceb8ea230ad0a1bf4895eb2ee6dec4088f02c21c96b9dddd7180711ae86d4d149dfc54337956d7814affe0ea0c230ee59d1534639a687d633b137e5a7be8c8942e734a6588e6b2a5d28939f63c2d7d7798e796421fbc51a63d2c2fa06aaee10c0bd15354ac4dbf361fa79cd3ad4fd24863941b2ceb41a614d08c8597109a0f30c78b493d6ecd21fb4ec52af19db033bb9104d287d74016a916ef425fb35572dc1a6fa899b940d65c5aade07bfab10f5174dbc04262beaccb5a967df973db9e509d886aacae65103a1fff293b4530a81e273388de24903c7c7321f58350bc489eb3590311f8b6a15c6647b7b18acf451f67dba59aa0e644c07e315748a6a3178e9879208d2a0c047f814f10d50970d490216a65d30e49ba1641398cd1f36a9794c0fe51a2fd312747a4f05a3d928c680ce91f0b8c7477ead0fa470372147fb55edd455535deb85dce4277ac5fa528d6b9144d69cff4f9f862a7a01d5867e5215a56f6a1ca9dc9ea2e324c7781f06e07483092cc89a2e88aaa2f514abc7a5a5f4c4039a309f9c9d5433abff7a4c97ba126f979701679a7fe42ebf76885412e0829752ffc1fbe2aaf9293c51501b47d55bfa658c3188dd9b7bad0f501fa459570398638f25eed7de131bee19a831a280d61da0b27e3add475faa8fd571d9cdd9fa37944172438430d10d810953cdba2bc5181371348d5845ef3d3009004539f720f025d212b0ad17984ff0ad92091eee4f96ffcb881546071a1300023b81314e10ef3da97d9d97dcf4247cfc279db42b7fbcd87aa59f6ca4091ce972cd7604a1db908319e934ed190ef86d9696988a4ea31188e0e2585a4309b7614f9acd9a908077f70a8695e9907730b65b01abf2c74240c8769f3a5e862c6421f62b32bd5c706d62b7e55c -d7b4852ee6e758181cbe0caacd73120e5eaa6968ecc6fe1cfc37cb2a3f5c47b7a19957aad440ea33fbe7a6f9be63c207b205afe56b41fcdde73450377cb9fdeda49be79af86eb9c6a64b0f215f4b9489feed339e9cb0e9306b27d7d59236845cd6233a41eaf881562a17ec4beb80505fe8be7e8a94c76312549d9ecc8f81604a8cb66db18c3d8541c0bad976042132312de59df95416bda2b5b1ebc232bde2cc8c0dab778fcdb1d347ce192fd1e12b321fcd1f1c2086a397d3d9f81d9748f9e48a9588a20a4a616b98e5895ff763b3f845164e5b2d2927c75567d26001aec658ac9c25b755eb79f139863ede05f3a3e3482b5e652f37db08591471a2520edaf39f10f932672580ce74561719e3438c6907ed10f20e450c3bd20eed8a513458b49396ad114d21d6d4d557c1779bc182dc52d9f5257e70d1f9aa4dfdc3cdbf50cc8092290e6013d942a205971ffe41abd540c697e50f7c7b73817f92951bf3ebffa9cf28702fe0d77e9d6f102e47e90a164c3701745fb45b680662f0ccc89c5bddcfb41c5268f865493bcc0c98a3405a1d2b19615eed554bee3216c23532e723caaccbf97b63746f80cbdd36c3c439cbf862c476ec3f028544449589390daaddbba4403ab9cf67804058156f9b5392e2eb0076be382db78d0555b60e4989323ae5a3a27cffddf691a6dd4b0974cd6e93a8c7df3082518e8a5433d1df94c84cb39cc7be355c0f5e9d2ef0067bd48096f4c9984228dda4b40fee06b7b5597af9920fa6f43860d08908947014a28151016e3a4b9606c73d153ad7ea9c5a4ba13793db9968752d31c62bad4ee0d0f36e29a0d167db5d12681aa4a379b8165f21a691e5a0883aaf807fb3f706a00b16e004a37380bad61cceed26ac8986cd19ead287e0877d03fc51a5b6adb781f67b6dbe9b38fcdfdf76b99e9f34a0e1782d3f0426a5ad4b2f4f300909032fba8de7482a8042376c248ed4f32a28dd7332e8c9aeeaac8c64ee5fc5490fd00a83896dc249450a77adebc28f330fdc4849c992b23d5b79872c6c788acc14f065f03639bbd3178171f9c71648630b595490df398560afea9a37a79eb9e7a48b35184f7ec59b49acc323673bc9c957f538e7d710060e5c77856453548a11593d5377df7fe61aa7fd37c34dc4834a5bdfc2a8926a00d723b890ade3d4a8827f0057d780cb9941b6fb875d50e3f59e84b85c70500146f5df7eed52778e5e29c0f0de344ad5925be5e30dac4fa1957d70eff9c8b330954f0835ad0a9253dd2eaf0fa1cb676ed53acfa436944a33f46e53bde72fdcd28cd15262cff91119dfe7d4d990bd876bea3fbf384cdace107728559beda2c778b05fcfa9e1171e4e67fb054ceeea25d8411a3bfd61d5eb5005b03ccb7290a672857ee4e3ed26d321fb89a8c08add7b8ff210ccad6737f2083a9d89f2a703b1a71603c431ddbb4f291e210ac1b17d7d6fdab1f03a174da5112ee5203fca1e1ee45b8e2932d64d4efbf3e98926fb9582300ce2da2230cae2e4208cf392164e71e82fd468e390ab7ea2e3071291dfa83bbf2db7ea69b8fcbbc063ce72ea1d0f371dbdda0d53c37ba9392da1a766cc5cd2cedc6669373633e332d1e7d88e8426e6bfeae1ad9ce60bdc43f36a3ec0bd56a6a427097d8160c372c093f461d3f77681eadeae21f29d790d893de1fca3549e82977c4d75faf38425d4b1cd709f32a872788bb539b6c09ee718c311437e90a7d7a84dfd94c8e27db5b8abbc9a0c5e0d10c3aa8a9208884498c3a88fd63213d9bb36b218c0d347e3fffb71a30ff2f67522426513caeadf1fb60a7c972596cbba92bbec5e6b753e66ed3bd1c8e86a33306d586c1ed48cb0519eef7a8e2702bb37c923954440fd155b6af07edeb3d915787c7616dd9316e1c7ca80cb5e9f17685b2983fbe80e78942689f61b857838f2e275c62cf85687ca9e847413d7f7078389a06e2740589f47966a1dca8f0985cf424f003083e735a8d5d4e2b5a09f602bce3d4e1bb07a3c2fd0e27b8dcc4bef1a2eabcbf1c93e1beaaad948e2a59cb28ea11a33a6717442d638259c403fd03044069cb03165b7a293c81e3da34b44942b95ae8256e346d57695844068f5f0cbd626e541fe420a7b8b3c3eba195cc600067635a2f6bc71c0fbf4e4d4f1fc60fe359f72b61ac06ad1ea8a34cfbdce589fcb1293c557cb43bb14370e798f2081fc8c32337cbaf6bc46e5b34217630f8e31e8a7e8c9780339e0627d0be6388e240af0005e84f1b6c47091ec7bfd71aeac0850715aaa32f27cb28c31b8e6307dd6aaafc29e153bd3ff33cc0072a00a9dca8cae32a17d745c60f77d52991e2f2b429defc7bdf6a74ed02de45a5e52ff7de54bce64ac3876ab2435317f8405624859934cc73c93ea5dc1948663821a50cf513f654acf4be2abc6e41e969756a2bed6935f1bb92de1da36a182e534bc6a421bae908c299dc9d6a6bfdc68ae261bac5f0674491dc5d3e55bcf9c8e0bdee843440e244347b2dbea3481272249d5adbbca5669556266d303edd1eead1b4aac02ea0956ba52f770706642819bfc19f8453b473d9e82151e4b6de090fb25e35643a24dbb0b64ed0aaf35b91aab18b8911ed13ec112ef6c4ea998a8812062460cb915afcc664a809e156f051d1a3e9d273419876c9d8445ff11f477ae4c11b0e190bc44d79c40521679336d703832365ba8898d4c7438545a58ff3ec19816001e83b8b6a3d397a258961e3d130244e7bbcb69cf5e691566830310a9d8e1e5abaa7f08f2f9e5f110ccaf1760235e16fff16aaa316fdf64eab78ca793a7521e3a156ef11568df5d0af6fb87993463d0be8b61b759ae4668c7ae83f70acef46a3b5db3ccf8f9fc37143dd510bc5b7f88565dda1329a2c8819457cc20ec -d9bed8f7e805024050e8d447e1d7a4c200c20af682a0257cf098a96aad63754fcaa790ac09d72becaf59014e2d9006ee97bc8dc4bcc336820237c59620ecaa9f9ba75cf436ca35ccbf2c6e277ef6d33bbec45dc2d45fc29abb37369c97c422dc8b009214aa6182902097375b80ea5ac8ea31f977031f04b1d5c69d046ac205d9e0ab4c663d49d9626940a600ad8dda8fe73f0cb360df1b187e3e987a625cfd1ed797701b44f47dcbd96c2e34c7519b78ca3053d98126486c101bb6592553ba1cccfba28f98e97159cda052856ff88de9638b86051f8b39681b66dd802376c3f8caced7958178c2233bffd76b87ab80361eb819279b1f1e72f9ecdf1d2f77fa9ad82e340f31bc6a4ea620c69c2913e5e8c4cfb1fa2a6bfbd745082cc03d5bf732c116f3b12e872d721215a79c40c94e7e0ae661f2f5ec0b03bcf9cf1797996893df478bdd7fe84ecd7fa10f76d9e746f43263cd4ba3c36638edc72731516b7157d1180a623c12e8fa6627c24723c577528ee1a13c56e5240a1a7141d3ca694674c02ba25d759ff77d30a1461f77dcf486dd6c953919809572138de9acd9d8ec02cfd48f2fdfe8a8d6b5a7deafc58995e308d000ab527db6efa92cfc96e3af29988d50ddac98373f02f4e6e9bc8fdb12f1f19f156e95236a2ec2bb88a48929b8cea8d65efbf8b7d8a4ec82ce545a2d82aedc2336337eb9dbf05f09331eb8d5a5afae53921f5b9ed4874172565e9e55a82b12b18212b700bd86297df3aa41f23172e6fb56ef0cd2f4593c5a4f0e8c4f6300dd3ea12bb8ee7fb6afcd13e7f42000b6e14d93191d84dc63ba2ae4d3622baa1f61ff9f53b35c4e98e416966762f2e374a230e66c850ef274aa10bc7f5eb60f86ce4bbee69c126a38589f7143aab94f4284e1e36aeee2ca8d57919374dc47e1654d4a0a40c380a2aa115cf19e8870de2fa8d6a0877e1d6590c08a2e1951a12a7393905a74d2343898f4e47a1485557f22c9fc96d3239e5383e039c73293796aaa3d4ebb7a2d5ad7dac825c7faff8436d7e41f56f9794f94be51ec371c2a2b6978f7a749b2045635e7edf60ddaee9baf9dca2c2a760aece41137d30b646a19215105e759814b5be476476d3f823bc63f59ab6ddc6cb1f40e174c0e4b3cedffd675ba19c8ef22d76189b6a899cbceb525aea6b42e3fbeda9aa70b96daa6a174c0df48ef3a01a5e4fef25a5f51f9b5b24ce7c441275452614dd97dba7b8a02acdb5b09b015828d9b42379b705eb54831e8889ad4bfa71161acb69eb368605f9345aa373fac84e0b4281ef15186efd804ea5ea129b8ec7aac491580fb525b30e96aa1d40c6cb8933ebcb5e8a5851db703154cd039d4e876f0df849f6ba633b8ec7c9ad6c1110bec1a4f77b4a1acc97dca5a70d85645f87bc708079d74a9b38d95bcb254d471750f1df0ee67a68c3672406dd7ee8365530b2a895078e92b920798e0d90ea8eafec989a34dc3781b2eee0116d49fb53ecffc84cf5682a8a64eec9dbf4df14d96b403412dd29c97eb61785c8678cf6f4500ec3203299cde4a7948b04a862ecdc074893eeb761f5284e5ca192328e25f3cf4402760c86b3be3dc154ebafc57a3d88dfd404b60762655779890a546aaf29acf59a3367f79698f7eb93ff1289d6c363ad86964badd379e97aabc91adcb14a2da464e20e993bdd270f15a44898f09ee9171ec2b64b94bb997a2aaf74fe6f25fda67f9245529227a9e5a6072697c36f9987777abbd20a711a5353b05a3cc890618456b8a59f3deca02ec648d565f8fca5951d5c05a1e31508e58c140f1a74bf627889cf5b3818996ed49f37345d845760751b7fa9bed656282cb3362788db97f6b64a1d82d90de82770ed918853c045230a720172e4038216c417a89f8cda698e10c7bad5741b696ddb7f1bc39a38e15d46b508bddb406ecfc054e216c85957a038959fe2612bca4f68bfefb45d049472725809db3bc53a49950e7a7e8d1d8b3cd4491d12c39e40f654e626d7d16fbdbc8e2a35aae3a8f985ddf301f76dfba3aabffdf7e986905015dd5f1cf40797d51d9caa00a73083e52ed6aa7b58d8dc491ffd93964eb170ae8acedd251d2d838f4a7a7eade1c8de739aa3a8d6a7a946a784aa1aecc684ac12a552ee348ff320605598c80c51ce0fa9d61b64b3448df2bf37cf10c16880c8a7256b41f5a9c9ad1dabafc0d7d518ee100e67a2c1b868d4cc34c2e93ab3e97eb58d3763c3268d18e0418d71e63fa5576b026544cb76685ecf7e60538507566b6cbde81838cbea5bbb724e3000a596ad6c5b2d95376c7ed6116f6513ad37a6d327132f2dceb59818101a1d1e389334ddc94e920a7e5bf9efcd61ab4d22f15a2f1d9363cef209947cbb8482265d3e508b964ca6019fad1ed19224e6a3117b76f82c41c0ec4a7bcef64f23551fe2348858ab0efedf0ee31db4fb6dd8c88cffa9576b2459c5ff509636d05e1beee0816ba9b6e68f1375b8ee8ad4ad3dd4b9944c17ce9c64853f8415fd7e04cd16ce749dad153670bcb7642dc1ea6dbeb5f5be5e9396586297be1dd299a66b10414d5cb5a835721e3737bf5817ff0616ebe78f56524c737d978056d7e0cb654a03be0327377c4edfd08f04fac8da6af31ccd6699368c60cfe9ea51e408bd3a9f7c0315ee78c24c053d8f11aeee9dd9c37e275769e740a67fcfa56beb0436602fbc182b328d57f9a566a7898a6eeee7091f6e9680bdc9b3f9bac59417e4eb3e4251068d93a7919e7501ebf70871169c8971ef1d7d7faf372522be3dfe407d7d469c4825fecdc2424a4fb92c2e8b16afad761db7eaaac29dc155f3c5e7290b728e06971a2c97525c3a15a6323ad6435b0cc1e3e0f0008e701275ac935c90ceed74076007cdc0a84f99f76e23a diff --git a/pkg/encoding/kzgEncoder/encoder.go b/pkg/encoding/kzgEncoder/encoder.go index 241a07ebf2..fbfa2c8904 100644 --- a/pkg/encoding/kzgEncoder/encoder.go +++ b/pkg/encoding/kzgEncoder/encoder.go @@ -3,6 +3,7 @@ package kzgEncoder import ( "context" "errors" + "fmt" "log" "math" "time" @@ -157,6 +158,9 @@ func (g *KzgEncoder) Encode(inputFr []bls.Fr) (*bls.G1Point, *bls.G1Point, []Fra polyDegreePlus1 := uint64(len(inputFr)) + fmt.Println("PolyDegree: ", polyDegreePlus1) + fmt.Println("NumCoeffs: ", len(poly.Coeffs)) + if g.Verbose { log.Printf(" Commiting takes %v\n", time.Since(intermediate)) intermediate = time.Now() @@ -185,7 +189,10 @@ func (g *KzgEncoder) Encode(inputFr []bls.Fr) (*bls.G1Point, *bls.G1Point, []Fra } // compute proofs - proofs, err := g.ProveAllCosetThreads(poly.Coeffs, g.NumChunks, g.ChunkLen, g.NumWorker) + paddedCoeffs := make([]bls.Fr, g.NumEvaluations) + copy(paddedCoeffs, poly.Coeffs) + + proofs, err := g.ProveAllCosetThreads(paddedCoeffs, g.NumChunks, g.ChunkLen, g.NumWorker) if err != nil { return nil, nil, nil, nil, err } diff --git a/pkg/encoding/kzgEncoder/encoder_suite_test.go b/pkg/encoding/kzgEncoder/encoder_suite_test.go index 503b8f6c7f..e9de5cf1a8 100644 --- a/pkg/encoding/kzgEncoder/encoder_suite_test.go +++ b/pkg/encoding/kzgEncoder/encoder_suite_test.go @@ -27,9 +27,9 @@ func setupSuite(t *testing.T) func(t *testing.T) { log.Println("Setting up suite") kzgConfig = &kzgRs.KzgConfig{ - G1Path: "../../../integration/data/kzg/g1.point", - G2Path: "../../../integration/data/kzg/g2.point", - CacheDir: "../../../integration/data/kzg/SRSTables", + G1Path: "../../../test/resources/kzg/g1.point", + G2Path: "../../../test/resources/kzg/g2.point", + CacheDir: "../../../test/resources/kzg/SRSTables", SRSOrder: 3000, NumWorker: uint64(runtime.GOMAXPROCS(0)), } From 8cc910fc4ab604dd851b52d210e174ea89c7c1cc Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 29 May 2023 11:35:20 -0700 Subject: [PATCH 5/7] Add gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..02d4daa5ba --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +test/resources/kzg \ No newline at end of file From 065492ca12b6bee9a3c47d9dfabdbeec203941f2 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 31 May 2023 11:40:35 -0700 Subject: [PATCH 6/7] Finish reparameterizing --- pkg/encoding/encoder/decode.go | 4 +- pkg/encoding/encoder/encode.go | 2 +- pkg/encoding/encoder/encode_test.go | 10 +++-- pkg/encoding/encoder/encoder.go | 27 +++--------- pkg/encoding/encoder/encoder_fuzz_test.go | 4 +- pkg/encoding/encoder/frame_test.go | 3 +- pkg/encoding/encoder/params.go | 43 ++++++++++++++------ pkg/encoding/encoder/utils_test.go | 5 ++- pkg/encoding/kzgEncoder/encoder.go | 15 +++---- pkg/encoding/kzgEncoder/encoder_fuzz_test.go | 5 ++- pkg/encoding/kzgEncoder/frame_test.go | 16 +++++--- pkg/encoding/kzgEncoder/multiprover_test.go | 4 +- pkg/encoding/kzgEncoder/verifier.go | 2 +- pkg/encoding/kzgEncoder/zero_padding_test.go | 4 +- 14 files changed, 84 insertions(+), 60 deletions(-) diff --git a/pkg/encoding/encoder/decode.go b/pkg/encoding/encoder/decode.go index 257cd6a6ea..aa8485951e 100644 --- a/pkg/encoding/encoder/decode.go +++ b/pkg/encoding/encoder/decode.go @@ -28,7 +28,7 @@ func (g *Encoder) Decode(frames []Frame, indices []uint64, inputSize uint64) ([] return nil, errors.New("number of frame must be sufficient") } - samples := make([]*bls.Fr, g.NumEvaluations) + samples := make([]*bls.Fr, g.NumEvaluations()) // copy evals based on frame coeffs into samples for i, d := range indices { f := frames[i] @@ -50,7 +50,7 @@ func (g *Encoder) Decode(frames []Frame, indices []uint64, inputSize uint64) ([] } } - reconstructedData := make([]bls.Fr, g.NumEvaluations) + reconstructedData := make([]bls.Fr, g.NumEvaluations()) missingIndices := false for i, s := range samples { if s == nil { diff --git a/pkg/encoding/encoder/encode.go b/pkg/encoding/encoder/encode.go index c47e0d0057..52a357db35 100644 --- a/pkg/encoding/encoder/encode.go +++ b/pkg/encoding/encoder/encode.go @@ -132,7 +132,7 @@ func (g *Encoder) ExtendPolyEval(coeffs []bls.Fr) ([]bls.Fr, []bls.Fr, error) { defer log.Println("Exiting ExtendPolyEval function") } - pdCoeffs := make([]bls.Fr, g.NumEvaluations) + pdCoeffs := make([]bls.Fr, g.NumEvaluations()) for i := 0; i < len(coeffs); i++ { bls.CopyFr(&pdCoeffs[i], &coeffs[i]) } diff --git a/pkg/encoding/encoder/encode_test.go b/pkg/encoding/encoder/encode_test.go index d30a7f8cb8..188f882998 100644 --- a/pkg/encoding/encoder/encode_test.go +++ b/pkg/encoding/encoder/encode_test.go @@ -14,7 +14,9 @@ func TestEncodeDecode_InvertsWhenSamplingAllFrames(t *testing.T) { teardownSuite := setupSuite(t) defer teardownSuite(t) - enc, _ := rs.NewEncoder(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES)), true) + params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + + enc, _ := rs.NewEncoder(params, true) require.NotNil(t, enc) inputFr := rs.ToFrArray(GETTYSBURG_ADDRESS_BYTES) @@ -34,7 +36,8 @@ func TestEncodeDecode_InvertsWhenSamplingMissingFrame(t *testing.T) { teardownSuite := setupSuite(t) defer teardownSuite(t) - enc, _ := rs.NewEncoder(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES)), true) + params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + enc, _ := rs.NewEncoder(params, true) require.NotNil(t, enc) inputFr := rs.ToFrArray(GETTYSBURG_ADDRESS_BYTES) @@ -54,7 +57,8 @@ func TestEncodeDecode_ErrorsWhenNotEnoughSampledFrames(t *testing.T) { teardownSuite := setupSuite(t) defer teardownSuite(t) - enc, _ := rs.NewEncoder(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES)), true) + params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + enc, _ := rs.NewEncoder(params, true) require.NotNil(t, enc) fmt.Println("Num Chunks: ", enc.NumChunks) diff --git a/pkg/encoding/encoder/encoder.go b/pkg/encoding/encoder/encoder.go index ca01e81895..ca29f4a567 100644 --- a/pkg/encoding/encoder/encoder.go +++ b/pkg/encoding/encoder/encoder.go @@ -1,7 +1,6 @@ package encoder import ( - "errors" "math" kzg "github.com/Layr-Labs/eigenda/pkg/kzg" @@ -23,14 +22,14 @@ type Encoder struct { // original data. When some systematic chunks are missing but identical parity chunk are // available, the receive can go through a Reed Solomon decoding to reconstruct the // original data. -func NewEncoder(numSys, numPar, dataByteLen uint64, verbose bool) (*Encoder, error) { - if !CheckPreconditions(numSys, numPar) { - return nil, errors.New("kzgFFT input precondition not satisfied") - } +func NewEncoder(params EncodingParams, verbose bool) (*Encoder, error) { - params := GetEncodingParams(numSys, numPar, dataByteLen) + err := params.Validate() + if err != nil { + return nil, err + } - n := uint8(math.Log2(float64(params.NumEvaluations))) + n := uint8(math.Log2(float64(params.NumEvaluations()))) fs := kzg.NewFFTSettings(n) return &Encoder{ @@ -40,17 +39,3 @@ func NewEncoder(numSys, numPar, dataByteLen uint64, verbose bool) (*Encoder, err }, nil } - -// This function checks preconditions for kzgFFT library -// 1. numPar must be non-zero -// 2. numSys must be non-zero -func CheckPreconditions(numSys, numPar uint64) bool { - if numSys == 0 { - return false - } - - if numPar == 0 { - return false - } - return true -} diff --git a/pkg/encoding/encoder/encoder_fuzz_test.go b/pkg/encoding/encoder/encoder_fuzz_test.go index 60e067652f..3ee377c432 100644 --- a/pkg/encoding/encoder/encoder_fuzz_test.go +++ b/pkg/encoding/encoder/encoder_fuzz_test.go @@ -11,7 +11,9 @@ func FuzzOnlySystematic(f *testing.F) { f.Add(GETTYSBURG_ADDRESS_BYTES) f.Fuzz(func(t *testing.T, input []byte) { - enc, err := rs.NewEncoder(10, 3, uint64(len(input)), true) + + params := rs.GetEncodingParams(10, 3, uint64(len(input))) + enc, err := rs.NewEncoder(params, true) if err != nil { t.Errorf("Error making rs: %q", err) } diff --git a/pkg/encoding/encoder/frame_test.go b/pkg/encoding/encoder/frame_test.go index 3739d6e65d..c76576e60e 100644 --- a/pkg/encoding/encoder/frame_test.go +++ b/pkg/encoding/encoder/frame_test.go @@ -12,7 +12,8 @@ func TestEncodeDecodeFrame_AreInverses(t *testing.T) { teardownSuite := setupSuite(t) defer teardownSuite(t) - enc, _ := rs.NewEncoder(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES)), true) + params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + enc, _ := rs.NewEncoder(params, true) require.NotNil(t, enc) _, frames, _, err := enc.EncodeBytes(GETTYSBURG_ADDRESS_BYTES) diff --git a/pkg/encoding/encoder/params.go b/pkg/encoding/encoder/params.go index dddcde85f4..212e8ad2b7 100644 --- a/pkg/encoding/encoder/params.go +++ b/pkg/encoding/encoder/params.go @@ -1,14 +1,39 @@ package encoder import ( + "errors" + bls "github.com/Layr-Labs/eigenda/pkg/kzg/bn254" ) +var ( + ErrInvalidParams = errors.New("invalid encoding params") +) + type EncodingParams struct { - NumChunks uint64 // number of total chunks that are padded to power of 2 - ChunkLen uint64 // number of Fr symbol stored inside a chunk - ChunkDegree uint64 // degree of the polynomial interpolating a chunk. ChunkDegree = ChunkLen-1 - NumEvaluations uint64 // the size of the group (power of 2) on which the global polynomial is evaluted in order to extend to NumPar chunks PaddedNodeGroupSize = NumNodeE*ChunkLen + NumChunks uint64 // number of total chunks that are padded to power of 2 + ChunkLen uint64 // number of Fr symbol stored inside a chunk +} + +func (p EncodingParams) ChunkDegree() uint64 { + return p.ChunkLen - 1 +} + +func (p EncodingParams) NumEvaluations() uint64 { + return p.NumChunks * p.ChunkLen +} + +func (p EncodingParams) Validate() error { + + if NextPowerOf2(p.NumChunks) != p.NumChunks { + return ErrInvalidParams + } + + if NextPowerOf2(p.ChunkLen) != p.ChunkLen { + return ErrInvalidParams + } + + return nil } func GetNumSys(dataByteLen uint64, chunkLen uint64) uint64 { @@ -27,15 +52,9 @@ func GetEncodingParams(numSys, numPar, dataByteLen uint64) EncodingParams { dataLen := RoundUpDivision(dataByteLen, bls.BYTES_PER_COEFFICIENT) chunkLen := NextPowerOf2(RoundUpDivision(dataLen, numSys)) - // Order of the global polynomial + 1 - numEvaluations := numChunks * chunkLen // This will always be a power of 2, since both factors are powers of 2. - params := EncodingParams{ - NumChunks: numChunks, - ChunkLen: chunkLen, - ChunkDegree: chunkLen - 1, - NumEvaluations: numEvaluations, + NumChunks: numChunks, + ChunkLen: chunkLen, } - return params } diff --git a/pkg/encoding/encoder/utils_test.go b/pkg/encoding/encoder/utils_test.go index 68453dd0e0..e5fc0d656f 100644 --- a/pkg/encoding/encoder/utils_test.go +++ b/pkg/encoding/encoder/utils_test.go @@ -16,7 +16,7 @@ func TestGetEncodingParams(t *testing.T) { assert.Equal(t, params.ChunkLen, uint64(64)) // assert.Equal(t, params.DataLen, uint64(1000)) assert.Equal(t, params.NumChunks, uint64(8)) - assert.Equal(t, params.NumEvaluations, uint64(512)) + assert.Equal(t, params.NumEvaluations(), uint64(512)) } func TestGetLeadingCoset(t *testing.T) { @@ -37,7 +37,8 @@ func TestToFrArrayAndToByteArray_AreInverses(t *testing.T) { numEle := rs.GetNumElement(1000, BYTES_PER_COEFFICIENT) assert.Equal(t, numEle, uint64(33)) - enc, _ := rs.NewEncoder(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES)), true) + params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + enc, _ := rs.NewEncoder(params, true) require.NotNil(t, enc) dataFr := rs.ToFrArray(GETTYSBURG_ADDRESS_BYTES) diff --git a/pkg/encoding/kzgEncoder/encoder.go b/pkg/encoding/kzgEncoder/encoder.go index fbfa2c8904..513d6cd32a 100644 --- a/pkg/encoding/kzgEncoder/encoder.go +++ b/pkg/encoding/kzgEncoder/encoder.go @@ -73,14 +73,14 @@ func NewKzgEncoderGroup(config *KzgConfig) (*KzgEncoderGroup, error) { } -func (g *KzgEncoderGroup) GetKzgEncoder(numSys, numPar, dataByteLen uint64) (*KzgEncoder, error) { - params := rs.GetEncodingParams(numSys, numPar, dataByteLen) +func (g *KzgEncoderGroup) GetKzgEncoder(params rs.EncodingParams) (*KzgEncoder, error) { + enc, ok := g.Encoders[params] if ok { return enc, nil } - enc, err := g.NewKzgEncoder(numSys, numPar, dataByteLen) + enc, err := g.NewKzgEncoder(params) if err == nil { g.Encoders[params] = enc } @@ -88,8 +88,9 @@ func (g *KzgEncoderGroup) GetKzgEncoder(numSys, numPar, dataByteLen uint64) (*Kz return enc, err } -func (g *KzgEncoderGroup) NewKzgEncoder(numSys, numPar, dataByteLen uint64) (*KzgEncoder, error) { - encoder, err := rs.NewEncoder(numSys, numPar, dataByteLen, g.Verbose) +func (g *KzgEncoderGroup) NewKzgEncoder(params rs.EncodingParams) (*KzgEncoder, error) { + + encoder, err := rs.NewEncoder(params, g.Verbose) if err != nil { log.Println("Could not create encoder", err) return nil, err @@ -107,7 +108,7 @@ func (g *KzgEncoderGroup) NewKzgEncoder(numSys, numPar, dataByteLen uint64) (*Kz return nil, err } - n := uint8(math.Log2(float64(encoder.NumEvaluations))) + n := uint8(math.Log2(float64(encoder.NumEvaluations()))) fs := kzg.NewFFTSettings(n) ks, err := kzg.NewKZGSettings(fs, g.Srs) @@ -189,7 +190,7 @@ func (g *KzgEncoder) Encode(inputFr []bls.Fr) (*bls.G1Point, *bls.G1Point, []Fra } // compute proofs - paddedCoeffs := make([]bls.Fr, g.NumEvaluations) + paddedCoeffs := make([]bls.Fr, g.NumEvaluations()) copy(paddedCoeffs, poly.Coeffs) proofs, err := g.ProveAllCosetThreads(paddedCoeffs, g.NumChunks, g.ChunkLen, g.NumWorker) diff --git a/pkg/encoding/kzgEncoder/encoder_fuzz_test.go b/pkg/encoding/kzgEncoder/encoder_fuzz_test.go index 56bb0ce5e6..17e5bf89a6 100644 --- a/pkg/encoding/kzgEncoder/encoder_fuzz_test.go +++ b/pkg/encoding/kzgEncoder/encoder_fuzz_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + rs "github.com/Layr-Labs/eigenda/pkg/encoding/encoder" kzgRs "github.com/Layr-Labs/eigenda/pkg/encoding/kzgEncoder" "github.com/stretchr/testify/assert" ) @@ -14,7 +15,9 @@ func FuzzOnlySystematic(f *testing.F) { f.Fuzz(func(t *testing.T, input []byte) { group, _ := kzgRs.NewKzgEncoderGroup(kzgConfig) - enc, err := group.NewKzgEncoder(10, 3, uint64(len(input))) + + params := rs.GetEncodingParams(10, 3, uint64(len(input))) + enc, err := group.NewKzgEncoder(params) if err != nil { t.Errorf("Error making rs: %q", err) } diff --git a/pkg/encoding/kzgEncoder/frame_test.go b/pkg/encoding/kzgEncoder/frame_test.go index 28fdb4251f..d197d865cc 100644 --- a/pkg/encoding/kzgEncoder/frame_test.go +++ b/pkg/encoding/kzgEncoder/frame_test.go @@ -18,7 +18,11 @@ func TestEncodeDecodeFrame_AreInverses(t *testing.T) { defer teardownSuite(t) group, _ := kzgRs.NewKzgEncoderGroup(kzgConfig) - enc, err := group.NewKzgEncoder(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + + params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + + enc, err := group.NewKzgEncoder(params) + require.Nil(t, err) require.NotNil(t, enc) @@ -42,7 +46,10 @@ func TestVerify(t *testing.T) { defer teardownSuite(t) group, _ := kzgRs.NewKzgEncoderGroup(kzgConfig) - enc, err := group.NewKzgEncoder(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + + params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + + enc, err := group.NewKzgEncoder(params) require.Nil(t, err) require.NotNil(t, enc) @@ -51,10 +58,7 @@ func TestVerify(t *testing.T) { require.NotNil(t, commit) require.NotNil(t, frames) - params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) - require.NotNil(t, params) - - n := uint8(math.Log2(float64(params.NumEvaluations))) + n := uint8(math.Log2(float64(params.NumEvaluations()))) fs := kzg.NewFFTSettings(n) require.NotNil(t, fs) diff --git a/pkg/encoding/kzgEncoder/multiprover_test.go b/pkg/encoding/kzgEncoder/multiprover_test.go index 9f054028b5..843150d1ac 100644 --- a/pkg/encoding/kzgEncoder/multiprover_test.go +++ b/pkg/encoding/kzgEncoder/multiprover_test.go @@ -15,7 +15,9 @@ func TestProveAllCosetThreads(t *testing.T) { defer teardownSuite(t) group, _ := kzgRs.NewKzgEncoderGroup(kzgConfig) - enc, err := group.NewKzgEncoder(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + + params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + enc, err := group.NewKzgEncoder(params) require.Nil(t, err) inputFr := rs.ToFrArray(GETTYSBURG_ADDRESS_BYTES) diff --git a/pkg/encoding/kzgEncoder/verifier.go b/pkg/encoding/kzgEncoder/verifier.go index eaba679e48..cf999cf07c 100644 --- a/pkg/encoding/kzgEncoder/verifier.go +++ b/pkg/encoding/kzgEncoder/verifier.go @@ -41,7 +41,7 @@ func (g *KzgEncoderGroup) NewKzgVerifier(numSys, numPar, dataByteLen uint64) (*K params := rs.GetEncodingParams(numSys, numPar, dataByteLen) - n := uint8(math.Log2(float64(params.NumEvaluations))) + n := uint8(math.Log2(float64(params.NumEvaluations()))) fs := kzg.NewFFTSettings(n) ks, err := kzg.NewKZGSettings(fs, g.Srs) diff --git a/pkg/encoding/kzgEncoder/zero_padding_test.go b/pkg/encoding/kzgEncoder/zero_padding_test.go index f92bc3906d..e79dfe5234 100644 --- a/pkg/encoding/kzgEncoder/zero_padding_test.go +++ b/pkg/encoding/kzgEncoder/zero_padding_test.go @@ -17,7 +17,9 @@ func TestProveZeroPadding(t *testing.T) { defer teardownSuite(t) group, _ := kzgRs.NewKzgEncoderGroup(kzgConfig) - enc, err := group.NewKzgEncoder(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + + params := rs.GetEncodingParams(numSys, numPar, uint64(len(GETTYSBURG_ADDRESS_BYTES))) + enc, err := group.NewKzgEncoder(params) require.Nil(t, err) inputFr := rs.ToFrArray(GETTYSBURG_ADDRESS_BYTES) From 44a5ccc43802f1423677ecb2719b4fc4a2bcf7f8 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 31 May 2023 16:03:27 -0700 Subject: [PATCH 7/7] Build out core encoder component --- core/assignment.go | 26 +++-- core/data.go | 32 ++++-- core/encoding.go | 7 +- core/encoding/.keep | 0 core/encoding/encoder.go | 108 +++++++++++++++++++ node/core/validator.go | 14 ++- node/node.go | 2 +- pkg/encoding/encoder/encode.go | 9 +- pkg/encoding/kzgEncoder/encoder.go | 3 +- pkg/encoding/kzgEncoder/encoder_fuzz_test.go | 3 +- pkg/encoding/kzgEncoder/frame_test.go | 5 +- pkg/encoding/kzgEncoder/verifier.go | 15 +-- 12 files changed, 170 insertions(+), 54 deletions(-) delete mode 100644 core/encoding/.keep create mode 100644 core/encoding/encoder.go diff --git a/core/assignment.go b/core/assignment.go index 4983dd91fa..c7d1295167 100644 --- a/core/assignment.go +++ b/core/assignment.go @@ -15,10 +15,9 @@ type OperatorIndex uint type ChunkIndex uint -type Assignments struct { +type AssignmentInfo struct { StakeThreshold uint - NumChunks uint - Assignments []Assignment + TotalChunks uint } type Assignment struct { @@ -35,9 +34,9 @@ func (c *Assignment) GetIndices() []ChunkIndex { } type AssignmentCoordinator interface { - GetAssignments(state OperatorState, quorum QuorumParams) (Assignments, error) + GetAssignments(state OperatorState, quorum QuorumParams) ([]Assignment, AssignmentInfo, error) - GetOperatorAssignment(state OperatorState, quorum QuorumParams, id OperatorId) (Assignment, error) + GetOperatorAssignment(state OperatorState, quorum QuorumParams, id OperatorId) (Assignment, AssignmentInfo, error) ValidateConglomerateChunkSize(state OperatorState, headers []BlobHeader, chunkSize uint) error @@ -77,7 +76,7 @@ func getStakeThreshold(state OperatorState, quorum QuorumParams) uint { return uint(stakeThreshold.Uint64()) } -func (c *BasicAssignmentCoordinator) GetAssignments(state OperatorState, quorum QuorumParams) (Assignments, error) { +func (c *BasicAssignmentCoordinator) GetAssignments(state OperatorState, quorum QuorumParams) ([]Assignment, AssignmentInfo, error) { numOperators := len(state.Operators) numOperatorsBig := new(big.Int).SetUint64(uint64(numOperators)) @@ -118,10 +117,9 @@ func (c *BasicAssignmentCoordinator) GetAssignments(state OperatorState, quorum stakeThreshold := getStakeThreshold(state, quorum) - return Assignments{ + return assignments, AssignmentInfo{ StakeThreshold: stakeThreshold, - NumChunks: numChunks, - Assignments: assignments, + TotalChunks: numChunks, }, nil } @@ -142,19 +140,19 @@ func GetOperatorAtIndex(headerHash [32]byte, index, numOperators int) int { return int(operatorIndex.Uint64()) } -func (c *BasicAssignmentCoordinator) GetOperatorAssignment(state OperatorState, quorum QuorumParams, id OperatorId) (Assignment, error) { +func (c *BasicAssignmentCoordinator) GetOperatorAssignment(state OperatorState, quorum QuorumParams, id OperatorId) (Assignment, AssignmentInfo, error) { - assignments, err := c.GetAssignments(state, quorum) + assignments, info, err := c.GetAssignments(state, quorum) if err != nil { - return Assignment{}, err + return Assignment{}, AssignmentInfo{}, err } operator, ok := state.OperatorMap[id] if !ok { - return Assignment{}, ErrNotFound + return Assignment{}, AssignmentInfo{}, ErrNotFound } - return assignments.Assignments[operator.Index], nil + return assignments[operator.Index], info, nil } func (c *BasicAssignmentCoordinator) ValidateConglomerateChunkSize(state OperatorState, headers []BlobHeader, chunkSize uint) error { diff --git a/core/data.go b/core/data.go index 2413a75f0e..f0249c4a7b 100644 --- a/core/data.go +++ b/core/data.go @@ -27,19 +27,36 @@ type BlobHeader struct { // Conglomerate type Conglomerate interface { + Header() ConglomerateHeader + Data() [][]byte ProveInclusion(header BlobHeader, index uint) error } +type ConglomerateCommitments struct { + Commitment Commitment + DegreeProof Commitment + Degree uint +} + type ConglomerateHeader struct { Commitment Commitment DegreeProof Commitment Degree uint ChunkSize uint NumOperators uint + NumBlobs uint Quorum QuorumParams ReferenceBlockNumber uint } +func (h ConglomerateHeader) Commitments() ConglomerateCommitments { + return ConglomerateCommitments{ + Commitment: h.Commitment, + DegreeProof: h.DegreeProof, + Degree: h.Degree, + } +} + // Batch type Batch struct { @@ -53,20 +70,15 @@ type HeaderBatch struct { // Chunks type Chunk struct { - Header ConglomerateHeader - Data ChunkData - Proof Proof + Data ChunkData + Proof Proof } -type ChunkData interface { -} +type ChunkData interface{} -type Proof interface { - Verify(data ChunkData, commitment Commitment, indices []ChunkIndex) error -} +type Proof interface{} -type Commitment interface { -} +type Commitment interface{} type ChunkBatch struct { Chunks []Chunk diff --git a/core/encoding.go b/core/encoding.go index 9a8acf1c50..038cbded01 100644 --- a/core/encoding.go +++ b/core/encoding.go @@ -7,10 +7,7 @@ type EncodingParams struct { NumChunks uint } -type EncodingGroup interface { - GetEncoder(params EncodingParams) Encoder -} - type Encoder interface { - Encode(conglom Conglomerate) ([]ChunkBatch, error) + Encode(data [][]byte, params EncodingParams) (ConglomerateCommitments, []ChunkBatch, error) + VerifyChunks(chunks []Chunk, indices []ChunkIndex, commitments ConglomerateCommitments, params EncodingParams) error } diff --git a/core/encoding/.keep b/core/encoding/.keep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core/encoding/encoder.go b/core/encoding/encoder.go new file mode 100644 index 0000000000..d4b1c36f7e --- /dev/null +++ b/core/encoding/encoder.go @@ -0,0 +1,108 @@ +package encoding + +import ( + "errors" + + "github.com/Layr-Labs/eigenda/core" + enc "github.com/Layr-Labs/eigenda/pkg/encoding/encoder" + kzgEnc "github.com/Layr-Labs/eigenda/pkg/encoding/kzgEncoder" + "github.com/Layr-Labs/eigenda/pkg/kzg/bn254" +) + +var ( + ErrConglomFeatureNotSupported = errors.New("conglomerate feature not supported") +) + +type Conglomerate struct { + data [][]byte + header core.ConglomerateHeader +} + +func (c *Conglomerate) Data() [][]byte { + return c.data +} + +func (c *Conglomerate) Header() core.ConglomerateHeader { + return c.header +} + +func toEncParams(params core.EncodingParams) enc.EncodingParams { + return enc.EncodingParams{ + NumChunks: uint64(params.NumChunks), + ChunkLen: uint64(params.ChunkSize), + } +} + +type Encoder struct { + EncoderGroup kzgEnc.KzgEncoderGroup +} + +func (e *Encoder) Encode(data [][]byte, params core.EncodingParams) (core.ConglomerateCommitments, []core.Chunk, error) { + + encParams := toEncParams(params) + + encoder, err := e.EncoderGroup.GetKzgEncoder(encParams) + if err != nil { + return core.ConglomerateCommitments{}, nil, err + } + if len(data) != 1 { + return core.ConglomerateCommitments{}, nil, ErrConglomFeatureNotSupported + } + + blob := data[0] + + commit, lowDegreeProof, kzgFrames, _, err := encoder.EncodeBytes(blob) + if err != nil { + return core.ConglomerateCommitments{}, nil, ErrConglomFeatureNotSupported + } + + chunks := make([]core.Chunk, len(kzgFrames)) + for ind, frame := range kzgFrames { + + chunks[ind] = core.Chunk{ + Data: frame.Coeffs, + Proof: frame.Proof, + } + + } + + degree := uint(len(enc.ToFrArray(blob))) + commitments := core.ConglomerateCommitments{ + Commitment: commit, + DegreeProof: lowDegreeProof, + Degree: degree, + } + + return commitments, chunks, nil + +} + +func (e *Encoder) VerifyChunks(chunks []core.Chunk, indices []core.ChunkIndex, commitments core.ConglomerateCommitments, params core.EncodingParams) error { + + encParams := toEncParams(params) + + verifier, err := e.EncoderGroup.GetKzgVerifier(encParams) + if err != nil { + return err + } + + err = verifier.VerifyCommit(commitments.Commitment.(*bn254.G1Point), commitments.DegreeProof.(*bn254.G1Point), uint64(commitments.Degree)) + if err != nil { + return err + } + + for ind := range chunks { + err = verifier.VerifyFrame( + commitments.Commitment.(*bn254.G1Point), + chunks[ind].Data.(*kzgEnc.Frame), + uint64(indices[ind]), + ) + + if err != nil { + return err + } + } + + return nil + +} diff --git a/node/core/validator.go b/node/core/validator.go index 5c0466d86b..259b28b2c3 100644 --- a/node/core/validator.go +++ b/node/core/validator.go @@ -5,6 +5,7 @@ import ( ) type ChunkValidator struct { + Encoder core.Encoder Assignment core.AssignmentCoordinator ChainData core.ChainData Id core.OperatorId @@ -14,12 +15,19 @@ func NewChunkValidator() *ChunkValidator { return &ChunkValidator{} } -func (v *ChunkValidator) ValidateChunk(chunk core.Chunk, header core.ConglomerateHeader) error { +func (v *ChunkValidator) ValidateChunks(chunks []core.Chunk, header core.ConglomerateHeader) error { operatorState, _ := v.ChainData.GetOperatorState(header.ReferenceBlockNumber) - assignment, _ := v.Assignment.GetOperatorAssignment(operatorState, header.Quorum, v.Id) + assignment, info, _ := v.Assignment.GetOperatorAssignment(operatorState, header.Quorum, v.Id) + + params := core.EncodingParams{ + ChunkSize: header.ChunkSize, + NumChunks: info.TotalChunks, + } + + err := v.Encoder.VerifyChunks(chunks, assignment.GetIndices(), header.Commitments(), params) // TODO Check that chunk length is equal to that of header - return chunk.Proof.Verify(chunk.Data, chunk.Header.Commitment, assignment.GetIndices()) + return err } diff --git a/node/node.go b/node/node.go index 51c2fea96c..9fdef5e8e3 100644 --- a/node/node.go +++ b/node/node.go @@ -9,5 +9,5 @@ type ChunkServer interface { } type ChunkValidator interface { - ValidateChunk(chunk core.Chunk, header core.ConglomerateHeader) error + ValidateChunks(chunks []core.Chunk, header core.ConglomerateHeader) error } diff --git a/pkg/encoding/encoder/encode.go b/pkg/encoding/encoder/encode.go index 52a357db35..79df2b47ca 100644 --- a/pkg/encoding/encoder/encode.go +++ b/pkg/encoding/encoder/encode.go @@ -80,8 +80,6 @@ func (g *Encoder) MakeFrames( defer log.Println("Exiting MakeFrames function") } - numFrame := g.NumChunks - // reverse dataFr making easier to sample points err := rb.ReverseBitOrderFr(polyEvals) if err != nil { @@ -90,15 +88,10 @@ func (g *Encoder) MakeFrames( k := uint64(0) indices := make([]uint32, 0) - frames := make([]Frame, numFrame) + frames := make([]Frame, g.NumChunks) for i := uint64(0); i < uint64(g.NumChunks); i++ { - // if collect sufficient chunks - if k == numFrame { - return frames, indices, nil - } - // finds out which coset leader i-th node is having j := rb.ReverseBitsLimited(uint32(g.NumChunks), uint32(i)) diff --git a/pkg/encoding/kzgEncoder/encoder.go b/pkg/encoding/kzgEncoder/encoder.go index 513d6cd32a..78485842de 100644 --- a/pkg/encoding/kzgEncoder/encoder.go +++ b/pkg/encoding/kzgEncoder/encoder.go @@ -1,7 +1,6 @@ package kzgEncoder import ( - "context" "errors" "fmt" "log" @@ -131,7 +130,7 @@ func (g *KzgEncoderGroup) NewKzgEncoder(params rs.EncodingParams) (*KzgEncoder, } // just a wrapper to take bytes not Fr Element -func (g *KzgEncoder) EncodeBytes(ctx context.Context, inputBytes []byte) (*bls.G1Point, *bls.G1Point, []Frame, []uint32, error) { +func (g *KzgEncoder) EncodeBytes(inputBytes []byte) (*bls.G1Point, *bls.G1Point, []Frame, []uint32, error) { if g.Verbose { log.Println("Entering EncodeBytes function") defer log.Println("Exiting EncodeBytes function") diff --git a/pkg/encoding/kzgEncoder/encoder_fuzz_test.go b/pkg/encoding/kzgEncoder/encoder_fuzz_test.go index 17e5bf89a6..fd1454620e 100644 --- a/pkg/encoding/kzgEncoder/encoder_fuzz_test.go +++ b/pkg/encoding/kzgEncoder/encoder_fuzz_test.go @@ -1,7 +1,6 @@ package kzgEncoder_test import ( - "context" "testing" rs "github.com/Layr-Labs/eigenda/pkg/encoding/encoder" @@ -23,7 +22,7 @@ func FuzzOnlySystematic(f *testing.F) { } //encode the data - _, _, frames, _, err := enc.EncodeBytes(context.Background(), input) + _, _, frames, _, err := enc.EncodeBytes(input) for _, frame := range frames { assert.NotEqual(t, len(frame.Coeffs), 0) diff --git a/pkg/encoding/kzgEncoder/frame_test.go b/pkg/encoding/kzgEncoder/frame_test.go index d197d865cc..614b348a55 100644 --- a/pkg/encoding/kzgEncoder/frame_test.go +++ b/pkg/encoding/kzgEncoder/frame_test.go @@ -1,7 +1,6 @@ package kzgEncoder_test import ( - "context" "math" "testing" @@ -26,7 +25,7 @@ func TestEncodeDecodeFrame_AreInverses(t *testing.T) { require.Nil(t, err) require.NotNil(t, enc) - _, _, frames, _, err := enc.EncodeBytes(context.Background(), GETTYSBURG_ADDRESS_BYTES) + _, _, frames, _, err := enc.EncodeBytes(GETTYSBURG_ADDRESS_BYTES) require.Nil(t, err) require.NotNil(t, frames, err) @@ -53,7 +52,7 @@ func TestVerify(t *testing.T) { require.Nil(t, err) require.NotNil(t, enc) - commit, _, frames, _, err := enc.EncodeBytes(context.Background(), GETTYSBURG_ADDRESS_BYTES) + commit, _, frames, _, err := enc.EncodeBytes(GETTYSBURG_ADDRESS_BYTES) require.Nil(t, err) require.NotNil(t, commit) require.NotNil(t, frames) diff --git a/pkg/encoding/kzgEncoder/verifier.go b/pkg/encoding/kzgEncoder/verifier.go index cf999cf07c..0b90a7284b 100644 --- a/pkg/encoding/kzgEncoder/verifier.go +++ b/pkg/encoding/kzgEncoder/verifier.go @@ -19,17 +19,18 @@ type KzgVerifier struct { Ks *kzg.KZGSettings } -func (g *KzgEncoderGroup) GetKzgVerifier(numSys, numPar, dataByteLen uint64) (*KzgVerifier, error) { +func (g *KzgEncoderGroup) GetKzgVerifier(params rs.EncodingParams) (*KzgVerifier, error) { - // key := EncoderKey{numSys, numPar, dataByteLen} + if err := params.Validate(); err != nil { + return nil, err + } - params := rs.GetEncodingParams(numSys, numPar, dataByteLen) ver, ok := g.Verifiers[params] if ok { return ver, nil } - ver, err := g.NewKzgVerifier(numSys, numPar, dataByteLen) + ver, err := g.NewKzgVerifier(params) if err == nil { g.Verifiers[params] = ver } @@ -37,9 +38,11 @@ func (g *KzgEncoderGroup) GetKzgVerifier(numSys, numPar, dataByteLen uint64) (*K return ver, err } -func (g *KzgEncoderGroup) NewKzgVerifier(numSys, numPar, dataByteLen uint64) (*KzgVerifier, error) { +func (g *KzgEncoderGroup) NewKzgVerifier(params rs.EncodingParams) (*KzgVerifier, error) { - params := rs.GetEncodingParams(numSys, numPar, dataByteLen) + if err := params.Validate(); err != nil { + return nil, err + } n := uint8(math.Log2(float64(params.NumEvaluations()))) fs := kzg.NewFFTSettings(n)