add Poseidondecompress-modsqrt v0.0.1
@ -1,3 +1,4 @@ |
|||
# go-iden3-crypto [![Go Report Card](https://goreportcard.com/badge/github.com/iden3/go-iden3-crypto)](https://goreportcard.com/report/github.com/iden3/go-iden3-crypto) [![Build Status](https://travis-ci.org/iden3/go-iden3-crypto.svg?branch=master)](https://travis-ci.org/iden3/go-iden3-crypto) [![GoDoc](https://godoc.org/github.com/iden3/go-iden3-crypto?status.svg)](https://godoc.org/github.com/iden3/go-iden3-crypto) |
|||
Go implementation of some cryptographic primitives used in iden3 |
|||
|
|||
Go implementation of some cryptographic primitives (that fit inside the SNARK field) used in iden3 |
|||
|
@ -0,0 +1,26 @@ |
|||
package constants |
|||
|
|||
import ( |
|||
"github.com/iden3/go-iden3-crypto/utils" |
|||
"math/big" |
|||
) |
|||
|
|||
// Q is the order of the integer field (Zq) that fits inside the SNARK.
|
|||
var Q *big.Int |
|||
|
|||
// Zero is 0.
|
|||
var Zero *big.Int |
|||
|
|||
// One is 1.
|
|||
var One *big.Int |
|||
|
|||
// MinusOne is -1.
|
|||
var MinusOne *big.Int |
|||
|
|||
func init() { |
|||
Zero = big.NewInt(0) |
|||
One = big.NewInt(1) |
|||
MinusOne = big.NewInt(-1) |
|||
Q = utils.NewIntFromString( |
|||
"21888242871839275222246405745257275088548364400416034343698204186575808495617") |
|||
} |
@ -0,0 +1,166 @@ |
|||
package poseidon |
|||
|
|||
import ( |
|||
"bytes" |
|||
"errors" |
|||
"math/big" |
|||
"strconv" |
|||
|
|||
_constants "github.com/iden3/go-iden3-crypto/constants" |
|||
"github.com/iden3/go-iden3-crypto/field" |
|||
"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 constants = generateConstantsData() |
|||
|
|||
type constantsData struct { |
|||
fqR field.Fq |
|||
c []*big.Int |
|||
m [][]*big.Int |
|||
} |
|||
|
|||
func generateConstantsData() constantsData { |
|||
var constants constantsData |
|||
|
|||
fqR := field.NewFq(_constants.Q) |
|||
constants.fqR = fqR |
|||
constants.c = getPseudoRandom(fqR, SEED+"_constants", NROUNDSF+NROUNDSP) |
|||
constants.m = getMDS(fqR) |
|||
|
|||
return constants |
|||
} |
|||
|
|||
func leByteArrayToBigInt(b []byte) *big.Int { |
|||
res := big.NewInt(0) |
|||
for i := 0; i < len(b); i++ { |
|||
n := big.NewInt(int64(b[i])) |
|||
res = new(big.Int).Add(res, new(big.Int).Lsh(n, uint(i*8))) |
|||
} |
|||
return res |
|||
} |
|||
|
|||
func getPseudoRandom(fqR field.Fq, seed string, n int) []*big.Int { |
|||
var res []*big.Int |
|||
hash := blake2b.Sum256([]byte(seed)) |
|||
for len(res) < n { |
|||
hashBigInt := new(big.Int) |
|||
newN := fqR.Affine(utils.SetBigIntFromLEBytes(hashBigInt, hash[:])) |
|||
// newN := fqR.Affine(leByteArrayToBigInt(hash[:]))
|
|||
res = append(res, newN) |
|||
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(fqR field.Fq) [][]*big.Int { |
|||
nonce := 0 |
|||
cauchyMatrix := getPseudoRandom(fqR, SEED+"_matrix_"+nonceToString(nonce), T*2) |
|||
for !checkAllDifferent(cauchyMatrix) { |
|||
nonce += 1 |
|||
cauchyMatrix = getPseudoRandom(fqR, SEED+"_matrix_"+nonceToString(nonce), T*2) |
|||
} |
|||
var m [][]*big.Int |
|||
for i := 0; i < T; i++ { |
|||
var mi []*big.Int |
|||
for j := 0; j < T; j++ { |
|||
mi = append(mi, fqR.Inverse(fqR.Sub(cauchyMatrix[i], cauchyMatrix[T+j]))) |
|||
} |
|||
m = append(m, mi) |
|||
} |
|||
return m |
|||
} |
|||
|
|||
func checkAllDifferent(v []*big.Int) bool { |
|||
for i := 0; i < len(v); i++ { |
|||
if bytes.Equal(v[i].Bytes(), big.NewInt(int64(0)).Bytes()) { |
|||
return false |
|||
} |
|||
for j := i + 1; j < len(v); j++ { |
|||
if bytes.Equal(v[i].Bytes(), v[j].Bytes()) { |
|||
return false |
|||
} |
|||
} |
|||
} |
|||
return true |
|||
} |
|||
|
|||
// ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
|
|||
func ark(state []*big.Int, c *big.Int) []*big.Int { |
|||
for i := 0; i < len(state); i++ { |
|||
state[i] = constants.fqR.Add(state[i], c) |
|||
} |
|||
return state |
|||
} |
|||
|
|||
// cubic performs x^3 mod p
|
|||
func cubic(a *big.Int) *big.Int { |
|||
return constants.fqR.Mul(a, constants.fqR.Square(constants.fqR.Square(a))) |
|||
} |
|||
|
|||
// sbox https://eprint.iacr.org/2019/458.pdf pag.6
|
|||
func sbox(state []*big.Int, i int) []*big.Int { |
|||
if (i < NROUNDSF/2) || (i >= NROUNDSF/2+NROUNDSP) { |
|||
for j := 0; j < T; j++ { |
|||
state[j] = cubic(state[j]) |
|||
} |
|||
} else { |
|||
state[0] = cubic(state[0]) |
|||
} |
|||
return state |
|||
} |
|||
|
|||
// mix returns [[matrix]] * [vector]
|
|||
func mix(state []*big.Int, m [][]*big.Int) []*big.Int { |
|||
var newState []*big.Int |
|||
for i := 0; i < len(state); i++ { |
|||
newState = append(newState, constants.fqR.Zero()) |
|||
for j := 0; j < len(state); j++ { |
|||
newState[i] = constants.fqR.Add(newState[i], constants.fqR.Mul(m[i][j], state[j])) |
|||
} |
|||
} |
|||
for i := 0; i < len(state); i++ { |
|||
state[i] = newState[i] |
|||
} |
|||
return state |
|||
} |
|||
|
|||
// Hash computes the Poseidon hash for the given inputs
|
|||
func Hash(inp []*big.Int) (*big.Int, error) { |
|||
var state []*big.Int |
|||
if len(inp) == 0 || len(inp) > T { |
|||
return nil, errors.New("wrong inputs length") |
|||
} |
|||
if !utils.CheckBigIntArrayInField(inp, constants.fqR.Q) { |
|||
return nil, errors.New("inputs values not inside Finite Field") |
|||
} |
|||
|
|||
for i := 0; i < len(inp); i++ { |
|||
state = append(state, inp[i]) |
|||
} |
|||
for i := len(inp); i < T; i++ { |
|||
state = append(state, constants.fqR.Zero()) |
|||
} |
|||
|
|||
// ARK --> SBox --> M, https://eprint.iacr.org/2019/458.pdf pag.5
|
|||
for i := 0; i < NROUNDSF+NROUNDSP; i++ { |
|||
state = ark(state, constants.c[i]) |
|||
state = sbox(state, i) |
|||
state = mix(state, constants.m) |
|||
} |
|||
return state[0], nil |
|||
} |
@ -0,0 +1,29 @@ |
|||
package poseidon |
|||
|
|||
import ( |
|||
"encoding/hex" |
|||
"math/big" |
|||
"testing" |
|||
|
|||
"github.com/stretchr/testify/assert" |
|||
"golang.org/x/crypto/blake2b" |
|||
) |
|||
|
|||
func TestBlake2bVersion(t *testing.T) { |
|||
h := blake2b.Sum256([]byte("poseidon_constants")) |
|||
assert.Equal(t, "e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1", hex.EncodeToString(h[:])) |
|||
} |
|||
|
|||
func TestPoseidon(t *testing.T) { |
|||
b1 := big.NewInt(int64(1)) |
|||
b2 := big.NewInt(int64(2)) |
|||
h, err := Hash([]*big.Int{b1, b2}) |
|||
assert.Nil(t, err) |
|||
assert.Equal(t, "12242166908188651009877250812424843524687801523336557272219921456462821518061", h.String()) |
|||
|
|||
b3 := big.NewInt(int64(3)) |
|||
b4 := big.NewInt(int64(4)) |
|||
h, err = Hash([]*big.Int{b3, b4}) |
|||
assert.Nil(t, err) |
|||
assert.Equal(t, "17185195740979599334254027721507328033796809509313949281114643312710535000993", h.String()) |
|||
} |
@ -0,0 +1,106 @@ |
|||
package utils |
|||
|
|||
import ( |
|||
"bytes" |
|||
"encoding/hex" |
|||
"fmt" |
|||
"math/big" |
|||
"strings" |
|||
) |
|||
|
|||
// NewIntFromString creates a new big.Int from a decimal integer encoded as a
|
|||
// string. It will panic if the string is not a decimal integer.
|
|||
func NewIntFromString(s string) *big.Int { |
|||
v, ok := new(big.Int).SetString(s, 10) |
|||
if !ok { |
|||
panic(fmt.Sprintf("Bad base 10 string %s", s)) |
|||
} |
|||
return v |
|||
} |
|||
|
|||
// SwapEndianness swaps the endianness of the value encoded in xs. If xs is
|
|||
// Big-Endian, the result will be Little-Endian and viceversa.
|
|||
func SwapEndianness(xs []byte) []byte { |
|||
ys := make([]byte, len(xs)) |
|||
for i, b := range xs { |
|||
ys[len(xs)-1-i] = b |
|||
} |
|||
return ys |
|||
} |
|||
|
|||
// BigIntLEBytes encodes a big.Int into an array in Little-Endian.
|
|||
func BigIntLEBytes(v *big.Int) [32]byte { |
|||
le := SwapEndianness(v.Bytes()) |
|||
res := [32]byte{} |
|||
copy(res[:], le) |
|||
return res |
|||
} |
|||
|
|||
// SetBigIntFromLEBytes sets the value of a big.Int from a Little-Endian
|
|||
// encoded value.
|
|||
func SetBigIntFromLEBytes(v *big.Int, leBuf []byte) *big.Int { |
|||
beBuf := SwapEndianness(leBuf) |
|||
return v.SetBytes(beBuf) |
|||
} |
|||
|
|||
// Hex is a byte slice type that can be marshalled and unmarshaled in hex
|
|||
type Hex []byte |
|||
|
|||
// MarshalText encodes buf as hex
|
|||
func (buf Hex) MarshalText() ([]byte, error) { |
|||
return []byte(hex.EncodeToString(buf)), nil |
|||
} |
|||
|
|||
// String encodes buf as hex
|
|||
func (buf Hex) String() string { |
|||
return hex.EncodeToString(buf) |
|||
} |
|||
|
|||
// HexEncode encodes an array of bytes into a string in hex.
|
|||
func HexEncode(bs []byte) string { |
|||
return fmt.Sprintf("0x%s", hex.EncodeToString(bs)) |
|||
} |
|||
|
|||
// HexDecode decodes a hex string into an array of bytes.
|
|||
func HexDecode(h string) ([]byte, error) { |
|||
if strings.HasPrefix(h, "0x") { |
|||
h = h[2:] |
|||
} |
|||
return hex.DecodeString(h) |
|||
} |
|||
|
|||
// HexDecodeInto decodes a hex string into an array of bytes (dst), verifying
|
|||
// that the decoded array has the same length as dst.
|
|||
func HexDecodeInto(dst []byte, h []byte) error { |
|||
if bytes.HasPrefix(h, []byte("0x")) { |
|||
h = h[2:] |
|||
} |
|||
if len(h)/2 != len(dst) { |
|||
return fmt.Errorf("expected %v bytes in hex string, got %v", len(dst), len(h)/2) |
|||
} |
|||
n, err := hex.Decode(dst, h) |
|||
if err != nil { |
|||
return err |
|||
} else if n != len(dst) { |
|||
return fmt.Errorf("expected %v bytes when decoding hex string, got %v", len(dst), n) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
// CheckBigIntInField checks if given big.Int fits in a Field Q element
|
|||
func CheckBigIntInField(a *big.Int, q *big.Int) bool { |
|||
if a.Cmp(q) != -1 { |
|||
return false |
|||
} |
|||
return true |
|||
} |
|||
|
|||
// CheckBigIntArrayInField checks if given big.Int fits in a Field Q element
|
|||
func CheckBigIntArrayInField(arr []*big.Int, q *big.Int) bool { |
|||
for _, a := range arr { |
|||
if !CheckBigIntInField(a, q) { |
|||
return false |
|||
} |
|||
} |
|||
return true |
|||
} |