@ -0,0 +1,87 @@ |
|||||
|
package arbo |
||||
|
|
||||
|
import ( |
||||
|
"crypto/sha256" |
||||
|
"math/big" |
||||
|
|
||||
|
"github.com/iden3/go-iden3-crypto/poseidon" |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
// TypeHashSha256 represents the label for the HashFunction of Sha256
|
||||
|
TypeHashSha256 = []byte("sha256") |
||||
|
// TypeHashPoseidon represents the label for the HashFunction of
|
||||
|
// Poseidon
|
||||
|
TypeHashPoseidon = []byte("poseidon") |
||||
|
|
||||
|
// HashFunctionSha256 contains the HashSha256 struct which implements
|
||||
|
// the HashFunction interface
|
||||
|
HashFunctionSha256 HashSha256 |
||||
|
// HashFunctionPoseidon contains the HashPoseidon struct which implements
|
||||
|
// the HashFunction interface
|
||||
|
HashFunctionPoseidon HashPoseidon |
||||
|
) |
||||
|
|
||||
|
// Once Generics are at Go, this will be updated (August 2021
|
||||
|
// https://blog.golang.org/generics-next-step)
|
||||
|
|
||||
|
// HashFunction defines the interface that is expected for a hash function to be
|
||||
|
// used in a generic way in the Tree.
|
||||
|
type HashFunction interface { |
||||
|
Type() []byte |
||||
|
Len() int |
||||
|
Hash(...[]byte) ([]byte, error) |
||||
|
// CheckInputs checks if the inputs are valid without computing the hash
|
||||
|
// CheckInputs(...[]byte) error
|
||||
|
} |
||||
|
|
||||
|
// HashSha256 implements the HashFunction interface for the Sha256 hash
|
||||
|
type HashSha256 struct{} |
||||
|
|
||||
|
// Type returns the type of HashFunction for the HashSha256
|
||||
|
func (f HashSha256) Type() []byte { |
||||
|
return TypeHashSha256 |
||||
|
} |
||||
|
|
||||
|
// Len returns the length of the Hash output
|
||||
|
func (f HashSha256) Len() int { |
||||
|
return 32 //nolint:gomnd
|
||||
|
} |
||||
|
|
||||
|
// Hash implements the hash method for the HashFunction HashSha256
|
||||
|
func (f HashSha256) Hash(b ...[]byte) ([]byte, error) { |
||||
|
var toHash []byte |
||||
|
for i := 0; i < len(b); i++ { |
||||
|
toHash = append(toHash, b[i]...) |
||||
|
} |
||||
|
h := sha256.Sum256(toHash) |
||||
|
return h[:], nil |
||||
|
} |
||||
|
|
||||
|
// HashPoseidon implements the HashFunction interface for the Poseidon hash
|
||||
|
type HashPoseidon struct{} |
||||
|
|
||||
|
// Type returns the type of HashFunction for the HashPoseidon
|
||||
|
func (f HashPoseidon) Type() []byte { |
||||
|
return TypeHashPoseidon |
||||
|
} |
||||
|
|
||||
|
// Len returns the length of the Hash output
|
||||
|
func (f HashPoseidon) Len() int { |
||||
|
return 32 //nolint:gomnd
|
||||
|
} |
||||
|
|
||||
|
// Hash implements the hash method for the HashFunction HashPoseidon
|
||||
|
func (f HashPoseidon) Hash(b ...[]byte) ([]byte, error) { |
||||
|
var toHash []*big.Int |
||||
|
for i := 0; i < len(b); i++ { |
||||
|
bi := BytesToBigInt(b[i]) |
||||
|
toHash = append(toHash, bi) |
||||
|
} |
||||
|
h, err := poseidon.Hash(toHash) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
hB := BigIntToBytes(h) |
||||
|
return hB, nil |
||||
|
} |
@ -0,0 +1,38 @@ |
|||||
|
package arbo |
||||
|
|
||||
|
import ( |
||||
|
"encoding/hex" |
||||
|
"math/big" |
||||
|
"testing" |
||||
|
|
||||
|
"github.com/stretchr/testify/assert" |
||||
|
) |
||||
|
|
||||
|
func TestHashSha256(t *testing.T) { |
||||
|
// Sha256 hash
|
||||
|
hashFunc := &HashSha256{} |
||||
|
b := []byte("test") |
||||
|
h, err := hashFunc.Hash(b) |
||||
|
if err != nil { |
||||
|
t.Fatal(err) |
||||
|
} |
||||
|
assert.Equal(t, |
||||
|
"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", |
||||
|
hex.EncodeToString(h)) |
||||
|
} |
||||
|
|
||||
|
func TestHashPoseidon(t *testing.T) { |
||||
|
// Poseidon hash
|
||||
|
hashFunc := &HashPoseidon{} |
||||
|
h, err := hashFunc.Hash( |
||||
|
BigIntToBytes(big.NewInt(1)), |
||||
|
BigIntToBytes(big.NewInt(2))) |
||||
|
if err != nil { |
||||
|
t.Fatal(err) |
||||
|
} |
||||
|
hBI := BytesToBigInt(h) |
||||
|
// value checked with circomlib
|
||||
|
assert.Equal(t, |
||||
|
"7853200120776062878684798364095072458815029376092732009249414926327459813530", |
||||
|
hBI.String()) |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package arbo |
||||
|
|
||||
|
import "math/big" |
||||
|
|
||||
|
// SwapEndianness swaps the order of the bytes in the byte slice.
|
||||
|
func SwapEndianness(b []byte) []byte { |
||||
|
o := make([]byte, len(b)) |
||||
|
for i := range b { |
||||
|
o[len(b)-1-i] = b[i] |
||||
|
} |
||||
|
return o |
||||
|
} |
||||
|
|
||||
|
// BigIntToBytes converts a *big.Int into a byte array in Little-Endian
|
||||
|
func BigIntToBytes(bi *big.Int) []byte { |
||||
|
var b [32]byte |
||||
|
copy(b[:], SwapEndianness(bi.Bytes())) |
||||
|
return b[:] |
||||
|
} |
||||
|
|
||||
|
// BytesToBigInt converts a byte array in Little-Endian representation into
|
||||
|
// *big.Int
|
||||
|
func BytesToBigInt(b []byte) *big.Int { |
||||
|
return new(big.Int).SetBytes(SwapEndianness(b)) |
||||
|
} |