|
|
package poseidon
import ( "math/big"
"github.com/iden3/go-iden3-crypto/ffg" )
func zero() *ffg.Element { return ffg.NewElement() }
// exp7 performs x^7 mod p
func exp7(a *ffg.Element) { a.Exp(*a, big.NewInt(7)) //nolint:gomnd
}
// exp7state perform exp7 for whole state
func exp7state(state []*ffg.Element) { for i := 0; i < len(state); i++ { exp7(state[i]) } }
// ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
func ark(state []*ffg.Element, it int) { for i := 0; i < len(state); i++ { state[i].Add(state[i], C[it+i]) } }
// arkOpt computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
func arkOpt(state []*ffg.Element, it int) { for i := 0; i < len(state); i++ { state[i].Add(state[i], COpt[it+i]) } }
// mix returns [[matrix]] * [vector]
func mix(state []*ffg.Element, opt bool) []*ffg.Element { mul := zero() newState := make([]*ffg.Element, mLen) for i := 0; i < mLen; i++ { newState[i] = zero() } for i := 0; i < mLen; i++ { newState[i].SetUint64(0) for j := 0; j < mLen; j++ { if opt { mul.Mul(P[j][i], state[j]) } else { mul.Mul(M[j][i], state[j]) } newState[i].Add(newState[i], mul) } } return newState }
// Hash computes the Poseidon hash for the given inputs
func Hash(inpBI [NROUNDSF]uint64, capBI [CAPLEN]uint64) ([CAPLEN]uint64, error) { state := make([]*ffg.Element, mLen) for i := 0; i < NROUNDSF; i++ { state[i] = ffg.NewElement().SetUint64(inpBI[i]) } for i := 0; i < CAPLEN; i++ { state[i+NROUNDSF] = ffg.NewElement().SetUint64(capBI[i]) }
for r := 0; r < NROUNDSF+NROUNDSP; r++ { ark(state, r*mLen)
if r < NROUNDSF/2 || r >= NROUNDSF/2+NROUNDSP { exp7state(state) } else { exp7(state[0]) }
state = mix(state, false) }
return [CAPLEN]uint64{ state[0].ToUint64Regular(), state[1].ToUint64Regular(), state[2].ToUint64Regular(), state[3].ToUint64Regular(), }, nil }
// NeptuneHash computes the hash for the given inputs
func NeptuneHash(inpBI [NROUNDSF]uint64, capBI [CAPLEN]uint64) ([CAPLEN]uint64, error) { state := make([]*ffg.Element, mLen) for i := 0; i < NROUNDSF; i++ { state[i] = ffg.NewElement().SetUint64(inpBI[i]) } for i := 0; i < CAPLEN; i++ { state[i+NROUNDSF] = ffg.NewElement().SetUint64(capBI[i]) }
for i := 0; i < mLen; i++ { state[i].Add(state[i], COpt[i]) }
for r := 0; r < NROUNDSF/2; r++ { exp7state(state) arkOpt(state, (r+1)*mLen) state = mix(state, r == NROUNDSF/2-1) }
for r := 0; r < NROUNDSP; r++ { exp7(state[0]) state[0].Add(state[0], COpt[(NROUNDSF/2+1)*mLen+r])
s0 := zero() mul := zero() mul.Mul(S[(mLen*2-1)*r], state[0]) s0.Add(s0, mul) for i := 1; i < mLen; i++ { mul.Mul(S[(mLen*2-1)*r+i], state[i]) s0.Add(s0, mul) mul.Mul(S[(mLen*2-1)*r+mLen+i-1], state[0]) state[i].Add(state[i], mul) } state[0] = s0 }
for r := 0; r < NROUNDSF/2; r++ { exp7state(state) if r < NROUNDSF/2-1 { arkOpt(state, (NROUNDSF/2+1+r)*mLen+NROUNDSP) }
state = mix(state, false) }
return [CAPLEN]uint64{ state[0].ToUint64Regular(), state[1].ToUint64Regular(), state[2].ToUint64Regular(), state[3].ToUint64Regular(), }, nil }
|