Browse Source

calculated subgroupX

main
Kevin Jue 2 years ago
parent
commit
8e9591c964
4 changed files with 97 additions and 48 deletions
  1. +16
    -11
      field/field.go
  2. +55
    -17
      plonky2_verifier/fri.go
  3. +19
    -20
      plonky2_verifier/quadratic_extension.go
  4. +7
    -0
      plonky2_verifier/utils.go

+ 16
- 11
field/field.go

@ -1,10 +1,8 @@
package field
import (
"fmt"
"math/big"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/math/emulated"
)
@ -32,15 +30,22 @@ func NewFieldAPI(api frontend.API) frontend.API {
return field
}
var r EmulatedField
var ONE_F = NewFieldElement(1)
var ZERO_F = NewFieldElement(0)
func EmulatedFieldModulus() *big.Int {
return r.Modulus()
}
var GOLDILOCKS_MULTIPLICATIVE_GROUP_GENERATOR = goldilocks.NewElement(7)
var GOLDILOCKS_TWO_ADICITY = uint64(32)
var GOLDILOCKS_POWER_OF_TWO_GENERATOR = goldilocks.NewElement(1753635133440165772)
func PrintHash(f frontend.API, h Hash) {
for i := 0; i < 4; i++ {
fmt.Println("Hash Limb", i)
f.Println(h[i])
func GoldilocksPrimitiveRootOfUnity(nLog uint64) goldilocks.Element {
if nLog > GOLDILOCKS_TWO_ADICITY {
panic("nLog is greater than GOLDILOCKS_TWO_ADICITY")
}
res := goldilocks.NewElement(GOLDILOCKS_POWER_OF_TWO_GENERATOR.Uint64())
for i := 0; i < int(GOLDILOCKS_TWO_ADICITY-nLog); i++ {
res.Square(&res)
}
return res
}

+ 55
- 17
plonky2_verifier/fri.go

@ -6,7 +6,9 @@ import (
. "gnark-ed25519/field"
"gnark-ed25519/poseidon"
"math"
"math/big"
"github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/frontend"
)
@ -31,9 +33,9 @@ func (c *OpeningSet) ToFriOpenings() FriOpenings {
}
type FriChip struct {
api frontend.API
field frontend.API
qe *QuadraticExtensionAPI
api frontend.API
fieldAPI frontend.API
qeAPI *QuadraticExtensionAPI
poseidonChip *poseidon.PoseidonChip
@ -41,11 +43,11 @@ type FriChip struct {
verifierOnlyCircuitData *VerifierOnlyCircuitData
}
func NewFriChip(api frontend.API, field frontend.API, qe *QuadraticExtensionAPI, poseidonChip *poseidon.PoseidonChip, friParams *FriParams) *FriChip {
func NewFriChip(api frontend.API, fieldAPI frontend.API, qeAPI *QuadraticExtensionAPI, poseidonChip *poseidon.PoseidonChip, friParams *FriParams) *FriChip {
return &FriChip{
api: api,
field: field,
qe: qe,
fieldAPI: fieldAPI,
qeAPI: qeAPI,
poseidonChip: poseidonChip,
friParams: friParams,
}
@ -56,7 +58,7 @@ func (f *FriChip) assertLeadingZeros(powWitness F, friConfig FriConfig) {
// Note that this is assuming that the Goldilocks field is being used. Specfically that the
// field is 64 bits long
maxPowWitness := uint64(math.Pow(2, float64(64-friConfig.ProofOfWorkBits))) - 1
f.field.AssertIsLessOrEqual(powWitness, field.NewFieldElement(maxPowWitness))
f.fieldAPI.AssertIsLessOrEqual(powWitness, field.NewFieldElement(maxPowWitness))
}
func (f *FriChip) fromOpeningsAndAlpha(openings *FriOpenings, alpha QuadraticExtension) []QuadraticExtension {
@ -65,7 +67,7 @@ func (f *FriChip) fromOpeningsAndAlpha(openings *FriOpenings, alpha QuadraticExt
reducedOpenings := make([]QuadraticExtension, 0, 2)
for _, batch := range openings.Batches {
reducedOpenings = append(reducedOpenings, reduceWithPowers(f.qe, batch.values, alpha))
reducedOpenings = append(reducedOpenings, reduceWithPowers(f.qeAPI, batch.values, alpha))
}
return reducedOpenings
@ -79,7 +81,7 @@ func (f *FriChip) hashOrNoop(data []F) Hash {
elements[i] = inputElement
}
for i := len(data); i < 4; i++ {
elements[i] = f.qe.ZERO_F
elements[i] = field.ZERO_F
}
return elements
@ -100,7 +102,7 @@ func (f *FriChip) hashOrNoop(data []F) Hash {
func (f *FriChip) verifyMerkleProofToCapWithCapIndex(leafData []F, leafIndexBits []frontend.Variable, capIndexBits []frontend.Variable, merkleCap MerkleCap, proof *MerkleProof) {
currentDigest := f.hashOrNoop(leafData)
fourZeros := [4]F{f.qe.ZERO_F, f.qe.ZERO_F, f.qe.ZERO_F, f.qe.ZERO_F}
fourZeros := [4]F{field.ZERO_F, field.ZERO_F, field.ZERO_F, field.ZERO_F}
for i, sibling := range proof.Siblings {
bit := leafIndexBits[i]
@ -128,7 +130,7 @@ func (f *FriChip) verifyMerkleProofToCapWithCapIndex(leafData []F, leafIndexBits
rightHashCompress[2] = rightHash[2]
rightHashCompress[3] = rightHash[3]
currentDigest = SelectHash(f.field, bit, leftHashCompress, rightHashCompress)
currentDigest = SelectHash(f.fieldAPI, bit, leftHashCompress, rightHashCompress)
}
// We assume that the cap_height is 4. Create two levels of the Lookup2 circuit
@ -142,14 +144,14 @@ func (f *FriChip) verifyMerkleProofToCapWithCapIndex(leafData []F, leafIndexBits
// The will use the least significant bits of the capIndexBits array
for i := 0; i < NUM_LEAF_LOOKUPS; i++ {
leafLookups[i] = Lookup2Hash(
f.field, capIndexBits[0], capIndexBits[1],
f.fieldAPI, capIndexBits[0], capIndexBits[1],
merkleCap[i*NUM_LEAF_LOOKUPS], merkleCap[i*NUM_LEAF_LOOKUPS+1], merkleCap[i*NUM_LEAF_LOOKUPS+2], merkleCap[i*NUM_LEAF_LOOKUPS+3],
)
}
// Use the most 2 significant bits of the capIndexBits array for the "root" lookup
merkleCapEntry := Lookup2Hash(f.field, capIndexBits[2], capIndexBits[3], leafLookups[0], leafLookups[1], leafLookups[2], leafLookups[3])
AssertIsEqualHash(f.field, currentDigest, merkleCapEntry)
merkleCapEntry := Lookup2Hash(f.fieldAPI, capIndexBits[2], capIndexBits[3], leafLookups[0], leafLookups[1], leafLookups[2], leafLookups[3])
AssertIsEqualHash(f.fieldAPI, currentDigest, merkleCapEntry)
}
func (f *FriChip) verifyInitialProof(xIndexBits []frontend.Variable, proof *FriInitialTreeProof, initialMerkleCaps []MerkleCap, capIndexBits []frontend.Variable) {
@ -178,9 +180,9 @@ func (f *FriChip) verifyInitialProof(xIndexBits []frontend.Variable, proof *FriI
// /
// / Here we compare the probabilities as a sanity check, to verify the claim above.
func (f *FriChip) assertNoncanonicalIndicesOK() {
numAmbiguousElems := uint64(math.MaxUint64) - EmulatedFieldModulus().Uint64() + 1
numAmbiguousElems := uint64(math.MaxUint64) - goldilocks.Modulus().Uint64() + 1
queryError := f.friParams.Config.rate()
pAmbiguous := float64(numAmbiguousElems) / float64(EmulatedFieldModulus().Uint64())
pAmbiguous := float64(numAmbiguousElems) / float64(goldilocks.Modulus().Uint64())
// TODO: Check that pAmbiguous value is the same as the one in plonky2 verifier
if pAmbiguous >= queryError*1e-5 {
@ -199,10 +201,46 @@ func (f *FriChip) verifyQueryRound(
roundProof *FriQueryRound,
) {
f.assertNoncanonicalIndicesOK()
xIndexBits := f.qe.field.ToBinary(xIndex, int(nLog))
xIndexBits := f.fieldAPI.ToBinary(xIndex, int(nLog))
capIndexBits := xIndexBits[len(xIndexBits)-int(f.friParams.Config.CapHeight):]
f.verifyInitialProof(xIndexBits, &roundProof.InitialTreesProof, initialMerkleCaps, capIndexBits)
// Compute x from its index
// `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain.
// TODO - Make these as global values
g := field.NewFieldElement(field.GOLDILOCKS_MULTIPLICATIVE_GROUP_GENERATOR.Uint64())
base := field.GoldilocksPrimitiveRootOfUnity(nLog)
product := ONE_F
// Create a reverse list of xIndexBits
xIndexBitsRev := make([]frontend.Variable, 0)
for i := len(xIndexBits) - 1; i >= 0; i-- {
xIndexBitsRev = append(xIndexBitsRev, xIndexBits[i])
}
for i, bit := range xIndexBitsRev {
pow := int64(1 << i)
// If the bit is on, we multiply product by base^pow.
// We can arithmetize this as:
// product *= 1 + bit (base^pow - 1)
// product = (base^pow - 1) product bit + product
basePow := goldilocks.NewElement(0)
basePow.Exp(base, big.NewInt(pow))
basePowElement := NewFieldElement(basePow.Uint64() - 1)
product = f.fieldAPI.Add(
f.fieldAPI.Mul(
basePowElement,
product,
bit,
),
product,
).(F)
}
subgroupX := f.fieldAPI.Mul(g, product).(F)
}
func (f *FriChip) VerifyFriProof(

+ 19
- 20
plonky2_verifier/quadratic_extension.go

@ -8,7 +8,7 @@ import (
)
type QuadraticExtensionAPI struct {
field frontend.API
fieldAPI frontend.API
W F
DTH_ROOT F
@ -18,18 +18,17 @@ type QuadraticExtensionAPI struct {
ZERO_QE QuadraticExtension
}
func NewQuadraticExtensionAPI(field frontend.API, degreeBits uint64) *QuadraticExtensionAPI {
func NewQuadraticExtensionAPI(fieldAPI frontend.API, degreeBits uint64) *QuadraticExtensionAPI {
// TODO: Should degreeBits be verified that it fits within the field and that degree is within uint64?
return &QuadraticExtensionAPI{
field: field,
fieldAPI: fieldAPI,
W: NewFieldElement(7),
DTH_ROOT: NewFieldElement(18446744069414584320),
ZERO_F: NewFieldElement(0),
ONE: QuadraticExtension{NewFieldElement(1), NewFieldElement(0)},
ZERO_QE: QuadraticExtension{NewFieldElement(0), NewFieldElement(0)},
ONE: QuadraticExtension{ONE_F, ZERO_F},
ZERO_QE: QuadraticExtension{ZERO_F, ZERO_F},
}
}
@ -38,20 +37,20 @@ func (c *QuadraticExtensionAPI) SquareExtension(a QuadraticExtension) QuadraticE
}
func (c *QuadraticExtensionAPI) MulExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
c_0 := c.field.Add(c.field.Mul(a[0], b[0]).(F), c.field.Mul(c.W, a[1], b[1])).(F)
c_1 := c.field.Add(c.field.Mul(a[0], b[1]).(F), c.field.Mul(a[1], b[0])).(F)
c_0 := c.fieldAPI.Add(c.fieldAPI.Mul(a[0], b[0]).(F), c.fieldAPI.Mul(c.W, a[1], b[1])).(F)
c_1 := c.fieldAPI.Add(c.fieldAPI.Mul(a[0], b[1]).(F), c.fieldAPI.Mul(a[1], b[0])).(F)
return QuadraticExtension{c_0, c_1}
}
func (c *QuadraticExtensionAPI) AddExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
c_0 := c.field.Add(a[0], b[0]).(F)
c_1 := c.field.Add(a[1], b[1]).(F)
c_0 := c.fieldAPI.Add(a[0], b[0]).(F)
c_1 := c.fieldAPI.Add(a[1], b[1]).(F)
return QuadraticExtension{c_0, c_1}
}
func (c *QuadraticExtensionAPI) SubExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
c_0 := c.field.Sub(a[0], b[0]).(F)
c_1 := c.field.Sub(a[1], b[1]).(F)
c_0 := c.fieldAPI.Sub(a[0], b[0]).(F)
c_1 := c.fieldAPI.Sub(a[1], b[1]).(F)
return QuadraticExtension{c_0, c_1}
}
@ -63,19 +62,19 @@ func (c *QuadraticExtensionAPI) DivExtension(a QuadraticExtension, b QuadraticEx
// inverse and assert that a_inverse * a = 1. Should reduce # of constraints.
func (c *QuadraticExtensionAPI) InverseExtension(a QuadraticExtension) QuadraticExtension {
// First assert that a doesn't have 0 value coefficients
a0_is_zero := c.field.IsZero(a[0])
a1_is_zero := c.field.IsZero(a[1])
a0_is_zero := c.fieldAPI.IsZero(a[0])
a1_is_zero := c.fieldAPI.IsZero(a[1])
// assert that a0_is_zero OR a1_is_zero == false
c.field.AssertIsEqual(c.field.Mul(a0_is_zero, a1_is_zero).(F), c.ZERO_F)
c.fieldAPI.AssertIsEqual(c.fieldAPI.Mul(a0_is_zero, a1_is_zero).(F), c.ZERO_F)
a_pow_r_minus_1 := QuadraticExtension{a[0], c.field.Mul(a[1], c.DTH_ROOT).(F)}
a_pow_r_minus_1 := QuadraticExtension{a[0], c.fieldAPI.Mul(a[1], c.DTH_ROOT).(F)}
a_pow_r := c.MulExtension(a_pow_r_minus_1, a)
return c.ScalarMulExtension(a_pow_r_minus_1, c.field.Inverse(a_pow_r[0]).(F))
return c.ScalarMulExtension(a_pow_r_minus_1, c.fieldAPI.Inverse(a_pow_r[0]).(F))
}
func (c *QuadraticExtensionAPI) ScalarMulExtension(a QuadraticExtension, scalar F) QuadraticExtension {
return QuadraticExtension{c.field.Mul(a[0], scalar).(F), c.field.Mul(a[1], scalar).(F)}
return QuadraticExtension{c.fieldAPI.Mul(a[0], scalar).(F), c.fieldAPI.Mul(a[1], scalar).(F)}
}
func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension {
@ -84,8 +83,8 @@ func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension {
func (c *QuadraticExtensionAPI) Println(a QuadraticExtension) {
fmt.Print("Degree 0 coefficient")
c.field.Println(a[0])
c.fieldAPI.Println(a[0])
fmt.Print("Degree 1 coefficient")
c.field.Println(a[1])
c.fieldAPI.Println(a[1])
}

+ 7
- 0
plonky2_verifier/utils.go

@ -57,3 +57,10 @@ func AssertIsEqualHash(fieldAPI frontend.API, h1, h2 Hash) {
fieldAPI.AssertIsEqual(h1[0], h2[0])
}
}
func PrintHash(f frontend.API, h Hash) {
for i := 0; i < 4; i++ {
fmt.Println("Hash Limb", i)
f.Println(h[i])
}
}

Loading…
Cancel
Save