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 package field
import ( import (
"fmt"
"math/big"
"github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/math/emulated"
) )
@ -32,15 +30,22 @@ func NewFieldAPI(api frontend.API) frontend.API {
return field 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/field"
"gnark-ed25519/poseidon" "gnark-ed25519/poseidon"
"math" "math"
"math/big"
"github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
) )
@ -31,9 +33,9 @@ func (c *OpeningSet) ToFriOpenings() FriOpenings {
} }
type FriChip struct { type FriChip struct {
api frontend.API
field frontend.API
qe *QuadraticExtensionAPI
api frontend.API
fieldAPI frontend.API
qeAPI *QuadraticExtensionAPI
poseidonChip *poseidon.PoseidonChip poseidonChip *poseidon.PoseidonChip
@ -41,11 +43,11 @@ type FriChip struct {
verifierOnlyCircuitData *VerifierOnlyCircuitData 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{ return &FriChip{
api: api, api: api,
field: field,
qe: qe,
fieldAPI: fieldAPI,
qeAPI: qeAPI,
poseidonChip: poseidonChip, poseidonChip: poseidonChip,
friParams: friParams, 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 // Note that this is assuming that the Goldilocks field is being used. Specfically that the
// field is 64 bits long // field is 64 bits long
maxPowWitness := uint64(math.Pow(2, float64(64-friConfig.ProofOfWorkBits))) - 1 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 { 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) reducedOpenings := make([]QuadraticExtension, 0, 2)
for _, batch := range openings.Batches { 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 return reducedOpenings
@ -79,7 +81,7 @@ func (f *FriChip) hashOrNoop(data []F) Hash {
elements[i] = inputElement elements[i] = inputElement
} }
for i := len(data); i < 4; i++ { for i := len(data); i < 4; i++ {
elements[i] = f.qe.ZERO_F
elements[i] = field.ZERO_F
} }
return elements 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) { func (f *FriChip) verifyMerkleProofToCapWithCapIndex(leafData []F, leafIndexBits []frontend.Variable, capIndexBits []frontend.Variable, merkleCap MerkleCap, proof *MerkleProof) {
currentDigest := f.hashOrNoop(leafData) 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 { for i, sibling := range proof.Siblings {
bit := leafIndexBits[i] bit := leafIndexBits[i]
@ -128,7 +130,7 @@ func (f *FriChip) verifyMerkleProofToCapWithCapIndex(leafData []F, leafIndexBits
rightHashCompress[2] = rightHash[2] rightHashCompress[2] = rightHash[2]
rightHashCompress[3] = rightHash[3] 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 // 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 // The will use the least significant bits of the capIndexBits array
for i := 0; i < NUM_LEAF_LOOKUPS; i++ { for i := 0; i < NUM_LEAF_LOOKUPS; i++ {
leafLookups[i] = Lookup2Hash( 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], 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 // 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) { 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. // / Here we compare the probabilities as a sanity check, to verify the claim above.
func (f *FriChip) assertNoncanonicalIndicesOK() { func (f *FriChip) assertNoncanonicalIndicesOK() {
numAmbiguousElems := uint64(math.MaxUint64) - EmulatedFieldModulus().Uint64() + 1
numAmbiguousElems := uint64(math.MaxUint64) - goldilocks.Modulus().Uint64() + 1
queryError := f.friParams.Config.rate() 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 // TODO: Check that pAmbiguous value is the same as the one in plonky2 verifier
if pAmbiguous >= queryError*1e-5 { if pAmbiguous >= queryError*1e-5 {
@ -199,10 +201,46 @@ func (f *FriChip) verifyQueryRound(
roundProof *FriQueryRound, roundProof *FriQueryRound,
) { ) {
f.assertNoncanonicalIndicesOK() 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):] capIndexBits := xIndexBits[len(xIndexBits)-int(f.friParams.Config.CapHeight):]
f.verifyInitialProof(xIndexBits, &roundProof.InitialTreesProof, initialMerkleCaps, capIndexBits) 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( func (f *FriChip) VerifyFriProof(

+ 19
- 20
plonky2_verifier/quadratic_extension.go

@ -8,7 +8,7 @@ import (
) )
type QuadraticExtensionAPI struct { type QuadraticExtensionAPI struct {
field frontend.API
fieldAPI frontend.API
W F W F
DTH_ROOT F DTH_ROOT F
@ -18,18 +18,17 @@ type QuadraticExtensionAPI struct {
ZERO_QE QuadraticExtension 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? // TODO: Should degreeBits be verified that it fits within the field and that degree is within uint64?
return &QuadraticExtensionAPI{ return &QuadraticExtensionAPI{
field: field,
fieldAPI: fieldAPI,
W: NewFieldElement(7), W: NewFieldElement(7),
DTH_ROOT: NewFieldElement(18446744069414584320), 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 { 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} return QuadraticExtension{c_0, c_1}
} }
func (c *QuadraticExtensionAPI) AddExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension { 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} return QuadraticExtension{c_0, c_1}
} }
func (c *QuadraticExtensionAPI) SubExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension { 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} 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. // inverse and assert that a_inverse * a = 1. Should reduce # of constraints.
func (c *QuadraticExtensionAPI) InverseExtension(a QuadraticExtension) QuadraticExtension { func (c *QuadraticExtensionAPI) InverseExtension(a QuadraticExtension) QuadraticExtension {
// First assert that a doesn't have 0 value coefficients // 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 // 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) 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 { 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 { func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension {
@ -84,8 +83,8 @@ func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension {
func (c *QuadraticExtensionAPI) Println(a QuadraticExtension) { func (c *QuadraticExtensionAPI) Println(a QuadraticExtension) {
fmt.Print("Degree 0 coefficient") fmt.Print("Degree 0 coefficient")
c.field.Println(a[0])
c.fieldAPI.Println(a[0])
fmt.Print("Degree 1 coefficient") 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]) 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