mirror of
https://github.com/arnaucube/go-iden3-crypto.git
synced 2026-02-07 11:36:41 +01:00
Compare commits
25 Commits
feature/po
...
feature/po
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
590573a0af | ||
|
|
58e589b6eb | ||
|
|
2318fd7044 | ||
|
|
a0722b9e8f | ||
|
|
71dbddb5f1 | ||
|
|
0a5c6acba3 | ||
|
|
a366175021 | ||
|
|
a2015adb2f | ||
|
|
6d75396b4b | ||
|
|
821a601d20 | ||
|
|
5dd19b46dd | ||
|
|
94e92e88fb | ||
|
|
5ef832f175 | ||
|
|
59d8c7a4ca | ||
|
|
91767c7b61 | ||
|
|
aab1a681dd | ||
|
|
e04ca5764a | ||
|
|
70841d78e7 | ||
|
|
674e8a6739 | ||
|
|
66519124ca | ||
|
|
a86308cb0b | ||
|
|
d91a4261f1 | ||
|
|
327a8175d6 | ||
|
|
833f68a614 | ||
|
|
29a66457f0 |
22
.github/workflows/lint.yml
vendored
22
.github/workflows/lint.yml
vendored
@@ -1,16 +1,16 @@
|
|||||||
on: [ push, pull_request ]
|
|
||||||
name: Lint
|
name: Lint
|
||||||
|
on: [ push, pull_request ]
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v1
|
||||||
with:
|
with:
|
||||||
go-version: 1.14.x
|
go-version: 1.14.x
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: |
|
run: |
|
||||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.24.0
|
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.30.0
|
||||||
$(go env GOPATH)/bin/golangci-lint run
|
$(go env GOPATH)/bin/golangci-lint run --timeout=5m -c .golangci.yml
|
||||||
|
|||||||
17
.golangci.yml
Normal file
17
.golangci.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
issues:
|
||||||
|
max-same-issues: 0
|
||||||
|
exclude-use-default: false
|
||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
- whitespace
|
||||||
|
- gosec
|
||||||
|
- gci
|
||||||
|
- misspell
|
||||||
|
- gomnd
|
||||||
|
- gofmt
|
||||||
|
- goimports
|
||||||
|
- lll
|
||||||
|
- golint
|
||||||
|
linters-settings:
|
||||||
|
lll:
|
||||||
|
line-length: 100
|
||||||
@@ -5,15 +5,22 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/iden3/go-iden3-crypto/constants"
|
"github.com/iden3/go-iden3-crypto/constants"
|
||||||
|
"github.com/iden3/go-iden3-crypto/ff"
|
||||||
"github.com/iden3/go-iden3-crypto/utils"
|
"github.com/iden3/go-iden3-crypto/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A is one of the babyjub constants.
|
// A is one of the babyjub constants.
|
||||||
var A *big.Int
|
var A *big.Int
|
||||||
|
|
||||||
|
// Aff is A value in *ff.Element representation
|
||||||
|
var Aff *ff.Element
|
||||||
|
|
||||||
// D is one of the babyjub constants.
|
// D is one of the babyjub constants.
|
||||||
var D *big.Int
|
var D *big.Int
|
||||||
|
|
||||||
|
// Dff is D value in *ff.Element representation
|
||||||
|
var Dff *ff.Element
|
||||||
|
|
||||||
// Order of the babyjub curve.
|
// Order of the babyjub curve.
|
||||||
var Order *big.Int
|
var Order *big.Int
|
||||||
|
|
||||||
@@ -29,6 +36,8 @@ var B8 *Point
|
|||||||
func init() {
|
func init() {
|
||||||
A = utils.NewIntFromString("168700")
|
A = utils.NewIntFromString("168700")
|
||||||
D = utils.NewIntFromString("168696")
|
D = utils.NewIntFromString("168696")
|
||||||
|
Aff = ff.NewElement().SetBigInt(A)
|
||||||
|
Dff = ff.NewElement().SetBigInt(D)
|
||||||
|
|
||||||
Order = utils.NewIntFromString(
|
Order = utils.NewIntFromString(
|
||||||
"21888242871839275222246405745257275088614511777268538073601725287587578984328")
|
"21888242871839275222246405745257275088614511777268538073601725287587578984328")
|
||||||
@@ -41,6 +50,73 @@ func init() {
|
|||||||
"16950150798460657717958625567821834550301663161624707787222815936182638968203")
|
"16950150798460657717958625567821834550301663161624707787222815936182638968203")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PointProjective is the Point representation in projective coordinates
|
||||||
|
type PointProjective struct {
|
||||||
|
X *ff.Element
|
||||||
|
Y *ff.Element
|
||||||
|
Z *ff.Element
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPointProjective creates a new Point in projective coordinates.
|
||||||
|
func NewPointProjective() *PointProjective {
|
||||||
|
return &PointProjective{X: ff.NewElement().SetZero(),
|
||||||
|
Y: ff.NewElement().SetOne(), Z: ff.NewElement().SetOne()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Affine returns the Point from the projective representation
|
||||||
|
func (p *PointProjective) Affine() *Point {
|
||||||
|
if p.Z.Equal(ff.NewElement().SetZero()) {
|
||||||
|
return &Point{
|
||||||
|
X: big.NewInt(0),
|
||||||
|
Y: big.NewInt(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zinv := ff.NewElement().Inverse(p.Z)
|
||||||
|
x := ff.NewElement().Mul(p.X, zinv)
|
||||||
|
|
||||||
|
y := ff.NewElement().Mul(p.Y, zinv)
|
||||||
|
xBig := big.NewInt(0)
|
||||||
|
x.ToBigIntRegular(xBig)
|
||||||
|
yBig := big.NewInt(0)
|
||||||
|
y.ToBigIntRegular(yBig)
|
||||||
|
return &Point{
|
||||||
|
X: xBig,
|
||||||
|
Y: yBig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add computes the addition of two points in projective coordinates
|
||||||
|
// representation
|
||||||
|
func (p *PointProjective) Add(q *PointProjective, o *PointProjective) *PointProjective {
|
||||||
|
// add-2008-bbjlp
|
||||||
|
// https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp
|
||||||
|
a := ff.NewElement().Mul(q.Z, o.Z)
|
||||||
|
b := ff.NewElement().Square(a)
|
||||||
|
c := ff.NewElement().Mul(q.X, o.X)
|
||||||
|
d := ff.NewElement().Mul(q.Y, o.Y)
|
||||||
|
e := ff.NewElement().Mul(Dff, c)
|
||||||
|
e.MulAssign(d)
|
||||||
|
f := ff.NewElement().Sub(b, e)
|
||||||
|
g := ff.NewElement().Add(b, e)
|
||||||
|
x1y1 := ff.NewElement().Add(q.X, q.Y)
|
||||||
|
x2y2 := ff.NewElement().Add(o.X, o.Y)
|
||||||
|
x3 := ff.NewElement().Mul(x1y1, x2y2)
|
||||||
|
x3.SubAssign(c)
|
||||||
|
x3.SubAssign(d)
|
||||||
|
x3.MulAssign(a)
|
||||||
|
x3.MulAssign(f)
|
||||||
|
ac := ff.NewElement().Mul(Aff, c)
|
||||||
|
y3 := ff.NewElement().Sub(d, ac)
|
||||||
|
y3.MulAssign(a)
|
||||||
|
y3.MulAssign(g)
|
||||||
|
z3 := ff.NewElement().Mul(f, g)
|
||||||
|
|
||||||
|
p.X = x3
|
||||||
|
p.Y = y3
|
||||||
|
p.Z = z3
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
// Point represents a point of the babyjub curve.
|
// Point represents a point of the babyjub curve.
|
||||||
type Point struct {
|
type Point struct {
|
||||||
X *big.Int
|
X *big.Int
|
||||||
@@ -59,63 +135,33 @@ func (p *Point) Set(c *Point) *Point {
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds Point a and b into res
|
// Projective returns a PointProjective from the Point
|
||||||
func (res *Point) Add(a *Point, b *Point) *Point {
|
func (p *Point) Projective() *PointProjective {
|
||||||
// x = (a.x * b.y + b.x * a.y) * (1 + D * a.x * b.x * a.y * b.y)^-1 mod q
|
return &PointProjective{
|
||||||
x1a := new(big.Int).Mul(a.X, b.Y)
|
X: ff.NewElement().SetBigInt(p.X),
|
||||||
x1b := new(big.Int).Mul(b.X, a.Y)
|
Y: ff.NewElement().SetBigInt(p.Y),
|
||||||
x1a.Add(x1a, x1b) // x1a = a.x * b.y + b.x * a.y
|
Z: ff.NewElement().SetOne(),
|
||||||
|
}
|
||||||
x2 := new(big.Int).Set(D)
|
|
||||||
x2.Mul(x2, a.X)
|
|
||||||
x2.Mul(x2, b.X)
|
|
||||||
x2.Mul(x2, a.Y)
|
|
||||||
x2.Mul(x2, b.Y)
|
|
||||||
x2.Add(constants.One, x2)
|
|
||||||
x2.Mod(x2, constants.Q)
|
|
||||||
x2.ModInverse(x2, constants.Q) // x2 = (1 + D * a.x * b.x * a.y * b.y)^-1
|
|
||||||
|
|
||||||
// y = (a.y * b.y - A * a.x * b.x) * (1 - D * a.x * b.x * a.y * b.y)^-1 mod q
|
|
||||||
y1a := new(big.Int).Mul(a.Y, b.Y)
|
|
||||||
y1b := new(big.Int).Set(A)
|
|
||||||
y1b.Mul(y1b, a.X)
|
|
||||||
y1b.Mul(y1b, b.X)
|
|
||||||
|
|
||||||
y1a.Sub(y1a, y1b) // y1a = a.y * b.y - A * a.x * b.x
|
|
||||||
|
|
||||||
y2 := new(big.Int).Set(D)
|
|
||||||
y2.Mul(y2, a.X)
|
|
||||||
y2.Mul(y2, b.X)
|
|
||||||
y2.Mul(y2, a.Y)
|
|
||||||
y2.Mul(y2, b.Y)
|
|
||||||
y2.Sub(constants.One, y2)
|
|
||||||
y2.Mod(y2, constants.Q)
|
|
||||||
y2.ModInverse(y2, constants.Q) // y2 = (1 - D * a.x * b.x * a.y * b.y)^-1
|
|
||||||
|
|
||||||
res.X = x1a.Mul(x1a, x2)
|
|
||||||
res.X = res.X.Mod(res.X, constants.Q)
|
|
||||||
|
|
||||||
res.Y = y1a.Mul(y1a, y2)
|
|
||||||
res.Y = res.Y.Mod(res.Y, constants.Q)
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mul multiplies the Point p by the scalar s and stores the result in res,
|
// Mul multiplies the Point q by the scalar s and stores the result in p,
|
||||||
// which is also returned.
|
// which is also returned.
|
||||||
func (res *Point) Mul(s *big.Int, p *Point) *Point {
|
func (p *Point) Mul(s *big.Int, q *Point) *Point {
|
||||||
res.X = big.NewInt(0)
|
resProj := &PointProjective{
|
||||||
res.Y = big.NewInt(1)
|
X: ff.NewElement().SetZero(),
|
||||||
exp := NewPoint().Set(p)
|
Y: ff.NewElement().SetOne(),
|
||||||
|
Z: ff.NewElement().SetOne(),
|
||||||
|
}
|
||||||
|
exp := q.Projective()
|
||||||
|
|
||||||
for i := 0; i < s.BitLen(); i++ {
|
for i := 0; i < s.BitLen(); i++ {
|
||||||
if s.Bit(i) == 1 {
|
if s.Bit(i) == 1 {
|
||||||
res.Add(res, exp)
|
resProj.Add(resProj, exp)
|
||||||
}
|
}
|
||||||
exp.Add(exp, exp)
|
exp = exp.Add(exp, exp)
|
||||||
}
|
}
|
||||||
|
p = resProj.Affine()
|
||||||
return res
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// InCurve returns true when the Point p is in the babyjub curve.
|
// InCurve returns true when the Point p is in the babyjub curve.
|
||||||
@@ -157,30 +203,54 @@ func PointCoordSign(c *big.Int) bool {
|
|||||||
return c.Cmp(new(big.Int).Rsh(constants.Q, 1)) == 1
|
return c.Cmp(new(big.Int).Rsh(constants.Q, 1)) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func PackPoint(ay *big.Int, sign bool) [32]byte {
|
// PackSignY packs the given sign and the coordinate Y of a point into a 32
|
||||||
leBuf := utils.BigIntLEBytes(ay)
|
// byte array. This method does not check that the values belong to a valid
|
||||||
|
// Point in the curve.
|
||||||
|
func PackSignY(sign bool, y *big.Int) [32]byte {
|
||||||
|
leBuf := utils.BigIntLEBytes(y)
|
||||||
if sign {
|
if sign {
|
||||||
leBuf[31] = leBuf[31] | 0x80
|
leBuf[31] = leBuf[31] | 0x80 //nolint:gomnd
|
||||||
}
|
}
|
||||||
return leBuf
|
return leBuf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnpackSignY returns the sign and coordinate Y from a given compressed point.
|
||||||
|
// This method does not check that the Point belongs to the BabyJubJub curve,
|
||||||
|
// thus does not return error in such case. This method is intended to obtain
|
||||||
|
// the sign and the Y coordinate without checking if the point belongs to the
|
||||||
|
// curve, if the objective is to uncompress a point, Decompress method should
|
||||||
|
// be used instead.
|
||||||
|
func UnpackSignY(leBuf [32]byte) (bool, *big.Int) {
|
||||||
|
sign := false
|
||||||
|
y := big.NewInt(0)
|
||||||
|
if (leBuf[31] & 0x80) != 0x00 { //nolint:gomnd
|
||||||
|
sign = true
|
||||||
|
leBuf[31] = leBuf[31] & 0x7F //nolint:gomnd
|
||||||
|
}
|
||||||
|
utils.SetBigIntFromLEBytes(y, leBuf[:])
|
||||||
|
return sign, y
|
||||||
|
}
|
||||||
|
|
||||||
// Compress the point into a 32 byte array that contains the y coordinate in
|
// Compress the point into a 32 byte array that contains the y coordinate in
|
||||||
// little endian and the sign of the x coordinate.
|
// little endian and the sign of the x coordinate.
|
||||||
func (p *Point) Compress() [32]byte {
|
func (p *Point) Compress() [32]byte {
|
||||||
sign := PointCoordSign(p.X)
|
sign := PointCoordSign(p.X)
|
||||||
return PackPoint(p.Y, sign)
|
return PackSignY(sign, p.Y)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decompress a compressed Point into p, and also returns the decompressed
|
// Decompress a compressed Point into p, and also returns the decompressed
|
||||||
// Point. Returns error if the compressed Point is invalid.
|
// Point. Returns error if the compressed Point is invalid.
|
||||||
func (p *Point) Decompress(leBuf [32]byte) (*Point, error) {
|
func (p *Point) Decompress(leBuf [32]byte) (*Point, error) {
|
||||||
sign := false
|
var sign bool
|
||||||
if (leBuf[31] & 0x80) != 0x00 {
|
sign, p.Y = UnpackSignY(leBuf)
|
||||||
sign = true
|
return PointFromSignAndY(sign, p.Y)
|
||||||
leBuf[31] = leBuf[31] & 0x7F
|
}
|
||||||
}
|
|
||||||
utils.SetBigIntFromLEBytes(p.Y, leBuf[:])
|
// PointFromSignAndY returns a Point from a Sign and the Y coordinate
|
||||||
|
func PointFromSignAndY(sign bool, y *big.Int) (*Point, error) {
|
||||||
|
var p Point
|
||||||
|
p.X = big.NewInt(0)
|
||||||
|
p.Y = y
|
||||||
if p.Y.Cmp(constants.Q) >= 0 {
|
if p.Y.Cmp(constants.Q) >= 0 {
|
||||||
return nil, fmt.Errorf("p.y >= Q")
|
return nil, fmt.Errorf("p.y >= Q")
|
||||||
}
|
}
|
||||||
@@ -209,5 +279,5 @@ func (p *Point) Decompress(leBuf [32]byte) (*Point, error) {
|
|||||||
}
|
}
|
||||||
p.X.Mod(p.X, constants.Q)
|
p.X.Mod(p.X, constants.Q)
|
||||||
|
|
||||||
return p, nil
|
return &p, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func TestAdd1(t *testing.T) {
|
|||||||
a := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
|
a := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
|
||||||
b := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
|
b := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
|
||||||
|
|
||||||
c := NewPoint().Add(a, b)
|
c := NewPoint().Projective().Add(a.Projective(), b.Projective())
|
||||||
// fmt.Printf("%v = 2 * %v", *c, *a)
|
// fmt.Printf("%v = 2 * %v", *c, *a)
|
||||||
assert.Equal(t, "0", c.X.String())
|
assert.Equal(t, "0", c.X.String())
|
||||||
assert.Equal(t, "1", c.Y.String())
|
assert.Equal(t, "1", c.Y.String())
|
||||||
@@ -34,7 +34,7 @@ func TestAdd2(t *testing.T) {
|
|||||||
"2626589144620713026669568689430873010625803728049924121243784502389097019475")
|
"2626589144620713026669568689430873010625803728049924121243784502389097019475")
|
||||||
b := &Point{X: bX, Y: bY}
|
b := &Point{X: bX, Y: bY}
|
||||||
|
|
||||||
c := NewPoint().Add(a, b)
|
c := NewPoint().Projective().Add(a.Projective(), b.Projective()).Affine()
|
||||||
// fmt.Printf("%v = 2 * %v", *c, *a)
|
// fmt.Printf("%v = 2 * %v", *c, *a)
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"6890855772600357754907169075114257697580319025794532037257385534741338397365",
|
"6890855772600357754907169075114257697580319025794532037257385534741338397365",
|
||||||
@@ -42,6 +42,18 @@ func TestAdd2(t *testing.T) {
|
|||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"4338620300185947561074059802482547481416142213883829469920100239455078257889",
|
"4338620300185947561074059802482547481416142213883829469920100239455078257889",
|
||||||
c.Y.String())
|
c.Y.String())
|
||||||
|
|
||||||
|
d := NewPointProjective().Add(c.Projective(), c.Projective()).Affine()
|
||||||
|
assert.Equal(t,
|
||||||
|
"2f6458832049e917c95867185a96621336df33e13c98e81d1ef4928cdbb77772",
|
||||||
|
hex.EncodeToString(d.X.Bytes()))
|
||||||
|
|
||||||
|
// Projective
|
||||||
|
aP := a.Projective()
|
||||||
|
bP := b.Projective()
|
||||||
|
cP := NewPointProjective().Add(aP, bP)
|
||||||
|
c2 := cP.Affine()
|
||||||
|
assert.Equal(t, c, c2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdd3(t *testing.T) {
|
func TestAdd3(t *testing.T) {
|
||||||
@@ -57,7 +69,7 @@ func TestAdd3(t *testing.T) {
|
|||||||
"20819045374670962167435360035096875258406992893633759881276124905556507972311")
|
"20819045374670962167435360035096875258406992893633759881276124905556507972311")
|
||||||
b := &Point{X: bX, Y: bY}
|
b := &Point{X: bX, Y: bY}
|
||||||
|
|
||||||
c := NewPoint().Add(a, b)
|
c := NewPoint().Projective().Add(a.Projective(), b.Projective()).Affine()
|
||||||
// fmt.Printf("%v = 2 * %v", *c, *a)
|
// fmt.Printf("%v = 2 * %v", *c, *a)
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"7916061937171219682591368294088513039687205273691143098332585753343424131937",
|
"7916061937171219682591368294088513039687205273691143098332585753343424131937",
|
||||||
@@ -80,7 +92,7 @@ func TestAdd4(t *testing.T) {
|
|||||||
"20819045374670962167435360035096875258406992893633759881276124905556507972311")
|
"20819045374670962167435360035096875258406992893633759881276124905556507972311")
|
||||||
b := &Point{X: bX, Y: bY}
|
b := &Point{X: bX, Y: bY}
|
||||||
|
|
||||||
c := NewPoint().Add(a, b)
|
c := NewPoint().Projective().Add(a.Projective(), b.Projective()).Affine()
|
||||||
// fmt.Printf("%v = 2 * %v", *c, *a)
|
// fmt.Printf("%v = 2 * %v", *c, *a)
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"16540640123574156134436876038791482806971768689494387082833631921987005038935",
|
"16540640123574156134436876038791482806971768689494387082833631921987005038935",
|
||||||
@@ -108,8 +120,8 @@ func TestMul0(t *testing.T) {
|
|||||||
p := &Point{X: x, Y: y}
|
p := &Point{X: x, Y: y}
|
||||||
s := utils.NewIntFromString("3")
|
s := utils.NewIntFromString("3")
|
||||||
|
|
||||||
r2 := NewPoint().Add(p, p)
|
r2 := NewPoint().Projective().Add(p.Projective(), p.Projective()).Affine()
|
||||||
r2 = NewPoint().Add(r2, p)
|
r2 = NewPoint().Projective().Add(r2.Projective(), p.Projective()).Affine()
|
||||||
r := NewPoint().Mul(s, p)
|
r := NewPoint().Mul(s, p)
|
||||||
assert.Equal(t, r2.X.String(), r.X.String())
|
assert.Equal(t, r2.X.String(), r.X.String())
|
||||||
assert.Equal(t, r2.Y.String(), r.Y.String())
|
assert.Equal(t, r2.Y.String(), r.Y.String())
|
||||||
@@ -192,6 +204,40 @@ func TestInSubGroup2(t *testing.T) {
|
|||||||
assert.Equal(t, true, p.InSubGroup())
|
assert.Equal(t, true, p.InSubGroup())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPointFromSignAndy(t *testing.T) {
|
||||||
|
x := utils.NewIntFromString(
|
||||||
|
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
|
||||||
|
y := utils.NewIntFromString(
|
||||||
|
"2626589144620713026669568689430873010625803728049924121243784502389097019475")
|
||||||
|
p := &Point{X: x, Y: y}
|
||||||
|
|
||||||
|
sign := PointCoordSign(p.X)
|
||||||
|
p2, err := PointFromSignAndY(sign, p.Y)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, p.X.String(), p2.X.String())
|
||||||
|
assert.Equal(t, p.Y.String(), p2.Y.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPackAndUnpackSignY(t *testing.T) {
|
||||||
|
x := utils.NewIntFromString(
|
||||||
|
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
|
||||||
|
y := utils.NewIntFromString(
|
||||||
|
"2626589144620713026669568689430873010625803728049924121243784502389097019475")
|
||||||
|
p := &Point{X: x, Y: y}
|
||||||
|
pComp := p.Compress()
|
||||||
|
|
||||||
|
s, y := UnpackSignY(pComp)
|
||||||
|
|
||||||
|
pComp2 := PackSignY(s, y)
|
||||||
|
assert.Equal(t, pComp, pComp2)
|
||||||
|
|
||||||
|
emptyPointComp := [32]byte{}
|
||||||
|
s, y = UnpackSignY(emptyPointComp)
|
||||||
|
|
||||||
|
pComp2 = PackSignY(s, y)
|
||||||
|
assert.Equal(t, emptyPointComp, pComp2)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCompressDecompress1(t *testing.T) {
|
func TestCompressDecompress1(t *testing.T) {
|
||||||
x := utils.NewIntFromString(
|
x := utils.NewIntFromString(
|
||||||
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
|
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
|
||||||
@@ -200,7 +246,9 @@ func TestCompressDecompress1(t *testing.T) {
|
|||||||
p := &Point{X: x, Y: y}
|
p := &Point{X: x, Y: y}
|
||||||
|
|
||||||
buf := p.Compress()
|
buf := p.Compress()
|
||||||
assert.Equal(t, "53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85", hex.EncodeToString(buf[:]))
|
assert.Equal(t,
|
||||||
|
"53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85",
|
||||||
|
hex.EncodeToString(buf[:]))
|
||||||
|
|
||||||
p2, err := NewPoint().Decompress(buf)
|
p2, err := NewPoint().Decompress(buf)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
@@ -216,7 +264,9 @@ func TestCompressDecompress2(t *testing.T) {
|
|||||||
p := &Point{X: x, Y: y}
|
p := &Point{X: x, Y: y}
|
||||||
|
|
||||||
buf := p.Compress()
|
buf := p.Compress()
|
||||||
assert.Equal(t, "e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709", hex.EncodeToString(buf[:]))
|
assert.Equal(t,
|
||||||
|
"e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709",
|
||||||
|
hex.EncodeToString(buf[:]))
|
||||||
|
|
||||||
p2, err := NewPoint().Decompress(buf)
|
p2, err := NewPoint().Decompress(buf)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
@@ -230,14 +280,15 @@ func TestCompressDecompressRnd(t *testing.T) {
|
|||||||
buf := p1.Compress()
|
buf := p1.Compress()
|
||||||
p2, err := NewPoint().Decompress(buf)
|
p2, err := NewPoint().Decompress(buf)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
assert.Equal(t, p1, p2)
|
assert.Equal(t, p1.X.Bytes(), p2.X.Bytes())
|
||||||
|
assert.Equal(t, p1.Y.Bytes(), p2.Y.Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkBabyjub(b *testing.B) {
|
func BenchmarkBabyjub(b *testing.B) {
|
||||||
const n = 256
|
const n = 256
|
||||||
|
|
||||||
rnd := rand.New(rand.NewSource(42))
|
rnd := rand.New(rand.NewSource(42)) //nolint:gosec
|
||||||
|
|
||||||
var badpoints [n]*Point
|
var badpoints [n]*Point
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
@@ -247,6 +298,7 @@ func BenchmarkBabyjub(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var points [n]*Point
|
var points [n]*Point
|
||||||
|
var pointsProj [n]*PointProjective
|
||||||
baseX := utils.NewIntFromString(
|
baseX := utils.NewIntFromString(
|
||||||
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
|
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
|
||||||
baseY := utils.NewIntFromString(
|
baseY := utils.NewIntFromString(
|
||||||
@@ -255,6 +307,7 @@ func BenchmarkBabyjub(b *testing.B) {
|
|||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
s := new(big.Int).Rand(rnd, constants.Q)
|
s := new(big.Int).Rand(rnd, constants.Q)
|
||||||
points[i] = NewPoint().Mul(s, base)
|
points[i] = NewPoint().Mul(s, base)
|
||||||
|
pointsProj[i] = NewPoint().Mul(s, base).Projective()
|
||||||
}
|
}
|
||||||
|
|
||||||
var scalars [n]*big.Int
|
var scalars [n]*big.Int
|
||||||
@@ -265,17 +318,19 @@ func BenchmarkBabyjub(b *testing.B) {
|
|||||||
b.Run("AddConst", func(b *testing.B) {
|
b.Run("AddConst", func(b *testing.B) {
|
||||||
p0 := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
|
p0 := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
|
||||||
p1 := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
|
p1 := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
|
||||||
|
p0Proj := p0.Projective()
|
||||||
|
p1Proj := p1.Projective()
|
||||||
|
|
||||||
p2 := NewPoint()
|
p2 := NewPoint().Projective()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
p2.Add(p0, p1)
|
p2.Add(p0Proj, p1Proj)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
b.Run("AddRnd", func(b *testing.B) {
|
b.Run("AddRnd", func(b *testing.B) {
|
||||||
res := NewPoint()
|
res := NewPoint().Projective()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
res.Add(points[i%(n/2)], points[i%(n/2)+1])
|
res.Add(pointsProj[i%(n/2)], pointsProj[i%(n/2)+1])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
174
babyjub/eddsa.go
174
babyjub/eddsa.go
@@ -1,13 +1,16 @@
|
|||||||
|
// Package babyjub eddsa implements the EdDSA over the BabyJubJub curve
|
||||||
|
//nolint:gomnd
|
||||||
package babyjub
|
package babyjub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"github.com/iden3/go-iden3-crypto/mimc7"
|
"github.com/iden3/go-iden3-crypto/mimc7"
|
||||||
"github.com/iden3/go-iden3-crypto/poseidon"
|
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||||
"github.com/iden3/go-iden3-crypto/utils"
|
"github.com/iden3/go-iden3-crypto/utils"
|
||||||
|
|
||||||
"math/big"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// pruneBuffer prunes the buffer during key generation according to RFC 8032.
|
// pruneBuffer prunes the buffer during key generation according to RFC 8032.
|
||||||
@@ -53,7 +56,7 @@ func SkToBigInt(k *PrivateKey) *big.Int {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pub returns the public key corresponding to a private key.
|
// Public returns the public key corresponding to a private key.
|
||||||
func (k *PrivateKey) Public() *PublicKey {
|
func (k *PrivateKey) Public() *PublicKey {
|
||||||
return k.Scalar().Public()
|
return k.Scalar().Public()
|
||||||
}
|
}
|
||||||
@@ -67,8 +70,8 @@ func NewPrivKeyScalar(s *big.Int) *PrivKeyScalar {
|
|||||||
return &sk
|
return &sk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pub returns the public key corresponding to the scalar value s of a private
|
// Public returns the public key corresponding to the scalar value s of a
|
||||||
// key.
|
// private key.
|
||||||
func (s *PrivKeyScalar) Public() *PublicKey {
|
func (s *PrivKeyScalar) Public() *PublicKey {
|
||||||
p := NewPoint().Mul((*big.Int)(s), B8)
|
p := NewPoint().Mul((*big.Int)(s), B8)
|
||||||
pk := PublicKey(*p)
|
pk := PublicKey(*p)
|
||||||
@@ -83,16 +86,19 @@ func (s *PrivKeyScalar) BigInt() *big.Int {
|
|||||||
// PublicKey represents an EdDSA public key, which is a curve point.
|
// PublicKey represents an EdDSA public key, which is a curve point.
|
||||||
type PublicKey Point
|
type PublicKey Point
|
||||||
|
|
||||||
|
// MarshalText implements the marshaler for PublicKey
|
||||||
func (pk PublicKey) MarshalText() ([]byte, error) {
|
func (pk PublicKey) MarshalText() ([]byte, error) {
|
||||||
pkc := pk.Compress()
|
pkc := pk.Compress()
|
||||||
return utils.Hex(pkc[:]).MarshalText()
|
return utils.Hex(pkc[:]).MarshalText()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the PublicKey
|
||||||
func (pk PublicKey) String() string {
|
func (pk PublicKey) String() string {
|
||||||
pkc := pk.Compress()
|
pkc := pk.Compress()
|
||||||
return utils.Hex(pkc[:]).String()
|
return utils.Hex(pkc[:]).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements the unmarshaler for the PublicKey
|
||||||
func (pk *PublicKey) UnmarshalText(h []byte) error {
|
func (pk *PublicKey) UnmarshalText(h []byte) error {
|
||||||
var pkc PublicKeyComp
|
var pkc PublicKeyComp
|
||||||
if err := utils.HexDecodeInto(pkc[:], h); err != nil {
|
if err := utils.HexDecodeInto(pkc[:], h); err != nil {
|
||||||
@@ -107,24 +113,35 @@ func (pk *PublicKey) UnmarshalText(h []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Point returns the Point corresponding to a PublicKey.
|
// Point returns the Point corresponding to a PublicKey.
|
||||||
func (p *PublicKey) Point() *Point {
|
func (pk *PublicKey) Point() *Point {
|
||||||
return (*Point)(p)
|
return (*Point)(pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicKeyComp represents a compressed EdDSA Public key; it's a compressed curve
|
// PublicKeyComp represents a compressed EdDSA Public key; it's a compressed curve
|
||||||
// point.
|
// point.
|
||||||
type PublicKeyComp [32]byte
|
type PublicKeyComp [32]byte
|
||||||
|
|
||||||
func (buf PublicKeyComp) MarshalText() ([]byte, error) { return utils.Hex(buf[:]).MarshalText() }
|
// MarshalText implements the marshaler for the PublicKeyComp
|
||||||
func (buf PublicKeyComp) String() string { return utils.Hex(buf[:]).String() }
|
func (pkComp PublicKeyComp) MarshalText() ([]byte, error) {
|
||||||
func (buf *PublicKeyComp) UnmarshalText(h []byte) error { return utils.HexDecodeInto(buf[:], h) }
|
return utils.Hex(pkComp[:]).MarshalText()
|
||||||
|
|
||||||
func (p *PublicKey) Compress() PublicKeyComp {
|
|
||||||
return PublicKeyComp((*Point)(p).Compress())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicKeyComp) Decompress() (*PublicKey, error) {
|
// String returns the string representation of the PublicKeyComp
|
||||||
point, err := NewPoint().Decompress(*p)
|
func (pkComp PublicKeyComp) String() string { return utils.Hex(pkComp[:]).String() }
|
||||||
|
|
||||||
|
// UnmarshalText implements the unmarshaler for the PublicKeyComp
|
||||||
|
func (pkComp *PublicKeyComp) UnmarshalText(h []byte) error {
|
||||||
|
return utils.HexDecodeInto(pkComp[:], h)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compress returns the PublicKeyCompr for the given PublicKey
|
||||||
|
func (pk *PublicKey) Compress() PublicKeyComp {
|
||||||
|
return PublicKeyComp((*Point)(pk).Compress())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decompress returns the PublicKey for the given PublicKeyComp
|
||||||
|
func (pkComp *PublicKeyComp) Decompress() (*PublicKey, error) {
|
||||||
|
point, err := NewPoint().Decompress(*pkComp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -141,9 +158,18 @@ type Signature struct {
|
|||||||
// SignatureComp represents a compressed EdDSA signature.
|
// SignatureComp represents a compressed EdDSA signature.
|
||||||
type SignatureComp [64]byte
|
type SignatureComp [64]byte
|
||||||
|
|
||||||
func (buf SignatureComp) MarshalText() ([]byte, error) { return utils.Hex(buf[:]).MarshalText() }
|
// MarshalText implements the marshaler for the SignatureComp
|
||||||
func (buf SignatureComp) String() string { return utils.Hex(buf[:]).String() }
|
func (sComp SignatureComp) MarshalText() ([]byte, error) {
|
||||||
func (buf *SignatureComp) UnmarshalText(h []byte) error { return utils.HexDecodeInto(buf[:], h) }
|
return utils.Hex(sComp[:]).MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the SignatureComp
|
||||||
|
func (sComp SignatureComp) String() string { return utils.Hex(sComp[:]).String() }
|
||||||
|
|
||||||
|
// UnmarshalText implements the unmarshaler for the SignatureComp
|
||||||
|
func (sComp *SignatureComp) UnmarshalText(h []byte) error {
|
||||||
|
return utils.HexDecodeInto(sComp[:], h)
|
||||||
|
}
|
||||||
|
|
||||||
// Compress an EdDSA signature by concatenating the compression of
|
// Compress an EdDSA signature by concatenating the compression of
|
||||||
// the point R8 and the Little-Endian encoding of S.
|
// the point R8 and the Little-Endian encoding of S.
|
||||||
@@ -171,8 +197,47 @@ func (s *Signature) Decompress(buf [64]byte) (*Signature, error) {
|
|||||||
|
|
||||||
// Decompress a compressed signature. Returns error if the Point decompression
|
// Decompress a compressed signature. Returns error if the Point decompression
|
||||||
// fails.
|
// fails.
|
||||||
func (s *SignatureComp) Decompress() (*Signature, error) {
|
func (sComp *SignatureComp) Decompress() (*Signature, error) {
|
||||||
return new(Signature).Decompress(*s)
|
return new(Signature).Decompress(*sComp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements Scanner for database/sql.
|
||||||
|
func (sComp *SignatureComp) Scan(src interface{}) error {
|
||||||
|
srcB, ok := src.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("can't scan %T into Signature", src)
|
||||||
|
}
|
||||||
|
if len(srcB) != 64 {
|
||||||
|
return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64)
|
||||||
|
}
|
||||||
|
copy(sComp[:], srcB[:])
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements valuer for database/sql.
|
||||||
|
func (sComp SignatureComp) Value() (driver.Value, error) {
|
||||||
|
return sComp[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements Scanner for database/sql.
|
||||||
|
func (s *Signature) Scan(src interface{}) error {
|
||||||
|
srcB, ok := src.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("can't scan %T into Signature", src)
|
||||||
|
}
|
||||||
|
if len(srcB) != 64 {
|
||||||
|
return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64)
|
||||||
|
}
|
||||||
|
buf := [64]byte{}
|
||||||
|
copy(buf[:], srcB[:])
|
||||||
|
_, err := s.Decompress(buf)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements valuer for database/sql.
|
||||||
|
func (s Signature) Value() (driver.Value, error) {
|
||||||
|
comp := s.Compress()
|
||||||
|
return comp[:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignMimc7 signs a message encoded as a big.Int in Zq using blake-512 hash
|
// SignMimc7 signs a message encoded as a big.Int in Zq using blake-512 hash
|
||||||
@@ -202,18 +267,20 @@ func (k *PrivateKey) SignMimc7(msg *big.Int) *Signature {
|
|||||||
|
|
||||||
// VerifyMimc7 verifies the signature of a message encoded as a big.Int in Zq
|
// VerifyMimc7 verifies the signature of a message encoded as a big.Int in Zq
|
||||||
// using blake-512 hash for buffer hashing and mimc7 for big.Int hashing.
|
// using blake-512 hash for buffer hashing and mimc7 for big.Int hashing.
|
||||||
func (p *PublicKey) VerifyMimc7(msg *big.Int, sig *Signature) bool {
|
func (pk *PublicKey) VerifyMimc7(msg *big.Int, sig *Signature) bool {
|
||||||
hmInput := []*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg}
|
hmInput := []*big.Int{sig.R8.X, sig.R8.Y, pk.X, pk.Y, msg}
|
||||||
hm, err := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
|
hm, err := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
|
left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
|
||||||
r1 := big.NewInt(8)
|
r1 := big.NewInt(8)
|
||||||
r1.Mul(r1, hm)
|
r1.Mul(r1, hm)
|
||||||
right := NewPoint().Mul(r1, p.Point())
|
right := NewPoint().Mul(r1, pk.Point())
|
||||||
right.Add(sig.R8, right) // right = 8 * R + 8 * hm * A
|
rightProj := right.Projective()
|
||||||
|
rightProj.Add(sig.R8.Projective(), rightProj) // right = 8 * R + 8 * hm * A
|
||||||
|
right = rightProj.Affine()
|
||||||
return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
|
return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +297,7 @@ func (k *PrivateKey) SignPoseidon(msg *big.Int) *Signature {
|
|||||||
R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
|
R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
|
||||||
A := k.Public().Point()
|
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}
|
||||||
hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
|
hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -246,17 +313,62 @@ func (k *PrivateKey) SignPoseidon(msg *big.Int) *Signature {
|
|||||||
|
|
||||||
// VerifyPoseidon verifies the signature of a message encoded as a big.Int in Zq
|
// 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.
|
// using blake-512 hash for buffer hashing and Poseidon for big.Int hashing.
|
||||||
func (p *PublicKey) VerifyPoseidon(msg *big.Int, sig *Signature) bool {
|
func (pk *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, pk.X, pk.Y, msg}
|
||||||
hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
|
hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
|
left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
|
||||||
r1 := big.NewInt(8)
|
r1 := big.NewInt(8)
|
||||||
r1.Mul(r1, hm)
|
r1.Mul(r1, hm)
|
||||||
right := NewPoint().Mul(r1, p.Point())
|
right := NewPoint().Mul(r1, pk.Point())
|
||||||
right.Add(sig.R8, right) // right = 8 * R + 8 * hm * A
|
rightProj := right.Projective()
|
||||||
|
rightProj.Add(sig.R8.Projective(), rightProj) // right = 8 * R + 8 * hm * A
|
||||||
|
right = rightProj.Affine()
|
||||||
return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
|
return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan implements Scanner for database/sql.
|
||||||
|
func (pk *PublicKey) Scan(src interface{}) error {
|
||||||
|
srcB, ok := src.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("can't scan %T into PublicKey", src)
|
||||||
|
}
|
||||||
|
if len(srcB) != 32 {
|
||||||
|
return fmt.Errorf("can't scan []byte of len %d into PublicKey, want %d", len(srcB), 32)
|
||||||
|
}
|
||||||
|
var comp PublicKeyComp
|
||||||
|
copy(comp[:], srcB)
|
||||||
|
decomp, err := comp.Decompress()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*pk = *decomp
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements valuer for database/sql.
|
||||||
|
func (pk PublicKey) Value() (driver.Value, error) {
|
||||||
|
comp := pk.Compress()
|
||||||
|
return comp[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements Scanner for database/sql.
|
||||||
|
func (pkComp *PublicKeyComp) Scan(src interface{}) error {
|
||||||
|
srcB, ok := src.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("can't scan %T into PublicKeyComp", src)
|
||||||
|
}
|
||||||
|
if len(srcB) != 32 {
|
||||||
|
return fmt.Errorf("can't scan []byte of len %d into PublicKeyComp, want %d", len(srcB), 32)
|
||||||
|
}
|
||||||
|
copy(pkComp[:], srcB)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements valuer for database/sql.
|
||||||
|
func (pkComp PublicKeyComp) Value() (driver.Value, error) {
|
||||||
|
return pkComp[:], nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package babyjub
|
package babyjub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
@@ -24,7 +26,8 @@ func TestPublicKey(t *testing.T) {
|
|||||||
|
|
||||||
func TestSignVerifyMimc7(t *testing.T) {
|
func TestSignVerifyMimc7(t *testing.T) {
|
||||||
var k PrivateKey
|
var k PrivateKey
|
||||||
_, err := hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
_, err := hex.Decode(k[:],
|
||||||
|
[]byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
msgBuf, err := hex.DecodeString("00010203040506070809")
|
msgBuf, err := hex.DecodeString("00010203040506070809")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -69,7 +72,8 @@ func TestSignVerifyMimc7(t *testing.T) {
|
|||||||
|
|
||||||
func TestSignVerifyPoseidon(t *testing.T) {
|
func TestSignVerifyPoseidon(t *testing.T) {
|
||||||
var k PrivateKey
|
var k PrivateKey
|
||||||
_, err := hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
_, err := hex.Decode(k[:],
|
||||||
|
[]byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
msgBuf, err := hex.DecodeString("00010203040506070809")
|
msgBuf, err := hex.DecodeString("00010203040506070809")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -93,7 +97,7 @@ func TestSignVerifyPoseidon(t *testing.T) {
|
|||||||
"15383486972088797283337779941324724402501462225528836549661220478783371668959",
|
"15383486972088797283337779941324724402501462225528836549661220478783371668959",
|
||||||
sig.R8.Y.String())
|
sig.R8.Y.String())
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"248298168863866362217836334079793350221620631973732197668910946177382043688",
|
"1672775540645840396591609181675628451599263765380031905495115170613215233181",
|
||||||
sig.S.String())
|
sig.S.String())
|
||||||
|
|
||||||
ok := pk.VerifyPoseidon(msg, sig)
|
ok := pk.VerifyPoseidon(msg, sig)
|
||||||
@@ -105,7 +109,7 @@ func TestSignVerifyPoseidon(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, ""+
|
assert.Equal(t, ""+
|
||||||
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
|
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
|
||||||
"28506bce274aa1b3f7e7c2fd7e4fe09bff8f9aa37a42def7994e98f322888c00",
|
"9d043ece562a8f82bfc0adb640c0107a7d3a27c1c7c1a6179a0da73de5c1b203",
|
||||||
hex.EncodeToString(sigBuf[:]))
|
hex.EncodeToString(sigBuf[:]))
|
||||||
|
|
||||||
ok = pk.VerifyPoseidon(msg, sig2)
|
ok = pk.VerifyPoseidon(msg, sig2)
|
||||||
@@ -114,7 +118,8 @@ func TestSignVerifyPoseidon(t *testing.T) {
|
|||||||
|
|
||||||
func TestCompressDecompress(t *testing.T) {
|
func TestCompressDecompress(t *testing.T) {
|
||||||
var k PrivateKey
|
var k PrivateKey
|
||||||
_, err := hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
_, err := hex.Decode(k[:],
|
||||||
|
[]byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
pk := k.Public()
|
pk := k.Public()
|
||||||
for i := 0; i < 64; i++ {
|
for i := 0; i < 64; i++ {
|
||||||
@@ -132,9 +137,63 @@ func TestCompressDecompress(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSignatureCompScannerValuer(t *testing.T) {
|
||||||
|
privK := NewRandPrivKey()
|
||||||
|
var value driver.Valuer //nolint:gosimple this is done to ensure interface compatibility
|
||||||
|
value = privK.SignPoseidon(big.NewInt(674238462)).Compress()
|
||||||
|
scan := privK.SignPoseidon(big.NewInt(1)).Compress()
|
||||||
|
fromDB, err := value.Value()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Nil(t, scan.Scan(fromDB))
|
||||||
|
assert.Equal(t, value, scan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSignatureScannerValuer(t *testing.T) {
|
||||||
|
privK := NewRandPrivKey()
|
||||||
|
var value driver.Valuer
|
||||||
|
var scan sql.Scanner
|
||||||
|
value = privK.SignPoseidon(big.NewInt(674238462))
|
||||||
|
scan = privK.SignPoseidon(big.NewInt(1))
|
||||||
|
fromDB, err := value.Value()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Nil(t, scan.Scan(fromDB))
|
||||||
|
assert.Equal(t, value, scan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPublicKeyScannerValuer(t *testing.T) {
|
||||||
|
privKValue := NewRandPrivKey()
|
||||||
|
pubKValue := privKValue.Public()
|
||||||
|
privKScan := NewRandPrivKey()
|
||||||
|
pubKScan := privKScan.Public()
|
||||||
|
var value driver.Valuer
|
||||||
|
var scan sql.Scanner
|
||||||
|
value = pubKValue
|
||||||
|
scan = pubKScan
|
||||||
|
fromDB, err := value.Value()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Nil(t, scan.Scan(fromDB))
|
||||||
|
assert.Equal(t, value, scan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPublicKeyCompScannerValuer(t *testing.T) {
|
||||||
|
privKValue := NewRandPrivKey()
|
||||||
|
pubKCompValue := privKValue.Public().Compress()
|
||||||
|
privKScan := NewRandPrivKey()
|
||||||
|
pubKCompScan := privKScan.Public().Compress()
|
||||||
|
var value driver.Valuer
|
||||||
|
var scan sql.Scanner
|
||||||
|
value = &pubKCompValue
|
||||||
|
scan = &pubKCompScan
|
||||||
|
fromDB, err := value.Value()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Nil(t, scan.Scan(fromDB))
|
||||||
|
assert.Equal(t, value, scan)
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkBabyjubEddsa(b *testing.B) {
|
func BenchmarkBabyjubEddsa(b *testing.B) {
|
||||||
var k PrivateKey
|
var k PrivateKey
|
||||||
_, err := hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
_, err := hex.Decode(k[:],
|
||||||
|
[]byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
require.Nil(b, err)
|
require.Nil(b, err)
|
||||||
pk := k.Public()
|
pk := k.Public()
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package babyjub
|
package babyjub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/dchest/blake512" // I have personally reviewed that this module doesn't do anything suspicious
|
"github.com/dchest/blake512"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Note on dchest/blake512: This specific blake512 module is compatible with
|
||||||
|
// the version of Blake512 used at circomlib, and this module has been reviewed
|
||||||
|
// to don't be doing do anything suspicious.
|
||||||
|
|
||||||
// Blake512 performs the blake-512 hash over the buffer m. Note that this is
|
// Blake512 performs the blake-512 hash over the buffer m. Note that this is
|
||||||
// the original blake from the SHA3 competition and not the new blake2 version.
|
// the original blake from the SHA3 competition and not the new blake2 version.
|
||||||
func Blake512(m []byte) []byte {
|
func Blake512(m []byte) []byte {
|
||||||
|
|||||||
@@ -3,13 +3,10 @@ package constants
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/iden3/go-iden3-crypto/ff"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Q is the order of the integer field (Zq) that fits inside the SNARK.
|
// Q is the order of the integer field (Zq) that fits inside the SNARK.
|
||||||
var Q *big.Int
|
var Q *big.Int
|
||||||
var QE *ff.Element
|
|
||||||
|
|
||||||
// Zero is 0.
|
// Zero is 0.
|
||||||
var Zero *big.Int
|
var Zero *big.Int
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ff
|
package ff
|
||||||
|
|
||||||
|
// NewElement returns a new empty *Element
|
||||||
func NewElement() *Element {
|
func NewElement() *Element {
|
||||||
return &Element{}
|
return &Element{}
|
||||||
}
|
}
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -7,4 +7,5 @@ require (
|
|||||||
github.com/ethereum/go-ethereum v1.9.12
|
github.com/ethereum/go-ethereum v1.9.12
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4
|
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
11
go.sum
11
go.sum
@@ -50,8 +50,6 @@ github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbT
|
|||||||
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa h1:XKAhUk/dtp+CV0VO6mhG2V7jA9vbcGcnYF/Ay9NjZrY=
|
github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa h1:XKAhUk/dtp+CV0VO6mhG2V7jA9vbcGcnYF/Ay9NjZrY=
|
||||||
github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
|
github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
|
||||||
github.com/ethereum/go-ethereum v1.8.27 h1:d+gkiLaBDk5fn3Pe/xNVaMrB/ozI+AUB2IlVBp29IrY=
|
|
||||||
github.com/ethereum/go-ethereum v1.8.27/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
|
|
||||||
github.com/ethereum/go-ethereum v1.9.12 h1:EPtimwsp/KGDSiXcNunzsI4kefdsMHZGJntKx3fvbaI=
|
github.com/ethereum/go-ethereum v1.9.12 h1:EPtimwsp/KGDSiXcNunzsI4kefdsMHZGJntKx3fvbaI=
|
||||||
github.com/ethereum/go-ethereum v1.9.12/go.mod h1:PvsVkQmhZFx92Y+h2ylythYlheEDt/uBgFbl61Js/jo=
|
github.com/ethereum/go-ethereum v1.9.12/go.mod h1:PvsVkQmhZFx92Y+h2ylythYlheEDt/uBgFbl61Js/jo=
|
||||||
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
@@ -76,15 +74,16 @@ github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1
|
|||||||
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
|
github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
|
||||||
github.com/iden3/go-iden3 v0.0.5 h1:NV6HXnLmp+1YmKd2FmymzU6OAP77q1WWDcB/B+BUL9g=
|
|
||||||
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
@@ -127,6 +126,7 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1
|
|||||||
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
|
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
|
||||||
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
|
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
|
||||||
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
|
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
|
||||||
|
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
@@ -138,8 +138,6 @@ github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:s
|
|||||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
|
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A=
|
|
||||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA=
|
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA=
|
||||||
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -154,12 +152,15 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5
|
|||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/iden3/go-iden3-crypto/utils"
|
"github.com/iden3/go-iden3-crypto/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SEED defines the seed used to constants
|
||||||
const SEED = "mimc"
|
const SEED = "mimc"
|
||||||
|
|
||||||
var constants = generateConstantsData()
|
var constants = generateConstantsData()
|
||||||
@@ -47,8 +48,9 @@ func getConstants(seed string, nRounds int) []*ff.Element {
|
|||||||
return cts
|
return cts
|
||||||
}
|
}
|
||||||
|
|
||||||
// MIMC7HashGeneric performs the MIMC7 hash over a *big.Int, in a generic way, where it can be specified the Finite Field over R, and the number of rounds
|
// MIMC7HashGeneric performs the MIMC7 hash over a *big.Int, in a generic way,
|
||||||
func MIMC7HashGeneric(xInBI, kBI *big.Int, nRounds int) *big.Int {
|
// where it can be specified the Finite Field over R, and the number of rounds
|
||||||
|
func MIMC7HashGeneric(xInBI, kBI *big.Int, nRounds int) *big.Int { //nolint:golint
|
||||||
xIn := ff.NewElement().SetBigInt(xInBI)
|
xIn := ff.NewElement().SetBigInt(xInBI)
|
||||||
k := ff.NewElement().SetBigInt(kBI)
|
k := ff.NewElement().SetBigInt(kBI)
|
||||||
|
|
||||||
@@ -72,7 +74,8 @@ func MIMC7HashGeneric(xInBI, kBI *big.Int, nRounds int) *big.Int {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashGeneric performs the MIMC7 hash over a *big.Int array, in a generic way, where it can be specified the Finite Field over R, and the number of rounds
|
// HashGeneric performs the MIMC7 hash over a *big.Int array, in a generic way,
|
||||||
|
// where it can be specified the Finite Field over R, and the number of rounds
|
||||||
func HashGeneric(iv *big.Int, arr []*big.Int, nRounds int) (*big.Int, error) {
|
func HashGeneric(iv *big.Int, arr []*big.Int, nRounds int) (*big.Int, error) {
|
||||||
if !utils.CheckBigIntArrayInField(arr) {
|
if !utils.CheckBigIntArrayInField(arr) {
|
||||||
return nil, errors.New("inputs values not inside Finite Field")
|
return nil, errors.New("inputs values not inside Finite Field")
|
||||||
@@ -88,8 +91,9 @@ func HashGeneric(iv *big.Int, arr []*big.Int, nRounds int) (*big.Int, error) {
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MIMC7Hash performs the MIMC7 hash over a *big.Int, using the Finite Field over R and the number of rounds setted in the `constants` variable
|
// MIMC7Hash performs the MIMC7 hash over a *big.Int, using the Finite Field
|
||||||
func MIMC7Hash(xInBI, kBI *big.Int) *big.Int {
|
// over R and the number of rounds setted in the `constants` variable
|
||||||
|
func MIMC7Hash(xInBI, kBI *big.Int) *big.Int { //nolint:golint
|
||||||
xIn := ff.NewElement().SetBigInt(xInBI)
|
xIn := ff.NewElement().SetBigInt(xInBI)
|
||||||
k := ff.NewElement().SetBigInt(kBI)
|
k := ff.NewElement().SetBigInt(kBI)
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,13 @@ import (
|
|||||||
|
|
||||||
func TestKeccak256(t *testing.T) {
|
func TestKeccak256(t *testing.T) {
|
||||||
res := crypto.Keccak256([]byte(SEED))
|
res := crypto.Keccak256([]byte(SEED))
|
||||||
assert.Equal(t, "b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e", hex.EncodeToString(res))
|
assert.Equal(t,
|
||||||
|
"b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e",
|
||||||
|
hex.EncodeToString(res))
|
||||||
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
|
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
|
||||||
assert.Equal(t, "82724731331859054037315113496710413141112897654334566532528783843265082629790", c.String())
|
assert.Equal(t,
|
||||||
|
"82724731331859054037315113496710413141112897654334566532528783843265082629790",
|
||||||
|
c.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMIMC7Generic(t *testing.T) {
|
func TestMIMC7Generic(t *testing.T) {
|
||||||
@@ -25,10 +29,14 @@ func TestMIMC7Generic(t *testing.T) {
|
|||||||
|
|
||||||
// Generic Hash
|
// Generic Hash
|
||||||
mhg := MIMC7HashGeneric(b1, b2, 91)
|
mhg := MIMC7HashGeneric(b1, b2, 91)
|
||||||
assert.Equal(t, "10594780656576967754230020536574539122676596303354946869887184401991294982664", mhg.String())
|
assert.Equal(t,
|
||||||
|
"10594780656576967754230020536574539122676596303354946869887184401991294982664",
|
||||||
|
mhg.String())
|
||||||
hg, err := HashGeneric(big.NewInt(0), bigArray, 91)
|
hg, err := HashGeneric(big.NewInt(0), bigArray, 91)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "6464402164086696096195815557694604139393321133243036833927490113253119343397", (*big.Int)(hg).String())
|
assert.Equal(t,
|
||||||
|
"6464402164086696096195815557694604139393321133243036833927490113253119343397",
|
||||||
|
(*big.Int)(hg).String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMIMC7(t *testing.T) {
|
func TestMIMC7(t *testing.T) {
|
||||||
@@ -43,7 +51,8 @@ func TestMIMC7(t *testing.T) {
|
|||||||
h1, err := Hash(bigArray1, nil)
|
h1, err := Hash(bigArray1, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// same hash value than the iden3js and circomlib tests:
|
// same hash value than the iden3js and circomlib tests:
|
||||||
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h1).Bytes()), "0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd")
|
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h1).Bytes()),
|
||||||
|
"0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd")
|
||||||
|
|
||||||
// h2a, hash of 2 elements
|
// h2a, hash of 2 elements
|
||||||
bigArray2a := []*big.Int{b78, b41}
|
bigArray2a := []*big.Int{b78, b41}
|
||||||
@@ -51,19 +60,22 @@ func TestMIMC7(t *testing.T) {
|
|||||||
h2a, err := Hash(bigArray2a, nil)
|
h2a, err := Hash(bigArray2a, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// same hash value than the iden3js and circomlib tests:
|
// same hash value than the iden3js and circomlib tests:
|
||||||
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h2a).Bytes()), "0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70")
|
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h2a).Bytes()),
|
||||||
|
"0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70")
|
||||||
|
|
||||||
// h2b, hash of 2 elements
|
// h2b, hash of 2 elements
|
||||||
bigArray2b := []*big.Int{b12, b45}
|
bigArray2b := []*big.Int{b12, b45}
|
||||||
|
|
||||||
mh2b := MIMC7Hash(b12, b45)
|
mh2b := MIMC7Hash(b12, b45)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(mh2b).Bytes()), "0x2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4")
|
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(mh2b).Bytes()),
|
||||||
|
"0x2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4")
|
||||||
|
|
||||||
h2b, err := Hash(bigArray2b, nil)
|
h2b, err := Hash(bigArray2b, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// same hash value than the iden3js and circomlib tests:
|
// same hash value than the iden3js and circomlib tests:
|
||||||
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h2b).Bytes()), "0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879")
|
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h2b).Bytes()),
|
||||||
|
"0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879")
|
||||||
|
|
||||||
// h4, hash of 4 elements
|
// h4, hash of 4 elements
|
||||||
bigArray4 := []*big.Int{b12, b45, b78, b41}
|
bigArray4 := []*big.Int{b12, b45, b78, b41}
|
||||||
@@ -71,11 +83,14 @@ func TestMIMC7(t *testing.T) {
|
|||||||
h4, err := Hash(bigArray4, nil)
|
h4, err := Hash(bigArray4, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// same hash value than the iden3js and circomlib tests:
|
// same hash value than the iden3js and circomlib tests:
|
||||||
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h4).Bytes()), "0x284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb")
|
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h4).Bytes()),
|
||||||
|
"0x284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb")
|
||||||
|
|
||||||
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.")
|
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.") //nolint:lll
|
||||||
hmsg := HashBytes(msg)
|
hmsg := HashBytes(msg)
|
||||||
assert.Equal(t, "16855787120419064316734350414336285711017110414939748784029922801367685456065", hmsg.String())
|
assert.Equal(t,
|
||||||
|
"16855787120419064316734350414336285711017110414939748784029922801367685456065",
|
||||||
|
hmsg.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMIMC7(b *testing.B) {
|
func BenchmarkMIMC7(b *testing.B) {
|
||||||
@@ -86,6 +101,6 @@ func BenchmarkMIMC7(b *testing.B) {
|
|||||||
bigArray4 := []*big.Int{b12, b45, b78, b41}
|
bigArray4 := []*big.Int{b12, b45, b78, b41}
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
Hash(bigArray4, nil) //nolint:errcheck
|
Hash(bigArray4, nil) //nolint:errcheck,gosec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3511
poseidon/constants.go
Normal file
3511
poseidon/constants.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,118 +2,51 @@ package poseidon
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/iden3/go-iden3-crypto/constants"
|
|
||||||
"github.com/iden3/go-iden3-crypto/ff"
|
"github.com/iden3/go-iden3-crypto/ff"
|
||||||
"github.com/iden3/go-iden3-crypto/utils"
|
"github.com/iden3/go-iden3-crypto/utils"
|
||||||
"golang.org/x/crypto/blake2b"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const SEED = "poseidon"
|
const NROUNDSF = 8 //nolint:golint
|
||||||
const NROUNDSF = 8
|
|
||||||
const NROUNDSP = 57
|
|
||||||
const T = 6
|
|
||||||
|
|
||||||
var constC []*ff.Element
|
var NROUNDSP = []int{56, 57, 56, 60, 60, 63, 64, 63} //nolint:golint
|
||||||
var constM [T][T]*ff.Element
|
|
||||||
|
|
||||||
func Zero() *ff.Element {
|
func zero() *ff.Element {
|
||||||
return ff.NewElement()
|
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
|
// ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
|
||||||
func ark(state [T]*ff.Element, c *ff.Element) {
|
func ark(state []*ff.Element, c []*ff.Element, it int) {
|
||||||
for i := 0; i < T; i++ {
|
for i := 0; i < len(state); i++ {
|
||||||
state[i].Add(state[i], c)
|
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
|
// https://eprint.iacr.org/2019/458.pdf page 8
|
||||||
|
func exp5(a *ff.Element) {
|
||||||
func cubic(a *ff.Element) {
|
|
||||||
a.Exp(*a, 5)
|
a.Exp(*a, 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sbox https://eprint.iacr.org/2019/458.pdf page 6
|
// sbox https://eprint.iacr.org/2019/458.pdf page 6
|
||||||
func sbox(state [T]*ff.Element, i int) {
|
func sbox(nRoundsF, nRoundsP int, state []*ff.Element, i int) {
|
||||||
if (i < NROUNDSF/2) || (i >= NROUNDSF/2+NROUNDSP) {
|
if (i < nRoundsF/2) || (i >= nRoundsF/2+nRoundsP) {
|
||||||
for j := 0; j < T; j++ {
|
for j := 0; j < len(state); j++ {
|
||||||
cubic(state[j])
|
exp5(state[j])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cubic(state[0])
|
exp5(state[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// mix returns [[matrix]] * [vector]
|
// mix returns [[matrix]] * [vector]
|
||||||
func mix(state [T]*ff.Element, newState [T]*ff.Element, m [T][T]*ff.Element) {
|
func mix(state []*ff.Element, newState []*ff.Element, m [][]*ff.Element) {
|
||||||
mul := Zero()
|
mul := zero()
|
||||||
for i := 0; i < T; i++ {
|
for i := 0; i < len(state); i++ {
|
||||||
newState[i].SetUint64(0)
|
newState[i].SetUint64(0)
|
||||||
for j := 0; j < T; j++ {
|
for j := 0; j < len(state); j++ {
|
||||||
mul.Mul(m[i][j], state[j])
|
mul.Mul(m[i][j], state[j])
|
||||||
newState[i].Add(newState[i], mul)
|
newState[i].Add(newState[i], mul)
|
||||||
}
|
}
|
||||||
@@ -121,25 +54,32 @@ func mix(state [T]*ff.Element, newState [T]*ff.Element, m [T][T]*ff.Element) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hash computes the Poseidon hash for the given inputs
|
// 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[:]) {
|
if !utils.CheckBigIntArrayInField(inpBI[:]) {
|
||||||
return nil, errors.New("inputs values not inside Finite Field")
|
return nil, errors.New("inputs values not inside Finite Field")
|
||||||
}
|
}
|
||||||
inp := utils.BigIntArrayToElementArray(inpBI[:])
|
inp := utils.BigIntArrayToElementArray(inpBI[:])
|
||||||
state := [T]*ff.Element{}
|
state := make([]*ff.Element, t)
|
||||||
for i := 0; i < T; i++ {
|
state[0] = zero()
|
||||||
state[i] = ff.NewElement().Set(inp[i])
|
copy(state[1:], inp[:])
|
||||||
|
|
||||||
|
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
|
// ARK --> SBox --> M, https://eprint.iacr.org/2019/458.pdf pag.5
|
||||||
var newState [T]*ff.Element
|
for i := 0; i < nRoundsF+nRoundsP; i++ {
|
||||||
for i := 0; i < T; i++ {
|
ark(state, c.c[t-2], i*t)
|
||||||
newState[i] = Zero()
|
sbox(nRoundsF, nRoundsP, state, i)
|
||||||
}
|
mix(state, newState, c.m[t-2])
|
||||||
for i := 0; i < NROUNDSF+NROUNDSP; i++ {
|
|
||||||
ark(state, constC[i])
|
|
||||||
sbox(state, i)
|
|
||||||
mix(state, newState, constM)
|
|
||||||
state, newState = newState, state
|
state, newState = newState, state
|
||||||
}
|
}
|
||||||
rE := state[0]
|
rE := state[0]
|
||||||
@@ -147,32 +87,3 @@ func Hash(inpBI [T]*big.Int) (*big.Int, error) {
|
|||||||
rE.ToBigIntRegular(r)
|
rE.ToBigIntRegular(r)
|
||||||
return r, nil
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,121 +12,86 @@ import (
|
|||||||
|
|
||||||
func TestBlake2bVersion(t *testing.T) {
|
func TestBlake2bVersion(t *testing.T) {
|
||||||
h := blake2b.Sum256([]byte("poseidon_constants"))
|
h := blake2b.Sum256([]byte("poseidon_constants"))
|
||||||
assert.Equal(t, "e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1", hex.EncodeToString(h[:]))
|
assert.Equal(t,
|
||||||
|
"e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1",
|
||||||
|
hex.EncodeToString(h[:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPoseidonHash(t *testing.T) {
|
func TestPoseidonHash(t *testing.T) {
|
||||||
b0 := big.NewInt(0)
|
b0 := big.NewInt(0)
|
||||||
b1 := big.NewInt(1)
|
b1 := big.NewInt(1)
|
||||||
b2 := big.NewInt(2)
|
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.Nil(t, err)
|
||||||
assert.Equal(t, "12242166908188651009877250812424843524687801523336557272219921456462821518061", h.String())
|
assert.Equal(t,
|
||||||
|
"18586133768512220936620570745912940619677854269274689475585506675881198879027",
|
||||||
|
h.String())
|
||||||
|
|
||||||
|
h, err = Hash([]*big.Int{b1, b2})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t,
|
||||||
|
"7853200120776062878684798364095072458815029376092732009249414926327459813530",
|
||||||
|
h.String())
|
||||||
|
|
||||||
|
h, err = Hash([]*big.Int{b1, b2, b0, b0, b0})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t,
|
||||||
|
"1018317224307729531995786483840663576608797660851238720571059489595066344487",
|
||||||
|
h.String())
|
||||||
|
h, err = Hash([]*big.Int{b1, b2, b0, b0, b0, b0})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t,
|
||||||
|
"15336558801450556532856248569924170992202208561737609669134139141992924267169",
|
||||||
|
h.String())
|
||||||
|
|
||||||
b3 := big.NewInt(3)
|
b3 := big.NewInt(3)
|
||||||
b4 := big.NewInt(4)
|
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.Nil(t, err)
|
||||||
assert.Equal(t, "17185195740979599334254027721507328033796809509313949281114643312710535000993", h.String())
|
assert.Equal(t,
|
||||||
}
|
"5811595552068139067952687508729883632420015185677766880877743348592482390548",
|
||||||
|
h.String())
|
||||||
func TestPoseidonHashArbitraryLen(t *testing.T) {
|
h, err = Hash([]*big.Int{b3, b4, b0, b0, b0, b0})
|
||||||
b1 := big.NewInt(1)
|
|
||||||
b2 := big.NewInt(2)
|
|
||||||
h, err := HashSlice([]*big.Int{b1, b2})
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "4932297968297298434239270129193057052722409868268166443802652458940273154855", h.String())
|
assert.Equal(t,
|
||||||
|
"12263118664590987767234828103155242843640892839966517009184493198782366909018",
|
||||||
b3 := big.NewInt(3)
|
h.String())
|
||||||
b4 := big.NewInt(4)
|
|
||||||
h, err = HashSlice([]*big.Int{b3, b4})
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "4635491972858758537477743930622086396911540895966845494943021655521913507504", h.String())
|
|
||||||
|
|
||||||
b5 := big.NewInt(5)
|
b5 := big.NewInt(5)
|
||||||
b6 := big.NewInt(6)
|
b6 := big.NewInt(6)
|
||||||
b7 := big.NewInt(7)
|
h, err = Hash([]*big.Int{b1, b2, b3, b4, b5, b6})
|
||||||
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})
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "15278801138972282646981503374384603641625274360649669926363020545395022098027", h.String())
|
assert.Equal(t,
|
||||||
|
"20400040500897583745843009878988256314335038853985262692600694741116813247201",
|
||||||
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.")
|
h.String())
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPoseidonHashArbitraryLenBrokenChunks(t *testing.T) {
|
func TestErrorInputs(t *testing.T) {
|
||||||
h1, err := HashSlice([]*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(2), big.NewInt(3), big.NewInt(4),
|
b0 := big.NewInt(0)
|
||||||
big.NewInt(5), big.NewInt(6), big.NewInt(7), big.NewInt(8), big.NewInt(9)})
|
b1 := big.NewInt(1)
|
||||||
assert.Nil(t, err)
|
b2 := big.NewInt(2)
|
||||||
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 TestPoseidonHashArbitraryLenBrokenPadding(t *testing.T) {
|
_, err := Hash([]*big.Int{b1, b2, b0, b0, b0, b0})
|
||||||
h1, err := HashSlice([]*big.Int{big.NewInt(int64(1))})
|
|
||||||
assert.Nil(t, err)
|
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) {
|
_, err = Hash([]*big.Int{b1, b2, b0, b0, b0, b0, b0})
|
||||||
b12 := big.NewInt(int64(12))
|
assert.NotNil(t, err)
|
||||||
b45 := big.NewInt(int64(45))
|
assert.Equal(t, "invalid inputs length 7, max 7", err.Error())
|
||||||
b78 := big.NewInt(int64(78))
|
|
||||||
b41 := big.NewInt(int64(41))
|
|
||||||
bigArray4 := []*big.Int{b12, b45, b78, b41}
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
_, err = Hash([]*big.Int{b1, b2, b0, b0, b0, b0, b0, b0})
|
||||||
HashSlice(bigArray4) //nolint:errcheck
|
assert.NotNil(t, err)
|
||||||
}
|
assert.Equal(t, "invalid inputs length 8, max 7", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkPoseidonHash(b *testing.B) {
|
func BenchmarkPoseidonHash(b *testing.B) {
|
||||||
b0 := big.NewInt(0)
|
b0 := big.NewInt(0)
|
||||||
b1 := utils.NewIntFromString("12242166908188651009877250812424843524687801523336557272219921456462821518061")
|
b1 := utils.NewIntFromString("12242166908188651009877250812424843524687801523336557272219921456462821518061") //nolint:lll
|
||||||
b2 := utils.NewIntFromString("12242166908188651009877250812424843524687801523336557272219921456462821518061")
|
b2 := utils.NewIntFromString("12242166908188651009877250812424843524687801523336557272219921456462821518061") //nolint:lll
|
||||||
|
|
||||||
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++ {
|
for i := 0; i < b.N; i++ {
|
||||||
Hash(bigArray4) //nolint:errcheck
|
Hash(bigArray4) //nolint:errcheck,gosec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func HexDecodeInto(dst []byte, h []byte) error {
|
|||||||
h = h[2:]
|
h = h[2:]
|
||||||
}
|
}
|
||||||
if len(h)/2 != len(dst) {
|
if len(h)/2 != len(dst) {
|
||||||
return fmt.Errorf("expected %v bytes in hex string, got %v", len(dst), len(h)/2)
|
return fmt.Errorf("expected %v bytes in hex string, got %v", len(dst), len(h)/2) //nolint:gomnd
|
||||||
}
|
}
|
||||||
n, err := hex.Decode(dst, h)
|
n, err := hex.Decode(dst, h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user