mirror of
https://github.com/arnaucube/go-iden3-crypto.git
synced 2026-02-07 03:26:39 +01:00
Poseidon Sponge Hash with different frame sizes (#52)
* Poseidon Sponge Hash with different frame sizes * Update deps. Bump go version * Update & fix linter. * Refactor a bit. * Reduce gc pressure
This commit is contained in:
committed by
GitHub
parent
edc36bfa52
commit
e5cf066b8b
@@ -96,7 +96,7 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:lll
|
||||
//nolint:lll,dupl // long lines, duplicated parts
|
||||
var cs = constantsStr{
|
||||
C: [][]string{{
|
||||
"9c46e9ec68e9bd4fe1faaba294cba38a71aa177534cdd1b6c7dc0dbd0abd7a7",
|
||||
|
||||
@@ -9,9 +9,11 @@ import (
|
||||
"github.com/iden3/go-iden3-crypto/utils"
|
||||
)
|
||||
|
||||
const NROUNDSF = 8 //nolint:golint
|
||||
// NROUNDSF constant from Poseidon paper
|
||||
const NROUNDSF = 8
|
||||
|
||||
var NROUNDSP = []int{56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68} //nolint:golint
|
||||
// NROUNDSP constant from Poseidon paper
|
||||
var NROUNDSP = []int{56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68}
|
||||
|
||||
const spongeChunkSize = 31
|
||||
const spongeInputs = 16
|
||||
@@ -20,10 +22,12 @@ func zero() *ff.Element {
|
||||
return ff.NewElement()
|
||||
}
|
||||
|
||||
var big5 = big.NewInt(5)
|
||||
|
||||
// exp5 performs x^5 mod p
|
||||
// https://eprint.iacr.org/2019/458.pdf page 8
|
||||
func exp5(a *ff.Element) {
|
||||
a.Exp(*a, big.NewInt(5)) //nolint:gomnd
|
||||
a.Exp(*a, big5)
|
||||
}
|
||||
|
||||
// exp5state perform exp5 for whole state
|
||||
@@ -34,7 +38,7 @@ func exp5state(state []*ff.Element) {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
func ark(state, c []*ff.Element, it int) {
|
||||
for i := 0; i < len(state); i++ {
|
||||
state[i].Add(state[i], c[it+i])
|
||||
}
|
||||
@@ -61,12 +65,12 @@ func mix(state []*ff.Element, t int, m [][]*ff.Element) []*ff.Element {
|
||||
func Hash(inpBI []*big.Int) (*big.Int, error) {
|
||||
t := len(inpBI) + 1
|
||||
if len(inpBI) == 0 || len(inpBI) > len(NROUNDSP) {
|
||||
return nil, fmt.Errorf("invalid inputs length %d, max %d", len(inpBI), len(NROUNDSP)) //nolint:gomnd,lll
|
||||
return nil, fmt.Errorf("invalid inputs length %d, max %d", len(inpBI), len(NROUNDSP))
|
||||
}
|
||||
if !utils.CheckBigIntArrayInField(inpBI[:]) {
|
||||
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]
|
||||
@@ -77,7 +81,7 @@ func Hash(inpBI []*big.Int) (*big.Int, error) {
|
||||
|
||||
state := make([]*ff.Element, t)
|
||||
state[0] = zero()
|
||||
copy(state[1:], inp[:])
|
||||
copy(state[1:], inp)
|
||||
|
||||
ark(state, C, 0)
|
||||
|
||||
@@ -90,11 +94,12 @@ func Hash(inpBI []*big.Int) (*big.Int, error) {
|
||||
ark(state, C, (nRoundsF/2)*t)
|
||||
state = mix(state, t, P)
|
||||
|
||||
mul := zero()
|
||||
for i := 0; i < nRoundsP; i++ {
|
||||
exp5(state[0])
|
||||
state[0].Add(state[0], C[(nRoundsF/2+1)*t+i])
|
||||
|
||||
mul := zero()
|
||||
mul.SetZero()
|
||||
newState0 := zero()
|
||||
for j := 0; j < len(state); j++ {
|
||||
mul.Mul(S[(t*2-1)*i+j], state[j])
|
||||
@@ -102,7 +107,7 @@ func Hash(inpBI []*big.Int) (*big.Int, error) {
|
||||
}
|
||||
|
||||
for k := 1; k < t; k++ {
|
||||
mul = zero()
|
||||
mul.SetZero()
|
||||
state[k] = state[k].Add(state[k], mul.Mul(state[0], S[(t*2-1)*i+t+k-1]))
|
||||
}
|
||||
state[0] = newState0
|
||||
@@ -124,9 +129,18 @@ func Hash(inpBI []*big.Int) (*big.Int, error) {
|
||||
|
||||
// HashBytes returns a sponge hash of a msg byte slice split into blocks of 31 bytes
|
||||
func HashBytes(msg []byte) (*big.Int, error) {
|
||||
return HashBytesX(msg, spongeInputs)
|
||||
}
|
||||
|
||||
// HashBytesX returns a sponge hash of a msg byte slice split into blocks of 31 bytes
|
||||
func HashBytesX(msg []byte, frameSize int) (*big.Int, error) {
|
||||
if frameSize < 2 || frameSize > 16 {
|
||||
return nil, errors.New("incorrect frame size")
|
||||
}
|
||||
|
||||
// not used inputs default to zero
|
||||
inputs := make([]*big.Int, spongeInputs)
|
||||
for j := 0; j < spongeInputs; j++ {
|
||||
inputs := make([]*big.Int, frameSize)
|
||||
for j := 0; j < frameSize; j++ {
|
||||
inputs[j] = new(big.Int)
|
||||
}
|
||||
dirty := false
|
||||
@@ -137,15 +151,15 @@ func HashBytes(msg []byte) (*big.Int, error) {
|
||||
for i := 0; i < len(msg)/spongeChunkSize; i++ {
|
||||
dirty = true
|
||||
inputs[k].SetBytes(msg[spongeChunkSize*i : spongeChunkSize*(i+1)])
|
||||
if k == spongeInputs-1 {
|
||||
if k == frameSize-1 {
|
||||
hash, err = Hash(inputs)
|
||||
dirty = false
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inputs = make([]*big.Int, spongeInputs)
|
||||
inputs = make([]*big.Int, frameSize)
|
||||
inputs[0] = hash
|
||||
for j := 1; j < spongeInputs; j++ {
|
||||
for j := 1; j < frameSize; j++ {
|
||||
inputs[j] = new(big.Int)
|
||||
}
|
||||
k = 1
|
||||
@@ -174,3 +188,55 @@ func HashBytes(msg []byte) (*big.Int, error) {
|
||||
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
// SpongeHash returns a sponge hash of inputs (using Poseidon with frame size of 16 inputs)
|
||||
func SpongeHash(inputs []*big.Int) (*big.Int, error) {
|
||||
return SpongeHashX(inputs, spongeInputs)
|
||||
}
|
||||
|
||||
// SpongeHashX returns a sponge hash of inputs using Poseidon with configurable frame size
|
||||
func SpongeHashX(inputs []*big.Int, frameSize int) (*big.Int, error) {
|
||||
if frameSize < 2 || frameSize > 16 {
|
||||
return nil, errors.New("incorrect frame size")
|
||||
}
|
||||
|
||||
// not used frame default to zero
|
||||
frame := make([]*big.Int, frameSize)
|
||||
for j := 0; j < frameSize; j++ {
|
||||
frame[j] = new(big.Int)
|
||||
}
|
||||
dirty := false
|
||||
var hash *big.Int
|
||||
var err error
|
||||
|
||||
k := 0
|
||||
for i := 0; i < len(inputs); i++ {
|
||||
dirty = true
|
||||
frame[k] = inputs[i]
|
||||
if k == frameSize-1 {
|
||||
hash, err = Hash(frame)
|
||||
dirty = false
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frame = make([]*big.Int, frameSize)
|
||||
frame[0] = hash
|
||||
for j := 1; j < frameSize; j++ {
|
||||
frame[j] = new(big.Int)
|
||||
}
|
||||
k = 1
|
||||
} else {
|
||||
k++
|
||||
}
|
||||
}
|
||||
|
||||
if dirty {
|
||||
// we haven't hashed something in the main sponge loop and need to do hash here
|
||||
hash, err = Hash(frame)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user