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.SPONGE_WIDTH]gl.Variable
19 inputBuffer []gl.Variable
20 outputBuffer []gl.Variable
21}
22
23func NewChip(api frontend.API) *Chip {
24 var spongeState [poseidon.SPONGE_WIDTH]gl.Variable
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 c.outputBuffer = clearBuffer(c.outputBuffer)
44 c.inputBuffer = append(c.inputBuffer, element)
45 if len(c.inputBuffer) == poseidon.SPONGE_RATE {
46 c.duplexing()
47 }
48}
49
50func (c *Chip) ObserveElements(elements []gl.Variable) {
51 for i := 0; i < len(elements); i++ {
52 c.ObserveElement(elements[i])
53 }
54}
55
56func (c *Chip) ObserveHash(hash poseidon.GoldilocksHashOut) {
57 elements := c.poseidonChip.ToVec(hash)
58 c.ObserveElements(elements)
59}
60
61func (c *Chip) ObserveBN254Hash(hash poseidon.BN254HashOut) {
62 elements := c.poseidonBN254Chip.ToVec(hash)
63 c.ObserveElements(elements)
64}
65
66func (c *Chip) ObserveCap(cap []poseidon.BN254HashOut) {
67 for i := 0; i < len(cap); i++ {
68 c.ObserveBN254Hash(cap[i])
69 }
70}
71
72func (c *Chip) ObserveExtensionElement(element gl.QuadraticExtensionVariable) {
73 c.ObserveElements(element[:])
74}
75
76func (c *Chip) ObserveExtensionElements(elements []gl.QuadraticExtensionVariable) {
77 for i := 0; i < len(elements); i++ {
78 c.ObserveExtensionElement(elements[i])
79 }
80}
81
82func (c *Chip) ObserveOpenings(openings fri.Openings) {
83 for i := 0; i < len(openings.Batches); i++ {
84 c.ObserveExtensionElements(openings.Batches[i].Values)
85 }
86}
87
88func (c *Chip) GetChallenge() gl.Variable {
89 if len(c.inputBuffer) != 0 || len(c.outputBuffer) == 0 {
90 c.duplexing()
91 }
92
93 challenge := c.outputBuffer[len(c.outputBuffer)-1]
94 c.outputBuffer = c.outputBuffer[:len(c.outputBuffer)-1]
95
96 return challenge
97}
98
99func (c *Chip) GetNChallenges(n uint64) []gl.Variable {
100 challenges := make([]gl.Variable, n)
101 for i := uint64(0); i < n; i++ {
102 challenges[i] = c.GetChallenge()
103 }
104 return challenges
105}
106
107func (c *Chip) GetExtensionChallenge() gl.QuadraticExtensionVariable {
108 values := c.GetNChallenges(2)
109 return gl.QuadraticExtensionVariable{values[0], values[1]}
110}
111
112func (c *Chip) GetHash() poseidon.GoldilocksHashOut {
113 return [4]gl.Variable{c.GetChallenge(), c.GetChallenge(), c.GetChallenge(), c.GetChallenge()}
114}
115
116func (c *Chip) GetFriChallenges(
117 commitPhaseMerkleCaps []variables.FriMerkleCap,
118 finalPoly variables.PolynomialCoeffs,
119 powWitness gl.Variable,
120 degreeBits uint64,
121 config types.FriConfig,
122) variables.FriChallenges {
123 numFriQueries := config.NumQueryRounds
124 friAlpha := c.GetExtensionChallenge()
125
126 var friBetas []gl.QuadraticExtensionVariable
127 for i := 0; i < len(commitPhaseMerkleCaps); i++ {
128 c.ObserveCap(commitPhaseMerkleCaps[i])
129 friBetas = append(friBetas, c.GetExtensionChallenge())
130 }
131
132 c.ObserveExtensionElements(finalPoly.Coeffs)
133 c.ObserveElement(powWitness)
134
135 friPowResponse := c.GetChallenge()
136 friQueryIndices := c.GetNChallenges(numFriQueries)
137
138 return variables.FriChallenges{
139 FriAlpha: friAlpha,
140 FriBetas: friBetas,
141 FriPowResponse: friPowResponse,
142 FriQueryIndices: friQueryIndices,
143 }
144}
145
146func clearBuffer(buffer []gl.Variable) []gl.Variable {
147 return make([]gl.Variable, 0)
148}
149
150func (c *Chip) duplexing() {
151 if len(c.inputBuffer) > poseidon.SPONGE_RATE {
152 fmt.Println(len(c.inputBuffer))
153 panic("something went wrong")
154 }
155
156 glApi := gl.New(c.api)
157
158 for i := 0; i < len(c.inputBuffer); i++ {
159 c.spongeState[i] = glApi.Reduce(c.inputBuffer[i])
160 }
161 c.inputBuffer = clearBuffer(c.inputBuffer)
162 c.spongeState = c.poseidonChip.Poseidon(c.spongeState)
163 clearBuffer(c.outputBuffer)
164 for i := 0; i < poseidon.SPONGE_RATE; i++ {
165 c.outputBuffer = append(c.outputBuffer, c.spongeState[i])
166 }
167}