Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(DO NOT MERGE): #98 completed #100

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,8 @@ func NewContext4096(trustedSetup *JSONTrustedSetup) (*Context, error) {
// The bit reversal is not needed for simple KZG however it was
// implemented to make the step for full dank-sharding easier.
commitKeyLagrange.ReversePoints()
domainBlobLen.ReverseRoots()

domainExtended := domain.NewDomain(scalarsPerExtBlob)
domainExtended.ReverseRoots()

fk20 := fk20.NewFK20(commitKeyMonomial.G1, scalarsPerExtBlob, scalarsPerCell)

Expand Down
111 changes: 0 additions & 111 deletions internal/domain/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@
// Roots of unity for the multiplicative subgroup
// Note that these may or may not be in bit-reversed order.
Roots []fr.Element

// Precomputed inverses of the domain which
// we will use to speed up the computation of
// f(x)/g(x) where g(x) is a linear polynomial
// which vanishes on a point on the domain
PreComputedInverses []fr.Element
}

// NewDomain returns a new domain with the desired number of points x.
Expand Down Expand Up @@ -72,7 +66,7 @@
panic(fmt.Sprintf("x (%d) is too big: the required root of unity does not exist", x))
}
expo := uint64(1 << (maxOrderRoot - logx))
domain.Generator.Exp(rootOfUnity, big.NewInt(int64(expo))) // Domain.Generator has order x now.

Check failure on line 69 in internal/domain/domain.go

View workflow job for this annotation

GitHub Actions / Lint

G115: integer overflow conversion uint64 -> int64 (gosec)

// Store Inverse of the generator and inverse of the domain size (as field elements).
domain.GeneratorInv.Inverse(&domain.Generator)
Expand All @@ -87,28 +81,9 @@
current.Mul(&current, &domain.Generator)
}

// Compute precomputed inverses: 1 / w^i
// Note: domain.PreComputedInverses[i] == domain.Roots[x-i mod x], so
// these are redundant, but simplify writing down some algorithms
// and not deal with the case where the roots are bit-reversed.
// We use BatchInvert instead of the above for clarity.
domain.PreComputedInverses = fr.BatchInvert(domain.Roots)

return domain
}

/*
Taken from a chat with Dr Dankrad Feist:
- Samples are going to be contiguous when we switch on full sharding.
- Technically there is nothing that requires samples to be contiguous
pieces of data, but it seems a lot nicer.
- also the relationship between original and interpolated data would
look really strange, with them being interleaved.
- Everything is just nice in brp and looks really strange in direct order
once you introduce sharding. So best to use it from the start and not have
to think about all these when you add DAS.
*/

// BitReverse applies the bit-reversal permutation to `list`.
// `len(list)` must be a power of 2
//
Expand Down Expand Up @@ -147,89 +122,3 @@
shiftCorrection := uint64(64 - bits.TrailingZeros64(bitsize))
return bits.Reverse64(k) >> shiftCorrection
}

// ReverseRoots applies the bit-reversal permutation to the list of precomputed roots of unity and their inverses in the domain.
//
// [bit_reversal_permutation]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#bit_reversal_permutation
func (domain *Domain) ReverseRoots() {
BitReverse(domain.Roots)
BitReverse(domain.PreComputedInverses)
}

// FindRootIndex returns the index of the element in the domain or -1 if not found.
//
// - If point is in the domain (meaning that point is a domain.Cardinality'th root of unity), returns the index of the point in the domain.
// - If point is not in the domain, returns -1.
func (domain *Domain) FindRootIndex(point fr.Element) int64 {
for i := int64(0); i < int64(domain.Cardinality); i++ {
if point.Equal(&domain.Roots[i]) {
return i
}
}

return -1
}

// EvaluateLagrangePolynomial evaluates a Lagrange polynomial at the given point of evaluation.
//
// The input polynomial is given in evaluation form, meaning a list of evaluations at the points in the domain.
// If len(poly) != domain.Cardinality, returns an error.
//
// [evaluate_polynomial_in_evaluation_form]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#evaluate_polynomial_in_evaluation_form
func (domain *Domain) EvaluateLagrangePolynomial(poly []fr.Element, evalPoint fr.Element) (*fr.Element, error) {
outputPoint, _, err := domain.EvaluateLagrangePolynomialWithIndex(poly, evalPoint)

return outputPoint, err
}

