gnark-plonky2-verifier/verifier/internal/plonk/challenger.go
verifier/internal/plonk/challenger.goRaw
1package plonk
2
3import (
4 "fmt"
5
6 "github.com/consensys/gnark/frontend"
7 "github.com/succinctlabs/gnark-plonky2-verifier/field"
8 "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
9 "github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
10 "github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/fri"
11)
12
13type ChallengerChip struct {
14 api frontend.API `gnark:"-"`
15 field field.FieldAPI `gnark:"-"`
16 poseidonChip *poseidon.PoseidonChip
17 poseidonBN128Chip *poseidon.PoseidonBN128Chip
18 spongeState [poseidon.SPONGE_WIDTH]frontend.Variable
19 inputBuffer []field.F
20 outputBuffer []field.F
21}
22
23func NewChallengerChip(api frontend.API, fieldAPI field.FieldAPI, poseidonChip *poseidon.PoseidonChip, poseidonBN128Chip *poseidon.PoseidonBN128Chip) *ChallengerChip {
24 var spongeState [poseidon.SPONGE_WIDTH]frontend.Variable
25 var inputBuffer []field.F
26 var outputBuffer []field.F
27
28 for i := 0; i < poseidon.SPONGE_WIDTH; i++ {
29 spongeState[i] = frontend.Variable(0)
30 }
31
32 return &ChallengerChip{
33 api: api,
34 field: fieldAPI,
35 poseidonChip: poseidonChip,
36 poseidonBN128Chip: poseidonBN128Chip,
37 spongeState: spongeState,
38 inputBuffer: inputBuffer,
39 outputBuffer: outputBuffer,
40 }
41}
42
43func (c *ChallengerChip) ObserveElement(element field.F) {
44 c.outputBuffer = clearBuffer(c.outputBuffer)
45 c.inputBuffer = append(c.inputBuffer, element)
46 if len(c.inputBuffer) == poseidon.SPONGE_RATE {
47 c.duplexing()
48 }
49}
50
51func (c *ChallengerChip) ObserveElements(elements []field.F) {
52 for i := 0; i < len(elements); i++ {
53 c.ObserveElement(elements[i])
54 }
55}
56
57func (c *ChallengerChip) ObserveHash(hash poseidon.PoseidonHashOut) {
58 elements := c.poseidonChip.ToVec(hash)
59 c.ObserveElements(elements)
60}
61
62func (c *ChallengerChip) ObserveBN128Hash(hash poseidon.PoseidonBN128HashOut) {
63 elements := c.poseidonBN128Chip.ToVec(hash)
64 c.ObserveElements(elements)
65}
66
67func (c *ChallengerChip) ObserveCap(cap []poseidon.PoseidonBN128HashOut) {
68 for i := 0; i < len(cap); i++ {
69 c.ObserveBN128Hash(cap[i])
70 }
71}
72
73func (c *ChallengerChip) ObserveExtensionElement(element field.QuadraticExtension) {
74 c.ObserveElements(element[:])
75}
76
77func (c *ChallengerChip) ObserveExtensionElements(elements []field.QuadraticExtension) {
78 for i := 0; i < len(elements); i++ {
79 c.ObserveExtensionElement(elements[i])
80 }
81}
82
83func (c *ChallengerChip) ObserveOpenings(openings fri.FriOpenings) {
84 for i := 0; i < len(openings.Batches); i++ {
85 c.ObserveExtensionElements(openings.Batches[i].Values)
86 }
87}
88
89func (c *ChallengerChip) GetChallenge() field.F {
90 if len(c.inputBuffer) != 0 || len(c.outputBuffer) == 0 {
91 c.duplexing()
92 }
93
94 challenge := c.outputBuffer[len(c.outputBuffer)-1]
95 c.outputBuffer = c.outputBuffer[:len(c.outputBuffer)-1]
96
97 return challenge
98}
99
100func (c *ChallengerChip) GetNChallenges(n uint64) []field.F {
101 challenges := make([]field.F, n)
102 for i := uint64(0); i < n; i++ {
103 challenges[i] = c.GetChallenge()
104 }
105 return challenges
106}
107
108func (c *ChallengerChip) GetExtensionChallenge() field.QuadraticExtension {
109 values := c.GetNChallenges(2)
110 return field.QuadraticExtension{values[0], values[1]}
111}
112
113func (c *ChallengerChip) GetHash() poseidon.PoseidonHashOut {
114 return [4]field.F{c.GetChallenge(), c.GetChallenge(), c.GetChallenge(), c.GetChallenge()}
115}
116
117func (c *ChallengerChip) GetFriChallenges(commitPhaseMerkleCaps []common.MerkleCap, finalPoly common.PolynomialCoeffs, powWitness field.F, degreeBits uint64, config common.FriConfig) common.FriChallenges {
118 numFriQueries := config.NumQueryRounds
119 friAlpha := c.GetExtensionChallenge()
120
121 var friBetas []field.QuadraticExtension
122 for i := 0; i < len(commitPhaseMerkleCaps); i++ {
123 c.ObserveCap(commitPhaseMerkleCaps[i])
124 friBetas = append(friBetas, c.GetExtensionChallenge())
125 }
126
127 c.ObserveExtensionElements(finalPoly.Coeffs)
128 c.ObserveElement(powWitness)
129
130 friPowResponse := c.GetChallenge()
131 friQueryIndices := c.GetNChallenges(numFriQueries)
132
133 return common.FriChallenges{
134 FriAlpha: friAlpha,
135 FriBetas: friBetas,
136 FriPowResponse: friPowResponse,
137 FriQueryIndices: friQueryIndices,
138 }
139}
140
141func clearBuffer(buffer []field.F) []field.F {
142 return make([]field.F, 0)
143}
144
145func (c *ChallengerChip) duplexing() {
146 if len(c.inputBuffer) > poseidon.SPONGE_RATE {
147 fmt.Println(len(c.inputBuffer))
148 panic("something went wrong")
149 }
150
151 for i := 0; i < len(c.inputBuffer); i++ {
152 c.spongeState[i] = c.field.Reduce(c.inputBuffer[i]).Limbs[0]
153 }
154 c.inputBuffer = clearBuffer(c.inputBuffer)
155 c.spongeState = c.poseidonChip.Poseidon(c.spongeState)
156 clearBuffer(c.outputBuffer)
157 for i := 0; i < poseidon.SPONGE_RATE; i++ {
158 c.outputBuffer = append(c.outputBuffer, c.field.NewElement(c.spongeState[i]))
159 }
160}