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