// EvaluateLagrangePolynomialWithIndex is the implementation for [EvaluateLagrangePolynomial].
//
// It evaluates a Lagrange polynomial at the given point of evaluation and reports whether the given point was among the points of the domain:
// - The input polynomial is given in evaluation form, that is, a list of evaluations at the points in the domain.
// - The evaluationResult is the result of evaluation at evalPoint.
// - indexInDomain is the index inside domain.Roots, if evalPoint is among them, -1 otherwise
//
// This semantics was copied from the go library, see: https://cs.opensource.google/go/x/exp/+/522b1b58:slices/slices.go;l=117
func (domain *Domain) EvaluateLagrangePolynomialWithIndex(poly []fr.Element, evalPoint fr.Element) (*fr.Element, int64, error) {
var indexInDomain int64 = -1

if domain.Cardinality != uint64(len(poly)) {
return nil, indexInDomain, ErrPolynomialMismatchedSizeDomain
}

// If the evaluation point is in the domain
// then evaluation of the polynomial in lagrange form
// is the same as indexing it with the position
// that the evaluation point is in, in the domain
indexInDomain = domain.FindRootIndex(evalPoint)
if indexInDomain != -1 {
return &poly[indexInDomain], indexInDomain, nil
}

denom := make([]fr.Element, domain.Cardinality)
for i := range denom {
denom[i].Sub(&evalPoint, &domain.Roots[i])
}
invDenom := fr.BatchInvert(denom)

var result fr.Element
for i := 0; i < int(domain.Cardinality); i++ {
var num fr.Element
num.Mul(&poly[i], &domain.Roots[i])

var div fr.Element
div.Mul(&num, &invDenom[i])

result.Add(&result, &div)
}

// result * (x^width - 1) * 1/width
var tmp fr.Element
tmp.Exp(evalPoint, big.NewInt(0).SetUint64(domain.Cardinality))
one := fr.One()
tmp.Sub(&tmp, &one)
tmp.Mul(&tmp, &domain.CardinalityInv)
result.Mul(&tmp, &result)

return &result, indexInDomain, nil
}
94 changes: 0 additions & 94 deletions internal/domain/domain_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package domain

import (
"crypto/rand"
"encoding/binary"
"math"
"math/big"
"math/bits"
Expand Down Expand Up @@ -86,98 +84,6 @@ func bitReversalPermutation(l []fr.Element) []fr.Element {
return out
}

func TestEvalPolynomialSmoke(t *testing.T) {
// The polynomial in question is: f(x) = x^2 + x
f := func(x fr.Element) fr.Element {
var tmp fr.Element
tmp.Square(&x)
tmp.Add(&tmp, &x)
return tmp
}

// You need at least 3 evaluations to determine a degree 2 polynomial
// Due to restriction of the library, we use 4 points.
numEvaluations := 4
domain := NewDomain(uint64(numEvaluations))

// lagrangePoly are the evaluations of the coefficient polynomial over
// `domain`
lagrangePoly := make([]fr.Element, domain.Cardinality)
for i := 0; i < int(domain.Cardinality); i++ {
x := domain.Roots[i]
lagrangePoly[i] = f(x)
}

// Evaluate the lagrange polynomial at all points in the domain
//
for i := int64(0); i < int64(domain.Cardinality); i++ {
inputPoint := domain.Roots[i]

gotOutputPoint, indexInDomain, err := domain.EvaluateLagrangePolynomialWithIndex(lagrangePoly, inputPoint)
if err != nil {
t.Error(err)
}

expectedOutputPoint := lagrangePoly[i]

if !expectedOutputPoint.Equal(gotOutputPoint) {
t.Fatalf("incorrect output point computed from evaluateLagrangePolynomial")
}

if indexInDomain != i {
t.Fatalf("Expected %d as the index of the point being evaluated in the domain. Got %d", i, indexInDomain)
}
}

// Evaluate polynomial at points outside of the domain
//
numPointsToEval := 10

for i := 0; i < numPointsToEval; i++ {
// Sample some random point
inputPoint := samplePointOutsideDomain(*domain)

gotOutputPoint, indexInDomain, err := domain.EvaluateLagrangePolynomialWithIndex(lagrangePoly, *inputPoint)
if err != nil {
t.Errorf(err.Error(), inputPoint.Bytes())
}

// Now we evaluate the polynomial in monomial form
// on the point outside of the domain
expectedPoint := f(*inputPoint)

if !expectedPoint.Equal(gotOutputPoint) {
t.Fatalf("unexpected evaluation of polynomial at point %v", inputPoint.Bytes())
}

if indexInDomain != -1 {
t.Fatalf("point was sampled to be outside of the domain, but returned index is %d", indexInDomain)
}
}
}

func samplePointOutsideDomain(domain Domain) *fr.Element {
var randElement fr.Element

for {
randElement.SetUint64(randUint64())
if domain.FindRootIndex(randElement) == -1 {
break
}
}

return &randElement
}

func randUint64() uint64 {
buf := make([]byte, 8)
_, err := rand.Read(buf)
if err != nil {
panic("could not generate random number")
}
return binary.BigEndian.Uint64(buf)
}

func testScalars(size int) []fr.Element {
res := make([]fr.Element, size)
for i := 0; i < size; i++ {
Expand Down
Loading
Loading