package poseidon
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/iden3/go-iden3-crypto/ff"
|
|
"github.com/iden3/go-iden3-crypto/utils"
|
|
)
|
|
|
|
const NROUNDSF = 8 //nolint:golint
|
|
|
|
var NROUNDSP = []int{56, 57, 56, 60, 60, 63, 64, 63} //nolint:golint
|
|
|
|
func zero() *ff.Element {
|
|
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
|
|
// https://eprint.iacr.org/2019/458.pdf page 8
|
|
func exp5(a *ff.Element) {
|
|
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])
|
|
}
|
|
}
|
|
|
|
// mix returns [[matrix]] * [vector]
|
|
func mix(state []*ff.Element, newState []*ff.Element, m [][]*ff.Element) {
|
|
mul := zero()
|
|
for i := 0; i < len(state); i++ {
|
|
newState[i].SetUint64(0)
|
|
for j := 0; j < len(state); j++ {
|
|
mul.Mul(m[j][i], state[j])
|
|
newState[i].Add(newState[i], mul)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Hash computes the Poseidon hash for the given inputs
|
|
func Hash(inpBI []*big.Int) (*big.Int, error) {
|
|
t := len(inpBI) + 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)
|
|
}
|
|
if !utils.CheckBigIntArrayInField(inpBI[:]) {
|
|
return nil, errors.New("inputs values not inside Finite Field")
|
|
}
|
|
inp := utils.BigIntArrayToElementArray(inpBI[:])
|
|
state := make([]*ff.Element, t)
|
|
copy(state[:], inp[:])
|
|
state[len(state)-1] = zero()
|
|
|
|
nRoundsF := NROUNDSF
|
|
nRoundsP := NROUNDSP[t-2]
|
|
|
|
newState := make([]*ff.Element, t)
|
|
for i := 0; i < t; i++ {
|
|
newState[i] = zero()
|
|
}
|
|
|
|
// 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)
|
|
if i < nRoundsF+nRoundsP-1 {
|
|
mix(state, newState, c.m[t-2])
|
|
state, newState = newState, state
|
|
}
|
|
}
|
|
rE := state[0]
|
|
r := big.NewInt(0)
|
|
rE.ToBigIntRegular(r)
|
|
return r, nil
|
|
}
|