gnark-plonky2-verifier/challenger/challenger.go
challenger/challenger.goRaw
1package challenger
2
3import (
4 "fmt"
5
6 "github.com/consensys/gnark/frontend"
7 "github.com/succinctlabs/gnark-plonky2-verifier/fri"
8 gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
9 "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
10 "github.com/succinctlabs/gnark-plonky2-verifier/types"
11 "github.com/succinctlabs/gnark-plonky2-verifier/variables"
12)
13
14type Chip struct {
15 api frontend.API `gnark:"-"`
16 poseidonChip *poseidon.GoldilocksChip
17 poseidonBN254Chip *poseidon.BN254Chip
18 spongeState poseidon.GoldilocksState
19 inputBuffer []gl.Variable
20 outputBuffer []gl.Variable
21}
22
23func NewChip(api frontend.API) *Chip {
24 var spongeState poseidon.GoldilocksState
25 var inputBuffer []gl.Variable
26 var outputBuffer []gl.Variable
27 for i := 0; i < poseidon.SPONGE_WIDTH; i++ {
28 spongeState[i] = gl.Zero()
29 }
30 poseidonChip := poseidon.NewGoldilocksChip(api)
31 poseidonBN254Chip := poseidon.NewBN254Chip(api)
32 return &Chip{
33 api: api,
34 poseidonChip: poseidonChip,
35 poseidonBN254Chip: poseidonBN254Chip,
36 spongeState: spongeState,
37 inputBuffer: inputBuffer,
38 outputBuffer: outputBuffer,
39 }
40}
41
42func (c *Chip) ObserveElement(element gl.Variable) {
43 // Clear the output buffer
44 c.outputBuffer = make([]gl.Variable, 0)
45 c.inputBuffer = append(c.inputBuffer, element)
46 if len(c.inputBuffer) == poseidon.SPONGE_RATE {
47 c.duplexing()
48 }
49}
50
51func (c *Chip) ObserveElements(elements []gl.Variable) {
52 for i := 0; i < len(elements); i++ {
53 c.ObserveElement(elements[i])
54 }
55}
56
57func (c *Chip) ObserveHash(hash poseidon.GoldilocksHashOut) {
58 elements := c.poseidonChip.ToVec(hash)
59 c.ObserveElements(elements)
60}
61
62func (c *Chip) ObserveBN254Hash(hash poseidon.BN254HashOut) {
63 elements := c.poseidonBN254Chip.ToVec(hash)
64 c.ObserveElements(elements)
65}
66
67func (c *Chip) ObserveCap(cap []poseidon.BN254HashOut) {
68 for i := 0; i < len(cap); i++ {
69 c.ObserveBN254Hash(cap[i])
70 }
71}
72
73func (c *Chip) ObserveExtensionElement(element gl.QuadraticExtensionVariable) {
74 c.ObserveElements(element[:])
75}
76
77func (c *Chip) ObserveExtensionElements(elements []gl.QuadraticExtensionVariable) {
78 for i := 0; i < len(elements); i++ {
79 c.ObserveExtensionElement(elements[i])
80 }
81}
82
83func (c *Chip) ObserveOpenings(openings fri.Openings) {
84 for i := 0; i < len(openings.Batches); i++ {
85 c.ObserveExtensionElements(openings.Batches[i].Values)
86 }
87}
88
89func (c *Chip) ObserveFriConfig(
90 config types.FriConfig,
91) {
92 c.ObserveElement(gl.NewVariable(config.RateBits))
93 c.ObserveElement(gl.NewVariable(config.CapHeight))
94 c.ObserveElement(gl.NewVariable(config.ProofOfWorkBits))
95 for i := 0; i < len(config.ReductionStrategy); i++ {
96 c.ObserveElement(gl.NewVariable(config.ReductionStrategy[i]))
97 }
98 c.ObserveElement(gl.NewVariable(config.NumQueryRounds))
99}
100
101func (c *Chip) ObserveFriParams(
102 params types.FriParams,
103) {
104 c.ObserveFriConfig(params.Config)
105 c.ObserveElement(gl.NewVariable(0)) // Hiding, should be always false as hiding is not supported in gnark-plonky2-verifier
106 c.ObserveElement(gl.NewVariable(params.DegreeBits))
107 for i := 0; i < len(params.ReductionArityBits); i++ {
108 c.ObserveElement(gl.NewVariable(params.ReductionArityBits[i]))
109 }
110}
111
112func (c *Chip) GetChallenge() gl.Variable {
113 if len(c.inputBuffer) != 0 || len(c.outputBuffer) == 0 {
114 c.duplexing()
115 }
116
117 challenge := c.outputBuffer[len(c.outputBuffer)-1]
118 c.outputBuffer = c.outputBuffer[:len(c.outputBuffer)-1]
119
120 return challenge
121}
122
123func (c *Chip) GetNChallenges(n uint64) []gl.Variable {
124 challenges := make([]gl.Variable, n)
125 for i := uint64(0); i < n; i++ {
126 challenges[i] = c.GetChallenge()
127 }
128 return challenges
129}
130
131func (c *Chip) GetExtensionChallenge() gl.QuadraticExtensionVariable {
132 values := c.GetNChallenges(2)
133 return gl.QuadraticExtensionVariable{values[0], values[1]}
134}
135
136func (c *Chip) GetHash() poseidon.GoldilocksHashOut {
137 return [poseidon.POSEIDON_GL_HASH_SIZE]gl.Variable{c.GetChallenge(), c.GetChallenge(), c.GetChallenge(), c.GetChallenge()}
138}
139
140func (c *Chip) GetFriChallenges(
141 commitPhaseMerkleCaps []variables.FriMerkleCap,
142 finalPoly variables.PolynomialCoeffs,
143 powWitness gl.Variable,
144 config types.FriConfig,
145) variables.FriChallenges {
146 numFriQueries := config.NumQueryRounds
147 friAlpha := c.GetExtensionChallenge()
148
149 var friBetas []gl.QuadraticExtensionVariable
150 for i := 0; i < len(commitPhaseMerkleCaps); i++ {
151 c.ObserveCap(commitPhaseMerkleCaps[i])
152 friBetas = append(friBetas, c.GetExtensionChallenge())
153 }
154
155 c.ObserveExtensionElements(finalPoly.Coeffs)
156 c.ObserveElement(powWitness)
157
158 friPowResponse := c.GetChallenge()
159 friQueryIndices := c.GetNChallenges(numFriQueries)
160
161 return variables.FriChallenges{
162 FriAlpha: friAlpha,
163 FriBetas: friBetas,
164 FriPowResponse: friPowResponse,
165 FriQueryIndices: friQueryIndices,
166 }
167}
168
169func (c *Chip) duplexing() {
170 if len(c.inputBuffer) > poseidon.SPONGE_RATE {
171 fmt.Println(len(c.inputBuffer))
172 panic("something went wrong")
173 }
174
175 glApi := gl.New(c.api)
176
177 for i := 0; i < len(c.inputBuffer); i++ {
178 c.spongeState[i] = glApi.Reduce(c.inputBuffer[i])
179 }
180 // Clear the input buffer
181 c.inputBuffer = make([]gl.Variable, 0)
182 c.spongeState = c.poseidonChip.Poseidon(c.spongeState)
183
184 // Clear the output buffer
185 c.outputBuffer = make([]gl.Variable, 0)
186 for i := 0; i < poseidon.SPONGE_RATE; i++ {
187 c.outputBuffer = append(c.outputBuffer, c.spongeState[i])
188 }
189}