|
@ -1,7 +1,6 @@ |
|
|
package poseidon |
|
|
package poseidon |
|
|
|
|
|
|
|
|
import ( |
|
|
import ( |
|
|
"errors" |
|
|
|
|
|
"fmt" |
|
|
"fmt" |
|
|
"math/big" |
|
|
"math/big" |
|
|
|
|
|
|
|
@ -17,40 +16,41 @@ func zero() *ff.Element { |
|
|
return ff.NewElement() |
|
|
return ff.NewElement() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
|
|
|
|
|
|
func ark(state []*ff.Element, c []*ff.Element, it int) { |
|
|
|
|
|
for i := 0; i < len(state); i++ { |
|
|
|
|
|
state[i].Add(state[i], c[it+i]) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// exp5 performs x^5 mod p
|
|
|
// exp5 performs x^5 mod p
|
|
|
// https://eprint.iacr.org/2019/458.pdf page 8
|
|
|
// https://eprint.iacr.org/2019/458.pdf page 8
|
|
|
func exp5(a *ff.Element) { |
|
|
func exp5(a *ff.Element) { |
|
|
a.Exp(*a, 5) |
|
|
a.Exp(*a, 5) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// sbox https://eprint.iacr.org/2019/458.pdf page 6
|
|
|
|
|
|
func sbox(nRoundsF, nRoundsP int, state []*ff.Element, i int) { |
|
|
|
|
|
if (i < nRoundsF/2) || (i >= nRoundsF/2+nRoundsP) { |
|
|
|
|
|
for j := 0; j < len(state); j++ { |
|
|
|
|
|
exp5(state[j]) |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
exp5(state[0]) |
|
|
|
|
|
|
|
|
// exp5state perform exp5 for whole state
|
|
|
|
|
|
func exp5state(state []*ff.Element) { |
|
|
|
|
|
for i := 0; i < len(state); i++ { |
|
|
|
|
|
exp5(state[i]) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
|
|
|
|
|
|
func ark(state []*ff.Element, c []*ff.Element, it int) { |
|
|
|
|
|
for i := 0; i < len(state); i++ { |
|
|
|
|
|
state[i].Add(state[i], c[it+i]) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// mix returns [[matrix]] * [vector]
|
|
|
// mix returns [[matrix]] * [vector]
|
|
|
func mix(state []*ff.Element, newState []*ff.Element, m [][]*ff.Element) { |
|
|
|
|
|
|
|
|
func mix(state []*ff.Element, t int, m [][]*ff.Element) []*ff.Element { |
|
|
mul := zero() |
|
|
mul := zero() |
|
|
|
|
|
newState := make([]*ff.Element, t) |
|
|
|
|
|
for i := 0; i < t; i++ { |
|
|
|
|
|
newState[i] = zero() |
|
|
|
|
|
} |
|
|
for i := 0; i < len(state); i++ { |
|
|
for i := 0; i < len(state); i++ { |
|
|
newState[i].SetUint64(0) |
|
|
newState[i].SetUint64(0) |
|
|
for j := 0; j < len(state); j++ { |
|
|
for j := 0; j < len(state); j++ { |
|
|
mul.Mul(m[i][j], state[j]) |
|
|
|
|
|
|
|
|
mul.Mul(m[j][i], state[j]) |
|
|
newState[i].Add(newState[i], mul) |
|
|
newState[i].Add(newState[i], mul) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return newState |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Hash computes the Poseidon hash for the given inputs
|
|
|
// Hash computes the Poseidon hash for the given inputs
|
|
@ -59,29 +59,56 @@ func Hash(inpBI []*big.Int) (*big.Int, error) { |
|
|
if len(inpBI) == 0 || len(inpBI) >= len(NROUNDSP)-1 { |
|
|
if len(inpBI) == 0 || len(inpBI) >= len(NROUNDSP)-1 { |
|
|
return nil, fmt.Errorf("invalid inputs length %d, max %d", len(inpBI), len(NROUNDSP)-1) |
|
|
return nil, fmt.Errorf("invalid inputs length %d, max %d", len(inpBI), len(NROUNDSP)-1) |
|
|
} |
|
|
} |
|
|
if !utils.CheckBigIntArrayInField(inpBI[:]) { |
|
|
|
|
|
return nil, errors.New("inputs values not inside Finite Field") |
|
|
|
|
|
} |
|
|
|
|
|
inp := utils.BigIntArrayToElementArray(inpBI[:]) |
|
|
inp := utils.BigIntArrayToElementArray(inpBI[:]) |
|
|
|
|
|
|
|
|
|
|
|
nRoundsF := NROUNDSF |
|
|
|
|
|
nRoundsP := NROUNDSP[t-2] |
|
|
|
|
|
C := c.c[t-2] |
|
|
|
|
|
S := c.s[t-2] |
|
|
|
|
|
M := c.m[t-2] |
|
|
|
|
|
P := c.p[t-2] |
|
|
|
|
|
|
|
|
state := make([]*ff.Element, t) |
|
|
state := make([]*ff.Element, t) |
|
|
state[0] = zero() |
|
|
state[0] = zero() |
|
|
copy(state[1:], inp[:]) |
|
|
copy(state[1:], inp[:]) |
|
|
|
|
|
|
|
|
nRoundsF := NROUNDSF |
|
|
|
|
|
nRoundsP := NROUNDSP[t-2] |
|
|
|
|
|
|
|
|
ark(state, C, 0) |
|
|
|
|
|
|
|
|
newState := make([]*ff.Element, t) |
|
|
|
|
|
for i := 0; i < t; i++ { |
|
|
|
|
|
newState[i] = zero() |
|
|
|
|
|
|
|
|
for i := 0; i < nRoundsF/2-1; i++ { |
|
|
|
|
|
exp5state(state) |
|
|
|
|
|
ark(state, C, (i+1)*t) |
|
|
|
|
|
state = mix(state, t, M) |
|
|
|
|
|
} |
|
|
|
|
|
exp5state(state) |
|
|
|
|
|
ark(state, C, (nRoundsF/2)*t) |
|
|
|
|
|
state = mix(state, t, P) |
|
|
|
|
|
|
|
|
|
|
|
for i := 0; i < nRoundsP; i++ { |
|
|
|
|
|
exp5(state[0]) |
|
|
|
|
|
state[0].Add(state[0], C[(nRoundsF/2+1)*t+i]) |
|
|
|
|
|
|
|
|
|
|
|
mul := zero() |
|
|
|
|
|
newState0 := zero() |
|
|
|
|
|
for j := 0; j < len(state); j++ { |
|
|
|
|
|
mul.Mul(S[(t*2-1)*i+j], state[j]) |
|
|
|
|
|
newState0.Add(newState0, mul) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for k := 1; k < t; k++ { |
|
|
|
|
|
mul = zero() |
|
|
|
|
|
state[k] = state[k].Add(state[k], mul.Mul(state[0], S[(t*2-1)*i+t+k-1])) |
|
|
|
|
|
} |
|
|
|
|
|
state[0] = newState0 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// ARK --> SBox --> M, https://eprint.iacr.org/2019/458.pdf pag.5
|
|
|
|
|
|
for i := 0; i < nRoundsF+nRoundsP; i++ { |
|
|
|
|
|
ark(state, c.c[t-2], i*t) |
|
|
|
|
|
sbox(nRoundsF, nRoundsP, state, i) |
|
|
|
|
|
mix(state, newState, c.m[t-2]) |
|
|
|
|
|
state, newState = newState, state |
|
|
|
|
|
|
|
|
for i := 0; i < nRoundsF/2-1; i++ { |
|
|
|
|
|
exp5state(state) |
|
|
|
|
|
ark(state, C, (nRoundsF/2+1)*t+nRoundsP+i*t) |
|
|
|
|
|
state = mix(state, t, M) |
|
|
} |
|
|
} |
|
|
|
|
|
exp5state(state) |
|
|
|
|
|
state = mix(state, t, M) |
|
|
|
|
|
|
|
|
rE := state[0] |
|
|
rE := state[0] |
|
|
r := big.NewInt(0) |
|
|
r := big.NewInt(0) |
|
|
rE.ToBigIntRegular(r) |
|
|
rE.ToBigIntRegular(r) |
|
|