arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/poseidon/goldilocks.go
poseidon/goldilocks.goRaw
  1package poseidon
  2
  3import (
  4	"github.com/consensys/gnark/frontend"
  5	gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
  6)
  7
  8const HALF_N_FULL_ROUNDS = 4
  9const N_PARTIAL_ROUNDS = 22
 10const SPONGE_WIDTH = 12
 11const SPONGE_RATE = 8
 12
 13type GoldilocksState = [SPONGE_WIDTH]gl.Variable
 14type GoldilocksStateExtension = [SPONGE_WIDTH]gl.QuadraticExtensionVariable
 15type GoldilocksHashOut = [4]gl.Variable
 16
 17type GoldilocksChip struct {
 18	api frontend.API `gnark:"-"`
 19	gl  gl.Chip      `gnark:"-"`
 20}
 21
 22func NewGoldilocksChip(api frontend.API) *GoldilocksChip {
 23	return &GoldilocksChip{api: api, gl: *gl.New(api)}
 24}
 25
 26// The permutation function.
 27// The input state MUST have all it's elements be within Goldilocks field (e.g. this function will not reduce the input elements).
 28// The returned state's elements will all be within Goldilocks field.
 29func (c *GoldilocksChip) Poseidon(input GoldilocksState) GoldilocksState {
 30	state := input
 31	roundCounter := 0
 32	state = c.fullRounds(state, &roundCounter)
 33	state = c.partialRounds(state, &roundCounter)
 34	state = c.fullRounds(state, &roundCounter)
 35	return state
 36}
 37
 38// The input elements MUST have all it's elements be within Goldilocks field.
 39// The returned slice's elements will all be within Goldilocks field.
 40func (c *GoldilocksChip) HashNToMNoPad(input []gl.Variable, nbOutputs int) []gl.Variable {
 41	var state GoldilocksState
 42
 43	for i := 0; i < SPONGE_WIDTH; i++ {
 44		state[i] = gl.NewVariable(0)
 45	}
 46
 47	for i := 0; i < len(input); i += SPONGE_RATE {
 48		for j := 0; j < SPONGE_RATE; j++ {
 49			if i+j < len(input) {
 50				state[j] = input[i+j]
 51			}
 52		}
 53		state = c.Poseidon(state)
 54	}
 55
 56	var outputs []gl.Variable
 57
 58	for {
 59		for i := 0; i < SPONGE_RATE; i++ {
 60			outputs = append(outputs, state[i])
 61			if len(outputs) == nbOutputs {
 62				return outputs
 63			}
 64		}
 65		state = c.Poseidon(state)
 66	}
 67}
 68
 69// The input elements can be outside of the Goldilocks field.
 70// The returned slice's elements will all be within Goldilocks field.
 71func (c *GoldilocksChip) HashNoPad(input []gl.Variable) GoldilocksHashOut {
 72	var hash GoldilocksHashOut
 73	inputVars := []gl.Variable{}
 74
 75	for i := 0; i < len(input); i++ {
 76		inputVars = append(inputVars, c.gl.Reduce(input[i]))
 77	}
 78
 79	outputVars := c.HashNToMNoPad(inputVars, len(hash))
 80	for i := 0; i < len(hash); i++ {
 81		hash[i] = outputVars[i]
 82	}
 83
 84	return hash
 85}
 86
 87func (c *GoldilocksChip) ToVec(hash GoldilocksHashOut) []gl.Variable {
 88	return hash[:]
 89}
 90
 91func (c *GoldilocksChip) fullRounds(state GoldilocksState, roundCounter *int) GoldilocksState {
 92	for i := 0; i < HALF_N_FULL_ROUNDS; i++ {
 93		state = c.constantLayer(state, roundCounter)
 94		state = c.sBoxLayer(state)
 95		state = c.mdsLayer(state)
 96		*roundCounter += 1
 97	}
 98	return state
 99}
