Update Poseidon to new circomlib version & https://extgit.iaik.tugraz.at/krypto/hadeshash

This commit is contained in:
arnaucube
2020-08-18 18:25:00 +02:00
parent 70841d78e7
commit e04ca5764a
5 changed files with 3587 additions and 214 deletions

View File

@@ -253,7 +253,7 @@ func (k *PrivateKey) SignPoseidon(msg *big.Int) *Signature {
R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
A := k.Public().Point()
hmInput := [poseidon.T]*big.Int{R8.X, R8.Y, A.X, A.Y, msg, big.NewInt(int64(0))}
hmInput := []*big.Int{R8.X, R8.Y, A.X, A.Y, msg, big.NewInt(int64(0))}
hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
if err != nil {
panic(err)
@@ -270,7 +270,7 @@ func (k *PrivateKey) SignPoseidon(msg *big.Int) *Signature {
// VerifyPoseidon verifies the signature of a message encoded as a big.Int in Zq
// using blake-512 hash for buffer hashing and Poseidon for big.Int hashing.
func (p *PublicKey) VerifyPoseidon(msg *big.Int, sig *Signature) bool {
hmInput := [poseidon.T]*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg, big.NewInt(int64(0))}
hmInput := []*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg, big.NewInt(int64(0))}
hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
if err != nil {
panic(err)

View File

@@ -96,7 +96,7 @@ func TestSignVerifyPoseidon(t *testing.T) {
"15383486972088797283337779941324724402501462225528836549661220478783371668959",
sig.R8.Y.String())
assert.Equal(t,
"248298168863866362217836334079793350221620631973732197668910946177382043688",
"1662463587877312619203503803508234533733252768380479199263194005796068211378",
sig.S.String())
ok := pk.VerifyPoseidon(msg, sig)
@@ -108,7 +108,7 @@ func TestSignVerifyPoseidon(t *testing.T) {
assert.Equal(t, ""+
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"28506bce274aa1b3f7e7c2fd7e4fe09bff8f9aa37a42def7994e98f322888c00",
"b23a1f04909fc088dec7e4835d85a326f7c0d0b2a3d0232d84448ca7c9ebac03",
hex.EncodeToString(sigBuf[:]))
ok = pk.VerifyPoseidon(msg, sig2)

3511
poseidon/constants.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,177 +2,90 @@ package poseidon
import (
"errors"
"fmt"
"math/big"
"strconv"
"github.com/iden3/go-iden3-crypto/constants"
"github.com/iden3/go-iden3-crypto/ff"
"github.com/iden3/go-iden3-crypto/utils"
"golang.org/x/crypto/blake2b"
)
const SEED = "poseidon"
const NROUNDSF = 8
const NROUNDSP = 57
const T = 6
var constC []*ff.Element
var constM [T][T]*ff.Element
var NROUNDSP = []int{56, 57, 56, 60, 60, 63, 64, 63}
func Zero() *ff.Element {
func zero() *ff.Element {
return ff.NewElement()
}
func modQ(v *big.Int) {
v.Mod(v, constants.Q)
}
func init() {
constC = getPseudoRandom(SEED+"_constants", NROUNDSF+NROUNDSP)
constM = getMDS()
}
func getPseudoRandom(seed string, n int) []*ff.Element {
res := make([]*ff.Element, n)
hash := blake2b.Sum256([]byte(seed))
for i := 0; i < n; i++ {
hashBigInt := big.NewInt(int64(0))
res[i] = ff.NewElement().SetBigInt(utils.SetBigIntFromLEBytes(hashBigInt, hash[:]))
hash = blake2b.Sum256(hash[:])
}
return res
}
func nonceToString(n int) string {
r := strconv.Itoa(n)
for len(r) < 4 {
r = "0" + r
}
return r
}
// https://eprint.iacr.org/2019/458.pdf pag.8
func getMDS() [T][T]*ff.Element {
nonce := 0
cauchyMatrix := getPseudoRandom(SEED+"_matrix_"+nonceToString(nonce), T*2)
for !checkAllDifferent(cauchyMatrix) {
nonce += 1
cauchyMatrix = getPseudoRandom(SEED+"_matrix_"+nonceToString(nonce), T*2)
}
var m [T][T]*ff.Element
for i := 0; i < T; i++ {
for j := 0; j < T; j++ {
m[i][j] = ff.NewElement().Sub(cauchyMatrix[i], cauchyMatrix[T+j])
m[i][j].Inverse(m[i][j])
}
}
return m
}
func checkAllDifferent(v []*ff.Element) bool {
for i := 0; i < len(v); i++ {
if v[i].Equal(ff.NewElement()) {
return false
}
for j := i + 1; j < len(v); j++ {
if v[i].Equal(v[j]) {
return false
}
}
}
return true
}
// ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
func ark(state [T]*ff.Element, c *ff.Element) {
for i := 0; i < T; i++ {
state[i].Add(state[i], c)
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])
}
}
// cubic performs x^5 mod p
// exp5 performs x^5 mod p
// https://eprint.iacr.org/2019/458.pdf page 8
func cubic(a *ff.Element) {
func exp5(a *ff.Element) {
a.Exp(*a, 5)
}
// sbox https://eprint.iacr.org/2019/458.pdf page 6
func sbox(state [T]*ff.Element, i int) {
if (i < NROUNDSF/2) || (i >= NROUNDSF/2+NROUNDSP) {
for j := 0; j < T; j++ {
cubic(state[j])
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 {
cubic(state[0])
exp5(state[0])
}
}
// mix returns [[matrix]] * [vector]
func mix(state [T]*ff.Element, newState [T]*ff.Element, m [T][T]*ff.Element) {
mul := Zero()
for i := 0; i < T; i++ {
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 < T; j++ {
mul.Mul(m[i][j], state[j])
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 [T]*big.Int) (*big.Int, error) {
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 := [T]*ff.Element{}
for i := 0; i < T; i++ {
state[i] = ff.NewElement().Set(inp[i])
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
var newState [T]*ff.Element
for i := 0; i < T; i++ {
newState[i] = Zero()
}
for i := 0; i < NROUNDSF+NROUNDSP; i++ {
ark(state, constC[i])
sbox(state, i)
mix(state, newState, constM)
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
}
// HashSlice performs the Poseidon hash over a ff.Element array
// in chunks of 5 elements
func HashSlice(arr []*big.Int) (*big.Int, error) {
r := big.NewInt(int64(1))
for i := 0; i < len(arr); i = i + T - 1 {
var toHash [T]*big.Int
j := 0
for ; j < T-1; j++ {
if i+j >= len(arr) {
break
}
toHash[j] = arr[i+j]
}
toHash[j] = r
j++
for ; j < T; j++ {
toHash[j] = big.NewInt(0)
}
ph, err := Hash(toHash)
if err != nil {
return nil, err
}
modQ(r.Add(r, ph))
}
return r, nil
}

View File

@@ -19,104 +19,53 @@ func TestPoseidonHash(t *testing.T) {
b0 := big.NewInt(0)
b1 := big.NewInt(1)
b2 := big.NewInt(2)
h, err := Hash([T]*big.Int{b1, b2, b0, b0, b0, b0})
h, err := Hash([]*big.Int{b1})
assert.Nil(t, err)
assert.Equal(t, "12242166908188651009877250812424843524687801523336557272219921456462821518061", h.String())
assert.Equal(t, "11043376183861534927536506085090418075369306574649619885724436265926427398571", h.String())
h, err = Hash([]*big.Int{b1, b2})
assert.Nil(t, err)
assert.Equal(t, "17117985411748610629288516079940078114952304104811071254131751175361957805920", h.String())
h, err = Hash([]*big.Int{b1, b2, b0, b0, b0})
assert.Nil(t, err)
assert.Equal(t, "3975478831357328722254985704342968745327876719981393787143845259590563829094", h.String())
h, err = Hash([]*big.Int{b1, b2, b0, b0, b0, b0})
assert.Nil(t, err)
assert.Equal(t, "19772360636270345724087386688434825760738403416279047262510528378903625000110", h.String())
b3 := big.NewInt(3)
b4 := big.NewInt(4)
h, err = Hash([T]*big.Int{b3, b4, b0, b0, b0, b0})
h, err = Hash([]*big.Int{b3, b4, b0, b0, b0})
assert.Nil(t, err)
assert.Equal(t, "17185195740979599334254027721507328033796809509313949281114643312710535000993", h.String())
}
func TestPoseidonHashArbitraryLen(t *testing.T) {
b1 := big.NewInt(1)
b2 := big.NewInt(2)
h, err := HashSlice([]*big.Int{b1, b2})
assert.Equal(t, "3181200837746671699652342497997860344148947482942465819251904554707352676086", h.String())
h, err = Hash([]*big.Int{b3, b4, b0, b0, b0, b0})
assert.Nil(t, err)
assert.Equal(t, "4932297968297298434239270129193057052722409868268166443802652458940273154855", h.String())
b3 := big.NewInt(3)
b4 := big.NewInt(4)
h, err = HashSlice([]*big.Int{b3, b4})
assert.Nil(t, err)
assert.Equal(t, "4635491972858758537477743930622086396911540895966845494943021655521913507504", h.String())
assert.Equal(t, "8386348873272147968934270337233829407378789978142456170950021426339096575008", h.String())
b5 := big.NewInt(5)
b6 := big.NewInt(6)
b7 := big.NewInt(7)
b8 := big.NewInt(8)
b9 := big.NewInt(9)
b10 := big.NewInt(10)
b11 := big.NewInt(11)
b12 := big.NewInt(12)
h, err = HashSlice([]*big.Int{b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12})
h, err = Hash([]*big.Int{b1, b2, b3, b4, b5, b6})
assert.Nil(t, err)
assert.Equal(t, "15278801138972282646981503374384603641625274360649669926363020545395022098027", h.String())
msg := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
n := 31
msgElems := make([]*big.Int, 0, len(msg)/n+1)
for i := 0; i < len(msg)/n; i++ {
v := new(big.Int)
utils.SetBigIntFromLEBytes(v, msg[n*i:n*(i+1)])
msgElems = append(msgElems, v)
}
if len(msg)%n != 0 {
v := new(big.Int)
utils.SetBigIntFromLEBytes(v, msg[(len(msg)/n)*n:])
msgElems = append(msgElems, v)
}
hmsg, err := HashSlice(msgElems)
assert.Nil(t, err)
assert.Equal(t, "16019700159595764790637132363672701294192939959594423814006267756172551741065", hmsg.String())
msg2 := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet.")
msg2Elems := make([]*big.Int, 0, len(msg2)/n+1)
for i := 0; i < len(msg2)/n; i++ {
v := new(big.Int)
utils.SetBigIntFromLEBytes(v, msg2[n*i:n*(i+1)])
msg2Elems = append(msg2Elems, v)
}
if len(msg2)%n != 0 {
v := new(big.Int)
utils.SetBigIntFromLEBytes(v, msg2[(len(msg2)/n)*n:])
msg2Elems = append(msg2Elems, v)
}
hmsg2, err := HashSlice(msg2Elems)
assert.Nil(t, err)
assert.Equal(t, "2978613163687734485261639854325792381691890647104372645321246092227111432722", hmsg2.String())
assert.Equal(t, "5202465217520500374834597824465244016759843635092906214933648999760272616044", h.String())
}
func TestPoseidonHashArbitraryLenBrokenChunks(t *testing.T) {
h1, err := HashSlice([]*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(2), big.NewInt(3), big.NewInt(4),
big.NewInt(5), big.NewInt(6), big.NewInt(7), big.NewInt(8), big.NewInt(9)})
assert.Nil(t, err)
h2, err := HashSlice([]*big.Int{big.NewInt(5), big.NewInt(6), big.NewInt(7), big.NewInt(8), big.NewInt(9),
big.NewInt(0), big.NewInt(1), big.NewInt(2), big.NewInt(3), big.NewInt(4)})
assert.Nil(t, err)
assert.NotEqual(t, h1, h2)
}
func TestErrorInputs(t *testing.T) {
b0 := big.NewInt(0)
b1 := big.NewInt(1)
b2 := big.NewInt(2)
func TestPoseidonHashArbitraryLenBrokenPadding(t *testing.T) {
h1, err := HashSlice([]*big.Int{big.NewInt(int64(1))})
_, err := Hash([]*big.Int{b1, b2, b0, b0, b0, b0})
assert.Nil(t, err)
h2, err := HashSlice([]*big.Int{big.NewInt(int64(1)), big.NewInt(int64(0))})
assert.Nil(t, err)
assert.NotEqual(t, h1, h2)
}
func BenchmarkPoseidonHashSmallValues(b *testing.B) {
b12 := big.NewInt(int64(12))
b45 := big.NewInt(int64(45))
b78 := big.NewInt(int64(78))
b41 := big.NewInt(int64(41))
bigArray4 := []*big.Int{b12, b45, b78, b41}
_, err = Hash([]*big.Int{b1, b2, b0, b0, b0, b0, b0})
assert.NotNil(t, err)
assert.Equal(t, "invalid inputs length 7, max 7", err.Error())
for i := 0; i < b.N; i++ {
HashSlice(bigArray4) //nolint:errcheck
}
_, err = Hash([]*big.Int{b1, b2, b0, b0, b0, b0, b0, b0})
assert.NotNil(t, err)
assert.Equal(t, "invalid inputs length 8, max 7", err.Error())
}
func BenchmarkPoseidonHash(b *testing.B) {
@@ -124,7 +73,7 @@ func BenchmarkPoseidonHash(b *testing.B) {
b1 := utils.NewIntFromString("12242166908188651009877250812424843524687801523336557272219921456462821518061")
b2 := utils.NewIntFromString("12242166908188651009877250812424843524687801523336557272219921456462821518061")
bigArray4 := [T]*big.Int{b1, b2, b0, b0, b0, b0}
bigArray4 := []*big.Int{b1, b2, b0, b0, b0, b0}
for i := 0; i < b.N; i++ {
Hash(bigArray4) //nolint:errcheck