mirror of
https://github.com/henrydcase/nobs.git
synced 2024-11-26 00:51:22 +00:00
csidh: cosmettic updates
This commit is contained in:
parent
7d891c7eb8
commit
91945fde1f
@ -7,7 +7,7 @@ import (
|
|||||||
// 511-bit number representing prime field element GF(p)
|
// 511-bit number representing prime field element GF(p)
|
||||||
type fp [numWords]uint64
|
type fp [numWords]uint64
|
||||||
|
|
||||||
// Represents projective point on elliptic curve E over fp
|
// Represents projective point on elliptic curve E over GF(p)
|
||||||
type point struct {
|
type point struct {
|
||||||
x fp
|
x fp
|
||||||
z fp
|
z fp
|
||||||
@ -27,17 +27,20 @@ type fpRngGen struct {
|
|||||||
// Defines operations on public key
|
// Defines operations on public key
|
||||||
type PublicKey struct {
|
type PublicKey struct {
|
||||||
fpRngGen
|
fpRngGen
|
||||||
// Montgomery coefficient: represents y^2 = x^3 + Ax^2 + x
|
// Montgomery coefficient A from GF(p) of the elliptic curve
|
||||||
|
// y^2 = x^3 + Ax^2 + x.
|
||||||
a fp
|
a fp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defines operations on private key
|
// Defines operations on private key
|
||||||
type PrivateKey struct {
|
type PrivateKey struct {
|
||||||
fpRngGen
|
fpRngGen
|
||||||
|
// private key is a set of integers randomly
|
||||||
|
// each sampled from a range [-5, 5].
|
||||||
e [PrivateKeySize]int8
|
e [PrivateKeySize]int8
|
||||||
}
|
}
|
||||||
|
|
||||||
// randFp generates random element from Fp
|
// randFp generates random element from Fp.
|
||||||
func (s *fpRngGen) randFp(v *fp, rng io.Reader) {
|
func (s *fpRngGen) randFp(v *fp, rng io.Reader) {
|
||||||
mask := uint64(1<<(pbits%limbBitSize)) - 1
|
mask := uint64(1<<(pbits%limbBitSize)) - 1
|
||||||
for {
|
for {
|
||||||
@ -60,23 +63,31 @@ func (s *fpRngGen) randFp(v *fp, rng io.Reader) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cofactorMultiples(p *point, a *coeff, halfL, halfR int, order *fp) (bool, bool) {
|
// cofactorMul helper implements batch cofactor multiplication as described
|
||||||
|
// in the ia.cr/2018/383 (algo. 3). Returns tuple of two booleans, first indicates
|
||||||
|
// if function has finished successfully. In case first return value is true,
|
||||||
|
// second return value indicates if curve represented by coffactor 'a' is
|
||||||
|
// supersingular.
|
||||||
|
// Implemenation uses divide-and-conquer strategy and recursion in order to
|
||||||
|
// speed up calculation of Q_i = [(p+1)/l_i] * P.
|
||||||
|
// Implementation is not constant time, but it operates on public data only.
|
||||||
|
func cofactorMul(p *point, a *coeff, halfL, halfR int, order *fp) (bool, bool) {
|
||||||
var Q point
|
var Q point
|
||||||
var r1, d1, r2, d2 bool
|
var r1, d1, r2, d2 bool
|
||||||
|
|
||||||
if (halfR - halfL) == 1 {
|
if (halfR - halfL) == 1 {
|
||||||
|
// base case
|
||||||
if !p.z.isZero() {
|
if !p.z.isZero() {
|
||||||
var tmp = fp{primes[halfL]}
|
var tmp = fp{primes[halfL]}
|
||||||
xMul512(p, p, a, &tmp)
|
xMul(p, p, a, &tmp)
|
||||||
|
|
||||||
if !p.z.isZero() {
|
if !p.z.isZero() {
|
||||||
// order does not divide p+1
|
// order does not divide p+1 -> ordinary curve
|
||||||
return false, true
|
return true, false
|
||||||
}
|
}
|
||||||
|
|
||||||
mul512(order, order, primes[halfL])
|
mul512(order, order, primes[halfL])
|
||||||
if sub512(&tmp, &fourSqrtP, order) == 1 {
|
if isLess(&fourSqrtP, order) {
|
||||||
// order > 4*sqrt(p) -> supersingular
|
// order > 4*sqrt(p) -> supersingular curve
|
||||||
return true, true
|
return true, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,21 +97,27 @@ func cofactorMultiples(p *point, a *coeff, halfL, halfR int, order *fp) (bool, b
|
|||||||
// perform another recursive step
|
// perform another recursive step
|
||||||
mid := halfL + ((halfR - halfL + 1) / 2)
|
mid := halfL + ((halfR - halfL + 1) / 2)
|
||||||
var mulL, mulR = fp{1}, fp{1}
|
var mulL, mulR = fp{1}, fp{1}
|
||||||
|
// compute u = primes_1 * ... * primes_m
|
||||||
for i := halfL; i < mid; i++ {
|
for i := halfL; i < mid; i++ {
|
||||||
mul512(&mulR, &mulR, primes[i])
|
mul512(&mulR, &mulR, primes[i])
|
||||||
}
|
}
|
||||||
|
// compute v = primes_m+1 * ... * primes_n
|
||||||
for i := mid; i < halfR; i++ {
|
for i := mid; i < halfR; i++ {
|
||||||
mul512(&mulL, &mulL, primes[i])
|
mul512(&mulL, &mulL, primes[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
xMul512(&Q, p, a, &mulR)
|
// calculate Q_i
|
||||||
xMul512(p, p, a, &mulL)
|
xMul(&Q, p, a, &mulR)
|
||||||
|
xMul(p, p, a, &mulL)
|
||||||
|
|
||||||
r1, d1 = cofactorMultiples(&Q, a, mid, halfR, order)
|
d1, r1 = cofactorMul(&Q, a, mid, halfR, order)
|
||||||
r2, d2 = cofactorMultiples(p, a, halfL, mid, order)
|
d2, r2 = cofactorMul(p, a, halfL, mid, order)
|
||||||
return r1 || r2, d1 || d2
|
return d1 || d2, r1 || r2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// groupAction evaluates group action of prv.e on a Montgomery
|
||||||
|
// curve represented by coefficient pub.A.
|
||||||
|
// This is implementation of algorithm 2 from ia.cr/2018/383.
|
||||||
func groupAction(pub *PublicKey, prv *PrivateKey, rng io.Reader) {
|
func groupAction(pub *PublicKey, prv *PrivateKey, rng io.Reader) {
|
||||||
var k [2]fp
|
var k [2]fp
|
||||||
var e [2][primeCount]uint8
|
var e [2][primeCount]uint8
|
||||||
@ -140,7 +157,7 @@ func groupAction(pub *PublicKey, prv *PrivateKey, rng io.Reader) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
xMul512(&P, &P, &A, &k[sign])
|
xMul(&P, &P, &A, &k[sign])
|
||||||
done[sign] = true
|
done[sign] = true
|
||||||
|
|
||||||
for i, v := range primes {
|
for i, v := range primes {
|
||||||
@ -154,9 +171,9 @@ func groupAction(pub *PublicKey, prv *PrivateKey, rng io.Reader) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xMul512(&K, &P, &A, &cof)
|
xMul(&K, &P, &A, &cof)
|
||||||
if !K.z.isZero() {
|
if !K.z.isZero() {
|
||||||
isom(&P, &A, &K, v)
|
xIso(&P, &A, &K, v)
|
||||||
e[sign][i] = e[sign][i] - 1
|
e[sign][i] = e[sign][i] - 1
|
||||||
if e[sign][i] == 0 {
|
if e[sign][i] == 0 {
|
||||||
mul512(&k[sign], &k[sign], primes[i])
|
mul512(&k[sign], &k[sign], primes[i])
|
||||||
@ -225,7 +242,7 @@ func GeneratePrivateKey(key *PrivateKey, rng io.Reader) error {
|
|||||||
|
|
||||||
// Public key operations
|
// Public key operations
|
||||||
|
|
||||||
// Assumes key is in Montgomery domain
|
// Assumes key is in Montgomery domain.
|
||||||
func (c *PublicKey) Import(key []byte) bool {
|
func (c *PublicKey) Import(key []byte) bool {
|
||||||
if len(key) != numWords*limbByteSize {
|
if len(key) != numWords*limbByteSize {
|
||||||
return false
|
return false
|
||||||
@ -238,7 +255,7 @@ func (c *PublicKey) Import(key []byte) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumes key is exported as encoded in Montgomery domain
|
// Assumes key is exported as encoded in Montgomery domain.
|
||||||
func (c *PublicKey) Export(out []byte) bool {
|
func (c *PublicKey) Export(out []byte) bool {
|
||||||
if len(out) != numWords*limbByteSize {
|
if len(out) != numWords*limbByteSize {
|
||||||
return false
|
return false
|
||||||
@ -251,44 +268,45 @@ func (c *PublicKey) Export(out []byte) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PublicKey) reset() {
|
|
||||||
for i := range c.a {
|
|
||||||
c.a[i] = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GeneratePublicKey(pub *PublicKey, prv *PrivateKey, rng io.Reader) {
|
func GeneratePublicKey(pub *PublicKey, prv *PrivateKey, rng io.Reader) {
|
||||||
pub.reset()
|
for i := range pub.a {
|
||||||
|
pub.a[i] = 0
|
||||||
|
}
|
||||||
groupAction(pub, prv, rng)
|
groupAction(pub, prv, rng)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate does public key validation. It returns true if
|
// Validate returns true if 'pub' is a valid cSIDH public key,
|
||||||
// a 'pub' is a valid cSIDH public key, otherwise false.
|
// otherwise false.
|
||||||
|
// More precisely, the function verifies that curve
|
||||||
|
// y^2 = x^3 + pub.a * x^2 + x
|
||||||
|
// is supersingular.
|
||||||
func Validate(pub *PublicKey, rng io.Reader) bool {
|
func Validate(pub *PublicKey, rng io.Reader) bool {
|
||||||
// Check if in range
|
// Check if in range
|
||||||
if !isLess(&pub.a, &p) {
|
if !isLess(&pub.a, &p) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// j-invariant for montgomery curves is something like
|
// Check if pub represents a smooth Montgomery curve.
|
||||||
// j = (256*(A^3-3)^3)/(A^2 - 4), so any |A| = 2 is invalid
|
|
||||||
if pub.a.equal(&two) || pub.a.equal(&twoNeg) {
|
if pub.a.equal(&two) || pub.a.equal(&twoNeg) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// P must have big enough order to prove supersingularity. The
|
// Check if pub represents a supersingular curve.
|
||||||
// probability that this loop will be repeated is negligible.
|
|
||||||
for {
|
for {
|
||||||
var P point
|
var P point
|
||||||
var A = point{pub.a, one}
|
var A = point{pub.a, one}
|
||||||
|
|
||||||
|
// Randomly chosen P must have big enough order to check
|
||||||
|
// supersingularity. Probability of random P having big
|
||||||
|
// enough order is very high, as proven by W.Castryck et
|
||||||
|
// al. (ia.cr/2018/383, ch 5)
|
||||||
pub.randFp(&P.x, rng)
|
pub.randFp(&P.x, rng)
|
||||||
P.z = one
|
P.z = one
|
||||||
|
|
||||||
xDbl(&P, &P, &A)
|
xDbl(&P, &P, &A)
|
||||||
xDbl(&P, &P, &A)
|
xDbl(&P, &P, &A)
|
||||||
|
|
||||||
res, done := cofactorMultiples(&P, &coeff{A.x, A.z}, 0, len(primes), &fp{1})
|
done, res := cofactorMul(&P, &coeff{A.x, A.z}, 0, len(primes), &fp{1})
|
||||||
if done {
|
if done {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
@ -297,6 +315,9 @@ func Validate(pub *PublicKey, rng io.Reader) bool {
|
|||||||
|
|
||||||
// DeriveSecret computes a cSIDH shared secret. If successful, returns true
|
// DeriveSecret computes a cSIDH shared secret. If successful, returns true
|
||||||
// and fills 'out' with shared secret. Function returns false in case 'pub' is invalid.
|
// and fills 'out' with shared secret. Function returns false in case 'pub' is invalid.
|
||||||
|
// More precisely, shared secret is a Montgomery coefficient A of a secret
|
||||||
|
// curve y^2 = x^3 + Ax^2 + x, computed by applying action of a prv.e
|
||||||
|
// on a curve represented by pub.a.
|
||||||
func DeriveSecret(out *[64]byte, pub *PublicKey, prv *PrivateKey, rng io.Reader) bool {
|
func DeriveSecret(out *[64]byte, pub *PublicKey, prv *PrivateKey, rng io.Reader) bool {
|
||||||
if !Validate(pub, rng) {
|
if !Validate(pub, rng) {
|
||||||
return false
|
return false
|
||||||
|
@ -2,14 +2,12 @@ package csidh
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
crand "crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
crand "crypto/rand"
|
|
||||||
|
|
||||||
"github.com/henrydcase/nobs/drbg"
|
"github.com/henrydcase/nobs/drbg"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,6 +28,20 @@ var StatusValues = map[int]string{
|
|||||||
InvalidPublicKey2: "invalid_public_key2",
|
InvalidPublicKey2: "invalid_public_key2",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkErr(t testing.TB, err error, msg string) {
|
||||||
|
t.Helper()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Ok(t testing.TB, f bool, msg string) {
|
||||||
|
t.Helper()
|
||||||
|
if !f {
|
||||||
|
t.Error(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type TestVector struct {
|
type TestVector struct {
|
||||||
ID int `json:"Id"`
|
ID int `json:"Id"`
|
||||||
Pk1 string `json:"Pk1"`
|
Pk1 string `json:"Pk1"`
|
||||||
@ -39,10 +51,6 @@ type TestVector struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestVectors struct {
|
|
||||||
Vectors []TestVector `json:"Vectors"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var rng *drbg.CtrDrbg
|
var rng *drbg.CtrDrbg
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -56,6 +64,10 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TestVectors struct {
|
||||||
|
Vectors []TestVector `json:"Vectors"`
|
||||||
|
}
|
||||||
|
|
||||||
func TestCompare64(t *testing.T) {
|
func TestCompare64(t *testing.T) {
|
||||||
const s uint64 = 0xFFFFFFFFFFFFFFFF
|
const s uint64 = 0xFFFFFFFFFFFFFFFF
|
||||||
var val1 = fp{0, 2, 3, 4, 5, 6, 7, 8}
|
var val1 = fp{0, 2, 3, 4, 5, 6, 7, 8}
|
||||||
@ -82,20 +94,17 @@ func TestEphemeralKeyExchange(t *testing.T) {
|
|||||||
prv1.Import(prvBytes1)
|
prv1.Import(prvBytes1)
|
||||||
GeneratePublicKey(&pub1, &prv1, rng)
|
GeneratePublicKey(&pub1, &prv1, rng)
|
||||||
|
|
||||||
GeneratePrivateKey(&prv2, rng)
|
checkErr(t, GeneratePrivateKey(&prv2, rng), "PrivateKey generation failed")
|
||||||
GeneratePublicKey(&pub2, &prv2, rng)
|
GeneratePublicKey(&pub2, &prv2, rng)
|
||||||
|
|
||||||
if !DeriveSecret(&ss1, &pub1, &prv2, rng) {
|
Ok(t,
|
||||||
t.Errorf("Derivation failed\n")
|
DeriveSecret(&ss1, &pub1, &prv2, rng),
|
||||||
}
|
"Derivation failed")
|
||||||
|
Ok(t,
|
||||||
if !DeriveSecret(&ss2, &pub2, &prv1, rng) {
|
DeriveSecret(&ss2, &pub2, &prv1, rng),
|
||||||
t.Errorf("Derivation failed\n")
|
"Derivation failed")
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(ss1[:], ss2[:]) {
|
if !bytes.Equal(ss1[:], ss2[:]) {
|
||||||
fmt.Printf("%X\n", ss1)
|
|
||||||
fmt.Printf("%X\n", ss2)
|
|
||||||
t.Error("ss1 != ss2")
|
t.Error("ss1 != ss2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +113,7 @@ func TestPrivateKeyExportImport(t *testing.T) {
|
|||||||
var buf [37]byte
|
var buf [37]byte
|
||||||
for i := 0; i < numIter; i++ {
|
for i := 0; i < numIter; i++ {
|
||||||
var prv1, prv2 PrivateKey
|
var prv1, prv2 PrivateKey
|
||||||
GeneratePrivateKey(&prv1, rng)
|
checkErr(t, GeneratePrivateKey(&prv1, rng), "PrivateKey generation failed")
|
||||||
prv1.Export(buf[:])
|
prv1.Export(buf[:])
|
||||||
prv2.Import(buf[:])
|
prv2.Import(buf[:])
|
||||||
|
|
||||||
@ -153,7 +162,7 @@ func TestPublicKeyExportImport(t *testing.T) {
|
|||||||
for i := 0; i < numIter; i++ {
|
for i := 0; i < numIter; i++ {
|
||||||
var prv PrivateKey
|
var prv PrivateKey
|
||||||
var pub1, pub2 PublicKey
|
var pub1, pub2 PublicKey
|
||||||
GeneratePrivateKey(&prv, rng)
|
checkErr(t, GeneratePrivateKey(&prv, rng), "PrivateKey generation failed")
|
||||||
GeneratePublicKey(&pub1, &prv, rng)
|
GeneratePublicKey(&pub1, &prv, rng)
|
||||||
|
|
||||||
pub1.Export(buf[:])
|
pub1.Export(buf[:])
|
||||||
@ -165,10 +174,10 @@ func TestPublicKeyExportImport(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test vectors generated by reference implementation
|
// Test vectors generated by reference implementation.
|
||||||
func TestKAT(t *testing.T) {
|
func TestKAT(t *testing.T) {
|
||||||
var tests TestVectors
|
var tests TestVectors
|
||||||
var testVectorFile string
|
var katFile string
|
||||||
|
|
||||||
// Helper checks if e==true and reports an error if not.
|
// Helper checks if e==true and reports an error if not.
|
||||||
checkExpr := func(e bool, vec *TestVector, t *testing.T, msg string) {
|
checkExpr := func(e bool, vec *TestVector, t *testing.T, msg string) {
|
||||||
@ -179,9 +188,9 @@ func TestKAT(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if hasADXandBMI2 {
|
if hasADXandBMI2 {
|
||||||
testVectorFile = "testdata/csidh_testvectors.dat"
|
katFile = "testdata/csidh_testvectors.dat"
|
||||||
} else {
|
} else {
|
||||||
testVectorFile = "testdata/csidh_testvectors_small.dat"
|
katFile = "testdata/csidh_testvectors_small.dat"
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkSharedSecret implements nominal case - imports asymmetric keys for
|
// checkSharedSecret implements nominal case - imports asymmetric keys for
|
||||||
@ -197,39 +206,24 @@ func TestKAT(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkExpr(
|
checkExpr(prv1.Import(prBuf[:]), vec, t, "PrivateKey wrong")
|
||||||
prv1.Import(prBuf[:]),
|
|
||||||
vec, t, "PrivateKey wrong")
|
|
||||||
|
|
||||||
pkBuf, err := hex.DecodeString(vec.Pk1)
|
pkBuf, err := hex.DecodeString(vec.Pk1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkExpr(
|
checkExpr(pub1.Import(pkBuf[:]), vec, t, "PublicKey 1 wrong")
|
||||||
pub1.Import(pkBuf[:]),
|
|
||||||
vec, t, "PublicKey 1 wrong")
|
|
||||||
|
|
||||||
pkBuf, err = hex.DecodeString(vec.Pk2)
|
pkBuf, err = hex.DecodeString(vec.Pk2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkExpr(
|
checkExpr(pub2.Import(pkBuf[:]), vec, t, "PublicKey 2 wrong")
|
||||||
pub2.Import(pkBuf[:]),
|
checkExpr(DeriveSecret(&ss, &pub2, &prv1, rng), vec, t, "Error when deriving key")
|
||||||
vec, t, "PublicKey 2 wrong")
|
|
||||||
|
|
||||||
checkExpr(
|
|
||||||
DeriveSecret(&ss, &pub2, &prv1, rng),
|
|
||||||
vec, t, "Error when deriving key")
|
|
||||||
|
|
||||||
ssExp, err := hex.DecodeString(vec.Ss)
|
ssExp, err := hex.DecodeString(vec.Ss)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkExpr(
|
checkExpr(bytes.Equal(ss[:], ssExp) == (status == Valid), vec, t, "Unexpected value of shared secret")
|
||||||
bytes.Equal(ss[:], ssExp) == (status == Valid),
|
|
||||||
vec, t, "Unexpected value of shared secret")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkPublicKey1 imports public and private key for one party A
|
// checkPublicKey1 imports public and private key for one party A
|
||||||
// and tries to generate public key for a private key. After that
|
// and tries to generate public key for a private key. After that
|
||||||
// it compares generated key to a key from test vector. Comparison
|
// it compares generated key to a key from test vector. Comparison
|
||||||
@ -254,7 +248,7 @@ func TestKAT(t *testing.T) {
|
|||||||
vec, t, "PrivateKey wrong")
|
vec, t, "PrivateKey wrong")
|
||||||
|
|
||||||
// Generate public key
|
// Generate public key
|
||||||
GeneratePrivateKey(&prv, rng)
|
checkErr(t, GeneratePrivateKey(&prv, rng), "PrivateKey generation failed")
|
||||||
pub.Export(pubBytesGot[:])
|
pub.Export(pubBytesGot[:])
|
||||||
|
|
||||||
// pubBytesGot must be different than pubBytesExp
|
// pubBytesGot must be different than pubBytesExp
|
||||||
@ -262,27 +256,23 @@ func TestKAT(t *testing.T) {
|
|||||||
!bytes.Equal(pubBytesGot[:], pubBytesExp),
|
!bytes.Equal(pubBytesGot[:], pubBytesExp),
|
||||||
vec, t, "Public key generated is the same as public key from the test vector")
|
vec, t, "Public key generated is the same as public key from the test vector")
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkPublicKey2 the goal is to test key validation. Test tries to
|
// checkPublicKey2 the goal is to test key validation. Test tries to
|
||||||
// import public key for B and ensure that import succeeds in case
|
// import public key for B and ensure that import succeeds in case
|
||||||
// status is "Valid" and fails otherwise.
|
// status is "Valid" and fails otherwise.
|
||||||
checkPublicKey2 := func(vec *TestVector, t *testing.T, status int) {
|
checkPublicKey2 := func(vec *TestVector, t *testing.T, status int) {
|
||||||
var pub PublicKey
|
var pub PublicKey
|
||||||
|
|
||||||
pubBytesExp, err := hex.DecodeString(vec.Pk2)
|
pubBytesExp, err := hex.DecodeString(vec.Pk2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import validates an input, so it must fail
|
// Import validates an input, so it must fail
|
||||||
pub.Import(pubBytesExp[:])
|
pub.Import(pubBytesExp[:])
|
||||||
checkExpr(
|
checkExpr(
|
||||||
Validate(&pub, rng) == (status == Valid || status == ValidPublicKey2),
|
Validate(&pub, rng) == (status == Valid || status == ValidPublicKey2),
|
||||||
vec, t, "PublicKey has been validated correctly")
|
vec, t, "PublicKey has been validated correctly")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load test data
|
// Load test data
|
||||||
file, err := os.Open(testVectorFile)
|
file, err := os.Open(katFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
@ -290,9 +280,14 @@ func TestKAT(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop over all test cases
|
// Loop over all test cases
|
||||||
for _, test := range tests.Vectors {
|
for i := range tests.Vectors {
|
||||||
|
if !hasADXandBMI2 && i >= numIter {
|
||||||
|
// The algorithm is relatively slow, so on slow systems test
|
||||||
|
// against smaller number of test vectors (otherwise CI may break)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
test := tests.Vectors[i]
|
||||||
switch test.Status {
|
switch test.Status {
|
||||||
case StatusValues[Valid]:
|
case StatusValues[Valid]:
|
||||||
checkSharedSecret(&test, t, Valid)
|
checkSharedSecret(&test, t, Valid)
|
||||||
@ -314,23 +309,23 @@ func TestKAT(t *testing.T) {
|
|||||||
var prv1, prv2 PrivateKey
|
var prv1, prv2 PrivateKey
|
||||||
var pub1, pub2 PublicKey
|
var pub1, pub2 PublicKey
|
||||||
|
|
||||||
// Private key generation
|
// Private key generation.
|
||||||
func BenchmarkGeneratePrivate(b *testing.B) {
|
func BenchmarkGeneratePrivate(b *testing.B) {
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
GeneratePrivateKey(&prv1, rng)
|
_ = GeneratePrivateKey(&prv1, rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public key generation from private (group action on empty key)
|
// Public key generation from private (group action on empty key).
|
||||||
func BenchmarkGenerateKeyPair(b *testing.B) {
|
func BenchmarkGenerateKeyPair(b *testing.B) {
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
var pub PublicKey
|
var pub PublicKey
|
||||||
GeneratePrivateKey(&prv1, rng)
|
_ = GeneratePrivateKey(&prv1, rng)
|
||||||
GeneratePublicKey(&pub, &prv1, rng)
|
GeneratePublicKey(&pub, &prv1, rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Benchmark validation on same key multiple times
|
// Benchmark validation on same key multiple times.
|
||||||
func BenchmarkValidate(b *testing.B) {
|
func BenchmarkValidate(b *testing.B) {
|
||||||
prvBytes := []byte{0xaa, 0x54, 0xe4, 0xd4, 0xd0, 0xbd, 0xee, 0xcb, 0xf4, 0xd0, 0xc2, 0xbc, 0x52, 0x44, 0x11, 0xee, 0xe1, 0x14, 0xd2, 0x24, 0xe5, 0x0, 0xcc, 0xf5, 0xc0, 0xe1, 0x1e, 0xb3, 0x43, 0x52, 0x45, 0xbe, 0xfb, 0x54, 0xc0, 0x55, 0xb2}
|
prvBytes := []byte{0xaa, 0x54, 0xe4, 0xd4, 0xd0, 0xbd, 0xee, 0xcb, 0xf4, 0xd0, 0xc2, 0xbc, 0x52, 0x44, 0x11, 0xee, 0xe1, 0x14, 0xd2, 0x24, 0xe5, 0x0, 0xcc, 0xf5, 0xc0, 0xe1, 0x1e, 0xb3, 0x43, 0x52, 0x45, 0xbe, 0xfb, 0x54, 0xc0, 0x55, 0xb2}
|
||||||
prv1.Import(prvBytes)
|
prv1.Import(prvBytes)
|
||||||
@ -343,7 +338,7 @@ func BenchmarkValidate(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Benchmark validation on random (most probably wrong) key
|
// Benchmark validation on random (most probably wrong) key.
|
||||||
func BenchmarkValidateRandom(b *testing.B) {
|
func BenchmarkValidateRandom(b *testing.B) {
|
||||||
var tmp [64]byte
|
var tmp [64]byte
|
||||||
var pub PublicKey
|
var pub PublicKey
|
||||||
@ -357,39 +352,40 @@ func BenchmarkValidateRandom(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Benchmark validation on different keys
|
// Benchmark validation on different keys.
|
||||||
func BenchmarkValidateGenerated(b *testing.B) {
|
func BenchmarkValidateGenerated(b *testing.B) {
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
GeneratePrivateKey(&prv1, rng)
|
_ = GeneratePrivateKey(&prv1, rng)
|
||||||
GeneratePublicKey(&pub1, &prv1, rng)
|
GeneratePublicKey(&pub1, &prv1, rng)
|
||||||
Validate(&pub1, rng)
|
Validate(&pub1, rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate some keys and benchmark derive
|
// Generate some keys and benchmark derive.
|
||||||
func BenchmarkDerive(b *testing.B) {
|
func BenchmarkDerive(b *testing.B) {
|
||||||
var ss [64]byte
|
var ss [64]byte
|
||||||
|
|
||||||
GeneratePrivateKey(&prv1, rng)
|
_ = GeneratePrivateKey(&prv1, rng)
|
||||||
GeneratePublicKey(&pub1, &prv1, rng)
|
GeneratePublicKey(&pub1, &prv1, rng)
|
||||||
|
|
||||||
GeneratePrivateKey(&prv2, rng)
|
_ = GeneratePrivateKey(&prv2, rng)
|
||||||
GeneratePublicKey(&pub2, &prv2, rng)
|
GeneratePublicKey(&pub2, &prv2, rng)
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
DeriveSecret(&ss, &pub2, &prv1, rng)
|
DeriveSecret(&ss, &pub2, &prv1, rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Benchmarks both - key generation and derivation
|
// Benchmarks both - key generation and derivation.
|
||||||
func BenchmarkDeriveGenerated(b *testing.B) {
|
func BenchmarkDeriveGenerated(b *testing.B) {
|
||||||
var ss [64]byte
|
var ss [64]byte
|
||||||
|
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
GeneratePrivateKey(&prv1, rng)
|
_ = GeneratePrivateKey(&prv1, rng)
|
||||||
GeneratePublicKey(&pub1, &prv1, rng)
|
GeneratePublicKey(&pub1, &prv1, rng)
|
||||||
|
|
||||||
GeneratePrivateKey(&prv2, rng)
|
_ = GeneratePrivateKey(&prv2, rng)
|
||||||
GeneratePublicKey(&pub2, &prv2, rng)
|
GeneratePublicKey(&pub2, &prv2, rng)
|
||||||
|
|
||||||
DeriveSecret(&ss, &pub2, &prv1, rng)
|
DeriveSecret(&ss, &pub2, &prv1, rng)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package csidh
|
package csidh
|
||||||
|
|
||||||
// Implements differential arithmetic in P^1 for montgomery
|
// xAdd implements differential arithmetic in P^1 for Montgomery
|
||||||
// curves a mapping: x(P),x(Q),x(P-Q) -> x(P+Q)
|
// curves E(x): x^3 + A*x^2 + x by using x-coordinate only arithmetic.
|
||||||
// PaQ = P + Q
|
// x(PaQ) = x(P) + x(Q) by using x(P-Q)
|
||||||
// This algorithms is correctly defined only for cases when
|
// This algorithms is correctly defined only for cases when
|
||||||
// P!=inf, Q!=inf, P!=Q and P!=-Q
|
// P!=inf, Q!=inf, P!=Q and P!=-Q.
|
||||||
func xAdd(PaQ, P, Q, PdQ *point) {
|
func xAdd(PaQ, P, Q, PdQ *point) {
|
||||||
var t0, t1, t2, t3 fp
|
var t0, t1, t2, t3 fp
|
||||||
addRdc(&t0, &P.x, &P.z)
|
addRdc(&t0, &P.x, &P.z)
|
||||||
@ -21,8 +21,10 @@ func xAdd(PaQ, P, Q, PdQ *point) {
|
|||||||
mulRdc(&PaQ.z, &PdQ.x, &t3)
|
mulRdc(&PaQ.z, &PdQ.x, &t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Q = 2*P on a montgomery curve E(x): x^3 + A*x^2 + x
|
// xDbl implements point doubling on a Montgomery curve
|
||||||
// It is correctly defined for all P != inf
|
// E(x): x^3 + A*x^2 + x by using x-coordinate onlyh arithmetic.
|
||||||
|
// x(Q) = [2]*x(P)
|
||||||
|
// It is correctly defined for all P != inf.
|
||||||
func xDbl(Q, P, A *point) {
|
func xDbl(Q, P, A *point) {
|
||||||
var t0, t1, t2 fp
|
var t0, t1, t2 fp
|
||||||
addRdc(&t0, &P.x, &P.z)
|
addRdc(&t0, &P.x, &P.z)
|
||||||
@ -40,8 +42,11 @@ func xDbl(Q, P, A *point) {
|
|||||||
mulRdc(&Q.z, &t0, &t2)
|
mulRdc(&Q.z, &t0, &t2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaP = 2*P; PaQ = P+Q
|
// xDblAdd implements combined doubling of point P
|
||||||
// PaP can override P and PaQ can override Q
|
// and addition of points P and Q on a Montgomery curve
|
||||||
|
// E(x): x^3 + A*x^2 + x by using x-coordinate onlyh arithmetic.
|
||||||
|
// x(PaP) = x(2*P)
|
||||||
|
// x(PaQ) = x(P+Q)
|
||||||
func xDblAdd(PaP, PaQ, P, Q, PdQ *point, A24 *coeff) {
|
func xDblAdd(PaP, PaQ, P, Q, PdQ *point, A24 *coeff) {
|
||||||
var t0, t1, t2 fp
|
var t0, t1, t2 fp
|
||||||
|
|
||||||
@ -67,7 +72,7 @@ func xDblAdd(PaP, PaQ, P, Q, PdQ *point, A24 *coeff) {
|
|||||||
mulRdc(&PaQ.x, &PaQ.x, &PdQ.z)
|
mulRdc(&PaQ.x, &PaQ.x, &PdQ.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swap P1 with P2 in constant time. The 'choice'
|
// cswappoint swaps P1 with P2 in constant time. The 'choice'
|
||||||
// parameter must have a value of either 1 (results
|
// parameter must have a value of either 1 (results
|
||||||
// in swap) or 0 (results in no-swap).
|
// in swap) or 0 (results in no-swap).
|
||||||
func cswappoint(P1, P2 *point, choice uint8) {
|
func cswappoint(P1, P2 *point, choice uint8) {
|
||||||
@ -75,13 +80,11 @@ func cswappoint(P1, P2 *point, choice uint8) {
|
|||||||
cswap512(&P1.z, &P2.z, choice)
|
cswap512(&P1.z, &P2.z, choice)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A uniform Montgomery ladder. co is A coefficient of
|
// xMul implements point multiplication with left-to-right Montgomery
|
||||||
// x^3 + A*x^2 + x curve. k MUST be > 0
|
// adder. co is A coefficient of x^3 + A*x^2 + x curve. k must be > 0
|
||||||
//
|
//
|
||||||
// kP = [k]P. xM=x(0 + k*P)
|
// Non-constant time!
|
||||||
//
|
func xMul(kP, P *point, co *coeff, k *fp) {
|
||||||
// non-constant time.
|
|
||||||
func xMul512(kP, P *point, co *coeff, k *fp) {
|
|
||||||
var A24 coeff
|
var A24 coeff
|
||||||
var Q point
|
var Q point
|
||||||
var j uint
|
var j uint
|
||||||
@ -107,16 +110,23 @@ func xMul512(kP, P *point, co *coeff, k *fp) {
|
|||||||
for i := j; i > 0; {
|
for i := j; i > 0; {
|
||||||
i--
|
i--
|
||||||
bit := uint8(k[i>>6] >> (i & 63) & 1)
|
bit := uint8(k[i>>6] >> (i & 63) & 1)
|
||||||
swap := prevBit ^ bit
|
cswappoint(&Q, &R, prevBit^bit)
|
||||||
prevBit = bit
|
|
||||||
cswappoint(&Q, &R, swap)
|
|
||||||
xDblAdd(&Q, &R, &Q, &R, P, &A24)
|
xDblAdd(&Q, &R, &Q, &R, P, &A24)
|
||||||
|
prevBit = bit
|
||||||
}
|
}
|
||||||
cswappoint(&Q, &R, uint8(k[0]&1))
|
cswappoint(&Q, &R, uint8(k[0]&1))
|
||||||
*kP = Q
|
*kP = Q
|
||||||
}
|
}
|
||||||
|
|
||||||
func isom(img *point, co *coeff, kern *point, order uint64) {
|
// xIso computes the isogeny with kernel point kern of a given order
|
||||||
|
// kernOrder. Returns the new curve coefficient co and the image img.
|
||||||
|
//
|
||||||
|
// During computation function switches between Montgomery and twisted
|
||||||
|
// Edwards curves in order to compute image curve parameters faster.
|
||||||
|
// This technique is described by Meyer and Reith in ia.cr/2018/782.
|
||||||
|
//
|
||||||
|
// Non-constant time.
|
||||||
|
func xIso(img *point, co *coeff, kern *point, kernOrder uint64) {
|
||||||
var t0, t1, t2, S, D fp
|
var t0, t1, t2, S, D fp
|
||||||
var Q, prod point
|
var Q, prod point
|
||||||
var coEd coeff
|
var coEd coeff
|
||||||
@ -145,8 +155,8 @@ func isom(img *point, co *coeff, kern *point, order uint64) {
|
|||||||
|
|
||||||
xDbl(&M[1], kern, &point{x: co.a, z: co.c})
|
xDbl(&M[1], kern, &point{x: co.a, z: co.c})
|
||||||
|
|
||||||
// TODO: Not constant time.
|
// NOTE: Not constant time.
|
||||||
for i := uint64(1); i < order>>1; i++ {
|
for i := uint64(1); i < kernOrder>>1; i++ {
|
||||||
if i >= 2 {
|
if i >= 2 {
|
||||||
xAdd(&M[i%3], &M[(i-1)%3], kern, &M[(i-2)%3])
|
xAdd(&M[i%3], &M[(i-1)%3], kern, &M[(i-2)%3])
|
||||||
}
|
}
|
||||||
@ -160,7 +170,6 @@ func isom(img *point, co *coeff, kern *point, order uint64) {
|
|||||||
mulRdc(&Q.x, &Q.x, &t2)
|
mulRdc(&Q.x, &Q.x, &t2)
|
||||||
subRdc(&t2, &t0, &t1)
|
subRdc(&t2, &t0, &t1)
|
||||||
mulRdc(&Q.z, &Q.z, &t2)
|
mulRdc(&Q.z, &Q.z, &t2)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mulRdc(&Q.x, &Q.x, &Q.x)
|
mulRdc(&Q.x, &Q.x, &Q.x)
|
||||||
@ -168,9 +177,9 @@ func isom(img *point, co *coeff, kern *point, order uint64) {
|
|||||||
mulRdc(&img.x, &img.x, &Q.x)
|
mulRdc(&img.x, &img.x, &Q.x)
|
||||||
mulRdc(&img.z, &img.z, &Q.z)
|
mulRdc(&img.z, &img.z, &Q.z)
|
||||||
|
|
||||||
// coEd.a^order and coEd.c^order
|
// coEd.a^kernOrder and coEd.c^kernOrder
|
||||||
modExpRdc64(&coEd.a, &coEd.a, order)
|
modExpRdc64(&coEd.a, &coEd.a, kernOrder)
|
||||||
modExpRdc64(&coEd.c, &coEd.c, order)
|
modExpRdc64(&coEd.c, &coEd.c, kernOrder)
|
||||||
|
|
||||||
// prod^8
|
// prod^8
|
||||||
mulRdc(&prod.x, &prod.x, &prod.x)
|
mulRdc(&prod.x, &prod.x, &prod.x)
|
||||||
@ -190,7 +199,7 @@ func isom(img *point, co *coeff, kern *point, order uint64) {
|
|||||||
addRdc(&co.a, &co.a, &co.a)
|
addRdc(&co.a, &co.a, &co.a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluates x^3 + Ax^2 + x
|
// montEval evaluates x^3 + Ax^2 + x.
|
||||||
func montEval(res, A, x *fp) {
|
func montEval(res, A, x *fp) {
|
||||||
var t fp
|
var t fp
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Actual test implementation
|
// Actual test implementation.
|
||||||
func TestXAdd(t *testing.T) {
|
func TestXAdd(t *testing.T) {
|
||||||
var P, Q, PdQ point
|
var P, Q, PdQ point
|
||||||
var PaQ point
|
var PaQ point
|
||||||
@ -180,14 +180,14 @@ func TestXMul(t *testing.T) {
|
|||||||
checkXMul := func() {
|
checkXMul := func() {
|
||||||
var kP point
|
var kP point
|
||||||
|
|
||||||
xMul512(&kP, &P, &co, &k)
|
xMul(&kP, &P, &co, &k)
|
||||||
retKP := toNormX(&kP)
|
retKP := toNormX(&kP)
|
||||||
if expKP.Cmp(&retKP) != 0 {
|
if expKP.Cmp(&retKP) != 0 {
|
||||||
t.Errorf("\nExp: %s\nGot: %s", expKP.Text(16), retKP.Text(16))
|
t.Errorf("\nExp: %s\nGot: %s", expKP.Text(16), retKP.Text(16))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if first and second argument can overlap
|
// Check if first and second argument can overlap
|
||||||
xMul512(&P, &P, &co, &k)
|
xMul(&P, &P, &co, &k)
|
||||||
retKP = toNormX(&P)
|
retKP = toNormX(&P)
|
||||||
if expKP.Cmp(&retKP) != 0 {
|
if expKP.Cmp(&retKP) != 0 {
|
||||||
t.Errorf("\nExp: %s\nGot: %s", expKP.Text(16), retKP.Text(16))
|
t.Errorf("\nExp: %s\nGot: %s", expKP.Text(16), retKP.Text(16))
|
||||||
@ -261,13 +261,13 @@ func TestMappointHardcoded3(t *testing.T) {
|
|||||||
var expP = point{
|
var expP = point{
|
||||||
x: fp{0x91aba9b39f280495, 0xfbd8ea69d2990aeb, 0xb03e1b8ed7fe3dba, 0x3d30a41499f08998, 0xb15a42630de9c606, 0xa7dd487fef16f5c8, 0x8673948afed8e968, 0x57ecc8710004cd4d},
|
x: fp{0x91aba9b39f280495, 0xfbd8ea69d2990aeb, 0xb03e1b8ed7fe3dba, 0x3d30a41499f08998, 0xb15a42630de9c606, 0xa7dd487fef16f5c8, 0x8673948afed8e968, 0x57ecc8710004cd4d},
|
||||||
z: fp{0xce8819869a942526, 0xb98ca2ff79ef8969, 0xd49c9703743a1812, 0x21dbb090f9152e03, 0xbabdcac831b1adea, 0x8cee90762baa2ddd, 0xa0dd2ddcef809d96, 0x1de2a8887a32f19b}}
|
z: fp{0xce8819869a942526, 0xb98ca2ff79ef8969, 0xd49c9703743a1812, 0x21dbb090f9152e03, 0xbabdcac831b1adea, 0x8cee90762baa2ddd, 0xa0dd2ddcef809d96, 0x1de2a8887a32f19b}}
|
||||||
isom(&P, &A, &K, k)
|
xIso(&P, &A, &K, k)
|
||||||
if !ceqFp(&P.x, &expP.x) || !ceqFp(&P.z, &expP.z) {
|
if !eqFp(&P.x, &expP.x) || !eqFp(&P.z, &expP.z) {
|
||||||
normP := toNormX(&P)
|
normP := toNormX(&P)
|
||||||
normPExp := toNormX(&expP)
|
normPExp := toNormX(&expP)
|
||||||
t.Errorf("P != expP [\n %s != %s\n]", normP.Text(16), normPExp.Text(16))
|
t.Errorf("P != expP [\n %s != %s\n]", normP.Text(16), normPExp.Text(16))
|
||||||
}
|
}
|
||||||
if !ceqFp(&A.a, &expA.a) || !ceqFp(&A.c, &expA.c) {
|
if !eqFp(&A.a, &expA.a) || !eqFp(&A.c, &expA.c) {
|
||||||
t.Errorf("A != expA %X %X", A.a[0], expA.a[0])
|
t.Errorf("A != expA %X %X", A.a[0], expA.a[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,13 +291,13 @@ func TestMappointHardcoded5(t *testing.T) {
|
|||||||
x: fp{0x3b75fc94b2a6df2d, 0x96d53dc9b0e867a0, 0x22e87202421d274e, 0x30a361440697ee1a, 0x8b52ee078bdbddcd, 0x64425d500e6b934d, 0xf47d1f568f6df391, 0x5d9d3607431395ab},
|
x: fp{0x3b75fc94b2a6df2d, 0x96d53dc9b0e867a0, 0x22e87202421d274e, 0x30a361440697ee1a, 0x8b52ee078bdbddcd, 0x64425d500e6b934d, 0xf47d1f568f6df391, 0x5d9d3607431395ab},
|
||||||
z: fp{0x746e02dafa040976, 0xcd408f2cddbf3a8e, 0xf643354e0e13a93f, 0x7c39ed96ce9a5e29, 0xfcdf26f1a1a550ca, 0x2fc8aafc4ca0a559, 0x5d204a2b14cf19ba, 0xbd2c3406762f05d}}
|
z: fp{0x746e02dafa040976, 0xcd408f2cddbf3a8e, 0xf643354e0e13a93f, 0x7c39ed96ce9a5e29, 0xfcdf26f1a1a550ca, 0x2fc8aafc4ca0a559, 0x5d204a2b14cf19ba, 0xbd2c3406762f05d}}
|
||||||
|
|
||||||
isom(&P, &A, &K, k)
|
xIso(&P, &A, &K, k)
|
||||||
if !ceqFp(&P.x, &expP.x) || !ceqFp(&P.z, &expP.z) {
|
if !eqFp(&P.x, &expP.x) || !eqFp(&P.z, &expP.z) {
|
||||||
normP := toNormX(&P)
|
normP := toNormX(&P)
|
||||||
normPExp := toNormX(&expP)
|
normPExp := toNormX(&expP)
|
||||||
t.Errorf("P != expP [\n %s != %s\n]", normP.Text(16), normPExp.Text(16))
|
t.Errorf("P != expP [\n %s != %s\n]", normP.Text(16), normPExp.Text(16))
|
||||||
}
|
}
|
||||||
if !ceqFp(&A.a, &expA.a) || !ceqFp(&A.c, &expA.c) {
|
if !eqFp(&A.a, &expA.a) || !eqFp(&A.c, &expA.c) {
|
||||||
t.Errorf("A != expA %X %X", A.a[0], expA.a[0])
|
t.Errorf("A != expA %X %X", A.a[0], expA.a[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,7 +317,7 @@ func BenchmarkXMul(b *testing.B) {
|
|||||||
k = fp{0x7A36C930A83EFBD5, 0xD0E80041ED0DDF9F, 0x5AA17134F1B8F877, 0x975711EC94168E51, 0xB3CAD962BED4BAC5, 0x3026DFDD7E4F5687, 0xE67F91AB8EC9C3AF, 0x34671D3FD8C317E7}
|
k = fp{0x7A36C930A83EFBD5, 0xD0E80041ED0DDF9F, 0x5AA17134F1B8F877, 0x975711EC94168E51, 0xB3CAD962BED4BAC5, 0x3026DFDD7E4F5687, 0xE67F91AB8EC9C3AF, 0x34671D3FD8C317E7}
|
||||||
|
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
xMul512(&kP, &P, &co, &k)
|
xMul(&kP, &P, &co, &k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,6 +366,6 @@ func BenchmarkIsom(b *testing.B) {
|
|||||||
kern.z = toFp("1")
|
kern.z = toFp("1")
|
||||||
|
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
isom(&P, &co, &kern, k)
|
xIso(&P, &co, &kern, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
dh/csidh/doc.go
Normal file
11
dh/csidh/doc.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Package csidh implements cSIDH key exchange, isogeny-based scheme
|
||||||
|
// resulting from the group action. Implementation uses only prime
|
||||||
|
// field of a size 512-bits and uses Ed some performance improvements
|
||||||
|
// by using twisted Edwards curves in the isogeny image curve
|
||||||
|
// computations. This work has been described by M. Meyer and S. Reith
|
||||||
|
// in the ia.cr/2018/782. Original cSIDH paper can be found in the
|
||||||
|
// ia.cr/2018/383.
|
||||||
|
//
|
||||||
|
// It is experimental implementation, not meant to be secure. Have fun!
|
||||||
|
//
|
||||||
|
package csidh
|
@ -12,7 +12,7 @@ import (
|
|||||||
// We declare variables not constants, in order to facilitate testing.
|
// We declare variables not constants, in order to facilitate testing.
|
||||||
var (
|
var (
|
||||||
// Signals support for BMI2 (MULX)
|
// Signals support for BMI2 (MULX)
|
||||||
hasBMI2 = cpu.X86.HasBMI2
|
hasBMI2 = cpu.X86.HasBMI2 //nolint
|
||||||
// Signals support for ADX and BMI2
|
// Signals support for ADX and BMI2
|
||||||
hasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX
|
hasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX
|
||||||
)
|
)
|
||||||
@ -20,7 +20,7 @@ var (
|
|||||||
// Constant time select.
|
// Constant time select.
|
||||||
// if pick == 0xFF..FF (out = in1)
|
// if pick == 0xFF..FF (out = in1)
|
||||||
// if pick == 0 (out = in2)
|
// if pick == 0 (out = in2)
|
||||||
// else out is undefined
|
// else out is undefined.
|
||||||
func ctPick64(which uint64, in1, in2 uint64) uint64 {
|
func ctPick64(which uint64, in1, in2 uint64) uint64 {
|
||||||
return (in1 & which) | (in2 & ^which)
|
return (in1 & which) | (in2 & ^which)
|
||||||
}
|
}
|
||||||
@ -41,7 +41,6 @@ func mulGeneric(r, x, y *fp) {
|
|||||||
var c, q uint64
|
var c, q uint64
|
||||||
|
|
||||||
for i := 0; i < numWords-1; i++ {
|
for i := 0; i < numWords-1; i++ {
|
||||||
|
|
||||||
q = ((x[i] * y[0]) + s[0]) * pNegInv[0]
|
q = ((x[i] * y[0]) + s[0]) * pNegInv[0]
|
||||||
mul576(&t1, &p, q)
|
mul576(&t1, &p, q)
|
||||||
mul576(&t2, y, x[i])
|
mul576(&t2, y, x[i])
|
||||||
@ -143,7 +142,7 @@ func addRdc(r, x, y *fp) {
|
|||||||
r[7] = ctPick64(w, r[7], t[7])
|
r[7] = ctPick64(w, r[7], t[7])
|
||||||
}
|
}
|
||||||
|
|
||||||
// r = x - y
|
// r = x - y.
|
||||||
func sub512(r, x, y *fp) uint64 {
|
func sub512(r, x, y *fp) uint64 {
|
||||||
var c uint64
|
var c uint64
|
||||||
r[0], c = bits.Sub64(x[0], y[0], 0)
|
r[0], c = bits.Sub64(x[0], y[0], 0)
|
||||||
@ -199,7 +198,7 @@ func modExpRdcCommon(r, b, e *fp, fpBitLen int) {
|
|||||||
precomp[0] = one // b ^ 0
|
precomp[0] = one // b ^ 0
|
||||||
precomp[1] = *b // b ^ 1
|
precomp[1] = *b // b ^ 1
|
||||||
for i := 2; i < 16; i = i + 2 {
|
for i := 2; i < 16; i = i + 2 {
|
||||||
// TODO: implement fast squering. Then interleaving fast squaring
|
// OPTIMIZE: implement fast squering. Then interleaving fast squaring
|
||||||
// with multiplication should improve performance.
|
// with multiplication should improve performance.
|
||||||
mulRdc(&precomp[i], &precomp[i/2], &precomp[i/2]) // sqr
|
mulRdc(&precomp[i], &precomp[i/2], &precomp[i/2]) // sqr
|
||||||
mulRdc(&precomp[i+1], &precomp[i], b)
|
mulRdc(&precomp[i+1], &precomp[i], b)
|
||||||
@ -234,7 +233,6 @@ func modExpRdcCommon(r, b, e *fp, fpBitLen int) {
|
|||||||
r[5] = ctPick64(w, r[5], t[5])
|
r[5] = ctPick64(w, r[5], t[5])
|
||||||
r[6] = ctPick64(w, r[6], t[6])
|
r[6] = ctPick64(w, r[6], t[6])
|
||||||
r[7] = ctPick64(w, r[7], t[7])
|
r[7] = ctPick64(w, r[7], t[7])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// modExpRdc does modular exponentation of 512-bit number.
|
// modExpRdc does modular exponentation of 512-bit number.
|
||||||
@ -280,7 +278,7 @@ func (v *fp) isZero() bool {
|
|||||||
return ctIsNonZero64(r) == 0
|
return ctIsNonZero64(r) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// equal checks if v is equal to in. Constant time
|
// equal checks if v is equal to in. Constant time.
|
||||||
func (v *fp) equal(in *fp) bool {
|
func (v *fp) equal(in *fp) bool {
|
||||||
var r uint64
|
var r uint64
|
||||||
for i := range v {
|
for i := range v {
|
||||||
|
@ -4,6 +4,9 @@ package csidh
|
|||||||
|
|
||||||
import "math/bits"
|
import "math/bits"
|
||||||
|
|
||||||
|
// mul576 implements schoolbook multiplication of
|
||||||
|
// 64x512-bit integer. Returns result modulo 2^512.
|
||||||
|
// r = m1*m2
|
||||||
func mul512(r, m1 *fp, m2 uint64) {
|
func mul512(r, m1 *fp, m2 uint64) {
|
||||||
var c, h, l uint64
|
var c, h, l uint64
|
||||||
|
|
||||||
@ -33,10 +36,14 @@ func mul512(r, m1 *fp, m2 uint64) {
|
|||||||
r[6], c = bits.Add64(l, c, 0)
|
r[6], c = bits.Add64(l, c, 0)
|
||||||
c = h + c
|
c = h + c
|
||||||
|
|
||||||
h, l = bits.Mul64(m2, m1[7])
|
_, l = bits.Mul64(m2, m1[7])
|
||||||
r[7], _ = bits.Add64(l, c, 0)
|
r[7], _ = bits.Add64(l, c, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mul576 implements schoolbook multiplication of
|
||||||
|
// 64x512-bit integer. Returns 576-bit result of
|
||||||
|
// multiplication.
|
||||||
|
// r = m1*m2
|
||||||
func mul576(r *[9]uint64, m1 *fp, m2 uint64) {
|
func mul576(r *[9]uint64, m1 *fp, m2 uint64) {
|
||||||
var c, h, l uint64
|
var c, h, l uint64
|
||||||
|
|
||||||
@ -72,6 +79,9 @@ func mul576(r *[9]uint64, m1 *fp, m2 uint64) {
|
|||||||
r[8] += c
|
r[8] += c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cswap512 implements constant time swap operation.
|
||||||
|
// If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x.
|
||||||
|
// If choice is neither 0 nor 1 then behaviour is undefined.
|
||||||
func cswap512(x, y *fp, choice uint8) {
|
func cswap512(x, y *fp, choice uint8) {
|
||||||
var tmp uint64
|
var tmp uint64
|
||||||
mask64 := 0 - uint64(choice)
|
mask64 := 0 - uint64(choice)
|
||||||
@ -83,10 +93,6 @@ func cswap512(x, y *fp, choice uint8) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mul(res, x, y *fp) {
|
|
||||||
mulGeneric(res, x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
// mulRdc performs montgomery multiplication r = x * y mod P.
|
// mulRdc performs montgomery multiplication r = x * y mod P.
|
||||||
// Returned result r is already reduced and in Montgomery domain.
|
// Returned result r is already reduced and in Montgomery domain.
|
||||||
func mulRdc(r, x, y *fp) {
|
func mulRdc(r, x, y *fp) {
|
||||||
|
@ -39,14 +39,13 @@ func testFp512Mul3Nominal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if mul512 produces result
|
// Check if mul512 produces result
|
||||||
// z = x*y mod 2^512
|
// z = x*y mod 2^512.
|
||||||
func TestFp512Mul3_Nominal(t *testing.T) {
|
func TestFp512Mul3_Nominal(t *testing.T) {
|
||||||
hasBMI2 = false
|
hasBMI2 = false
|
||||||
testFp512Mul3Nominal(t)
|
testFp512Mul3Nominal(t)
|
||||||
|
|
||||||
resetCPUFeatures()
|
resetCPUFeatures()
|
||||||
testFp512Mul3Nominal(t)
|
testFp512Mul3Nominal(t)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddRdcRandom(t *testing.T) {
|
func TestAddRdcRandom(t *testing.T) {
|
||||||
@ -78,26 +77,26 @@ func TestAddRdcNominal(t *testing.T) {
|
|||||||
|
|
||||||
tmp := oneFp512
|
tmp := oneFp512
|
||||||
addRdc(&res, &tmp, &p)
|
addRdc(&res, &tmp, &p)
|
||||||
if !ceq512(&res, &tmp) {
|
if !eqFp(&res, &tmp) {
|
||||||
t.Errorf("Wrong value\n%X", res)
|
t.Errorf("Wrong value\n%X", res)
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = zeroFp512
|
tmp = zeroFp512
|
||||||
addRdc(&res, &p, &p)
|
addRdc(&res, &p, &p)
|
||||||
if !ceq512(&res, &p) {
|
if !eqFp(&res, &p) {
|
||||||
t.Errorf("Wrong value\n%X", res)
|
t.Errorf("Wrong value\n%X", res)
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = fp{1, 1, 1, 1, 1, 1, 1, 1}
|
tmp = fp{1, 1, 1, 1, 1, 1, 1, 1}
|
||||||
addRdc(&res, &p, &tmp)
|
addRdc(&res, &p, &tmp)
|
||||||
if !ceq512(&res, &tmp) {
|
if !eqFp(&res, &tmp) {
|
||||||
t.Errorf("Wrong value\n%X", res)
|
t.Errorf("Wrong value\n%X", res)
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = fp{1, 1, 1, 1, 1, 1, 1, 1}
|
tmp = fp{1, 1, 1, 1, 1, 1, 1, 1}
|
||||||
exp := fp{2, 2, 2, 2, 2, 2, 2, 2}
|
exp := fp{2, 2, 2, 2, 2, 2, 2, 2}
|
||||||
addRdc(&res, &tmp, &tmp)
|
addRdc(&res, &tmp, &tmp)
|
||||||
if !ceq512(&res, &exp) {
|
if !eqFp(&res, &exp) {
|
||||||
t.Errorf("Wrong value\n%X", res)
|
t.Errorf("Wrong value\n%X", res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,19 +167,19 @@ func TestCswap(t *testing.T) {
|
|||||||
|
|
||||||
arg1cpy := arg1
|
arg1cpy := arg1
|
||||||
cswap512(&arg1, &arg2, 0)
|
cswap512(&arg1, &arg2, 0)
|
||||||
if !ceq512(&arg1, &arg1cpy) {
|
if !eqFp(&arg1, &arg1cpy) {
|
||||||
t.Error("cswap swapped")
|
t.Error("cswap swapped")
|
||||||
}
|
}
|
||||||
|
|
||||||
arg1cpy = arg1
|
arg1cpy = arg1
|
||||||
cswap512(&arg1, &arg2, 1)
|
cswap512(&arg1, &arg2, 1)
|
||||||
if ceq512(&arg1, &arg1cpy) {
|
if eqFp(&arg1, &arg1cpy) {
|
||||||
t.Error("cswap didn't swapped")
|
t.Error("cswap didn't swapped")
|
||||||
}
|
}
|
||||||
|
|
||||||
arg1cpy = arg1
|
arg1cpy = arg1
|
||||||
cswap512(&arg1, &arg2, 0xF2)
|
cswap512(&arg1, &arg2, 0xF2)
|
||||||
if ceq512(&arg1, &arg1cpy) {
|
if eqFp(&arg1, &arg1cpy) {
|
||||||
t.Error("cswap didn't swapped")
|
t.Error("cswap didn't swapped")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,7 +190,7 @@ func TestSubRdc(t *testing.T) {
|
|||||||
// 1 - 1 mod P
|
// 1 - 1 mod P
|
||||||
tmp := oneFp512
|
tmp := oneFp512
|
||||||
subRdc(&res, &tmp, &tmp)
|
subRdc(&res, &tmp, &tmp)
|
||||||
if !ceq512(&res, &zeroFp512) {
|
if !eqFp(&res, &zeroFp512) {
|
||||||
t.Errorf("Wrong value\n%X", res)
|
t.Errorf("Wrong value\n%X", res)
|
||||||
}
|
}
|
||||||
zero(&res)
|
zero(&res)
|
||||||
@ -201,7 +200,7 @@ func TestSubRdc(t *testing.T) {
|
|||||||
exp[0]--
|
exp[0]--
|
||||||
|
|
||||||
subRdc(&res, &zeroFp512, &oneFp512)
|
subRdc(&res, &zeroFp512, &oneFp512)
|
||||||
if !ceq512(&res, &exp) {
|
if !eqFp(&res, &exp) {
|
||||||
t.Errorf("Wrong value\n%X\n%X", res, exp)
|
t.Errorf("Wrong value\n%X\n%X", res, exp)
|
||||||
}
|
}
|
||||||
zero(&res)
|
zero(&res)
|
||||||
@ -210,13 +209,13 @@ func TestSubRdc(t *testing.T) {
|
|||||||
pMinusOne := p
|
pMinusOne := p
|
||||||
pMinusOne[0]--
|
pMinusOne[0]--
|
||||||
subRdc(&res, &p, &pMinusOne)
|
subRdc(&res, &p, &pMinusOne)
|
||||||
if !ceq512(&res, &oneFp512) {
|
if !eqFp(&res, &oneFp512) {
|
||||||
t.Errorf("Wrong value\n[%X != %X]", res, oneFp512)
|
t.Errorf("Wrong value\n[%X != %X]", res, oneFp512)
|
||||||
}
|
}
|
||||||
zero(&res)
|
zero(&res)
|
||||||
|
|
||||||
subRdc(&res, &p, &oneFp512)
|
subRdc(&res, &p, &oneFp512)
|
||||||
if !ceq512(&res, &pMinusOne) {
|
if !eqFp(&res, &pMinusOne) {
|
||||||
t.Errorf("Wrong value\n[%X != %X]", res, pMinusOne)
|
t.Errorf("Wrong value\n[%X != %X]", res, pMinusOne)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,28 +244,28 @@ func testMulRdc(t *testing.T) {
|
|||||||
// 0*0
|
// 0*0
|
||||||
tmp := zeroFp512
|
tmp := zeroFp512
|
||||||
mulRdc(&res, &tmp, &tmp)
|
mulRdc(&res, &tmp, &tmp)
|
||||||
if !ceq512(&res, &tmp) {
|
if !eqFp(&res, &tmp) {
|
||||||
t.Errorf("Wrong value\n%X", res)
|
t.Errorf("Wrong value\n%X", res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1*m1 == m1
|
// 1*m1 == m1
|
||||||
zero(&res)
|
zero(&res)
|
||||||
mulRdc(&res, &m1, &one)
|
mulRdc(&res, &m1, &one)
|
||||||
if !ceq512(&res, &m1) {
|
if !eqFp(&res, &m1) {
|
||||||
t.Errorf("Wrong value\n%X", res)
|
t.Errorf("Wrong value\n%X", res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// m1*m2 < p
|
// m1*m2 < p
|
||||||
zero(&res)
|
zero(&res)
|
||||||
mulRdc(&res, &m1, &m2)
|
mulRdc(&res, &m1, &m2)
|
||||||
if !ceq512(&res, &m1m2) {
|
if !eqFp(&res, &m1m2) {
|
||||||
t.Errorf("Wrong value\n%X", res)
|
t.Errorf("Wrong value\n%X", res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// m1*m1 > p
|
// m1*m1 > p
|
||||||
zero(&res)
|
zero(&res)
|
||||||
mulRdc(&res, &m1, &m1)
|
mulRdc(&res, &m1, &m1)
|
||||||
if !ceq512(&res, &m1m1) {
|
if !eqFp(&res, &m1m1) {
|
||||||
t.Errorf("Wrong value\n%X", res)
|
t.Errorf("Wrong value\n%X", res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,13 +299,13 @@ func TestModExp(t *testing.T) {
|
|||||||
// Perform modexp with our implementation
|
// Perform modexp with our implementation
|
||||||
modExpRdc512(&resFp, &baseFp, &expFp)
|
modExpRdc512(&resFp, &baseFp, &expFp)
|
||||||
|
|
||||||
if !ceq512(&resFp, &resFpExp) {
|
if !eqFp(&resFp, &resFpExp) {
|
||||||
t.Errorf("Wrong value\n%X!=%X", resFp, intGetU64(&resExp))
|
t.Errorf("Wrong value\n%X!=%X", resFp, intGetU64(&resExp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test uses Euler's Criterion
|
// Test uses Euler's Criterion.
|
||||||
func TestIsNonQuadRes(t *testing.T) {
|
func TestIsNonQuadRes(t *testing.T) {
|
||||||
var n, nMont big.Int
|
var n, nMont big.Int
|
||||||
var pm1o2, rawP big.Int
|
var pm1o2, rawP big.Int
|
||||||
@ -318,7 +317,7 @@ func TestIsNonQuadRes(t *testing.T) {
|
|||||||
rawP.SetString("0x65b48e8f740f89bffc8ab0d15e3e4c4ab42d083aedc88c425afbfcc69322c9cda7aac6c567f35507516730cc1f0b4f25c2721bf457aca8351b81b90533c6c87b", 0)
|
rawP.SetString("0x65b48e8f740f89bffc8ab0d15e3e4c4ab42d083aedc88c425afbfcc69322c9cda7aac6c567f35507516730cc1f0b4f25c2721bf457aca8351b81b90533c6c87b", 0)
|
||||||
|
|
||||||
// There is 641 quadratic residues in this range
|
// There is 641 quadratic residues in this range
|
||||||
for i := uint64(1); i < 1000; i++ {
|
for i := uint64(1); i < uint64(numIter); i++ {
|
||||||
n.SetUint64(i)
|
n.SetUint64(i)
|
||||||
n.Exp(&n, &pm1o2, &rawP)
|
n.Exp(&n, &pm1o2, &rawP)
|
||||||
// exp == 1 iff n is quadratic non-residue
|
// exp == 1 iff n is quadratic non-residue
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
mrand "math/rand"
|
mrand "math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Commonly used variables
|
|
||||||
var (
|
var (
|
||||||
// Number of interations
|
// Number of interations
|
||||||
numIter = 10
|
numIter = 10
|
||||||
@ -16,6 +15,8 @@ var (
|
|||||||
zeroFp512 = fp{}
|
zeroFp512 = fp{}
|
||||||
// One in fp
|
// One in fp
|
||||||
oneFp512 = fp{1, 0, 0, 0, 0, 0, 0, 0}
|
oneFp512 = fp{1, 0, 0, 0, 0, 0, 0, 0}
|
||||||
|
// file with KAT vectors
|
||||||
|
katFile = "testdata/csidh_testvectors.dat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Converts dst to Montgomery if "toMont==true" or from Montgomery domain otherwise.
|
// Converts dst to Montgomery if "toMont==true" or from Montgomery domain otherwise.
|
||||||
@ -41,14 +42,14 @@ func fp2S(v fp) string {
|
|||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
// zeroize fp
|
// zeroize fp.
|
||||||
func zero(v *fp) {
|
func zero(v *fp) {
|
||||||
for i := range *v {
|
for i := range *v {
|
||||||
v[i] = 0
|
v[i] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns random value in a range (0,p)
|
// returns random value in a range (0,p).
|
||||||
func randomFp() fp {
|
func randomFp() fp {
|
||||||
var u fp
|
var u fp
|
||||||
for i := 0; i < 8; i++ {
|
for i := 0; i < 8; i++ {
|
||||||
@ -57,25 +58,8 @@ func randomFp() fp {
|
|||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
// x<y: <0
|
// return x==y for fp.
|
||||||
// x>y: >0
|
func eqFp(l, r *fp) bool {
|
||||||
// x==y: 0
|
|
||||||
func cmp512(x, y *fp) int {
|
|
||||||
if len(*x) == len(*y) {
|
|
||||||
for i := len(*x) - 1; i >= 0; i-- {
|
|
||||||
if x[i] < y[i] {
|
|
||||||
return -1
|
|
||||||
} else if x[i] > y[i] {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return len(*x) - len(*y)
|
|
||||||
}
|
|
||||||
|
|
||||||
// return x==y for fp
|
|
||||||
func ceqFp(l, r *fp) bool {
|
|
||||||
for idx := range l {
|
for idx := range l {
|
||||||
if l[idx] != r[idx] {
|
if l[idx] != r[idx] {
|
||||||
return false
|
return false
|
||||||
@ -84,19 +68,14 @@ func ceqFp(l, r *fp) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// return x==y for point
|
// return x==y for point.
|
||||||
func ceqpoint(l, r *point) bool {
|
func ceqpoint(l, r *point) bool {
|
||||||
return ceqFp(&l.x, &r.x) && ceqFp(&l.z, &r.z)
|
return eqFp(&l.x, &r.x) && eqFp(&l.z, &r.z)
|
||||||
}
|
|
||||||
|
|
||||||
// return x==y
|
|
||||||
func ceq512(x, y *fp) bool {
|
|
||||||
return cmp512(x, y) == 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts src to big.Int. Function assumes that src is a slice of uint64
|
// Converts src to big.Int. Function assumes that src is a slice of uint64
|
||||||
// values encoded in little-endian byte order.
|
// values encoded in little-endian byte order.
|
||||||
func intSetU64(dst *big.Int, src []uint64) *big.Int {
|
func intSetU64(dst *big.Int, src []uint64) {
|
||||||
var tmp big.Int
|
var tmp big.Int
|
||||||
|
|
||||||
dst.SetUint64(0)
|
dst.SetUint64(0)
|
||||||
@ -105,7 +84,6 @@ func intSetU64(dst *big.Int, src []uint64) *big.Int {
|
|||||||
tmp.Lsh(&tmp, uint(i*64))
|
tmp.Lsh(&tmp, uint(i*64))
|
||||||
dst.Add(dst, &tmp)
|
dst.Add(dst, &tmp)
|
||||||
}
|
}
|
||||||
return dst
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts src to an array of uint64 values encoded in little-endian
|
// Converts src to an array of uint64 values encoded in little-endian
|
||||||
@ -140,7 +118,7 @@ func toNormX(point *point) big.Int {
|
|||||||
return bigDnt
|
return bigDnt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts string to fp element in Montgomery domain of cSIDH-512
|
// Converts string to fp element in Montgomery domain of cSIDH-512.
|
||||||
func toFp(num string) fp {
|
func toFp(num string) fp {
|
||||||
var tmp big.Int
|
var tmp big.Int
|
||||||
var ok bool
|
var ok bool
|
||||||
|
Loading…
Reference in New Issue
Block a user