100
101func (c *GoldilocksChip) partialRounds(state GoldilocksState, roundCounter *int) GoldilocksState {
102	state = c.partialFirstConstantLayer(state)
103	state = c.mdsPartialLayerInit(state)
104
105	for i := 0; i < N_PARTIAL_ROUNDS; i++ {
106		state[0] = c.sBoxMonomial(state[0])
107		state[0] = c.gl.Add(state[0], gl.NewVariable(FAST_PARTIAL_ROUND_CONSTANTS[i]))
108		state = c.mdsPartialLayerFast(state, i)
109	}
110
111	*roundCounter += N_PARTIAL_ROUNDS
112
113	return state
114}
115
116func (c *GoldilocksChip) constantLayer(state GoldilocksState, roundCounter *int) GoldilocksState {
117	for i := 0; i < 12; i++ {
118		if i < SPONGE_WIDTH {
119			roundConstant := ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)]
120			state[i] = c.gl.Add(state[i], gl.NewVariable(roundConstant))
121		}
122	}
123	return state
124}
125
126func (c *GoldilocksChip) ConstantLayerExtension(state GoldilocksStateExtension, roundCounter *int) GoldilocksStateExtension {
127	for i := 0; i < 12; i++ {
128		if i < SPONGE_WIDTH {
129			roundConstant := gl.NewVariable(ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)])
130			roundConstantQE := gl.NewQuadraticExtensionVariable(roundConstant, gl.Zero())
131			state[i] = c.gl.AddExtension(state[i], roundConstantQE)
132		}
133	}
134	return state
135}
136
137func (c *GoldilocksChip) sBoxMonomial(x gl.Variable) gl.Variable {
138	x2 := c.gl.MulNoReduce(x, x)
139	x3 := c.gl.MulNoReduce(x, x2)
140	x3 = c.gl.ReduceWithMaxBits(x3, 192)
141	x6 := c.gl.MulNoReduce(x3, x3)
142	x7 := c.gl.MulNoReduce(x, x6)
143	return c.gl.ReduceWithMaxBits(x7, 192)
144}
145
146func (c *GoldilocksChip) SBoxMonomialExtension(x gl.QuadraticExtensionVariable) gl.QuadraticExtensionVariable {
147	x2 := c.gl.MulExtension(x, x)
148	x4 := c.gl.MulExtension(x2, x2)
149	x3 := c.gl.MulExtension(x, x2)
150	return c.gl.MulExtension(x4, x3)
151}
152
153func (c *GoldilocksChip) sBoxLayer(state GoldilocksState) GoldilocksState {
154	for i := 0; i < 12; i++ {
155		if i < SPONGE_WIDTH {
156			state[i] = c.sBoxMonomial(state[i])
157		}
158	}
159	return state
160}
161
162func (c *GoldilocksChip) SBoxLayerExtension(state GoldilocksStateExtension) GoldilocksStateExtension {
163	for i := 0; i < 12; i++ {
164		if i < SPONGE_WIDTH {
165			state[i] = c.SBoxMonomialExtension(state[i])
166		}
167	}
168	return state
169}
170
171func (c *GoldilocksChip) mdsRowShf(r int, v GoldilocksState) gl.Variable {
172	res := gl.Zero()
173
174	for i := 0; i < 12; i++ {
175		if i < SPONGE_WIDTH {
176			res = c.gl.MulAddNoReduce(v[(i+r)%SPONGE_WIDTH], gl.NewVariable(MDS_MATRIX_CIRC_VARS[i]), res)
177		}
178	}
179
180	res = c.gl.MulAddNoReduce(v[r], gl.NewVariable(MDS_MATRIX_DIAG_VARS[r]), res)
181	return c.gl.Reduce(res)
182}
183
184func (c *GoldilocksChip) MdsRowShfExtension(r int, v GoldilocksStateExtension) gl.QuadraticExtensionVariable {
185	res := gl.ZeroExtension()
186
187	for i := 0; i < 12; i++ {
188		if i < SPONGE_WIDTH {
189			matrixVal := gl.NewVariable(MDS_MATRIX_CIRC[i])
190			matrixValQE := gl.NewQuadraticExtensionVariable(matrixVal, gl.Zero())
191			res1 := c.gl.MulExtension(v[(i+r)%SPONGE_WIDTH], matrixValQE)
192			res = c.gl.AddExtension(res, res1)
193		}
194	}
195
196	matrixVal := gl.NewVariable(MDS_MATRIX_DIAG[r])
197	matrixValQE := gl.NewQuadraticExtensionVariable(matrixVal, gl.Zero())
198	res = c.gl.AddExtension(res, c.gl.MulExtension(v[r], matrixValQE))
199	return res
200}
201
202func (c *GoldilocksChip) mdsLayer(state_ GoldilocksState) GoldilocksState {
203	var result GoldilocksState
204	for i := 0; i < SPONGE_WIDTH; i++ {
205		result[i] = gl.NewVariable(0)
206	}
207
208	for r := 0; r < 12; r++ {
209		if r < SPONGE_WIDTH {
210			result[r] = c.mdsRowShf(r, state_)
211		}
212	}
213
214	return result
215}
216
217func (c *GoldilocksChip) MdsLayerExtension(state_ GoldilocksStateExtension) GoldilocksStateExtension {
218	var result GoldilocksStateExtension
219
220	for r := 0; r < 12; r++ {
221		if r < SPONGE_WIDTH {
222			sum := c.MdsRowShfExtension(r, state_)
223			result[r] = sum
224		}
225	}
226
227	return result
228}
229
230func (c *GoldilocksChip) partialFirstConstantLayer(state GoldilocksState) GoldilocksState {
231	for i := 0; i < 12; i++ {
232		if i < SPONGE_WIDTH {
233			state[i] = c.gl.Add(state[i], gl.NewVariable(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i]))
234		}
235	}
236	return state
237}
238
239func (c *GoldilocksChip) PartialFirstConstantLayerExtension(state GoldilocksStateExtension) GoldilocksStateExtension {
240	for i := 0; i < 12; i++ {
241		if i < SPONGE_WIDTH {
242			fastPartialRoundConstant := gl.NewVariable(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])
243			fastPartialRoundConstantQE := gl.NewQuadraticExtensionVariable(fastPartialRoundConstant, gl.Zero())
244			state[i] = c.gl.AddExtension(state[i], fastPartialRoundConstantQE)
245		}
246	}
247	return state
248}
249
250func (c *GoldilocksChip) mdsPartialLayerInit(state GoldilocksState) GoldilocksState {
251	var result GoldilocksState
252	for i := 0; i < 12; i++ {
253		result[i] = gl.Zero()
254	}
255
256	result[0] = state[0]
257
258	for r := 1; r < 12; r++ {
259		if r < SPONGE_WIDTH {
260			for d := 1; d < 12; d++ {
261				if d < SPONGE_WIDTH {
262					t := FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1]
263					result[d] = c.gl.MulAddNoReduce(state[r], gl.NewVariable(t), result[d])
264				}
265			}
266		}
267	}
268
269	for i := 0; i < 12; i++ {
270		result[i] = c.gl.Reduce(result[i])
271	}
272
273	return result
274}
275
276func (c *GoldilocksChip) MdsPartialLayerInitExtension(state GoldilocksStateExtension) GoldilocksStateExtension {
277	var result GoldilocksStateExtension
278	for i := 0; i < 12; i++ {
279		result[i] = gl.ZeroExtension()
280	}
281
282	result[0] = state[0]
283
284	for r := 1; r < 12; r++ {
285		if r < SPONGE_WIDTH {
286			for d := 1; d < 12; d++ {
287				if d < SPONGE_WIDTH {
288					t := gl.NewVariable(FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1])
289					tQE := gl.NewQuadraticExtensionVariable(t, gl.Zero())
290					result[d] = c.gl.AddExtension(result[d], c.gl.MulExtension(state[r], tQE))
291				}
292			}
293		}
294	}
295
296	return result
297}
298
299func (c *GoldilocksChip) mdsPartialLayerFast(state GoldilocksState, r int) GoldilocksState {
300	dSum := gl.Zero()
301	for i := 1; i < 12; i++ {
302		if i < SPONGE_WIDTH {
303			t := FAST_PARTIAL_ROUND_W_HATS_VARS[r][i-1]
304			dSum = c.gl.MulAddNoReduce(state[i], gl.NewVariable(t), dSum)
305		}
306	}
307
308	d := c.gl.MulAddNoReduce(state[0], gl.NewVariable(MDS0TO0_VAR), dSum)
309	d = c.gl.Reduce(d)
310
311	var result GoldilocksState
312	for i := 0; i < SPONGE_WIDTH; i++ {
313		result[i] = gl.NewVariable(0)
314	}
315
316	result[0] = d
317
318	for i := 1; i < 12; i++ {
319		if i < SPONGE_WIDTH {
320			t := FAST_PARTIAL_ROUND_VS[r][i-1]
321			result[i] = c.gl.MulAddNoReduce(state[0], gl.NewVariable(t), state[i])
322		}
323	}
324
325	for i := 0; i < len(state); i++ {
326		result[i] = c.gl.Reduce(result[i])
327	}
328
329	return result
330}
331
332func (c *GoldilocksChip) MdsPartialLayerFastExtension(state GoldilocksStateExtension, r int) GoldilocksStateExtension {
333	s0 := state[0]
334	mds0to0 := gl.NewVariable(MDS0TO0)
335	mds0to0QE := gl.NewQuadraticExtensionVariable(mds0to0, gl.Zero())
336	d := c.gl.MulExtension(s0, mds0to0QE)
337	for i := 1; i < 12; i++ {
338		if i < SPONGE_WIDTH {
339			t := gl.NewVariable(FAST_PARTIAL_ROUND_W_HATS[r][i-1])
340			tQE := gl.NewQuadraticExtensionVariable(t, gl.Zero())
341			d = c.gl.AddExtension(d, c.gl.MulExtension(state[i], tQE))
342		}
343	}
344
345	var result GoldilocksStateExtension
346	result[0] = d
347	for i := 1; i < 12; i++ {
348		if i < SPONGE_WIDTH {
349			t := gl.NewVariable(FAST_PARTIAL_ROUND_VS[r][i-1])
350			tQE := gl.NewQuadraticExtensionVariable(t, gl.Zero())
351			result[i] = c.gl.AddExtension(c.gl.MulExtension(state[0], tQE), state[i])
352		}
353	}
354
355	return result
356}