arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/poseidon/poseidon.go
poseidon/poseidon.goRaw
  1package poseidon
  2
  3import (
  4	. "gnark-ed25519/goldilocks"
  5
  6	"github.com/consensys/gnark/frontend"
  7)
  8
  9/* Note: This package assumes usage of the BN254 curve in various places. */
 10
 11const HALF_N_FULL_ROUNDS = 4
 12const N_FULL_ROUNDS_TOTAL = 2 * HALF_N_FULL_ROUNDS
 13const N_PARTIAL_ROUNDS = 22
 14const N_ROUNDS = N_FULL_ROUNDS_TOTAL + N_PARTIAL_ROUNDS
 15const MAX_WIDTH = 12
 16const WIDTH = 12
 17const SPONGE_WIDTH = 12
 18const SPONGE_RATE = 8
 19
 20type PoseidonState = [WIDTH]GoldilocksElement
 21type PoseidonChip struct {
 22	api   frontend.API
 23	field frontend.API
 24}
 25
 26func Poseidon(api frontend.API, field frontend.API, input PoseidonState) PoseidonState {
 27	chip := &PoseidonChip{api: api, field: field}
 28	return chip.Poseidon(input)
 29}
 30
 31func (c *PoseidonChip) Poseidon(input PoseidonState) PoseidonState {
 32	state := input
 33	roundCounter := 0
 34	state = c.fullRounds(state, &roundCounter)
 35	state = c.partialRounds(state, &roundCounter)
 36	state = c.fullRounds(state, &roundCounter)
 37	return state
 38}
 39
 40func (c *PoseidonChip) fullRounds(state PoseidonState, roundCounter *int) PoseidonState {
 41	for i := 0; i < HALF_N_FULL_ROUNDS; i++ {
 42		state = c.constantLayer(state, roundCounter)
 43		state = c.sBoxLayer(state)
 44		state = c.mdsLayer(state)
 45		if *roundCounter >= 26 && i == 3 {
 46			break
 47		}
 48		*roundCounter += 1
 49	}
 50	return state
 51}
 52
 53func (c *PoseidonChip) partialRounds(state PoseidonState, roundCounter *int) PoseidonState {
 54	state = c.partialFirstConstantLayer(state)
 55	state = c.mdsPartialLayerInit(state)
 56
 57	for i := 0; i < N_PARTIAL_ROUNDS; i++ {
 58		state[0] = c.sBoxMonomial(state[0])
 59		state[0] = c.field.Add(state[0], FAST_PARTIAL_ROUND_CONSTANTS[i]).(GoldilocksElement)
 60		state = c.mdsPartialLayerFast(state, i)
 61	}
 62
 63	*roundCounter += N_PARTIAL_ROUNDS
 64
 65	return state
 66}
 67
 68func (c *PoseidonChip) constantLayer(state PoseidonState, roundCounter *int) PoseidonState {
 69	for i := 0; i < 12; i++ {
 70		if i < WIDTH {
 71			roundConstant := NewGoldilocksElement(ALL_ROUND_CONSTANTS[i+WIDTH*(*roundCounter)])
 72			state[i] = c.field.Add(state[i], roundConstant).(GoldilocksElement)
 73		}
 74	}
 75	return state
 76}
 77
 78func (c *PoseidonChip) sBoxLayer(state PoseidonState) PoseidonState {
 79	for i := 0; i < 12; i++ {
 80		if i < WIDTH {
 81			state[i] = c.sBoxMonomial(state[i])
 82		}
 83	}
 84	return state
 85}
 86
 87func (c *PoseidonChip) sBoxMonomial(x GoldilocksElement) GoldilocksElement {
 88	x2 := c.field.Mul(x, x)
 89	x4 := c.field.Mul(x2, x2)
 90	x3 := c.field.Mul(x2, x)
 91	return c.field.Mul(x3, x4).(GoldilocksElement)
 92}
 93
 94func (c *PoseidonChip) mdsRowShf(r int, v [WIDTH]frontend.Variable) frontend.Variable {
 95	res := frontend.Variable(0)
 96
 97	for i := 0; i < 12; i++ {
 98		if i < WIDTH {
 99			res1 := c.api.Mul(v[(i+r)%WIDTH], frontend.Variable(MDS_MATRIX_CIRC[i]))
100			res = c.api.Add(res, res1)
101		}
102	}
103
104	res = c.api.Add(res, c.api.Mul(v[r], MDS_MATRIX_DIAG[r]))
105	return res
106}
107
108func (c *PoseidonChip) mdsLayer(state_ PoseidonState) PoseidonState {
109	var result PoseidonState
110	for i := 0; i < WIDTH; i++ {
111		result[i] = NewGoldilocksElement(0)
112	}
113
114	var state [WIDTH]frontend.Variable
115	for i := 0; i < WIDTH; i++ {
116		state[i] = c.api.FromBinary(c.field.ToBinary(state_[i])...)
117	}
118
119	for r := 0; r < 12; r++ {
120		if r < WIDTH {
121			sum := c.mdsRowShf(r, state)
122			bits := c.api.ToBinary(sum)
123			result[r] = c.field.FromBinary(bits).(GoldilocksElement)
124		}
125	}
126
127	return result
128}
129
130func (c *PoseidonChip) partialFirstConstantLayer(state PoseidonState) PoseidonState {
131	for i := 0; i < 12; i++ {
132		if i < WIDTH {
133			state[i] = c.field.Add(state[i], NewGoldilocksElement(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])).(GoldilocksElement)
134		}
135	}
136	return state
137}
138
139func (c *PoseidonChip) mdsPartialLayerInit(state PoseidonState) PoseidonState {
140	var result PoseidonState
141	for i := 0; i < 12; i++ {
142		result[i] = NewGoldilocksElement(0)
143	}
144
145	result[0] = state[0]
146
147	for r := 1; r < 12; r++ {
148		if r < WIDTH {
149			for d := 1; d < 12; d++ {
150				if d < WIDTH {
151					t := NewGoldilocksElement(FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1])
152					result[d] = c.field.Add(result[d], c.field.Mul(state[r], t)).(GoldilocksElement)
153				}
154			}
155		}
156	}
157
158	return result
159}
160
161func (c *PoseidonChip) mdsPartialLayerFast(state PoseidonState, r int) PoseidonState {
162	dSum := frontend.Variable(0)
163	for i := 1; i < 12; i++ {
164		if i < WIDTH {
165			t := frontend.Variable(FAST_PARTIAL_ROUND_W_HATS[r][i-1])
166			si := c.api.FromBinary(c.field.ToBinary(state[i])...)
167			dSum = c.api.Add(dSum, c.api.Mul(si, t))
168		}
169	}
170
171	s0 := c.api.FromBinary(c.field.ToBinary(state[0])...)
172	mds0to0 := frontend.Variable(MDS_MATRIX_CIRC[0] + MDS_MATRIX_DIAG[0])
173	dSum = c.api.Add(dSum, c.api.Mul(s0, mds0to0))
174	d := c.field.FromBinary(c.api.ToBinary(dSum))
175
176	var result PoseidonState
177	for i := 0; i < WIDTH; i++ {
178		result[i] = NewGoldilocksElement(0)
179	}
180
181	result[0] = d.(GoldilocksElement)
182
183	for i := 1; i < 12; i++ {
184		if i < WIDTH {
185			t := NewGoldilocksElement(FAST_PARTIAL_ROUND_VS[r][i-1])
186			result[i] = c.field.Add(state[i], c.field.Mul(state[0], t)).(GoldilocksElement)
187		}
188	}
189
190	return result
191}