mirror of
https://github.com/arnaucube/go-iden3-crypto.git
synced 2026-02-07 11:36:41 +01:00
Compare commits
25 Commits
decompress
...
feature/go
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
048941e5e0 | ||
|
|
eb41fe0757 | ||
|
|
e10db811aa | ||
|
|
ee467c6215 | ||
|
|
4750e9c83c | ||
|
|
16a8a18a6d | ||
|
|
e8be761ec7 | ||
|
|
2a3f0d9ed5 | ||
|
|
5d88f7c4cd | ||
|
|
b45d8a582b | ||
|
|
83f87bfa46 | ||
|
|
17bad75853 | ||
|
|
97c76ce614 | ||
|
|
937500b203 | ||
|
|
c0c4ff2dd7 | ||
|
|
8d5a7a7ccb | ||
|
|
c754d01ce0 | ||
|
|
fcb586591a | ||
|
|
7c6170453e | ||
|
|
27ec5b26df | ||
|
|
53b9050d0a | ||
|
|
a5b6afcb16 | ||
|
|
4356f44a3d | ||
|
|
5ade04e079 | ||
|
|
eb7d86c5b3 |
@@ -4,5 +4,12 @@ language: go
|
|||||||
go:
|
go:
|
||||||
- "1.12"
|
- "1.12"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- name: "Unit Tests 64 bit arch"
|
||||||
|
env: GOARCH="amd64"
|
||||||
|
- name: "Unit Test 32 bit arch"
|
||||||
|
env: GOARCH="386"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- GO111MODULE=on
|
- GO111MODULE=on
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package babyjub
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/iden3/go-iden3-crypto/constants"
|
||||||
"github.com/iden3/go-iden3-crypto/utils"
|
"github.com/iden3/go-iden3-crypto/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@@ -231,3 +233,74 @@ func TestCompressDecompressRnd(t *testing.T) {
|
|||||||
assert.Equal(t, p1, p2)
|
assert.Equal(t, p1, p2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkBabyjub(b *testing.B) {
|
||||||
|
const n = 256
|
||||||
|
|
||||||
|
rnd := rand.New(rand.NewSource(42))
|
||||||
|
|
||||||
|
var badpoints [n]*Point
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
x := new(big.Int).Rand(rnd, constants.Q)
|
||||||
|
y := new(big.Int).Rand(rnd, constants.Q)
|
||||||
|
badpoints[i] = &Point{X: x, Y: y}
|
||||||
|
}
|
||||||
|
|
||||||
|
var points [n]*Point
|
||||||
|
baseX := utils.NewIntFromString(
|
||||||
|
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
|
||||||
|
baseY := utils.NewIntFromString(
|
||||||
|
"2626589144620713026669568689430873010625803728049924121243784502389097019475")
|
||||||
|
base := &Point{X: baseX, Y: baseY}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
s := new(big.Int).Rand(rnd, constants.Q)
|
||||||
|
points[i] = NewPoint().Mul(s, base)
|
||||||
|
}
|
||||||
|
|
||||||
|
var scalars [n]*big.Int
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
scalars[i] = new(big.Int).Rand(rnd, constants.Q)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Run("AddConst", func(b *testing.B) {
|
||||||
|
p0 := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
|
||||||
|
p1 := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
|
||||||
|
|
||||||
|
p2 := NewPoint()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
p2.Add(p0, p1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("AddRnd", func(b *testing.B) {
|
||||||
|
res := NewPoint()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
res.Add(points[i%(n/2)], points[i%(n/2)+1])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("MulRnd", func(b *testing.B) {
|
||||||
|
res := NewPoint()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
res.Mul(scalars[i%n], points[i%n])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("Compress", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
points[i%n].Compress()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("InCurve", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
badpoints[i%n].InCurve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("InSubGroup", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
points[i%n].InCurve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -222,11 +222,13 @@ func (k *PrivateKey) SignPoseidon(msg *big.Int) *Signature {
|
|||||||
r.Mod(r, SubOrder)
|
r.Mod(r, SubOrder)
|
||||||
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 := []*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)
|
hmInput := [poseidon.T]*big.Int{R8.X, R8.Y, A.X, A.Y, msg, big.NewInt(int64(0))}
|
||||||
|
hm, err := poseidon.PoseidonHash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
S := new(big.Int).Lsh(k.Scalar().BigInt(), 3)
|
S := new(big.Int).Lsh(k.Scalar().BigInt(), 3)
|
||||||
S = S.Mul(hm, S)
|
S = S.Mul(hm, S)
|
||||||
S.Add(r, S)
|
S.Add(r, S)
|
||||||
@@ -238,8 +240,8 @@ 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 (p *PublicKey) VerifyPoseidon(msg *big.Int, sig *Signature) bool {
|
||||||
hmInput := []*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg}
|
hmInput := [poseidon.T]*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg, big.NewInt(int64(0))}
|
||||||
hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
|
hm, err := poseidon.PoseidonHash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,16 @@ func genInputs() (*PrivateKey, *big.Int) {
|
|||||||
return &k, msg
|
return &k, msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPublicKey(t *testing.T) {
|
||||||
|
var k PrivateKey
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
hex.Decode(k[:], []byte{byte(i)})
|
||||||
|
}
|
||||||
|
pk := k.Public()
|
||||||
|
assert.True(t, pk.X.Cmp(constants.Q) == -1)
|
||||||
|
assert.True(t, pk.Y.Cmp(constants.Q) == -1)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSignVerifyMimc7(t *testing.T) {
|
func TestSignVerifyMimc7(t *testing.T) {
|
||||||
var k PrivateKey
|
var k PrivateKey
|
||||||
hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
@@ -131,3 +141,54 @@ func TestCompressDecompress(t *testing.T) {
|
|||||||
assert.Equal(t, true, ok)
|
assert.Equal(t, true, ok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkBabyjubEddsa(b *testing.B) {
|
||||||
|
var k PrivateKey
|
||||||
|
hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
|
pk := k.Public()
|
||||||
|
|
||||||
|
const n = 256
|
||||||
|
|
||||||
|
msgBuf, err := hex.DecodeString("00010203040506070809")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
msg := utils.SetBigIntFromLEBytes(new(big.Int), msgBuf)
|
||||||
|
var msgs [n]*big.Int
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
msgs[i] = new(big.Int).Add(msg, big.NewInt(int64(i)))
|
||||||
|
}
|
||||||
|
var sigs [n]*Signature
|
||||||
|
|
||||||
|
b.Run("SignMimc7", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
k.SignMimc7(msgs[i%n])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
sigs[i%n] = k.SignMimc7(msgs[i%n])
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Run("VerifyMimc7", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
pk.VerifyMimc7(msgs[i%n], sigs[i%n])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("SignPoseidon", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
k.SignPoseidon(msgs[i%n])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
sigs[i%n] = k.SignPoseidon(msgs[i%n])
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Run("VerifyPoseidon", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
pk.VerifyPoseidon(msgs[i%n], sigs[i%n])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/iden3/go-iden3-crypto/utils"
|
"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
|
||||||
@@ -21,6 +24,11 @@ func init() {
|
|||||||
Zero = big.NewInt(0)
|
Zero = big.NewInt(0)
|
||||||
One = big.NewInt(1)
|
One = big.NewInt(1)
|
||||||
MinusOne = big.NewInt(-1)
|
MinusOne = big.NewInt(-1)
|
||||||
Q = utils.NewIntFromString(
|
|
||||||
"21888242871839275222246405745257275088548364400416034343698204186575808495617")
|
qString := "21888242871839275222246405745257275088548364400416034343698204186575808495617"
|
||||||
|
var ok bool
|
||||||
|
Q, ok = new(big.Int).SetString(qString, 10)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("Bad base 10 string %s", qString))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
127
ff/arith.go
Normal file
127
ff/arith.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
// Copyright 2020 ConsenSys AG
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Code generated by goff (v0.2.0) DO NOT EDIT
|
||||||
|
|
||||||
|
// Package ff contains field arithmetic operations
|
||||||
|
package ff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/bits"
|
||||||
|
|
||||||
|
"golang.org/x/sys/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
var supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2
|
||||||
|
|
||||||
|
func madd(a, b, t, u, v uint64) (uint64, uint64, uint64) {
|
||||||
|
var carry uint64
|
||||||
|
hi, lo := bits.Mul64(a, b)
|
||||||
|
v, carry = bits.Add64(lo, v, 0)
|
||||||
|
u, carry = bits.Add64(hi, u, carry)
|
||||||
|
t, _ = bits.Add64(t, 0, carry)
|
||||||
|
return t, u, v
|
||||||
|
}
|
||||||
|
|
||||||
|
// madd0 hi = a*b + c (discards lo bits)
|
||||||
|
func madd0(a, b, c uint64) (hi uint64) {
|
||||||
|
var carry, lo uint64
|
||||||
|
hi, lo = bits.Mul64(a, b)
|
||||||
|
_, carry = bits.Add64(lo, c, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// madd1 hi, lo = a*b + c
|
||||||
|
func madd1(a, b, c uint64) (hi uint64, lo uint64) {
|
||||||
|
var carry uint64
|
||||||
|
hi, lo = bits.Mul64(a, b)
|
||||||
|
lo, carry = bits.Add64(lo, c, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// madd2 hi, lo = a*b + c + d
|
||||||
|
func madd2(a, b, c, d uint64) (hi uint64, lo uint64) {
|
||||||
|
var carry uint64
|
||||||
|
hi, lo = bits.Mul64(a, b)
|
||||||
|
c, carry = bits.Add64(c, d, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
lo, carry = bits.Add64(lo, c, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// madd2s superhi, hi, lo = 2*a*b + c + d + e
|
||||||
|
func madd2s(a, b, c, d, e uint64) (superhi, hi, lo uint64) {
|
||||||
|
var carry, sum uint64
|
||||||
|
|
||||||
|
hi, lo = bits.Mul64(a, b)
|
||||||
|
lo, carry = bits.Add64(lo, lo, 0)
|
||||||
|
hi, superhi = bits.Add64(hi, hi, carry)
|
||||||
|
|
||||||
|
sum, carry = bits.Add64(c, e, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
lo, carry = bits.Add64(lo, sum, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
hi, _ = bits.Add64(hi, 0, d)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func madd1s(a, b, d, e uint64) (superhi, hi, lo uint64) {
|
||||||
|
var carry uint64
|
||||||
|
|
||||||
|
hi, lo = bits.Mul64(a, b)
|
||||||
|
lo, carry = bits.Add64(lo, lo, 0)
|
||||||
|
hi, superhi = bits.Add64(hi, hi, carry)
|
||||||
|
lo, carry = bits.Add64(lo, e, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
hi, _ = bits.Add64(hi, 0, d)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func madd2sb(a, b, c, e uint64) (superhi, hi, lo uint64) {
|
||||||
|
var carry, sum uint64
|
||||||
|
|
||||||
|
hi, lo = bits.Mul64(a, b)
|
||||||
|
lo, carry = bits.Add64(lo, lo, 0)
|
||||||
|
hi, superhi = bits.Add64(hi, hi, carry)
|
||||||
|
|
||||||
|
sum, carry = bits.Add64(c, e, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
lo, carry = bits.Add64(lo, sum, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func madd1sb(a, b, e uint64) (superhi, hi, lo uint64) {
|
||||||
|
var carry uint64
|
||||||
|
|
||||||
|
hi, lo = bits.Mul64(a, b)
|
||||||
|
lo, carry = bits.Add64(lo, lo, 0)
|
||||||
|
hi, superhi = bits.Add64(hi, hi, carry)
|
||||||
|
lo, carry = bits.Add64(lo, e, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) {
|
||||||
|
var carry uint64
|
||||||
|
hi, lo = bits.Mul64(a, b)
|
||||||
|
c, carry = bits.Add64(c, d, 0)
|
||||||
|
hi, _ = bits.Add64(hi, 0, carry)
|
||||||
|
lo, carry = bits.Add64(lo, c, 0)
|
||||||
|
hi, _ = bits.Add64(hi, e, carry)
|
||||||
|
return
|
||||||
|
}
|
||||||
754
ff/element.go
Normal file
754
ff/element.go
Normal file
@@ -0,0 +1,754 @@
|
|||||||
|
// Copyright 2020 ConsenSys AG
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Code generated by goff (v0.2.0) DO NOT EDIT
|
||||||
|
|
||||||
|
// Package ff contains field arithmetic operations
|
||||||
|
package ff
|
||||||
|
|
||||||
|
// /!\ WARNING /!\
|
||||||
|
// this code has not been audited and is provided as-is. In particular,
|
||||||
|
// there is no security guarantees such as constant time implementation
|
||||||
|
// or side-channel attack resistance
|
||||||
|
// /!\ WARNING /!\
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"math/big"
|
||||||
|
"math/bits"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Element represents a field element stored on 4 words (uint64)
|
||||||
|
// Element are assumed to be in Montgomery form in all methods
|
||||||
|
// field modulus q =
|
||||||
|
//
|
||||||
|
// 21888242871839275222246405745257275088548364400416034343698204186575808495617
|
||||||
|
type Element [4]uint64
|
||||||
|
|
||||||
|
// ElementLimbs number of 64 bits words needed to represent Element
|
||||||
|
const ElementLimbs = 4
|
||||||
|
|
||||||
|
// ElementBits number bits needed to represent Element
|
||||||
|
const ElementBits = 254
|
||||||
|
|
||||||
|
// SetUint64 z = v, sets z LSB to v (non-Montgomery form) and convert z to Montgomery form
|
||||||
|
func (z *Element) SetUint64(v uint64) *Element {
|
||||||
|
z[0] = v
|
||||||
|
z[1] = 0
|
||||||
|
z[2] = 0
|
||||||
|
z[3] = 0
|
||||||
|
return z.ToMont()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set z = x
|
||||||
|
func (z *Element) Set(x *Element) *Element {
|
||||||
|
z[0] = x[0]
|
||||||
|
z[1] = x[1]
|
||||||
|
z[2] = x[2]
|
||||||
|
z[3] = x[3]
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetZero z = 0
|
||||||
|
func (z *Element) SetZero() *Element {
|
||||||
|
z[0] = 0
|
||||||
|
z[1] = 0
|
||||||
|
z[2] = 0
|
||||||
|
z[3] = 0
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOne z = 1 (in Montgomery form)
|
||||||
|
func (z *Element) SetOne() *Element {
|
||||||
|
z[0] = 12436184717236109307
|
||||||
|
z[1] = 3962172157175319849
|
||||||
|
z[2] = 7381016538464732718
|
||||||
|
z[3] = 1011752739694698287
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neg z = q - x
|
||||||
|
func (z *Element) Neg(x *Element) *Element {
|
||||||
|
if x.IsZero() {
|
||||||
|
return z.SetZero()
|
||||||
|
}
|
||||||
|
var borrow uint64
|
||||||
|
z[0], borrow = bits.Sub64(4891460686036598785, x[0], 0)
|
||||||
|
z[1], borrow = bits.Sub64(2896914383306846353, x[1], borrow)
|
||||||
|
z[2], borrow = bits.Sub64(13281191951274694749, x[2], borrow)
|
||||||
|
z[3], _ = bits.Sub64(3486998266802970665, x[3], borrow)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// Div z = x*y^-1 mod q
|
||||||
|
func (z *Element) Div(x, y *Element) *Element {
|
||||||
|
var yInv Element
|
||||||
|
yInv.Inverse(y)
|
||||||
|
z.Mul(x, &yInv)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal returns z == x
|
||||||
|
func (z *Element) Equal(x *Element) bool {
|
||||||
|
return (z[3] == x[3]) && (z[2] == x[2]) && (z[1] == x[1]) && (z[0] == x[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns z == 0
|
||||||
|
func (z *Element) IsZero() bool {
|
||||||
|
return (z[3] | z[2] | z[1] | z[0]) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// field modulus stored as big.Int
|
||||||
|
var _elementModulusBigInt big.Int
|
||||||
|
var onceelementModulus sync.Once
|
||||||
|
|
||||||
|
func elementModulusBigInt() *big.Int {
|
||||||
|
onceelementModulus.Do(func() {
|
||||||
|
_elementModulusBigInt.SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
|
||||||
|
})
|
||||||
|
return &_elementModulusBigInt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inverse z = x^-1 mod q
|
||||||
|
// Algorithm 16 in "Efficient Software-Implementation of Finite Fields with Applications to Cryptography"
|
||||||
|
// if x == 0, sets and returns z = x
|
||||||
|
func (z *Element) Inverse(x *Element) *Element {
|
||||||
|
if x.IsZero() {
|
||||||
|
return z.Set(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize u = q
|
||||||
|
var u = Element{
|
||||||
|
4891460686036598785,
|
||||||
|
2896914383306846353,
|
||||||
|
13281191951274694749,
|
||||||
|
3486998266802970665,
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize s = r^2
|
||||||
|
var s = Element{
|
||||||
|
1997599621687373223,
|
||||||
|
6052339484930628067,
|
||||||
|
10108755138030829701,
|
||||||
|
150537098327114917,
|
||||||
|
}
|
||||||
|
|
||||||
|
// r = 0
|
||||||
|
r := Element{}
|
||||||
|
|
||||||
|
v := *x
|
||||||
|
|
||||||
|
var carry, borrow, t, t2 uint64
|
||||||
|
var bigger, uIsOne, vIsOne bool
|
||||||
|
|
||||||
|
for !uIsOne && !vIsOne {
|
||||||
|
for v[0]&1 == 0 {
|
||||||
|
|
||||||
|
// v = v >> 1
|
||||||
|
t2 = v[3] << 63
|
||||||
|
v[3] >>= 1
|
||||||
|
t = t2
|
||||||
|
t2 = v[2] << 63
|
||||||
|
v[2] = (v[2] >> 1) | t
|
||||||
|
t = t2
|
||||||
|
t2 = v[1] << 63
|
||||||
|
v[1] = (v[1] >> 1) | t
|
||||||
|
t = t2
|
||||||
|
v[0] = (v[0] >> 1) | t
|
||||||
|
|
||||||
|
if s[0]&1 == 1 {
|
||||||
|
|
||||||
|
// s = s + q
|
||||||
|
s[0], carry = bits.Add64(s[0], 4891460686036598785, 0)
|
||||||
|
s[1], carry = bits.Add64(s[1], 2896914383306846353, carry)
|
||||||
|
s[2], carry = bits.Add64(s[2], 13281191951274694749, carry)
|
||||||
|
s[3], _ = bits.Add64(s[3], 3486998266802970665, carry)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// s = s >> 1
|
||||||
|
t2 = s[3] << 63
|
||||||
|
s[3] >>= 1
|
||||||
|
t = t2
|
||||||
|
t2 = s[2] << 63
|
||||||
|
s[2] = (s[2] >> 1) | t
|
||||||
|
t = t2
|
||||||
|
t2 = s[1] << 63
|
||||||
|
s[1] = (s[1] >> 1) | t
|
||||||
|
t = t2
|
||||||
|
s[0] = (s[0] >> 1) | t
|
||||||
|
|
||||||
|
}
|
||||||
|
for u[0]&1 == 0 {
|
||||||
|
|
||||||
|
// u = u >> 1
|
||||||
|
t2 = u[3] << 63
|
||||||
|
u[3] >>= 1
|
||||||
|
t = t2
|
||||||
|
t2 = u[2] << 63
|
||||||
|
u[2] = (u[2] >> 1) | t
|
||||||
|
t = t2
|
||||||
|
t2 = u[1] << 63
|
||||||
|
u[1] = (u[1] >> 1) | t
|
||||||
|
t = t2
|
||||||
|
u[0] = (u[0] >> 1) | t
|
||||||
|
|
||||||
|
if r[0]&1 == 1 {
|
||||||
|
|
||||||
|
// r = r + q
|
||||||
|
r[0], carry = bits.Add64(r[0], 4891460686036598785, 0)
|
||||||
|
r[1], carry = bits.Add64(r[1], 2896914383306846353, carry)
|
||||||
|
r[2], carry = bits.Add64(r[2], 13281191951274694749, carry)
|
||||||
|
r[3], _ = bits.Add64(r[3], 3486998266802970665, carry)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// r = r >> 1
|
||||||
|
t2 = r[3] << 63
|
||||||
|
r[3] >>= 1
|
||||||
|
t = t2
|
||||||
|
t2 = r[2] << 63
|
||||||
|
r[2] = (r[2] >> 1) | t
|
||||||
|
t = t2
|
||||||
|
t2 = r[1] << 63
|
||||||
|
r[1] = (r[1] >> 1) | t
|
||||||
|
t = t2
|
||||||
|
r[0] = (r[0] >> 1) | t
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// v >= u
|
||||||
|
bigger = !(v[3] < u[3] || (v[3] == u[3] && (v[2] < u[2] || (v[2] == u[2] && (v[1] < u[1] || (v[1] == u[1] && (v[0] < u[0])))))))
|
||||||
|
|
||||||
|
if bigger {
|
||||||
|
|
||||||
|
// v = v - u
|
||||||
|
v[0], borrow = bits.Sub64(v[0], u[0], 0)
|
||||||
|
v[1], borrow = bits.Sub64(v[1], u[1], borrow)
|
||||||
|
v[2], borrow = bits.Sub64(v[2], u[2], borrow)
|
||||||
|
v[3], _ = bits.Sub64(v[3], u[3], borrow)
|
||||||
|
|
||||||
|
// r >= s
|
||||||
|
bigger = !(r[3] < s[3] || (r[3] == s[3] && (r[2] < s[2] || (r[2] == s[2] && (r[1] < s[1] || (r[1] == s[1] && (r[0] < s[0])))))))
|
||||||
|
|
||||||
|
if bigger {
|
||||||
|
|
||||||
|
// s = s + q
|
||||||
|
s[0], carry = bits.Add64(s[0], 4891460686036598785, 0)
|
||||||
|
s[1], carry = bits.Add64(s[1], 2896914383306846353, carry)
|
||||||
|
s[2], carry = bits.Add64(s[2], 13281191951274694749, carry)
|
||||||
|
s[3], _ = bits.Add64(s[3], 3486998266802970665, carry)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// s = s - r
|
||||||
|
s[0], borrow = bits.Sub64(s[0], r[0], 0)
|
||||||
|
s[1], borrow = bits.Sub64(s[1], r[1], borrow)
|
||||||
|
s[2], borrow = bits.Sub64(s[2], r[2], borrow)
|
||||||
|
s[3], _ = bits.Sub64(s[3], r[3], borrow)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// u = u - v
|
||||||
|
u[0], borrow = bits.Sub64(u[0], v[0], 0)
|
||||||
|
u[1], borrow = bits.Sub64(u[1], v[1], borrow)
|
||||||
|
u[2], borrow = bits.Sub64(u[2], v[2], borrow)
|
||||||
|
u[3], _ = bits.Sub64(u[3], v[3], borrow)
|
||||||
|
|
||||||
|
// s >= r
|
||||||
|
bigger = !(s[3] < r[3] || (s[3] == r[3] && (s[2] < r[2] || (s[2] == r[2] && (s[1] < r[1] || (s[1] == r[1] && (s[0] < r[0])))))))
|
||||||
|
|
||||||
|
if bigger {
|
||||||
|
|
||||||
|
// r = r + q
|
||||||
|
r[0], carry = bits.Add64(r[0], 4891460686036598785, 0)
|
||||||
|
r[1], carry = bits.Add64(r[1], 2896914383306846353, carry)
|
||||||
|
r[2], carry = bits.Add64(r[2], 13281191951274694749, carry)
|
||||||
|
r[3], _ = bits.Add64(r[3], 3486998266802970665, carry)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// r = r - s
|
||||||
|
r[0], borrow = bits.Sub64(r[0], s[0], 0)
|
||||||
|
r[1], borrow = bits.Sub64(r[1], s[1], borrow)
|
||||||
|
r[2], borrow = bits.Sub64(r[2], s[2], borrow)
|
||||||
|
r[3], _ = bits.Sub64(r[3], s[3], borrow)
|
||||||
|
|
||||||
|
}
|
||||||
|
uIsOne = (u[0] == 1) && (u[3]|u[2]|u[1]) == 0
|
||||||
|
vIsOne = (v[0] == 1) && (v[3]|v[2]|v[1]) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if uIsOne {
|
||||||
|
z.Set(&r)
|
||||||
|
} else {
|
||||||
|
z.Set(&s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRandom sets z to a random element < q
|
||||||
|
func (z *Element) SetRandom() *Element {
|
||||||
|
bytes := make([]byte, 32)
|
||||||
|
io.ReadFull(rand.Reader, bytes)
|
||||||
|
z[0] = binary.BigEndian.Uint64(bytes[0:8])
|
||||||
|
z[1] = binary.BigEndian.Uint64(bytes[8:16])
|
||||||
|
z[2] = binary.BigEndian.Uint64(bytes[16:24])
|
||||||
|
z[3] = binary.BigEndian.Uint64(bytes[24:32])
|
||||||
|
z[3] %= 3486998266802970665
|
||||||
|
|
||||||
|
// if z > q --> z -= q
|
||||||
|
// note: this is NOT constant time
|
||||||
|
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
|
||||||
|
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
|
||||||
|
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// One returns 1 (in montgommery form)
|
||||||
|
func One() Element {
|
||||||
|
var one Element
|
||||||
|
one.SetOne()
|
||||||
|
return one
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromInterface converts i1 from uint64, int, string, or Element, big.Int into Element
|
||||||
|
// panic if provided type is not supported
|
||||||
|
func FromInterface(i1 interface{}) Element {
|
||||||
|
var val Element
|
||||||
|
|
||||||
|
switch c1 := i1.(type) {
|
||||||
|
case uint64:
|
||||||
|
val.SetUint64(c1)
|
||||||
|
case int:
|
||||||
|
val.SetString(strconv.Itoa(c1))
|
||||||
|
case string:
|
||||||
|
val.SetString(c1)
|
||||||
|
case big.Int:
|
||||||
|
val.SetBigInt(&c1)
|
||||||
|
case Element:
|
||||||
|
val = c1
|
||||||
|
case *Element:
|
||||||
|
val.Set(c1)
|
||||||
|
default:
|
||||||
|
panic("invalid type")
|
||||||
|
}
|
||||||
|
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add z = x + y mod q
|
||||||
|
func (z *Element) Add(x, y *Element) *Element {
|
||||||
|
var carry uint64
|
||||||
|
|
||||||
|
z[0], carry = bits.Add64(x[0], y[0], 0)
|
||||||
|
z[1], carry = bits.Add64(x[1], y[1], carry)
|
||||||
|
z[2], carry = bits.Add64(x[2], y[2], carry)
|
||||||
|
z[3], _ = bits.Add64(x[3], y[3], carry)
|
||||||
|
|
||||||
|
// if z > q --> z -= q
|
||||||
|
// note: this is NOT constant time
|
||||||
|
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
|
||||||
|
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
|
||||||
|
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAssign z = z + x mod q
|
||||||
|
func (z *Element) AddAssign(x *Element) *Element {
|
||||||
|
var carry uint64
|
||||||
|
|
||||||
|
z[0], carry = bits.Add64(z[0], x[0], 0)
|
||||||
|
z[1], carry = bits.Add64(z[1], x[1], carry)
|
||||||
|
z[2], carry = bits.Add64(z[2], x[2], carry)
|
||||||
|
z[3], _ = bits.Add64(z[3], x[3], carry)
|
||||||
|
|
||||||
|
// if z > q --> z -= q
|
||||||
|
// note: this is NOT constant time
|
||||||
|
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
|
||||||
|
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
|
||||||
|
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double z = x + x mod q, aka Lsh 1
|
||||||
|
func (z *Element) Double(x *Element) *Element {
|
||||||
|
var carry uint64
|
||||||
|
|
||||||
|
z[0], carry = bits.Add64(x[0], x[0], 0)
|
||||||
|
z[1], carry = bits.Add64(x[1], x[1], carry)
|
||||||
|
z[2], carry = bits.Add64(x[2], x[2], carry)
|
||||||
|
z[3], _ = bits.Add64(x[3], x[3], carry)
|
||||||
|
|
||||||
|
// if z > q --> z -= q
|
||||||
|
// note: this is NOT constant time
|
||||||
|
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
|
||||||
|
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
|
||||||
|
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub z = x - y mod q
|
||||||
|
func (z *Element) Sub(x, y *Element) *Element {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(x[0], y[0], 0)
|
||||||
|
z[1], b = bits.Sub64(x[1], y[1], b)
|
||||||
|
z[2], b = bits.Sub64(x[2], y[2], b)
|
||||||
|
z[3], b = bits.Sub64(x[3], y[3], b)
|
||||||
|
if b != 0 {
|
||||||
|
var c uint64
|
||||||
|
z[0], c = bits.Add64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], c = bits.Add64(z[1], 2896914383306846353, c)
|
||||||
|
z[2], c = bits.Add64(z[2], 13281191951274694749, c)
|
||||||
|
z[3], _ = bits.Add64(z[3], 3486998266802970665, c)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubAssign z = z - x mod q
|
||||||
|
func (z *Element) SubAssign(x *Element) *Element {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], x[0], 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], x[1], b)
|
||||||
|
z[2], b = bits.Sub64(z[2], x[2], b)
|
||||||
|
z[3], b = bits.Sub64(z[3], x[3], b)
|
||||||
|
if b != 0 {
|
||||||
|
var c uint64
|
||||||
|
z[0], c = bits.Add64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], c = bits.Add64(z[1], 2896914383306846353, c)
|
||||||
|
z[2], c = bits.Add64(z[2], 13281191951274694749, c)
|
||||||
|
z[3], _ = bits.Add64(z[3], 3486998266802970665, c)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exp z = x^exponent mod q
|
||||||
|
// (not optimized)
|
||||||
|
// exponent (non-montgomery form) is ordered from least significant word to most significant word
|
||||||
|
func (z *Element) Exp(x Element, exponent ...uint64) *Element {
|
||||||
|
r := 0
|
||||||
|
msb := 0
|
||||||
|
for i := len(exponent) - 1; i >= 0; i-- {
|
||||||
|
if exponent[i] == 0 {
|
||||||
|
r++
|
||||||
|
} else {
|
||||||
|
msb = (i * 64) + bits.Len64(exponent[i])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exponent = exponent[:len(exponent)-r]
|
||||||
|
if len(exponent) == 0 {
|
||||||
|
return z.SetOne()
|
||||||
|
}
|
||||||
|
|
||||||
|
z.Set(&x)
|
||||||
|
|
||||||
|
l := msb - 2
|
||||||
|
for i := l; i >= 0; i-- {
|
||||||
|
z.Square(z)
|
||||||
|
if exponent[i/64]&(1<<uint(i%64)) != 0 {
|
||||||
|
z.MulAssign(&x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation
|
||||||
|
// sets and returns z = z * 1
|
||||||
|
func (z *Element) FromMont() *Element {
|
||||||
|
|
||||||
|
// the following lines implement z = z * 1
|
||||||
|
// with a modified CIOS montgomery multiplication
|
||||||
|
{
|
||||||
|
// m = z[0]n'[0] mod W
|
||||||
|
m := z[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, z[0])
|
||||||
|
C, z[0] = madd2(m, 2896914383306846353, z[1], C)
|
||||||
|
C, z[1] = madd2(m, 13281191951274694749, z[2], C)
|
||||||
|
C, z[2] = madd2(m, 3486998266802970665, z[3], C)
|
||||||
|
z[3] = C
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// m = z[0]n'[0] mod W
|
||||||
|
m := z[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, z[0])
|
||||||
|
C, z[0] = madd2(m, 2896914383306846353, z[1], C)
|
||||||
|
C, z[1] = madd2(m, 13281191951274694749, z[2], C)
|
||||||
|
C, z[2] = madd2(m, 3486998266802970665, z[3], C)
|
||||||
|
z[3] = C
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// m = z[0]n'[0] mod W
|
||||||
|
m := z[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, z[0])
|
||||||
|
C, z[0] = madd2(m, 2896914383306846353, z[1], C)
|
||||||
|
C, z[1] = madd2(m, 13281191951274694749, z[2], C)
|
||||||
|
C, z[2] = madd2(m, 3486998266802970665, z[3], C)
|
||||||
|
z[3] = C
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// m = z[0]n'[0] mod W
|
||||||
|
m := z[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, z[0])
|
||||||
|
C, z[0] = madd2(m, 2896914383306846353, z[1], C)
|
||||||
|
C, z[1] = madd2(m, 13281191951274694749, z[2], C)
|
||||||
|
C, z[2] = madd2(m, 3486998266802970665, z[3], C)
|
||||||
|
z[3] = C
|
||||||
|
}
|
||||||
|
|
||||||
|
// if z > q --> z -= q
|
||||||
|
// note: this is NOT constant time
|
||||||
|
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
|
||||||
|
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
|
||||||
|
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToMont converts z to Montgomery form
|
||||||
|
// sets and returns z = z * r^2
|
||||||
|
func (z *Element) ToMont() *Element {
|
||||||
|
var rSquare = Element{
|
||||||
|
1997599621687373223,
|
||||||
|
6052339484930628067,
|
||||||
|
10108755138030829701,
|
||||||
|
150537098327114917,
|
||||||
|
}
|
||||||
|
return z.MulAssign(&rSquare)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRegular returns z in regular form (doesn't mutate z)
|
||||||
|
func (z Element) ToRegular() Element {
|
||||||
|
return *z.FromMont()
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string form of an Element in Montgomery form
|
||||||
|
func (z *Element) String() string {
|
||||||
|
var _z big.Int
|
||||||
|
return z.ToBigIntRegular(&_z).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToBigInt returns z as a big.Int in Montgomery form
|
||||||
|
func (z *Element) ToBigInt(res *big.Int) *big.Int {
|
||||||
|
if bits.UintSize == 64 {
|
||||||
|
bits := (*[4]big.Word)(unsafe.Pointer(z))
|
||||||
|
return res.SetBits(bits[:])
|
||||||
|
} else {
|
||||||
|
var bits [8]big.Word
|
||||||
|
for i := 0; i < len(z); i++ {
|
||||||
|
bits[i*2] = big.Word(z[i])
|
||||||
|
bits[i*2+1] = big.Word(z[i] >> 32)
|
||||||
|
}
|
||||||
|
return res.SetBits(bits[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToBigIntRegular returns z as a big.Int in regular form
|
||||||
|
func (z Element) ToBigIntRegular(res *big.Int) *big.Int {
|
||||||
|
z.FromMont()
|
||||||
|
if bits.UintSize == 64 {
|
||||||
|
bits := (*[4]big.Word)(unsafe.Pointer(&z))
|
||||||
|
return res.SetBits(bits[:])
|
||||||
|
} else {
|
||||||
|
var bits [8]big.Word
|
||||||
|
for i := 0; i < len(z); i++ {
|
||||||
|
bits[i*2] = big.Word(z[i])
|
||||||
|
bits[i*2+1] = big.Word(z[i] >> 32)
|
||||||
|
}
|
||||||
|
return res.SetBits(bits[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBigInt sets z to v (regular form) and returns z in Montgomery form
|
||||||
|
func (z *Element) SetBigInt(v *big.Int) *Element {
|
||||||
|
z.SetZero()
|
||||||
|
|
||||||
|
zero := big.NewInt(0)
|
||||||
|
q := elementModulusBigInt()
|
||||||
|
|
||||||
|
// fast path
|
||||||
|
c := v.Cmp(q)
|
||||||
|
if c == 0 {
|
||||||
|
return z
|
||||||
|
} else if c != 1 && v.Cmp(zero) != -1 {
|
||||||
|
// v should
|
||||||
|
vBits := v.Bits()
|
||||||
|
for i := 0; i < len(vBits); i++ {
|
||||||
|
z[i] = uint64(vBits[i])
|
||||||
|
}
|
||||||
|
return z.ToMont()
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy input
|
||||||
|
vv := new(big.Int).Set(v)
|
||||||
|
|
||||||
|
// while v < 0, v+=q
|
||||||
|
for vv.Cmp(zero) == -1 {
|
||||||
|
vv.Add(vv, q)
|
||||||
|
}
|
||||||
|
// while v > q, v-=q
|
||||||
|
for vv.Cmp(q) == 1 {
|
||||||
|
vv.Sub(vv, q)
|
||||||
|
}
|
||||||
|
// if v == q, return 0
|
||||||
|
if vv.Cmp(q) == 0 {
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
// v should
|
||||||
|
vBits := vv.Bits()
|
||||||
|
if bits.UintSize == 64 {
|
||||||
|
for i := 0; i < len(vBits); i++ {
|
||||||
|
z[i] = uint64(vBits[i])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := 0; i < len(vBits); i++ {
|
||||||
|
if i%2 == 0 {
|
||||||
|
z[i/2] = uint64(vBits[i])
|
||||||
|
} else {
|
||||||
|
z[i/2] |= uint64(vBits[i]) << 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return z.ToMont()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetString creates a big.Int with s (in base 10) and calls SetBigInt on z
|
||||||
|
func (z *Element) SetString(s string) *Element {
|
||||||
|
x, ok := new(big.Int).SetString(s, 10)
|
||||||
|
if !ok {
|
||||||
|
panic("Element.SetString failed -> can't parse number in base10 into a big.Int")
|
||||||
|
}
|
||||||
|
return z.SetBigInt(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legendre returns the Legendre symbol of z (either +1, -1, or 0.)
|
||||||
|
func (z *Element) Legendre() int {
|
||||||
|
var l Element
|
||||||
|
// z^((q-1)/2)
|
||||||
|
l.Exp(*z,
|
||||||
|
11669102379873075200,
|
||||||
|
10671829228508198984,
|
||||||
|
15863968012492123182,
|
||||||
|
1743499133401485332,
|
||||||
|
)
|
||||||
|
|
||||||
|
if l.IsZero() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// if l == 1
|
||||||
|
if (l[3] == 1011752739694698287) && (l[2] == 7381016538464732718) && (l[1] == 3962172157175319849) && (l[0] == 12436184717236109307) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sqrt z = √x mod q
|
||||||
|
// if the square root doesn't exist (x is not a square mod q)
|
||||||
|
// Sqrt leaves z unchanged and returns nil
|
||||||
|
func (z *Element) Sqrt(x *Element) *Element {
|
||||||
|
// q ≡ 1 (mod 4)
|
||||||
|
// see modSqrtTonelliShanks in math/big/int.go
|
||||||
|
// using https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf
|
||||||
|
|
||||||
|
var y, b, t, w Element
|
||||||
|
// w = x^((s-1)/2))
|
||||||
|
w.Exp(*x,
|
||||||
|
14829091926808964255,
|
||||||
|
867720185306366531,
|
||||||
|
688207751544974772,
|
||||||
|
6495040407,
|
||||||
|
)
|
||||||
|
|
||||||
|
// y = x^((s+1)/2)) = w * x
|
||||||
|
y.Mul(x, &w)
|
||||||
|
|
||||||
|
// b = x^s = w * w * x = y * x
|
||||||
|
b.Mul(&w, &y)
|
||||||
|
|
||||||
|
// g = nonResidue ^ s
|
||||||
|
var g = Element{
|
||||||
|
7164790868263648668,
|
||||||
|
11685701338293206998,
|
||||||
|
6216421865291908056,
|
||||||
|
1756667274303109607,
|
||||||
|
}
|
||||||
|
r := uint64(28)
|
||||||
|
|
||||||
|
// compute legendre symbol
|
||||||
|
// t = x^((q-1)/2) = r-1 squaring of x^s
|
||||||
|
t = b
|
||||||
|
for i := uint64(0); i < r-1; i++ {
|
||||||
|
t.Square(&t)
|
||||||
|
}
|
||||||
|
if t.IsZero() {
|
||||||
|
return z.SetZero()
|
||||||
|
}
|
||||||
|
if !((t[3] == 1011752739694698287) && (t[2] == 7381016538464732718) && (t[1] == 3962172157175319849) && (t[0] == 12436184717236109307)) {
|
||||||
|
// t != 1, we don't have a square root
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
var m uint64
|
||||||
|
t = b
|
||||||
|
|
||||||
|
// for t != 1
|
||||||
|
for !((t[3] == 1011752739694698287) && (t[2] == 7381016538464732718) && (t[1] == 3962172157175319849) && (t[0] == 12436184717236109307)) {
|
||||||
|
t.Square(&t)
|
||||||
|
m++
|
||||||
|
}
|
||||||
|
|
||||||
|
if m == 0 {
|
||||||
|
return z.Set(&y)
|
||||||
|
}
|
||||||
|
// t = g^(2^(r-m-1)) mod q
|
||||||
|
ge := int(r - m - 1)
|
||||||
|
t = g
|
||||||
|
for ge > 0 {
|
||||||
|
t.Square(&t)
|
||||||
|
ge--
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Square(&t)
|
||||||
|
y.MulAssign(&t)
|
||||||
|
b.MulAssign(&g)
|
||||||
|
r = m
|
||||||
|
}
|
||||||
|
}
|
||||||
170
ff/element_mul.go
Normal file
170
ff/element_mul.go
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
// +build !amd64
|
||||||
|
|
||||||
|
// Copyright 2020 ConsenSys AG
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Code generated by goff (v0.2.0) DO NOT EDIT
|
||||||
|
|
||||||
|
// Package ff contains field arithmetic operations
|
||||||
|
package ff
|
||||||
|
|
||||||
|
// /!\ WARNING /!\
|
||||||
|
// this code has not been audited and is provided as-is. In particular,
|
||||||
|
// there is no security guarantees such as constant time implementation
|
||||||
|
// or side-channel attack resistance
|
||||||
|
// /!\ WARNING /!\
|
||||||
|
|
||||||
|
import "math/bits"
|
||||||
|
|
||||||
|
// Mul z = x * y mod q
|
||||||
|
// see https://hackmd.io/@zkteam/modular_multiplication
|
||||||
|
func (z *Element) Mul(x, y *Element) *Element {
|
||||||
|
|
||||||
|
var t [4]uint64
|
||||||
|
var c [3]uint64
|
||||||
|
{
|
||||||
|
// round 0
|
||||||
|
v := x[0]
|
||||||
|
c[1], c[0] = bits.Mul64(v, y[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd1(v, y[1], c[1])
|
||||||
|
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd1(v, y[2], c[1])
|
||||||
|
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd1(v, y[3], c[1])
|
||||||
|
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 1
|
||||||
|
v := x[1]
|
||||||
|
c[1], c[0] = madd1(v, y[0], t[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd2(v, y[1], c[1], t[1])
|
||||||
|
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, y[2], c[1], t[2])
|
||||||
|
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, y[3], c[1], t[3])
|
||||||
|
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 2
|
||||||
|
v := x[2]
|
||||||
|
c[1], c[0] = madd1(v, y[0], t[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd2(v, y[1], c[1], t[1])
|
||||||
|
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, y[2], c[1], t[2])
|
||||||
|
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, y[3], c[1], t[3])
|
||||||
|
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 3
|
||||||
|
v := x[3]
|
||||||
|
c[1], c[0] = madd1(v, y[0], t[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd2(v, y[1], c[1], t[1])
|
||||||
|
c[2], z[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, y[2], c[1], t[2])
|
||||||
|
c[2], z[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, y[3], c[1], t[3])
|
||||||
|
z[3], z[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// if z > q --> z -= q
|
||||||
|
// note: this is NOT constant time
|
||||||
|
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
|
||||||
|
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
|
||||||
|
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// MulAssign z = z * x mod q
|
||||||
|
// see https://hackmd.io/@zkteam/modular_multiplication
|
||||||
|
func (z *Element) MulAssign(x *Element) *Element {
|
||||||
|
|
||||||
|
var t [4]uint64
|
||||||
|
var c [3]uint64
|
||||||
|
{
|
||||||
|
// round 0
|
||||||
|
v := z[0]
|
||||||
|
c[1], c[0] = bits.Mul64(v, x[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd1(v, x[1], c[1])
|
||||||
|
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd1(v, x[2], c[1])
|
||||||
|
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd1(v, x[3], c[1])
|
||||||
|
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 1
|
||||||
|
v := z[1]
|
||||||
|
c[1], c[0] = madd1(v, x[0], t[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[1], c[1], t[1])
|
||||||
|
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[2], c[1], t[2])
|
||||||
|
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[3], c[1], t[3])
|
||||||
|
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 2
|
||||||
|
v := z[2]
|
||||||
|
c[1], c[0] = madd1(v, x[0], t[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[1], c[1], t[1])
|
||||||
|
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[2], c[1], t[2])
|
||||||
|
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[3], c[1], t[3])
|
||||||
|
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 3
|
||||||
|
v := z[3]
|
||||||
|
c[1], c[0] = madd1(v, x[0], t[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[1], c[1], t[1])
|
||||||
|
c[2], z[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[2], c[1], t[2])
|
||||||
|
c[2], z[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[3], c[1], t[3])
|
||||||
|
z[3], z[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// if z > q --> z -= q
|
||||||
|
// note: this is NOT constant time
|
||||||
|
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
|
||||||
|
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
|
||||||
|
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
}
|
||||||
39
ff/element_mul_amd64.go
Normal file
39
ff/element_mul_amd64.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2020 ConsenSys AG
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Code generated by goff (v0.2.0) DO NOT EDIT
|
||||||
|
|
||||||
|
// Package ff contains field arithmetic operations
|
||||||
|
package ff
|
||||||
|
|
||||||
|
// MulAssignElement z = z * x mod q (constant time)
|
||||||
|
// calling this instead of z.MulAssign(x) is prefered for performance critical path
|
||||||
|
//go:noescape
|
||||||
|
func MulAssignElement(res, y *Element)
|
||||||
|
|
||||||
|
// Mul z = x * y mod q (constant time)
|
||||||
|
// see https://hackmd.io/@zkteam/modular_multiplication
|
||||||
|
func (z *Element) Mul(x, y *Element) *Element {
|
||||||
|
res := *x
|
||||||
|
MulAssignElement(&res, y)
|
||||||
|
z.Set(&res)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// MulAssign z = z * x mod q (constant time)
|
||||||
|
// see https://hackmd.io/@zkteam/modular_multiplication
|
||||||
|
func (z *Element) MulAssign(x *Element) *Element {
|
||||||
|
MulAssignElement(z, x)
|
||||||
|
return z
|
||||||
|
}
|
||||||
695
ff/element_mul_amd64.s
Normal file
695
ff/element_mul_amd64.s
Normal file
@@ -0,0 +1,695 @@
|
|||||||
|
// Code generated by goff (v0.2.0) DO NOT EDIT
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func MulAssignElement(res,y *Element)
|
||||||
|
// montgomery multiplication of res by y
|
||||||
|
// stores the result in res
|
||||||
|
TEXT ·MulAssignElement(SB), NOSPLIT, $0-16
|
||||||
|
|
||||||
|
// dereference our parameters
|
||||||
|
MOVQ res+0(FP), DI
|
||||||
|
MOVQ y+8(FP), R8
|
||||||
|
|
||||||
|
// check if we support adx and mulx
|
||||||
|
CMPB ·supportAdx(SB), $1
|
||||||
|
JNE no_adx
|
||||||
|
|
||||||
|
// the algorithm is described here
|
||||||
|
// https://hackmd.io/@zkteam/modular_multiplication
|
||||||
|
// however, to benefit from the ADCX and ADOX carry chains
|
||||||
|
// we split the inner loops in 2:
|
||||||
|
// for i=0 to N-1
|
||||||
|
// for j=0 to N-1
|
||||||
|
// (A,t[j]) := t[j] + a[j]*b[i] + A
|
||||||
|
// m := t[0]*q'[0] mod W
|
||||||
|
// C,_ := t[0] + m*q[0]
|
||||||
|
// for j=1 to N-1
|
||||||
|
// (C,t[j-1]) := t[j] + m*q[j] + C
|
||||||
|
// t[N-1] = C + A
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// outter loop 0
|
||||||
|
|
||||||
|
// clear up the carry flags
|
||||||
|
XORQ R9 , R9
|
||||||
|
|
||||||
|
// R12 = y[0]
|
||||||
|
MOVQ 0(R8), R12
|
||||||
|
|
||||||
|
// for j=0 to N-1
|
||||||
|
// (A,t[j]) := t[j] + x[j]*y[i] + A
|
||||||
|
|
||||||
|
// DX = res[0]
|
||||||
|
MOVQ 0(DI), DX
|
||||||
|
MULXQ R12, CX , R9
|
||||||
|
|
||||||
|
// DX = res[1]
|
||||||
|
MOVQ 8(DI), DX
|
||||||
|
MOVQ R9, BX
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, BX
|
||||||
|
|
||||||
|
// DX = res[2]
|
||||||
|
MOVQ 16(DI), DX
|
||||||
|
MOVQ R9, BP
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, BP
|
||||||
|
|
||||||
|
// DX = res[3]
|
||||||
|
MOVQ 24(DI), DX
|
||||||
|
MOVQ R9, SI
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, SI
|
||||||
|
|
||||||
|
// add the last carries to R9
|
||||||
|
MOVQ $0, DX
|
||||||
|
ADCXQ DX, R9
|
||||||
|
ADOXQ DX, R9
|
||||||
|
|
||||||
|
// m := t[0]*q'[0] mod W
|
||||||
|
MOVQ $0xc2e1f593efffffff, DX
|
||||||
|
MULXQ CX,R11, DX
|
||||||
|
|
||||||
|
// clear the carry flags
|
||||||
|
XORQ DX, DX
|
||||||
|
|
||||||
|
// C,_ := t[0] + m*q[0]
|
||||||
|
MOVQ $0x43e1f593f0000001, DX
|
||||||
|
MULXQ R11, AX, R10
|
||||||
|
ADCXQ CX ,AX
|
||||||
|
|
||||||
|
// for j=1 to N-1
|
||||||
|
// (C,t[j-1]) := t[j] + m*q[j] + C
|
||||||
|
|
||||||
|
MOVQ $0x2833e84879b97091, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ BX, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, CX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
MOVQ $0xb85045b68181585d, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ BP, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, BX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
MOVQ $0x30644e72e131a029, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ SI, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, BP
|
||||||
|
MOVQ $0, AX
|
||||||
|
ADCXQ AX, DX
|
||||||
|
ADOXQ DX, R9
|
||||||
|
MOVQ R9, SI
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// outter loop 1
|
||||||
|
|
||||||
|
// clear up the carry flags
|
||||||
|
XORQ R9 , R9
|
||||||
|
|
||||||
|
// R12 = y[1]
|
||||||
|
MOVQ 8(R8), R12
|
||||||
|
|
||||||
|
// for j=0 to N-1
|
||||||
|
// (A,t[j]) := t[j] + x[j]*y[i] + A
|
||||||
|
|
||||||
|
// DX = res[0]
|
||||||
|
MOVQ 0(DI), DX
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, CX
|
||||||
|
|
||||||
|
// DX = res[1]
|
||||||
|
MOVQ 8(DI), DX
|
||||||
|
ADCXQ R9, BX
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, BX
|
||||||
|
|
||||||
|
// DX = res[2]
|
||||||
|
MOVQ 16(DI), DX
|
||||||
|
ADCXQ R9, BP
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, BP
|
||||||
|
|
||||||
|
// DX = res[3]
|
||||||
|
MOVQ 24(DI), DX
|
||||||
|
ADCXQ R9, SI
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, SI
|
||||||
|
|
||||||
|
// add the last carries to R9
|
||||||
|
MOVQ $0, DX
|
||||||
|
ADCXQ DX, R9
|
||||||
|
ADOXQ DX, R9
|
||||||
|
|
||||||
|
// m := t[0]*q'[0] mod W
|
||||||
|
MOVQ $0xc2e1f593efffffff, DX
|
||||||
|
MULXQ CX,R11, DX
|
||||||
|
|
||||||
|
// clear the carry flags
|
||||||
|
XORQ DX, DX
|
||||||
|
|
||||||
|
// C,_ := t[0] + m*q[0]
|
||||||
|
MOVQ $0x43e1f593f0000001, DX
|
||||||
|
MULXQ R11, AX, R10
|
||||||
|
ADCXQ CX ,AX
|
||||||
|
|
||||||
|
// for j=1 to N-1
|
||||||
|
// (C,t[j-1]) := t[j] + m*q[j] + C
|
||||||
|
|
||||||
|
MOVQ $0x2833e84879b97091, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ BX, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, CX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
MOVQ $0xb85045b68181585d, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ BP, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, BX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
MOVQ $0x30644e72e131a029, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ SI, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, BP
|
||||||
|
MOVQ $0, AX
|
||||||
|
ADCXQ AX, DX
|
||||||
|
ADOXQ DX, R9
|
||||||
|
MOVQ R9, SI
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// outter loop 2
|
||||||
|
|
||||||
|
// clear up the carry flags
|
||||||
|
XORQ R9 , R9
|
||||||
|
|
||||||
|
// R12 = y[2]
|
||||||
|
MOVQ 16(R8), R12
|
||||||
|
|
||||||
|
// for j=0 to N-1
|
||||||
|
// (A,t[j]) := t[j] + x[j]*y[i] + A
|
||||||
|
|
||||||
|
// DX = res[0]
|
||||||
|
MOVQ 0(DI), DX
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, CX
|
||||||
|
|
||||||
|
// DX = res[1]
|
||||||
|
MOVQ 8(DI), DX
|
||||||
|
ADCXQ R9, BX
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, BX
|
||||||
|
|
||||||
|
// DX = res[2]
|
||||||
|
MOVQ 16(DI), DX
|
||||||
|
ADCXQ R9, BP
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, BP
|
||||||
|
|
||||||
|
// DX = res[3]
|
||||||
|
MOVQ 24(DI), DX
|
||||||
|
ADCXQ R9, SI
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, SI
|
||||||
|
|
||||||
|
// add the last carries to R9
|
||||||
|
MOVQ $0, DX
|
||||||
|
ADCXQ DX, R9
|
||||||
|
ADOXQ DX, R9
|
||||||
|
|
||||||
|
// m := t[0]*q'[0] mod W
|
||||||
|
MOVQ $0xc2e1f593efffffff, DX
|
||||||
|
MULXQ CX,R11, DX
|
||||||
|
|
||||||
|
// clear the carry flags
|
||||||
|
XORQ DX, DX
|
||||||
|
|
||||||
|
// C,_ := t[0] + m*q[0]
|
||||||
|
MOVQ $0x43e1f593f0000001, DX
|
||||||
|
MULXQ R11, AX, R10
|
||||||
|
ADCXQ CX ,AX
|
||||||
|
|
||||||
|
// for j=1 to N-1
|
||||||
|
// (C,t[j-1]) := t[j] + m*q[j] + C
|
||||||
|
|
||||||
|
MOVQ $0x2833e84879b97091, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ BX, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, CX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
MOVQ $0xb85045b68181585d, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ BP, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, BX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
MOVQ $0x30644e72e131a029, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ SI, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, BP
|
||||||
|
MOVQ $0, AX
|
||||||
|
ADCXQ AX, DX
|
||||||
|
ADOXQ DX, R9
|
||||||
|
MOVQ R9, SI
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// outter loop 3
|
||||||
|
|
||||||
|
// clear up the carry flags
|
||||||
|
XORQ R9 , R9
|
||||||
|
|
||||||
|
// R12 = y[3]
|
||||||
|
MOVQ 24(R8), R12
|
||||||
|
|
||||||
|
// for j=0 to N-1
|
||||||
|
// (A,t[j]) := t[j] + x[j]*y[i] + A
|
||||||
|
|
||||||
|
// DX = res[0]
|
||||||
|
MOVQ 0(DI), DX
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, CX
|
||||||
|
|
||||||
|
// DX = res[1]
|
||||||
|
MOVQ 8(DI), DX
|
||||||
|
ADCXQ R9, BX
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, BX
|
||||||
|
|
||||||
|
// DX = res[2]
|
||||||
|
MOVQ 16(DI), DX
|
||||||
|
ADCXQ R9, BP
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, BP
|
||||||
|
|
||||||
|
// DX = res[3]
|
||||||
|
MOVQ 24(DI), DX
|
||||||
|
ADCXQ R9, SI
|
||||||
|
MULXQ R12, AX, R9
|
||||||
|
ADOXQ AX, SI
|
||||||
|
|
||||||
|
// add the last carries to R9
|
||||||
|
MOVQ $0, DX
|
||||||
|
ADCXQ DX, R9
|
||||||
|
ADOXQ DX, R9
|
||||||
|
|
||||||
|
// m := t[0]*q'[0] mod W
|
||||||
|
MOVQ $0xc2e1f593efffffff, DX
|
||||||
|
MULXQ CX,R11, DX
|
||||||
|
|
||||||
|
// clear the carry flags
|
||||||
|
XORQ DX, DX
|
||||||
|
|
||||||
|
// C,_ := t[0] + m*q[0]
|
||||||
|
MOVQ $0x43e1f593f0000001, DX
|
||||||
|
MULXQ R11, AX, R10
|
||||||
|
ADCXQ CX ,AX
|
||||||
|
|
||||||
|
// for j=1 to N-1
|
||||||
|
// (C,t[j-1]) := t[j] + m*q[j] + C
|
||||||
|
|
||||||
|
MOVQ $0x2833e84879b97091, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ BX, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, CX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
MOVQ $0xb85045b68181585d, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ BP, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, BX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
MOVQ $0x30644e72e131a029, DX
|
||||||
|
MULXQ R11, AX, DX
|
||||||
|
ADCXQ SI, R10
|
||||||
|
ADOXQ AX, R10
|
||||||
|
MOVQ R10, BP
|
||||||
|
MOVQ $0, AX
|
||||||
|
ADCXQ AX, DX
|
||||||
|
ADOXQ DX, R9
|
||||||
|
MOVQ R9, SI
|
||||||
|
|
||||||
|
reduce:
|
||||||
|
// reduce, constant time version
|
||||||
|
// first we copy registers storing t in a separate set of registers
|
||||||
|
// as SUBQ modifies the 2nd operand
|
||||||
|
MOVQ CX, DX
|
||||||
|
MOVQ BX, R8
|
||||||
|
MOVQ BP, R9
|
||||||
|
MOVQ SI, R10
|
||||||
|
MOVQ $0x43e1f593f0000001, R11
|
||||||
|
SUBQ R11, DX
|
||||||
|
MOVQ $0x2833e84879b97091, R11
|
||||||
|
SBBQ R11, R8
|
||||||
|
MOVQ $0xb85045b68181585d, R11
|
||||||
|
SBBQ R11, R9
|
||||||
|
MOVQ $0x30644e72e131a029, R11
|
||||||
|
SBBQ R11, R10
|
||||||
|
JCS t_is_smaller // no borrow, we return t
|
||||||
|
|
||||||
|
// borrow is set, we return u
|
||||||
|
MOVQ DX, (DI)
|
||||||
|
MOVQ R8, 8(DI)
|
||||||
|
MOVQ R9, 16(DI)
|
||||||
|
MOVQ R10, 24(DI)
|
||||||
|
RET
|
||||||
|
t_is_smaller:
|
||||||
|
MOVQ CX, 0(DI)
|
||||||
|
MOVQ BX, 8(DI)
|
||||||
|
MOVQ BP, 16(DI)
|
||||||
|
MOVQ SI, 24(DI)
|
||||||
|
RET
|
||||||
|
|
||||||
|
no_adx:
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// outter loop 0
|
||||||
|
|
||||||
|
// (A,t[0]) := t[0] + x[0]*y[0]
|
||||||
|
MOVQ (DI), AX // x[0]
|
||||||
|
MOVQ 0(R8), R12
|
||||||
|
MULQ R12 // x[0] * y[0]
|
||||||
|
MOVQ DX, R9
|
||||||
|
MOVQ AX, CX
|
||||||
|
|
||||||
|
// m := t[0]*q'[0] mod W
|
||||||
|
MOVQ $0xc2e1f593efffffff, R11
|
||||||
|
IMULQ CX , R11
|
||||||
|
|
||||||
|
// C,_ := t[0] + m*q[0]
|
||||||
|
MOVQ $0x43e1f593f0000001, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ CX ,AX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
// for j=1 to N-1
|
||||||
|
// (A,t[j]) := t[j] + x[j]*y[i] + A
|
||||||
|
// (C,t[j-1]) := t[j] + m*q[j] + C
|
||||||
|
MOVQ 8(DI), AX
|
||||||
|
MULQ R12 // x[1] * y[0]
|
||||||
|
MOVQ R9, BX
|
||||||
|
ADDQ AX, BX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0x2833e84879b97091, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ BX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, CX
|
||||||
|
MOVQ DX, R10
|
||||||
|
MOVQ 16(DI), AX
|
||||||
|
MULQ R12 // x[2] * y[0]
|
||||||
|
MOVQ R9, BP
|
||||||
|
ADDQ AX, BP
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0xb85045b68181585d, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ BP, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, BX
|
||||||
|
MOVQ DX, R10
|
||||||
|
MOVQ 24(DI), AX
|
||||||
|
MULQ R12 // x[3] * y[0]
|
||||||
|
MOVQ R9, SI
|
||||||
|
ADDQ AX, SI
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0x30644e72e131a029, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ SI, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, BP
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
ADDQ R10, R9
|
||||||
|
MOVQ R9, SI
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// outter loop 1
|
||||||
|
|
||||||
|
// (A,t[0]) := t[0] + x[0]*y[1]
|
||||||
|
MOVQ (DI), AX // x[0]
|
||||||
|
MOVQ 8(R8), R12
|
||||||
|
MULQ R12 // x[0] * y[1]
|
||||||
|
ADDQ AX, CX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
// m := t[0]*q'[0] mod W
|
||||||
|
MOVQ $0xc2e1f593efffffff, R11
|
||||||
|
IMULQ CX , R11
|
||||||
|
|
||||||
|
// C,_ := t[0] + m*q[0]
|
||||||
|
MOVQ $0x43e1f593f0000001, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ CX ,AX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
// for j=1 to N-1
|
||||||
|
// (A,t[j]) := t[j] + x[j]*y[i] + A
|
||||||
|
// (C,t[j-1]) := t[j] + m*q[j] + C
|
||||||
|
MOVQ 8(DI), AX
|
||||||
|
MULQ R12 // x[1] * y[1]
|
||||||
|
ADDQ R9, BX
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, BX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0x2833e84879b97091, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ BX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, CX
|
||||||
|
MOVQ DX, R10
|
||||||
|
MOVQ 16(DI), AX
|
||||||
|
MULQ R12 // x[2] * y[1]
|
||||||
|
ADDQ R9, BP
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, BP
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0xb85045b68181585d, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ BP, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, BX
|
||||||
|
MOVQ DX, R10
|
||||||
|
MOVQ 24(DI), AX
|
||||||
|
MULQ R12 // x[3] * y[1]
|
||||||
|
ADDQ R9, SI
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, SI
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0x30644e72e131a029, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ SI, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, BP
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
ADDQ R10, R9
|
||||||
|
MOVQ R9, SI
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// outter loop 2
|
||||||
|
|
||||||
|
// (A,t[0]) := t[0] + x[0]*y[2]
|
||||||
|
MOVQ (DI), AX // x[0]
|
||||||
|
MOVQ 16(R8), R12
|
||||||
|
MULQ R12 // x[0] * y[2]
|
||||||
|
ADDQ AX, CX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
// m := t[0]*q'[0] mod W
|
||||||
|
MOVQ $0xc2e1f593efffffff, R11
|
||||||
|
IMULQ CX , R11
|
||||||
|
|
||||||
|
// C,_ := t[0] + m*q[0]
|
||||||
|
MOVQ $0x43e1f593f0000001, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ CX ,AX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
// for j=1 to N-1
|
||||||
|
// (A,t[j]) := t[j] + x[j]*y[i] + A
|
||||||
|
// (C,t[j-1]) := t[j] + m*q[j] + C
|
||||||
|
MOVQ 8(DI), AX
|
||||||
|
MULQ R12 // x[1] * y[2]
|
||||||
|
ADDQ R9, BX
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, BX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0x2833e84879b97091, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ BX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, CX
|
||||||
|
MOVQ DX, R10
|
||||||
|
MOVQ 16(DI), AX
|
||||||
|
MULQ R12 // x[2] * y[2]
|
||||||
|
ADDQ R9, BP
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, BP
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0xb85045b68181585d, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ BP, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, BX
|
||||||
|
MOVQ DX, R10
|
||||||
|
MOVQ 24(DI), AX
|
||||||
|
MULQ R12 // x[3] * y[2]
|
||||||
|
ADDQ R9, SI
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, SI
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0x30644e72e131a029, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ SI, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, BP
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
ADDQ R10, R9
|
||||||
|
MOVQ R9, SI
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// outter loop 3
|
||||||
|
|
||||||
|
// (A,t[0]) := t[0] + x[0]*y[3]
|
||||||
|
MOVQ (DI), AX // x[0]
|
||||||
|
MOVQ 24(R8), R12
|
||||||
|
MULQ R12 // x[0] * y[3]
|
||||||
|
ADDQ AX, CX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
// m := t[0]*q'[0] mod W
|
||||||
|
MOVQ $0xc2e1f593efffffff, R11
|
||||||
|
IMULQ CX , R11
|
||||||
|
|
||||||
|
// C,_ := t[0] + m*q[0]
|
||||||
|
MOVQ $0x43e1f593f0000001, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ CX ,AX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
// for j=1 to N-1
|
||||||
|
// (A,t[j]) := t[j] + x[j]*y[i] + A
|
||||||
|
// (C,t[j-1]) := t[j] + m*q[j] + C
|
||||||
|
MOVQ 8(DI), AX
|
||||||
|
MULQ R12 // x[1] * y[3]
|
||||||
|
ADDQ R9, BX
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, BX
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0x2833e84879b97091, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ BX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, CX
|
||||||
|
MOVQ DX, R10
|
||||||
|
MOVQ 16(DI), AX
|
||||||
|
MULQ R12 // x[2] * y[3]
|
||||||
|
ADDQ R9, BP
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, BP
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0xb85045b68181585d, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ BP, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, BX
|
||||||
|
MOVQ DX, R10
|
||||||
|
MOVQ 24(DI), AX
|
||||||
|
MULQ R12 // x[3] * y[3]
|
||||||
|
ADDQ R9, SI
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, SI
|
||||||
|
ADCQ $0, DX
|
||||||
|
MOVQ DX, R9
|
||||||
|
|
||||||
|
MOVQ $0x30644e72e131a029, AX
|
||||||
|
MULQ R11
|
||||||
|
ADDQ SI, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
ADDQ AX, R10
|
||||||
|
ADCQ $0, DX
|
||||||
|
|
||||||
|
MOVQ R10, BP
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
ADDQ R10, R9
|
||||||
|
MOVQ R9, SI
|
||||||
|
|
||||||
|
JMP reduce
|
||||||
93
ff/element_square.go
Normal file
93
ff/element_square.go
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
// +build !amd64
|
||||||
|
|
||||||
|
// Copyright 2020 ConsenSys AG
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Code generated by goff (v0.2.0) DO NOT EDIT
|
||||||
|
|
||||||
|
// Package ff contains field arithmetic operations
|
||||||
|
package ff
|
||||||
|
|
||||||
|
// /!\ WARNING /!\
|
||||||
|
// this code has not been audited and is provided as-is. In particular,
|
||||||
|
// there is no security guarantees such as constant time implementation
|
||||||
|
// or side-channel attack resistance
|
||||||
|
// /!\ WARNING /!\
|
||||||
|
|
||||||
|
import "math/bits"
|
||||||
|
|
||||||
|
// Square z = x * x mod q
|
||||||
|
// see https://hackmd.io/@zkteam/modular_multiplication
|
||||||
|
func (z *Element) Square(x *Element) *Element {
|
||||||
|
|
||||||
|
var p [4]uint64
|
||||||
|
|
||||||
|
var u, v uint64
|
||||||
|
{
|
||||||
|
// round 0
|
||||||
|
u, p[0] = bits.Mul64(x[0], x[0])
|
||||||
|
m := p[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, p[0])
|
||||||
|
var t uint64
|
||||||
|
t, u, v = madd1sb(x[0], x[1], u)
|
||||||
|
C, p[0] = madd2(m, 2896914383306846353, v, C)
|
||||||
|
t, u, v = madd1s(x[0], x[2], t, u)
|
||||||
|
C, p[1] = madd2(m, 13281191951274694749, v, C)
|
||||||
|
_, u, v = madd1s(x[0], x[3], t, u)
|
||||||
|
p[3], p[2] = madd3(m, 3486998266802970665, v, C, u)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 1
|
||||||
|
m := p[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, p[0])
|
||||||
|
u, v = madd1(x[1], x[1], p[1])
|
||||||
|
C, p[0] = madd2(m, 2896914383306846353, v, C)
|
||||||
|
var t uint64
|
||||||
|
t, u, v = madd2sb(x[1], x[2], p[2], u)
|
||||||
|
C, p[1] = madd2(m, 13281191951274694749, v, C)
|
||||||
|
_, u, v = madd2s(x[1], x[3], p[3], t, u)
|
||||||
|
p[3], p[2] = madd3(m, 3486998266802970665, v, C, u)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 2
|
||||||
|
m := p[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, p[0])
|
||||||
|
C, p[0] = madd2(m, 2896914383306846353, p[1], C)
|
||||||
|
u, v = madd1(x[2], x[2], p[2])
|
||||||
|
C, p[1] = madd2(m, 13281191951274694749, v, C)
|
||||||
|
_, u, v = madd2sb(x[2], x[3], p[3], u)
|
||||||
|
p[3], p[2] = madd3(m, 3486998266802970665, v, C, u)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 3
|
||||||
|
m := p[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, p[0])
|
||||||
|
C, z[0] = madd2(m, 2896914383306846353, p[1], C)
|
||||||
|
C, z[1] = madd2(m, 13281191951274694749, p[2], C)
|
||||||
|
u, v = madd1(x[3], x[3], p[3])
|
||||||
|
z[3], z[2] = madd3(m, 3486998266802970665, v, C, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if z > q --> z -= q
|
||||||
|
// note: this is NOT constant time
|
||||||
|
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
|
||||||
|
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
|
||||||
|
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
|
||||||
|
}
|
||||||
34
ff/element_square_amd64.go
Normal file
34
ff/element_square_amd64.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2020 ConsenSys AG
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Code generated by goff (v0.2.0) DO NOT EDIT
|
||||||
|
|
||||||
|
// Package ff contains field arithmetic operations
|
||||||
|
package ff
|
||||||
|
|
||||||
|
// SquareElement z = x * x mod q
|
||||||
|
// calling this instead of z.Square(x) is prefered for performance critical path
|
||||||
|
// go - noescape
|
||||||
|
// func SquareElement(res,x *Element)
|
||||||
|
|
||||||
|
// Square z = x * x mod q
|
||||||
|
// see https://hackmd.io/@zkteam/modular_multiplication
|
||||||
|
func (z *Element) Square(x *Element) *Element {
|
||||||
|
if z != x {
|
||||||
|
z.Set(x)
|
||||||
|
}
|
||||||
|
MulAssignElement(z, x)
|
||||||
|
// SquareElement(z, x)
|
||||||
|
return z
|
||||||
|
}
|
||||||
474
ff/element_test.go
Normal file
474
ff/element_test.go
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
// Copyright 2020 ConsenSys AG
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Code generated by goff (v0.2.0) DO NOT EDIT
|
||||||
|
|
||||||
|
// Package ff contains field arithmetic operations
|
||||||
|
package ff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"math/big"
|
||||||
|
"math/bits"
|
||||||
|
mrand "math/rand"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestELEMENTCorrectnessAgainstBigInt(t *testing.T) {
|
||||||
|
modulus, _ := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
|
||||||
|
cmpEandB := func(e *Element, b *big.Int, name string) {
|
||||||
|
var _e big.Int
|
||||||
|
if e.FromMont().ToBigInt(&_e).Cmp(b) != 0 {
|
||||||
|
t.Fatal(name, "failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var modulusMinusOne, one big.Int
|
||||||
|
one.SetUint64(1)
|
||||||
|
|
||||||
|
modulusMinusOne.Sub(modulus, &one)
|
||||||
|
|
||||||
|
var n int
|
||||||
|
if testing.Short() {
|
||||||
|
n = 10
|
||||||
|
} else {
|
||||||
|
n = 500
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
|
||||||
|
// sample 2 random big int
|
||||||
|
b1, _ := rand.Int(rand.Reader, modulus)
|
||||||
|
b2, _ := rand.Int(rand.Reader, modulus)
|
||||||
|
rExp := mrand.Uint64()
|
||||||
|
|
||||||
|
// adding edge cases
|
||||||
|
// TODO need more edge cases
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
rExp = 0
|
||||||
|
b1.SetUint64(0)
|
||||||
|
case 1:
|
||||||
|
b2.SetUint64(0)
|
||||||
|
case 2:
|
||||||
|
b1.SetUint64(0)
|
||||||
|
b2.SetUint64(0)
|
||||||
|
case 3:
|
||||||
|
rExp = 0
|
||||||
|
case 4:
|
||||||
|
rExp = 1
|
||||||
|
case 5:
|
||||||
|
rExp = ^uint64(0) // max uint
|
||||||
|
case 6:
|
||||||
|
rExp = 2
|
||||||
|
b1.Set(&modulusMinusOne)
|
||||||
|
case 7:
|
||||||
|
b2.Set(&modulusMinusOne)
|
||||||
|
case 8:
|
||||||
|
b1.Set(&modulusMinusOne)
|
||||||
|
b2.Set(&modulusMinusOne)
|
||||||
|
}
|
||||||
|
|
||||||
|
rbExp := new(big.Int).SetUint64(rExp)
|
||||||
|
|
||||||
|
var bMul, bAdd, bSub, bDiv, bNeg, bLsh, bInv, bExp, bExp2, bSquare big.Int
|
||||||
|
|
||||||
|
// e1 = mont(b1), e2 = mont(b2)
|
||||||
|
var e1, e2, eMul, eAdd, eSub, eDiv, eNeg, eLsh, eInv, eExp, eSquare, eMulAssign, eSubAssign, eAddAssign Element
|
||||||
|
e1.SetBigInt(b1)
|
||||||
|
e2.SetBigInt(b2)
|
||||||
|
|
||||||
|
// (e1*e2).FromMont() === b1*b2 mod q ... etc
|
||||||
|
eSquare.Square(&e1)
|
||||||
|
eMul.Mul(&e1, &e2)
|
||||||
|
eMulAssign.Set(&e1)
|
||||||
|
eMulAssign.MulAssign(&e2)
|
||||||
|
eAdd.Add(&e1, &e2)
|
||||||
|
eAddAssign.Set(&e1)
|
||||||
|
eAddAssign.AddAssign(&e2)
|
||||||
|
eSub.Sub(&e1, &e2)
|
||||||
|
eSubAssign.Set(&e1)
|
||||||
|
eSubAssign.SubAssign(&e2)
|
||||||
|
eDiv.Div(&e1, &e2)
|
||||||
|
eNeg.Neg(&e1)
|
||||||
|
eInv.Inverse(&e1)
|
||||||
|
eExp.Exp(e1, rExp)
|
||||||
|
eLsh.Double(&e1)
|
||||||
|
|
||||||
|
// same operations with big int
|
||||||
|
bAdd.Add(b1, b2).Mod(&bAdd, modulus)
|
||||||
|
bMul.Mul(b1, b2).Mod(&bMul, modulus)
|
||||||
|
bSquare.Mul(b1, b1).Mod(&bSquare, modulus)
|
||||||
|
bSub.Sub(b1, b2).Mod(&bSub, modulus)
|
||||||
|
bDiv.ModInverse(b2, modulus)
|
||||||
|
bDiv.Mul(&bDiv, b1).
|
||||||
|
Mod(&bDiv, modulus)
|
||||||
|
bNeg.Neg(b1).Mod(&bNeg, modulus)
|
||||||
|
|
||||||
|
bInv.ModInverse(b1, modulus)
|
||||||
|
bExp.Exp(b1, rbExp, modulus)
|
||||||
|
bLsh.Lsh(b1, 1).Mod(&bLsh, modulus)
|
||||||
|
|
||||||
|
cmpEandB(&eSquare, &bSquare, "Square")
|
||||||
|
cmpEandB(&eMul, &bMul, "Mul")
|
||||||
|
cmpEandB(&eMulAssign, &bMul, "MulAssign")
|
||||||
|
cmpEandB(&eAdd, &bAdd, "Add")
|
||||||
|
cmpEandB(&eAddAssign, &bAdd, "AddAssign")
|
||||||
|
cmpEandB(&eSub, &bSub, "Sub")
|
||||||
|
cmpEandB(&eSubAssign, &bSub, "SubAssign")
|
||||||
|
cmpEandB(&eDiv, &bDiv, "Div")
|
||||||
|
cmpEandB(&eNeg, &bNeg, "Neg")
|
||||||
|
cmpEandB(&eInv, &bInv, "Inv")
|
||||||
|
cmpEandB(&eExp, &bExp, "Exp")
|
||||||
|
|
||||||
|
cmpEandB(&eLsh, &bLsh, "Lsh")
|
||||||
|
|
||||||
|
// legendre symbol
|
||||||
|
if e1.Legendre() != big.Jacobi(b1, modulus) {
|
||||||
|
t.Fatal("legendre symbol computation failed")
|
||||||
|
}
|
||||||
|
if e2.Legendre() != big.Jacobi(b2, modulus) {
|
||||||
|
t.Fatal("legendre symbol computation failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// these are slow, killing circle ci
|
||||||
|
if n <= 5 {
|
||||||
|
// sqrt
|
||||||
|
var eSqrt, eExp2 Element
|
||||||
|
var bSqrt big.Int
|
||||||
|
bSqrt.ModSqrt(b1, modulus)
|
||||||
|
eSqrt.Sqrt(&e1)
|
||||||
|
cmpEandB(&eSqrt, &bSqrt, "Sqrt")
|
||||||
|
|
||||||
|
bits := b2.Bits()
|
||||||
|
exponent := make([]uint64, len(bits))
|
||||||
|
for k := 0; k < len(bits); k++ {
|
||||||
|
exponent[k] = uint64(bits[k])
|
||||||
|
}
|
||||||
|
eExp2.Exp(e1, exponent...)
|
||||||
|
bExp2.Exp(b1, b2, modulus)
|
||||||
|
cmpEandB(&eExp2, &bExp2, "Exp multi words")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestELEMENTIsRandom(t *testing.T) {
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
var x, y Element
|
||||||
|
x.SetRandom()
|
||||||
|
y.SetRandom()
|
||||||
|
if x.Equal(&y) {
|
||||||
|
t.Fatal("2 random numbers are unlikely to be equal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
// benchmarks
|
||||||
|
// most benchmarks are rudimentary and should sample a large number of random inputs
|
||||||
|
// or be run multiple times to ensure it didn't measure the fastest path of the function
|
||||||
|
|
||||||
|
var benchResElement Element
|
||||||
|
|
||||||
|
func BenchmarkInverseELEMENT(b *testing.B) {
|
||||||
|
var x Element
|
||||||
|
x.SetRandom()
|
||||||
|
benchResElement.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.Inverse(&x)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func BenchmarkExpELEMENT(b *testing.B) {
|
||||||
|
var x Element
|
||||||
|
x.SetRandom()
|
||||||
|
benchResElement.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.Exp(x, mrand.Uint64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDoubleELEMENT(b *testing.B) {
|
||||||
|
benchResElement.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.Double(&benchResElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAddELEMENT(b *testing.B) {
|
||||||
|
var x Element
|
||||||
|
x.SetRandom()
|
||||||
|
benchResElement.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.Add(&x, &benchResElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSubELEMENT(b *testing.B) {
|
||||||
|
var x Element
|
||||||
|
x.SetRandom()
|
||||||
|
benchResElement.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.Sub(&x, &benchResElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNegELEMENT(b *testing.B) {
|
||||||
|
benchResElement.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.Neg(&benchResElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDivELEMENT(b *testing.B) {
|
||||||
|
var x Element
|
||||||
|
x.SetRandom()
|
||||||
|
benchResElement.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.Div(&x, &benchResElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkFromMontELEMENT(b *testing.B) {
|
||||||
|
benchResElement.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.FromMont()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkToMontELEMENT(b *testing.B) {
|
||||||
|
benchResElement.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.ToMont()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func BenchmarkSquareELEMENT(b *testing.B) {
|
||||||
|
benchResElement.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.Square(&benchResElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSqrtELEMENT(b *testing.B) {
|
||||||
|
var a Element
|
||||||
|
a.SetRandom()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.Sqrt(&a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMulAssignELEMENT(b *testing.B) {
|
||||||
|
x := Element{
|
||||||
|
1997599621687373223,
|
||||||
|
6052339484930628067,
|
||||||
|
10108755138030829701,
|
||||||
|
150537098327114917,
|
||||||
|
}
|
||||||
|
benchResElement.SetOne()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchResElement.MulAssign(&x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMulAssignASMELEMENT(b *testing.B) {
|
||||||
|
x := Element{
|
||||||
|
1997599621687373223,
|
||||||
|
6052339484930628067,
|
||||||
|
10108755138030829701,
|
||||||
|
150537098327114917,
|
||||||
|
}
|
||||||
|
benchResElement.SetOne()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
MulAssignElement(&benchResElement, &x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestELEMENTAsm(t *testing.T) {
|
||||||
|
// ensure ASM implementations matches the ones using math/bits
|
||||||
|
modulus, _ := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
|
||||||
|
for i := 0; i < 500; i++ {
|
||||||
|
// sample 2 random big int
|
||||||
|
b1, _ := rand.Int(rand.Reader, modulus)
|
||||||
|
b2, _ := rand.Int(rand.Reader, modulus)
|
||||||
|
|
||||||
|
// e1 = mont(b1), e2 = mont(b2)
|
||||||
|
var e1, e2, eTestMul, eMulAssign, eSquare, eTestSquare Element
|
||||||
|
e1.SetBigInt(b1)
|
||||||
|
e2.SetBigInt(b2)
|
||||||
|
|
||||||
|
eTestMul = e1
|
||||||
|
eTestMul.testMulAssign(&e2)
|
||||||
|
eMulAssign = e1
|
||||||
|
eMulAssign.MulAssign(&e2)
|
||||||
|
|
||||||
|
if !eTestMul.Equal(&eMulAssign) {
|
||||||
|
t.Fatal("inconsisntencies between MulAssign and testMulAssign --> check if MulAssign is calling ASM implementaiton on amd64")
|
||||||
|
}
|
||||||
|
|
||||||
|
// square
|
||||||
|
eSquare.Square(&e1)
|
||||||
|
eTestSquare.testSquare(&e1)
|
||||||
|
|
||||||
|
if !eTestSquare.Equal(&eSquare) {
|
||||||
|
t.Fatal("inconsisntencies between Square and testSquare --> check if Square is calling ASM implementaiton on amd64")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is here for consistency purposes, to ensure MulAssign on AMD64 using asm implementation gives consistent results
|
||||||
|
func (z *Element) testMulAssign(x *Element) *Element {
|
||||||
|
|
||||||
|
var t [4]uint64
|
||||||
|
var c [3]uint64
|
||||||
|
{
|
||||||
|
// round 0
|
||||||
|
v := z[0]
|
||||||
|
c[1], c[0] = bits.Mul64(v, x[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd1(v, x[1], c[1])
|
||||||
|
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd1(v, x[2], c[1])
|
||||||
|
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd1(v, x[3], c[1])
|
||||||
|
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 1
|
||||||
|
v := z[1]
|
||||||
|
c[1], c[0] = madd1(v, x[0], t[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[1], c[1], t[1])
|
||||||
|
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[2], c[1], t[2])
|
||||||
|
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[3], c[1], t[3])
|
||||||
|
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 2
|
||||||
|
v := z[2]
|
||||||
|
c[1], c[0] = madd1(v, x[0], t[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[1], c[1], t[1])
|
||||||
|
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[2], c[1], t[2])
|
||||||
|
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[3], c[1], t[3])
|
||||||
|
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 3
|
||||||
|
v := z[3]
|
||||||
|
c[1], c[0] = madd1(v, x[0], t[0])
|
||||||
|
m := c[0] * 14042775128853446655
|
||||||
|
c[2] = madd0(m, 4891460686036598785, c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[1], c[1], t[1])
|
||||||
|
c[2], z[0] = madd2(m, 2896914383306846353, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[2], c[1], t[2])
|
||||||
|
c[2], z[1] = madd2(m, 13281191951274694749, c[2], c[0])
|
||||||
|
c[1], c[0] = madd2(v, x[3], c[1], t[3])
|
||||||
|
z[3], z[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// if z > q --> z -= q
|
||||||
|
// note: this is NOT constant time
|
||||||
|
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
|
||||||
|
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
|
||||||
|
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is here for consistency purposes, to ensure Square on AMD64 using asm implementation gives consistent results
|
||||||
|
func (z *Element) testSquare(x *Element) *Element {
|
||||||
|
|
||||||
|
var p [4]uint64
|
||||||
|
|
||||||
|
var u, v uint64
|
||||||
|
{
|
||||||
|
// round 0
|
||||||
|
u, p[0] = bits.Mul64(x[0], x[0])
|
||||||
|
m := p[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, p[0])
|
||||||
|
var t uint64
|
||||||
|
t, u, v = madd1sb(x[0], x[1], u)
|
||||||
|
C, p[0] = madd2(m, 2896914383306846353, v, C)
|
||||||
|
t, u, v = madd1s(x[0], x[2], t, u)
|
||||||
|
C, p[1] = madd2(m, 13281191951274694749, v, C)
|
||||||
|
_, u, v = madd1s(x[0], x[3], t, u)
|
||||||
|
p[3], p[2] = madd3(m, 3486998266802970665, v, C, u)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 1
|
||||||
|
m := p[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, p[0])
|
||||||
|
u, v = madd1(x[1], x[1], p[1])
|
||||||
|
C, p[0] = madd2(m, 2896914383306846353, v, C)
|
||||||
|
var t uint64
|
||||||
|
t, u, v = madd2sb(x[1], x[2], p[2], u)
|
||||||
|
C, p[1] = madd2(m, 13281191951274694749, v, C)
|
||||||
|
_, u, v = madd2s(x[1], x[3], p[3], t, u)
|
||||||
|
p[3], p[2] = madd3(m, 3486998266802970665, v, C, u)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 2
|
||||||
|
m := p[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, p[0])
|
||||||
|
C, p[0] = madd2(m, 2896914383306846353, p[1], C)
|
||||||
|
u, v = madd1(x[2], x[2], p[2])
|
||||||
|
C, p[1] = madd2(m, 13281191951274694749, v, C)
|
||||||
|
_, u, v = madd2sb(x[2], x[3], p[3], u)
|
||||||
|
p[3], p[2] = madd3(m, 3486998266802970665, v, C, u)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// round 3
|
||||||
|
m := p[0] * 14042775128853446655
|
||||||
|
C := madd0(m, 4891460686036598785, p[0])
|
||||||
|
C, z[0] = madd2(m, 2896914383306846353, p[1], C)
|
||||||
|
C, z[1] = madd2(m, 13281191951274694749, p[2], C)
|
||||||
|
u, v = madd1(x[3], x[3], p[3])
|
||||||
|
z[3], z[2] = madd3(m, 3486998266802970665, v, C, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if z > q --> z -= q
|
||||||
|
// note: this is NOT constant time
|
||||||
|
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
|
||||||
|
var b uint64
|
||||||
|
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
|
||||||
|
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
|
||||||
|
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
|
||||||
|
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
|
||||||
|
}
|
||||||
|
return z
|
||||||
|
|
||||||
|
}
|
||||||
5
ff/util.go
Normal file
5
ff/util.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package ff
|
||||||
|
|
||||||
|
func NewElement() *Element {
|
||||||
|
return &Element{}
|
||||||
|
}
|
||||||
152
field/field.go
152
field/field.go
@@ -1,152 +0,0 @@
|
|||||||
// code originally taken from https://github.com/arnaucube/go-snark (https://github.com/arnaucube/go-snark/blob/master/fields/fq.go), pasted here to ensure compatibility among future changes
|
|
||||||
|
|
||||||
package field
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/rand"
|
|
||||||
"math/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fq is the Z field over modulus Q
|
|
||||||
type Fq struct {
|
|
||||||
Q *big.Int // Q
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFq generates a new Fq
|
|
||||||
func NewFq(q *big.Int) Fq {
|
|
||||||
return Fq{
|
|
||||||
q,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zero returns a Zero value on the Fq
|
|
||||||
func (fq Fq) Zero() *big.Int {
|
|
||||||
return big.NewInt(int64(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
// One returns a One value on the Fq
|
|
||||||
func (fq Fq) One() *big.Int {
|
|
||||||
return big.NewInt(int64(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add performs an addition on the Fq
|
|
||||||
func (fq Fq) Add(a, b *big.Int) *big.Int {
|
|
||||||
r := new(big.Int).Add(a, b)
|
|
||||||
return new(big.Int).Mod(r, fq.Q)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Double performs a doubling on the Fq
|
|
||||||
func (fq Fq) Double(a *big.Int) *big.Int {
|
|
||||||
r := new(big.Int).Add(a, a)
|
|
||||||
return new(big.Int).Mod(r, fq.Q)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sub performs a subtraction on the Fq
|
|
||||||
func (fq Fq) Sub(a, b *big.Int) *big.Int {
|
|
||||||
r := new(big.Int).Sub(a, b)
|
|
||||||
return new(big.Int).Mod(r, fq.Q)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Neg performs a negation on the Fq
|
|
||||||
func (fq Fq) Neg(a *big.Int) *big.Int {
|
|
||||||
m := new(big.Int).Neg(a)
|
|
||||||
return new(big.Int).Mod(m, fq.Q)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mul performs a multiplication on the Fq
|
|
||||||
func (fq Fq) Mul(a, b *big.Int) *big.Int {
|
|
||||||
m := new(big.Int).Mul(a, b)
|
|
||||||
return new(big.Int).Mod(m, fq.Q)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fq Fq) MulScalar(base, e *big.Int) *big.Int {
|
|
||||||
return fq.Mul(base, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inverse returns the inverse on the Fq
|
|
||||||
func (fq Fq) Inverse(a *big.Int) *big.Int {
|
|
||||||
return new(big.Int).ModInverse(a, fq.Q)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Div performs the division over the finite field
|
|
||||||
func (fq Fq) Div(a, b *big.Int) *big.Int {
|
|
||||||
d := fq.Mul(a, fq.Inverse(b))
|
|
||||||
return new(big.Int).Mod(d, fq.Q)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Square performs a square operation on the Fq
|
|
||||||
func (fq Fq) Square(a *big.Int) *big.Int {
|
|
||||||
m := new(big.Int).Mul(a, a)
|
|
||||||
return new(big.Int).Mod(m, fq.Q)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exp performs the exponential over Fq
|
|
||||||
func (fq Fq) Exp(base *big.Int, e *big.Int) *big.Int {
|
|
||||||
res := fq.One()
|
|
||||||
rem := fq.Copy(e)
|
|
||||||
exp := base
|
|
||||||
|
|
||||||
for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
|
|
||||||
if BigIsOdd(rem) {
|
|
||||||
res = fq.Mul(res, exp)
|
|
||||||
}
|
|
||||||
exp = fq.Square(exp)
|
|
||||||
rem = new(big.Int).Rsh(rem, 1)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fq Fq) Rand() (*big.Int, error) {
|
|
||||||
|
|
||||||
maxbits := fq.Q.BitLen()
|
|
||||||
b := make([]byte, (maxbits/8)-1)
|
|
||||||
_, err := rand.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
r := new(big.Int).SetBytes(b)
|
|
||||||
rq := new(big.Int).Mod(r, fq.Q)
|
|
||||||
|
|
||||||
// r over q, nil
|
|
||||||
return rq, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fq Fq) IsZero(a *big.Int) bool {
|
|
||||||
return bytes.Equal(a.Bytes(), fq.Zero().Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fq Fq) Copy(a *big.Int) *big.Int {
|
|
||||||
return new(big.Int).SetBytes(a.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fq Fq) Affine(a *big.Int) *big.Int {
|
|
||||||
nq := fq.Neg(fq.Q)
|
|
||||||
|
|
||||||
aux := a
|
|
||||||
if aux.Cmp(big.NewInt(int64(0))) == -1 { // negative value
|
|
||||||
if aux.Cmp(nq) != 1 { // aux less or equal nq
|
|
||||||
aux = new(big.Int).Mod(aux, fq.Q)
|
|
||||||
}
|
|
||||||
if aux.Cmp(big.NewInt(int64(0))) == -1 { // negative value
|
|
||||||
aux = new(big.Int).Add(aux, fq.Q)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if aux.Cmp(fq.Q) != -1 { // aux greater or equal nq
|
|
||||||
aux = new(big.Int).Mod(aux, fq.Q)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return aux
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fq Fq) Equal(a, b *big.Int) bool {
|
|
||||||
aAff := fq.Affine(a)
|
|
||||||
bAff := fq.Affine(b)
|
|
||||||
return bytes.Equal(aAff.Bytes(), bAff.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func BigIsOdd(n *big.Int) bool {
|
|
||||||
one := big.NewInt(int64(1))
|
|
||||||
and := new(big.Int).And(n, one)
|
|
||||||
return bytes.Equal(and.Bytes(), big.NewInt(int64(1)).Bytes())
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// code originally taken from https://github.com/arnaucube/go-snark (https://github.com/arnaucube/go-snark/blob/master/fields/fq.go), pasted here to ensure compatibility among future changes
|
|
||||||
|
|
||||||
package field
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func iToBig(a int) *big.Int {
|
|
||||||
return big.NewInt(int64(a))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFq1(t *testing.T) {
|
|
||||||
fq1 := NewFq(iToBig(7))
|
|
||||||
|
|
||||||
res := fq1.Add(iToBig(4), iToBig(4))
|
|
||||||
assert.Equal(t, iToBig(1), fq1.Affine(res))
|
|
||||||
|
|
||||||
res = fq1.Double(iToBig(5))
|
|
||||||
assert.Equal(t, iToBig(3), fq1.Affine(res))
|
|
||||||
|
|
||||||
res = fq1.Sub(iToBig(5), iToBig(7))
|
|
||||||
assert.Equal(t, iToBig(5), fq1.Affine(res))
|
|
||||||
|
|
||||||
res = fq1.Neg(iToBig(5))
|
|
||||||
assert.Equal(t, iToBig(2), fq1.Affine(res))
|
|
||||||
|
|
||||||
res = fq1.Mul(iToBig(5), iToBig(11))
|
|
||||||
assert.Equal(t, iToBig(6), fq1.Affine(res))
|
|
||||||
|
|
||||||
res = fq1.Inverse(iToBig(4))
|
|
||||||
assert.Equal(t, iToBig(2), res)
|
|
||||||
|
|
||||||
res = fq1.Square(iToBig(5))
|
|
||||||
assert.Equal(t, iToBig(4), res)
|
|
||||||
}
|
|
||||||
1
go.mod
1
go.mod
@@ -7,4 +7,5 @@ require (
|
|||||||
github.com/ethereum/go-ethereum v1.8.27
|
github.com/ethereum/go-ethereum v1.8.27
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/stretchr/testify v1.3.0
|
||||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4
|
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
_constants "github.com/iden3/go-iden3-crypto/constants"
|
_constants "github.com/iden3/go-iden3-crypto/constants"
|
||||||
"github.com/iden3/go-iden3-crypto/field"
|
"github.com/iden3/go-iden3-crypto/ff"
|
||||||
"github.com/iden3/go-iden3-crypto/utils"
|
"github.com/iden3/go-iden3-crypto/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,73 +15,72 @@ const SEED = "mimc"
|
|||||||
var constants = generateConstantsData()
|
var constants = generateConstantsData()
|
||||||
|
|
||||||
type constantsData struct {
|
type constantsData struct {
|
||||||
maxFieldVal *big.Int
|
|
||||||
seedHash *big.Int
|
seedHash *big.Int
|
||||||
iv *big.Int
|
iv *big.Int
|
||||||
fqR field.Fq
|
|
||||||
nRounds int
|
nRounds int
|
||||||
cts []*big.Int
|
cts []*ff.Element
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateConstantsData() constantsData {
|
func generateConstantsData() constantsData {
|
||||||
var constants constantsData
|
var constants constantsData
|
||||||
|
|
||||||
fqR := field.NewFq(_constants.Q)
|
|
||||||
constants.fqR = fqR
|
|
||||||
|
|
||||||
// maxFieldVal is the R value of the Finite Field
|
|
||||||
constants.maxFieldVal = constants.fqR.Q
|
|
||||||
|
|
||||||
constants.seedHash = new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
|
constants.seedHash = new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
|
||||||
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED + "_iv")))
|
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED + "_iv")))
|
||||||
constants.iv = new(big.Int).Mod(c, constants.maxFieldVal)
|
constants.iv = new(big.Int).Mod(c, _constants.Q)
|
||||||
|
|
||||||
constants.nRounds = 91
|
constants.nRounds = 91
|
||||||
cts := getConstants(constants.fqR, SEED, constants.nRounds)
|
cts := getConstants(SEED, constants.nRounds)
|
||||||
constants.cts = cts
|
constants.cts = cts
|
||||||
return constants
|
return constants
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConstants(fqR field.Fq, seed string, nRounds int) []*big.Int {
|
func getConstants(seed string, nRounds int) []*ff.Element {
|
||||||
cts := make([]*big.Int, nRounds)
|
cts := make([]*ff.Element, nRounds)
|
||||||
cts[0] = big.NewInt(int64(0))
|
cts[0] = ff.NewElement()
|
||||||
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
|
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
|
||||||
for i := 1; i < nRounds; i++ {
|
for i := 1; i < nRounds; i++ {
|
||||||
c = new(big.Int).SetBytes(crypto.Keccak256(c.Bytes()))
|
c = new(big.Int).SetBytes(crypto.Keccak256(c.Bytes()))
|
||||||
|
|
||||||
n := fqR.Affine(c)
|
n := new(big.Int).Mod(c, _constants.Q)
|
||||||
cts[i] = n
|
cts[i] = ff.NewElement().SetBigInt(n)
|
||||||
}
|
}
|
||||||
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, where it can be specified the Finite Field over R, and the number of rounds
|
||||||
func MIMC7HashGeneric(fqR field.Fq, xIn, k *big.Int, nRounds int) *big.Int {
|
func MIMC7HashGeneric(xInBI, kBI *big.Int, nRounds int) *big.Int {
|
||||||
cts := getConstants(fqR, SEED, nRounds)
|
xIn := ff.NewElement().SetBigInt(xInBI)
|
||||||
var r *big.Int
|
k := ff.NewElement().SetBigInt(kBI)
|
||||||
|
|
||||||
|
cts := getConstants(SEED, nRounds)
|
||||||
|
var r *ff.Element
|
||||||
for i := 0; i < nRounds; i++ {
|
for i := 0; i < nRounds; i++ {
|
||||||
var t *big.Int
|
var t *ff.Element
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
t = fqR.Add(xIn, k)
|
t = ff.NewElement().Add(xIn, k)
|
||||||
} else {
|
} else {
|
||||||
t = fqR.Add(fqR.Add(r, k), cts[i])
|
t = ff.NewElement().Add(ff.NewElement().Add(r, k), cts[i])
|
||||||
}
|
}
|
||||||
t2 := fqR.Square(t)
|
t2 := ff.NewElement().Square(t)
|
||||||
t4 := fqR.Square(t2)
|
t4 := ff.NewElement().Square(t2)
|
||||||
r = fqR.Mul(fqR.Mul(t4, t2), t)
|
r = ff.NewElement().Mul(ff.NewElement().Mul(t4, t2), t)
|
||||||
}
|
}
|
||||||
return fqR.Affine(fqR.Add(r, k))
|
rE := ff.NewElement().Add(r, k)
|
||||||
|
|
||||||
|
res := big.NewInt(0)
|
||||||
|
rE.ToBigIntRegular(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, fqR field.Fq, nRounds int) (*big.Int, error) {
|
func HashGeneric(iv *big.Int, arr []*big.Int, nRounds int) (*big.Int, error) {
|
||||||
if !utils.CheckBigIntArrayInField(arr, constants.fqR.Q) {
|
if !utils.CheckBigIntArrayInField(arr) {
|
||||||
return nil, errors.New("inputs values not inside Finite Field")
|
return nil, errors.New("inputs values not inside Finite Field")
|
||||||
}
|
}
|
||||||
r := iv
|
r := iv
|
||||||
var err error
|
var err error
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
r = MIMC7HashGeneric(fqR, r, arr[i], nRounds)
|
r = MIMC7HashGeneric(r, arr[i], nRounds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
@@ -90,40 +89,48 @@ func HashGeneric(iv *big.Int, arr []*big.Int, fqR field.Fq, nRounds int) (*big.I
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 over R and the number of rounds setted in the `constants` variable
|
||||||
func MIMC7Hash(xIn, k *big.Int) *big.Int {
|
func MIMC7Hash(xInBI, kBI *big.Int) *big.Int {
|
||||||
var r *big.Int
|
xIn := ff.NewElement().SetBigInt(xInBI)
|
||||||
|
k := ff.NewElement().SetBigInt(kBI)
|
||||||
|
|
||||||
|
var r *ff.Element
|
||||||
for i := 0; i < constants.nRounds; i++ {
|
for i := 0; i < constants.nRounds; i++ {
|
||||||
var t *big.Int
|
var t *ff.Element
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
t = constants.fqR.Add(xIn, k)
|
t = ff.NewElement().Add(xIn, k)
|
||||||
} else {
|
} else {
|
||||||
t = constants.fqR.Add(constants.fqR.Add(r, k), constants.cts[i])
|
t = ff.NewElement().Add(ff.NewElement().Add(r, k), constants.cts[i])
|
||||||
}
|
}
|
||||||
t2 := constants.fqR.Square(t)
|
t2 := ff.NewElement().Square(t)
|
||||||
t4 := constants.fqR.Square(t2)
|
t4 := ff.NewElement().Square(t2)
|
||||||
r = constants.fqR.Mul(constants.fqR.Mul(t4, t2), t)
|
r = ff.NewElement().Mul(ff.NewElement().Mul(t4, t2), t)
|
||||||
}
|
}
|
||||||
return constants.fqR.Affine(constants.fqR.Add(r, k))
|
rE := ff.NewElement().Add(r, k)
|
||||||
|
|
||||||
|
res := big.NewInt(0)
|
||||||
|
rE.ToBigIntRegular(res)
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash performs the MIMC7 hash over a *big.Int array
|
// Hash performs the MIMC7 hash over a *big.Int array
|
||||||
func Hash(arr []*big.Int, key *big.Int) (*big.Int, error) {
|
func Hash(arr []*big.Int, key *big.Int) (*big.Int, error) {
|
||||||
if !utils.CheckBigIntArrayInField(arr, constants.fqR.Q) {
|
if !utils.CheckBigIntArrayInField(arr) {
|
||||||
return nil, errors.New("inputs values not inside Finite Field")
|
return nil, errors.New("inputs values not inside Finite Field")
|
||||||
}
|
}
|
||||||
var r *big.Int
|
var r *big.Int
|
||||||
if key == nil {
|
if key == nil {
|
||||||
r = constants.fqR.Zero()
|
r = big.NewInt(0)
|
||||||
} else {
|
} else {
|
||||||
r = key
|
r = key
|
||||||
}
|
}
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
r = constants.fqR.Add(
|
r = new(big.Int).Add(
|
||||||
constants.fqR.Add(
|
new(big.Int).Add(
|
||||||
r,
|
r,
|
||||||
arr[i],
|
arr[i],
|
||||||
),
|
),
|
||||||
MIMC7Hash(arr[i], r))
|
MIMC7Hash(arr[i], r))
|
||||||
|
r = new(big.Int).Mod(r, _constants.Q)
|
||||||
}
|
}
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/iden3/go-iden3-crypto/field"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,16 +21,12 @@ func TestMIMC7Generic(t *testing.T) {
|
|||||||
b2 := big.NewInt(int64(2))
|
b2 := big.NewInt(int64(2))
|
||||||
b3 := big.NewInt(int64(3))
|
b3 := big.NewInt(int64(3))
|
||||||
|
|
||||||
r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
|
|
||||||
assert.True(t, ok)
|
|
||||||
fqR := field.NewFq(r)
|
|
||||||
|
|
||||||
bigArray := []*big.Int{b1, b2, b3}
|
bigArray := []*big.Int{b1, b2, b3}
|
||||||
|
|
||||||
// Generic Hash
|
// Generic Hash
|
||||||
mhg := MIMC7HashGeneric(fqR, b1, b2, 91)
|
mhg := MIMC7HashGeneric(b1, b2, 91)
|
||||||
assert.Equal(t, "10594780656576967754230020536574539122676596303354946869887184401991294982664", mhg.String())
|
assert.Equal(t, "10594780656576967754230020536574539122676596303354946869887184401991294982664", mhg.String())
|
||||||
hg, err := HashGeneric(fqR.Zero(), bigArray, fqR, 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())
|
||||||
}
|
}
|
||||||
@@ -91,9 +86,7 @@ func BenchmarkMIMC7(b *testing.B) {
|
|||||||
b41 := big.NewInt(int64(41))
|
b41 := big.NewInt(int64(41))
|
||||||
bigArray4 := []*big.Int{b12, b45, b78, b41}
|
bigArray4 := []*big.Int{b12, b45, b78, b41}
|
||||||
|
|
||||||
var h4 *big.Int
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
h4, _ = Hash(bigArray4, nil)
|
Hash(bigArray4, nil)
|
||||||
}
|
}
|
||||||
println(h4)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package poseidon
|
package poseidon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
_constants "github.com/iden3/go-iden3-crypto/constants"
|
"github.com/iden3/go-iden3-crypto/constants"
|
||||||
"github.com/iden3/go-iden3-crypto/field"
|
"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"
|
"golang.org/x/crypto/blake2b"
|
||||||
)
|
)
|
||||||
@@ -17,42 +16,28 @@ const NROUNDSF = 8
|
|||||||
const NROUNDSP = 57
|
const NROUNDSP = 57
|
||||||
const T = 6
|
const T = 6
|
||||||
|
|
||||||
var constants = generateConstantsData()
|
var constC []*ff.Element
|
||||||
|
var constM [T][T]*ff.Element
|
||||||
|
|
||||||
type constantsData struct {
|
func Zero() *ff.Element {
|
||||||
fqR field.Fq
|
return ff.NewElement()
|
||||||
c []*big.Int
|
|
||||||
m [][]*big.Int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateConstantsData() constantsData {
|
func modQ(v *big.Int) {
|
||||||
var constants constantsData
|
v.Mod(v, constants.Q)
|
||||||
|
|
||||||
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 {
|
func init() {
|
||||||
res := big.NewInt(0)
|
constC = getPseudoRandom(SEED+"_constants", NROUNDSF+NROUNDSP)
|
||||||
for i := 0; i < len(b); i++ {
|
constM = getMDS()
|
||||||
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 {
|
func getPseudoRandom(seed string, n int) []*ff.Element {
|
||||||
var res []*big.Int
|
res := make([]*ff.Element, n)
|
||||||
hash := blake2b.Sum256([]byte(seed))
|
hash := blake2b.Sum256([]byte(seed))
|
||||||
for len(res) < n {
|
for i := 0; i < n; i++ {
|
||||||
hashBigInt := new(big.Int)
|
hashBigInt := big.NewInt(int64(0))
|
||||||
newN := fqR.Affine(utils.SetBigIntFromLEBytes(hashBigInt, hash[:]))
|
res[i] = ff.NewElement().SetBigInt(utils.SetBigIntFromLEBytes(hashBigInt, hash[:]))
|
||||||
// newN := fqR.Affine(leByteArrayToBigInt(hash[:]))
|
|
||||||
res = append(res, newN)
|
|
||||||
hash = blake2b.Sum256(hash[:])
|
hash = blake2b.Sum256(hash[:])
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
@@ -67,31 +52,30 @@ func nonceToString(n int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://eprint.iacr.org/2019/458.pdf pag.8
|
// https://eprint.iacr.org/2019/458.pdf pag.8
|
||||||
func getMDS(fqR field.Fq) [][]*big.Int {
|
func getMDS() [T][T]*ff.Element {
|
||||||
nonce := 0
|
nonce := 0
|
||||||
cauchyMatrix := getPseudoRandom(fqR, SEED+"_matrix_"+nonceToString(nonce), T*2)
|
cauchyMatrix := getPseudoRandom(SEED+"_matrix_"+nonceToString(nonce), T*2)
|
||||||
for !checkAllDifferent(cauchyMatrix) {
|
for !checkAllDifferent(cauchyMatrix) {
|
||||||
nonce += 1
|
nonce += 1
|
||||||
cauchyMatrix = getPseudoRandom(fqR, SEED+"_matrix_"+nonceToString(nonce), T*2)
|
cauchyMatrix = getPseudoRandom(SEED+"_matrix_"+nonceToString(nonce), T*2)
|
||||||
}
|
}
|
||||||
var m [][]*big.Int
|
var m [T][T]*ff.Element
|
||||||
for i := 0; i < T; i++ {
|
for i := 0; i < T; i++ {
|
||||||
var mi []*big.Int
|
|
||||||
for j := 0; j < T; j++ {
|
for j := 0; j < T; j++ {
|
||||||
mi = append(mi, fqR.Inverse(fqR.Sub(cauchyMatrix[i], cauchyMatrix[T+j])))
|
m[i][j] = ff.NewElement().Sub(cauchyMatrix[i], cauchyMatrix[T+j])
|
||||||
|
m[i][j].Inverse(m[i][j])
|
||||||
}
|
}
|
||||||
m = append(m, mi)
|
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkAllDifferent(v []*big.Int) bool {
|
func checkAllDifferent(v []*ff.Element) bool {
|
||||||
for i := 0; i < len(v); i++ {
|
for i := 0; i < len(v); i++ {
|
||||||
if bytes.Equal(v[i].Bytes(), big.NewInt(int64(0)).Bytes()) {
|
if v[i].Equal(ff.NewElement()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for j := i + 1; j < len(v); j++ {
|
for j := i + 1; j < len(v); j++ {
|
||||||
if bytes.Equal(v[i].Bytes(), v[j].Bytes()) {
|
if v[i].Equal(v[j]) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,89 +84,94 @@ func checkAllDifferent(v []*big.Int) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 []*big.Int, c *big.Int) []*big.Int {
|
func ark(state [T]*ff.Element, c *ff.Element) {
|
||||||
for i := 0; i < len(state); i++ {
|
for i := 0; i < T; i++ {
|
||||||
state[i] = constants.fqR.Add(state[i], c)
|
state[i].Add(state[i], c)
|
||||||
}
|
}
|
||||||
return state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cubic performs x^5 mod p
|
// cubic performs x^5 mod p
|
||||||
// https://eprint.iacr.org/2019/458.pdf page 8
|
// https://eprint.iacr.org/2019/458.pdf page 8
|
||||||
func cubic(a *big.Int) *big.Int {
|
|
||||||
return constants.fqR.Mul(a, constants.fqR.Square(constants.fqR.Square(a)))
|
func cubic(a *ff.Element) {
|
||||||
|
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 []*big.Int, i int) []*big.Int {
|
func sbox(state [T]*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 < T; j++ {
|
||||||
state[j] = cubic(state[j])
|
cubic(state[j])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state[0] = cubic(state[0])
|
cubic(state[0])
|
||||||
}
|
}
|
||||||
return state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mix returns [[matrix]] * [vector]
|
// mix returns [[matrix]] * [vector]
|
||||||
func mix(state []*big.Int, m [][]*big.Int) []*big.Int {
|
func mix(state [T]*ff.Element, newState [T]*ff.Element, m [T][T]*ff.Element) {
|
||||||
var newState []*big.Int
|
mul := Zero()
|
||||||
for i := 0; i < len(state); i++ {
|
for i := 0; i < T; i++ {
|
||||||
newState = append(newState, constants.fqR.Zero())
|
newState[i].SetUint64(0)
|
||||||
for j := 0; j < len(state); j++ {
|
for j := 0; j < T; j++ {
|
||||||
newState[i] = constants.fqR.Add(newState[i], constants.fqR.Mul(m[i][j], state[j]))
|
mul.Mul(m[i][j], state[j])
|
||||||
|
newState[i].Add(newState[i], mul)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newState
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PoseidonHash computes the Poseidon hash for the given inputs
|
// PoseidonHash computes the Poseidon hash for the given inputs
|
||||||
func PoseidonHash(inp []*big.Int) (*big.Int, error) {
|
func PoseidonHash(inpBI [T]*big.Int) (*big.Int, error) {
|
||||||
if len(inp) == 0 || len(inp) > T {
|
if !utils.CheckBigIntArrayInField(inpBI[:]) {
|
||||||
return nil, errors.New("wrong inputs length")
|
|
||||||
}
|
|
||||||
if !utils.CheckBigIntArrayInField(inp, constants.fqR.Q) {
|
|
||||||
return nil, errors.New("inputs values not inside Finite Field")
|
return nil, errors.New("inputs values not inside Finite Field")
|
||||||
}
|
}
|
||||||
state := inp
|
inp := utils.BigIntArrayToElementArray(inpBI[:])
|
||||||
for i := len(inp); i < T; i++ {
|
state := [T]*ff.Element{}
|
||||||
state = append(state, constants.fqR.Zero())
|
for i := 0; i < T; i++ {
|
||||||
|
state[i] = ff.NewElement().Set(inp[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
// ARK --> SBox --> M, https://eprint.iacr.org/2019/458.pdf pag.5
|
// ARK --> SBox --> M, https://eprint.iacr.org/2019/458.pdf pag.5
|
||||||
for i := 0; i < NROUNDSF+NROUNDSP; i++ {
|
var newState [T]*ff.Element
|
||||||
state = ark(state, constants.c[i])
|
for i := 0; i < T; i++ {
|
||||||
state = sbox(state, i)
|
newState[i] = Zero()
|
||||||
state = mix(state, constants.m)
|
|
||||||
}
|
}
|
||||||
return state[0], nil
|
for i := 0; i < NROUNDSF+NROUNDSP; i++ {
|
||||||
|
ark(state, constC[i])
|
||||||
|
sbox(state, i)
|
||||||
|
mix(state, newState, constM)
|
||||||
|
state, newState = newState, state
|
||||||
|
}
|
||||||
|
rE := state[0]
|
||||||
|
r := big.NewInt(0)
|
||||||
|
rE.ToBigIntRegular(r)
|
||||||
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash performs the Poseidon hash over a *big.Int array
|
// Hash performs the Poseidon hash over a ff.Element array
|
||||||
// in chunks of 5 elements
|
// in chunks of 5 elements
|
||||||
func Hash(arr []*big.Int) (*big.Int, error) {
|
func Hash(arr []*big.Int) (*big.Int, error) {
|
||||||
if !utils.CheckBigIntArrayInField(arr, constants.fqR.Q) {
|
r := big.NewInt(int64(1))
|
||||||
return nil, errors.New("inputs values not inside Finite Field")
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
r := constants.fqR.Zero()
|
ph, err := PoseidonHash(toHash)
|
||||||
for i := 0; i < len(arr); i = i + 5 {
|
|
||||||
var fiveElems []*big.Int
|
|
||||||
for j := 0; j < 5; j++ {
|
|
||||||
if i+j < len(arr) {
|
|
||||||
fiveElems = append(fiveElems, arr[i+j])
|
|
||||||
} else {
|
|
||||||
fiveElems = append(fiveElems, big.NewInt(int64(0)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ph, err := PoseidonHash(fiveElems)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r = constants.fqR.Add(
|
modQ(r.Add(r, ph))
|
||||||
r,
|
|
||||||
ph)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r, nil
|
return r, nil
|
||||||
@@ -194,12 +183,13 @@ func HashBytes(b []byte) (*big.Int, error) {
|
|||||||
n := 31
|
n := 31
|
||||||
bElems := make([]*big.Int, 0, len(b)/n+1)
|
bElems := make([]*big.Int, 0, len(b)/n+1)
|
||||||
for i := 0; i < len(b)/n; i++ {
|
for i := 0; i < len(b)/n; i++ {
|
||||||
v := new(big.Int)
|
v := big.NewInt(int64(0))
|
||||||
utils.SetBigIntFromLEBytes(v, b[n*i:n*(i+1)])
|
utils.SetBigIntFromLEBytes(v, b[n*i:n*(i+1)])
|
||||||
bElems = append(bElems, v)
|
bElems = append(bElems, v)
|
||||||
|
|
||||||
}
|
}
|
||||||
if len(b)%n != 0 {
|
if len(b)%n != 0 {
|
||||||
v := new(big.Int)
|
v := big.NewInt(int64(0))
|
||||||
utils.SetBigIntFromLEBytes(v, b[(len(b)/n)*n:])
|
utils.SetBigIntFromLEBytes(v, b[(len(b)/n)*n:])
|
||||||
bElems = append(bElems, v)
|
bElems = append(bElems, v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,17 +16,29 @@ func TestBlake2bVersion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPoseidon(t *testing.T) {
|
func TestPoseidon(t *testing.T) {
|
||||||
b1 := big.NewInt(int64(1))
|
b1 := big.NewInt(1)
|
||||||
b2 := big.NewInt(int64(2))
|
b2 := big.NewInt(2)
|
||||||
h, err := Hash([]*big.Int{b1, b2})
|
h, err := Hash([]*big.Int{b1, b2})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "12242166908188651009877250812424843524687801523336557272219921456462821518061", h.String())
|
assert.Equal(t, "4932297968297298434239270129193057052722409868268166443802652458940273154855", h.String())
|
||||||
|
|
||||||
b3 := big.NewInt(int64(3))
|
b3 := big.NewInt(3)
|
||||||
b4 := big.NewInt(int64(4))
|
b4 := big.NewInt(4)
|
||||||
h, err = Hash([]*big.Int{b3, b4})
|
h, err = Hash([]*big.Int{b3, b4})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "17185195740979599334254027721507328033796809509313949281114643312710535000993", h.String())
|
assert.Equal(t, "4635491972858758537477743930622086396911540895966845494943021655521913507504", h.String())
|
||||||
|
|
||||||
|
b5 := big.NewInt(5)
|
||||||
|
b6 := big.NewInt(6)
|
||||||
|
b7 := big.NewInt(7)
|
||||||
|
b8 := big.NewInt(8)
|
||||||
|
b9 := big.NewInt(9)
|
||||||
|
b10 := big.NewInt(10)
|
||||||
|
b11 := big.NewInt(11)
|
||||||
|
b12 := big.NewInt(12)
|
||||||
|
h, err = Hash([]*big.Int{b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "15278801138972282646981503374384603641625274360649669926363020545395022098027", h.String())
|
||||||
|
|
||||||
msg := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
|
msg := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
|
||||||
n := 31
|
n := 31
|
||||||
@@ -43,7 +55,7 @@ func TestPoseidon(t *testing.T) {
|
|||||||
}
|
}
|
||||||
hmsg, err := Hash(msgElems)
|
hmsg, err := Hash(msgElems)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "11821124228916291136371255062457365369197326845706357273715164664419275913793", hmsg.String())
|
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.")
|
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)
|
msg2Elems := make([]*big.Int, 0, len(msg2)/n+1)
|
||||||
@@ -59,9 +71,52 @@ func TestPoseidon(t *testing.T) {
|
|||||||
}
|
}
|
||||||
hmsg2, err := Hash(msg2Elems)
|
hmsg2, err := Hash(msg2Elems)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "10747013384255785702102976082726575658403084163954725275481577373644732938016", hmsg2.String())
|
assert.Equal(t, "2978613163687734485261639854325792381691890647104372645321246092227111432722", hmsg2.String())
|
||||||
|
|
||||||
hmsg2, err = HashBytes(msg2)
|
hmsg2, err = HashBytes(msg2)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "10747013384255785702102976082726575658403084163954725275481577373644732938016", hmsg2.String())
|
assert.Equal(t, "2978613163687734485261639854325792381691890647104372645321246092227111432722", hmsg2.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPoseidonBrokenChunks(t *testing.T) {
|
||||||
|
h1, err := Hash([]*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(2), big.NewInt(3), big.NewInt(4),
|
||||||
|
big.NewInt(5), big.NewInt(6), big.NewInt(7), big.NewInt(8), big.NewInt(9)})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
h2, err := Hash([]*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 TestPoseidonBrokenPadding(t *testing.T) {
|
||||||
|
h1, err := Hash([]*big.Int{big.NewInt(int64(1))})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
h2, err := Hash([]*big.Int{big.NewInt(int64(1)), big.NewInt(int64(0))})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotEqual(t, h1, h2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPoseidon(b *testing.B) {
|
||||||
|
b12 := big.NewInt(int64(12))
|
||||||
|
b45 := big.NewInt(int64(45))
|
||||||
|
b78 := big.NewInt(int64(78))
|
||||||
|
b41 := big.NewInt(int64(41))
|
||||||
|
bigArray4 := []*big.Int{b12, b45, b78, b41}
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Hash(bigArray4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPoseidonLarge(b *testing.B) {
|
||||||
|
b12 := utils.NewIntFromString("11384336176656855268977457483345535180380036354188103142384839473266348197733")
|
||||||
|
b45 := utils.NewIntFromString("11384336176656855268977457483345535180380036354188103142384839473266348197733")
|
||||||
|
b78 := utils.NewIntFromString("11384336176656855268977457483345535180380036354188103142384839473266348197733")
|
||||||
|
b41 := utils.NewIntFromString("11384336176656855268977457483345535180380036354188103142384839473266348197733")
|
||||||
|
|
||||||
|
bigArray4 := []*big.Int{b12, b45, b78, b41}
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Hash(bigArray4)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/iden3/go-iden3-crypto/constants"
|
||||||
|
"github.com/iden3/go-iden3-crypto/ff"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewIntFromString creates a new big.Int from a decimal integer encoded as a
|
// NewIntFromString creates a new big.Int from a decimal integer encoded as a
|
||||||
@@ -87,20 +90,28 @@ func HexDecodeInto(dst []byte, h []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckBigIntInField checks if given big.Int fits in a Field Q element
|
// CheckBigIntInField checks if given *big.Int fits in a Field Q element
|
||||||
func CheckBigIntInField(a *big.Int, q *big.Int) bool {
|
func CheckBigIntInField(a *big.Int) bool {
|
||||||
if a.Cmp(q) != -1 {
|
if a.Cmp(constants.Q) != -1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckBigIntArrayInField checks if given big.Int fits in a Field Q element
|
// CheckBigIntArrayInField checks if given *big.Int fits in a Field Q element
|
||||||
func CheckBigIntArrayInField(arr []*big.Int, q *big.Int) bool {
|
func CheckBigIntArrayInField(arr []*big.Int) bool {
|
||||||
for _, a := range arr {
|
for _, a := range arr {
|
||||||
if !CheckBigIntInField(a, q) {
|
if !CheckBigIntInField(a) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BigIntArrayToElementArray(bi []*big.Int) []*ff.Element {
|
||||||
|
var o []*ff.Element
|
||||||
|
for i := range bi {
|
||||||
|
o = append(o, ff.NewElement().SetBigInt(bi[i]))
|
||||||
|
}
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user