@ -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)) | 
				
			|||
} | 
				
			|||