espelhamento de
https://github.com/henrydcase/nobs.git
sincronizado 2024-11-26 00:51:22 +00:00
csidh: cosmettic updates
Esse commit está contido em:
pai
7d891c7eb8
commit
91945fde1f
@ -7,7 +7,7 @@ import (
|
||||
// 511-bit number representing prime field element GF(p)
|
||||
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 {
|
||||
x fp
|
||||
z fp
|
||||
@ -27,17 +27,20 @@ type fpRngGen struct {
|
||||
// Defines operations on public key
|
||||
type PublicKey struct {
|
||||
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
|
||||
}
|
||||
|
||||
// Defines operations on private key
|
||||
type PrivateKey struct {
|
||||
fpRngGen
|
||||
// private key is a set of integers randomly
|
||||
// each sampled from a range [-5, 5].
|
||||
e [PrivateKeySize]int8
|
||||
}
|
||||
|
||||
// randFp generates random element from Fp
|
||||
// randFp generates random element from Fp.
|
||||
func (s *fpRngGen) randFp(v *fp, rng io.Reader) {
|
||||
mask := uint64(1<<(pbits%limbBitSize)) - 1
|
||||
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 r1, d1, r2, d2 bool
|
||||
|
||||
if (halfR - halfL) == 1 {
|
||||
// base case
|
||||
if !p.z.isZero() {
|
||||
var tmp = fp{primes[halfL]}
|
||||
xMul512(p, p, a, &tmp)
|
||||
xMul(p, p, a, &tmp)
|
||||
|
||||
if !p.z.isZero() {
|
||||
// order does not divide p+1
|
||||
return false, true
|
||||
// order does not divide p+1 -> ordinary curve
|
||||
return true, false
|
||||
}
|
||||
|
||||
mul512(order, order, primes[halfL])
|
||||
if sub512(&tmp, &fourSqrtP, order) == 1 {
|
||||
// order > 4*sqrt(p) -> supersingular
|
||||
if isLess(&fourSqrtP, order) {
|
||||
// order > 4*sqrt(p) -> supersingular curve
|
||||
return true, true
|
||||
}
|
||||
}
|
||||
@ -86,21 +97,27 @@ func cofactorMultiples(p *point, a *coeff, halfL, halfR int, order *fp) (bool, b
|
||||
// perform another recursive step
|
||||
mid := halfL + ((halfR - halfL + 1) / 2)
|
||||
var mulL, mulR = fp{1}, fp{1}
|
||||
// compute u = primes_1 * ... * primes_m
|
||||
for i := halfL; i < mid; i++ {
|
||||
mul512(&mulR, &mulR, primes[i])
|
||||
}
|
||||
// compute v = primes_m+1 * ... * primes_n
|
||||
for i := mid; i < halfR; i++ {
|
||||
mul512(&mulL, &mulL, primes[i])
|
||||
}
|
||||
|
||||
xMul512(&Q, p, a, &mulR)
|
||||
xMul512(p, p, a, &mulL)
|
||||
// calculate Q_i
|
||||
xMul(&Q, p, a, &mulR)
|
||||
xMul(p, p, a, &mulL)
|
||||
|
||||
r1, d1 = cofactorMultiples(&Q, a, mid, halfR, order)
|
||||
r2, d2 = cofactorMultiples(p, a, halfL, mid, order)
|
||||
return r1 || r2, d1 || d2
|
||||
d1, r1 = cofactorMul(&Q, a, mid, halfR, order)
|
||||
d2, r2 = cofactorMul(p, a, halfL, mid, order)
|
||||
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) {
|
||||
var k [2]fp
|
||||
var e [2][primeCount]uint8
|
||||
@ -140,7 +157,7 @@ func groupAction(pub *PublicKey, prv *PrivateKey, rng io.Reader) {
|
||||
continue
|
||||
}
|
||||
|
||||
xMul512(&P, &P, &A, &k[sign])
|
||||
xMul(&P, &P, &A, &k[sign])
|
||||
done[sign] = true
|
||||
|
||||
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() {
|
||||
isom(&P, &A, &K, v)
|
||||
xIso(&P, &A, &K, v)
|
||||
e[sign][i] = e[sign][i] - 1
|
||||
if e[sign][i] == 0 {
|
||||
mul512(&k[sign], &k[sign], primes[i])
|
||||
@ -225,7 +242,7 @@ func GeneratePrivateKey(key *PrivateKey, rng io.Reader) error {
|
||||
|
||||
// Public key operations
|
||||
|
||||
// Assumes key is in Montgomery domain
|
||||
// Assumes key is in Montgomery domain.
|
||||
func (c *PublicKey) Import(key []byte) bool {
|
||||
if len(key) != numWords*limbByteSize {
|
||||
return false
|
||||
@ -238,7 +255,7 @@ func (c *PublicKey) Import(key []byte) bool {
|
||||
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 {
|
||||
if len(out) != numWords*limbByteSize {
|
||||
return false
|
||||
@ -251,44 +268,45 @@ func (c *PublicKey) Export(out []byte) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *PublicKey) reset() {
|
||||
for i := range c.a {
|
||||
c.a[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func GeneratePublicKey(pub *PublicKey, prv *PrivateKey, rng io.Reader) {
|
||||
pub.reset()
|
||||
for i := range pub.a {
|
||||
pub.a[i] = 0
|
||||
}
|
||||
groupAction(pub, prv, rng)
|
||||
}
|
||||
|
||||
// Validate does public key validation. It returns true if
|
||||
// a 'pub' is a valid cSIDH public key, otherwise false.
|
||||
// Validate returns true if 'pub' is a valid cSIDH public key,
|
||||
// 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 {
|
||||
// Check if in range
|
||||
if !isLess(&pub.a, &p) {
|
||||
return false
|
||||
}
|
||||
|
||||
// j-invariant for montgomery curves is something like
|
||||
// j = (256*(A^3-3)^3)/(A^2 - 4), so any |A| = 2 is invalid
|
||||
// Check if pub represents a smooth Montgomery curve.
|
||||
if pub.a.equal(&two) || pub.a.equal(&twoNeg) {
|
||||
return false
|
||||
}
|
||||
|
||||
// P must have big enough order to prove supersingularity. The
|
||||
// probability that this loop will be repeated is negligible.
|
||||
// Check if pub represents a supersingular curve.
|
||||
for {
|
||||
var P point
|
||||
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)
|
||||
P.z = one
|
||||
|
||||
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 {
|
||||
return res
|
||||
}
|
||||
@ -297,6 +315,9 @@ func Validate(pub *PublicKey, rng io.Reader) bool {
|
||||
|
||||
// DeriveSecret computes a cSIDH shared secret. If successful, returns true
|
||||
// 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 {
|
||||
if !Validate(pub, rng) {
|
||||
return false
|
||||
|
@ -2,14 +2,12 @@ package csidh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
crand "crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
crand "crypto/rand"
|
||||
|
||||
"github.com/henrydcase/nobs/drbg"
|
||||
)
|
||||
|
||||
@ -30,6 +28,20 @@ var StatusValues = map[int]string{
|
||||
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 {
|
||||
ID int `json:"Id"`
|
||||
Pk1 string `json:"Pk1"`
|
||||
@ -39,10 +51,6 @@ type TestVector struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type TestVectors struct {
|
||||
Vectors []TestVector `json:"Vectors"`
|
||||
}
|
||||
|
||||
var rng *drbg.CtrDrbg
|
||||
|
||||
func init() {
|
||||
@ -56,6 +64,10 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
type TestVectors struct {
|
||||
Vectors []TestVector `json:"Vectors"`
|
||||
}
|
||||
|
||||
func TestCompare64(t *testing.T) {
|
||||
const s uint64 = 0xFFFFFFFFFFFFFFFF
|
||||
var val1 = fp{0, 2, 3, 4, 5, 6, 7, 8}
|
||||
@ -82,20 +94,17 @@ func TestEphemeralKeyExchange(t *testing.T) {
|
||||
prv1.Import(prvBytes1)
|
||||
GeneratePublicKey(&pub1, &prv1, rng)
|
||||
|
||||
GeneratePrivateKey(&prv2, rng)
|
||||
checkErr(t, GeneratePrivateKey(&prv2, rng), "PrivateKey generation failed")
|
||||
GeneratePublicKey(&pub2, &prv2, rng)
|
||||
|
||||
if !DeriveSecret(&ss1, &pub1, &prv2, rng) {
|
||||
t.Errorf("Derivation failed\n")
|
||||
}
|
||||
|
||||
if !DeriveSecret(&ss2, &pub2, &prv1, rng) {
|
||||
t.Errorf("Derivation failed\n")
|
||||
}
|
||||
Ok(t,
|
||||
DeriveSecret(&ss1, &pub1, &prv2, rng),
|
||||
"Derivation failed")
|
||||
Ok(t,
|
||||
DeriveSecret(&ss2, &pub2, &prv1, rng),
|
||||
"Derivation failed")
|
||||
|
||||
if !bytes.Equal(ss1[:], ss2[:]) {
|
||||
fmt.Printf("%X\n", ss1)
|
||||
fmt.Printf("%X\n", ss2)
|
||||
t.Error("ss1 != ss2")
|
||||
}
|
||||
}
|
||||
@ -104,7 +113,7 @@ func TestPrivateKeyExportImport(t *testing.T) {
|
||||
var buf [37]byte
|
||||
for i := 0; i < numIter; i++ {
|
||||
var prv1, prv2 PrivateKey
|
||||
GeneratePrivateKey(&prv1, rng)
|
||||
checkErr(t, GeneratePrivateKey(&prv1, rng), "PrivateKey generation failed")
|
||||
prv1.Export(buf[:])
|
||||
prv2.Import(buf[:])
|
||||
|
||||
@ -153,7 +162,7 @@ func TestPublicKeyExportImport(t *testing.T) {
|
||||
for i := 0; i < numIter; i++ {
|
||||
var prv PrivateKey
|
||||
var pub1, pub2 PublicKey
|
||||
GeneratePrivateKey(&prv, rng)
|
||||
checkErr(t, GeneratePrivateKey(&prv, rng), "PrivateKey generation failed")
|
||||
GeneratePublicKey(&pub1, &prv, rng)
|
||||
|
||||
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) {
|
||||
var tests TestVectors
|
||||
var testVectorFile string
|
||||
var katFile string
|
||||
|
||||
// Helper checks if e==true and reports an error if not.
|
||||
checkExpr := func(e bool, vec *TestVector, t *testing.T, msg string) {
|
||||
@ -179,9 +188,9 @@ func TestKAT(t *testing.T) {
|
||||
}
|
||||
|
||||
if hasADXandBMI2 {
|
||||
testVectorFile = "testdata/csidh_testvectors.dat"
|
||||
katFile = "testdata/csidh_testvectors.dat"
|
||||
} else {
|
||||
testVectorFile = "testdata/csidh_testvectors_small.dat"
|
||||
katFile = "testdata/csidh_testvectors_small.dat"
|
||||
}
|
||||
|
||||
// checkSharedSecret implements nominal case - imports asymmetric keys for
|
||||
@ -197,39 +206,24 @@ func TestKAT(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkExpr(
|
||||
prv1.Import(prBuf[:]),
|
||||
vec, t, "PrivateKey wrong")
|
||||
|
||||
checkExpr(prv1.Import(prBuf[:]), vec, t, "PrivateKey wrong")
|
||||
pkBuf, err := hex.DecodeString(vec.Pk1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkExpr(
|
||||
pub1.Import(pkBuf[:]),
|
||||
vec, t, "PublicKey 1 wrong")
|
||||
|
||||
checkExpr(pub1.Import(pkBuf[:]), vec, t, "PublicKey 1 wrong")
|
||||
pkBuf, err = hex.DecodeString(vec.Pk2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkExpr(
|
||||
pub2.Import(pkBuf[:]),
|
||||
vec, t, "PublicKey 2 wrong")
|
||||
|
||||
checkExpr(
|
||||
DeriveSecret(&ss, &pub2, &prv1, rng),
|
||||
vec, t, "Error when deriving key")
|
||||
|
||||
checkExpr(pub2.Import(pkBuf[:]), vec, t, "PublicKey 2 wrong")
|
||||
checkExpr(DeriveSecret(&ss, &pub2, &prv1, rng), vec, t, "Error when deriving key")
|
||||
ssExp, err := hex.DecodeString(vec.Ss)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkExpr(
|
||||
bytes.Equal(ss[:], ssExp) == (status == Valid),
|
||||
vec, t, "Unexpected value of shared secret")
|
||||
checkExpr(bytes.Equal(ss[:], ssExp) == (status == Valid), vec, t, "Unexpected value of shared secret")
|
||||
}
|
||||
|
||||
// checkPublicKey1 imports public and private key for one party A
|
||||
// and tries to generate public key for a private key. After that
|
||||
// it compares generated key to a key from test vector. Comparison
|
||||
@ -254,7 +248,7 @@ func TestKAT(t *testing.T) {
|
||||
vec, t, "PrivateKey wrong")
|
||||
|
||||
// Generate public key
|
||||
GeneratePrivateKey(&prv, rng)
|
||||
checkErr(t, GeneratePrivateKey(&prv, rng), "PrivateKey generation failed")
|
||||
pub.Export(pubBytesGot[:])
|
||||
|
||||
// pubBytesGot must be different than pubBytesExp
|
||||
@ -262,27 +256,23 @@ func TestKAT(t *testing.T) {
|
||||
!bytes.Equal(pubBytesGot[:], pubBytesExp),
|
||||
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
|
||||
// import public key for B and ensure that import succeeds in case
|
||||
// status is "Valid" and fails otherwise.
|
||||
checkPublicKey2 := func(vec *TestVector, t *testing.T, status int) {
|
||||
var pub PublicKey
|
||||
|
||||
pubBytesExp, err := hex.DecodeString(vec.Pk2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Import validates an input, so it must fail
|
||||
pub.Import(pubBytesExp[:])
|
||||
checkExpr(
|
||||
Validate(&pub, rng) == (status == Valid || status == ValidPublicKey2),
|
||||
vec, t, "PublicKey has been validated correctly")
|
||||
}
|
||||
|
||||
// Load test data
|
||||
file, err := os.Open(testVectorFile)
|
||||
file, err := os.Open(katFile)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
@ -290,9 +280,14 @@ func TestKAT(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
// 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 {
|
||||
case StatusValues[Valid]:
|
||||
checkSharedSecret(&test, t, Valid)
|
||||
@ -314,23 +309,23 @@ func TestKAT(t *testing.T) {
|
||||
var prv1, prv2 PrivateKey
|
||||
var pub1, pub2 PublicKey
|
||||
|
||||
// Private key generation
|
||||
// Private key generation.
|
||||
func BenchmarkGeneratePrivate(b *testing.B) {
|
||||
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) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
var pub PublicKey
|
||||
GeneratePrivateKey(&prv1, rng)
|
||||
_ = GeneratePrivateKey(&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) {
|
||||
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)
|
||||
@ -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) {
|
||||
var tmp [64]byte
|
||||
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) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
GeneratePrivateKey(&prv1, rng)
|
||||
_ = GeneratePrivateKey(&prv1, rng)
|
||||
GeneratePublicKey(&pub1, &prv1, rng)
|
||||
Validate(&pub1, rng)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate some keys and benchmark derive
|
||||
// Generate some keys and benchmark derive.
|
||||
func BenchmarkDerive(b *testing.B) {
|
||||
var ss [64]byte
|
||||
|
||||
GeneratePrivateKey(&prv1, rng)
|
||||
_ = GeneratePrivateKey(&prv1, rng)
|
||||
GeneratePublicKey(&pub1, &prv1, rng)
|
||||
|
||||
GeneratePrivateKey(&prv2, rng)
|
||||
_ = GeneratePrivateKey(&prv2, rng)
|
||||
GeneratePublicKey(&pub2, &prv2, rng)
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
DeriveSecret(&ss, &pub2, &prv1, rng)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmarks both - key generation and derivation
|
||||
// Benchmarks both - key generation and derivation.
|
||||
func BenchmarkDeriveGenerated(b *testing.B) {
|
||||
var ss [64]byte
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
GeneratePrivateKey(&prv1, rng)
|
||||
_ = GeneratePrivateKey(&prv1, rng)
|
||||
GeneratePublicKey(&pub1, &prv1, rng)
|
||||
|
||||
GeneratePrivateKey(&prv2, rng)
|
||||
_ = GeneratePrivateKey(&prv2, rng)
|
||||
GeneratePublicKey(&pub2, &prv2, rng)
|
||||
|
||||
DeriveSecret(&ss, &pub2, &prv1, rng)
|
||||
|
@ -1,10 +1,10 @@
|
||||
package csidh
|
||||
|
||||
// Implements differential arithmetic in P^1 for montgomery
|
||||
// curves a mapping: x(P),x(Q),x(P-Q) -> x(P+Q)
|
||||
// PaQ = P + Q
|
||||
// xAdd implements differential arithmetic in P^1 for Montgomery
|
||||
// curves E(x): x^3 + A*x^2 + x by using x-coordinate only arithmetic.
|
||||
// x(PaQ) = x(P) + x(Q) by using x(P-Q)
|
||||
// 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) {
|
||||
var t0, t1, t2, t3 fp
|
||||
addRdc(&t0, &P.x, &P.z)
|
||||
@ -21,8 +21,10 @@ func xAdd(PaQ, P, Q, PdQ *point) {
|
||||
mulRdc(&PaQ.z, &PdQ.x, &t3)
|
||||
}
|
||||
|
||||
// Q = 2*P on a montgomery curve E(x): x^3 + A*x^2 + x
|
||||
// It is correctly defined for all P != inf
|
||||
// xDbl implements point doubling on a Montgomery curve
|
||||
// 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) {
|
||||
var t0, t1, t2 fp
|
||||
addRdc(&t0, &P.x, &P.z)
|
||||
@ -40,8 +42,11 @@ func xDbl(Q, P, A *point) {
|
||||
mulRdc(&Q.z, &t0, &t2)
|
||||
}
|
||||
|
||||
// PaP = 2*P; PaQ = P+Q
|
||||
// PaP can override P and PaQ can override Q
|
||||
// xDblAdd implements combined doubling of point P
|
||||
// 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) {
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
// in swap) or 0 (results in no-swap).
|
||||
func cswappoint(P1, P2 *point, choice uint8) {
|
||||
@ -75,13 +80,11 @@ func cswappoint(P1, P2 *point, choice uint8) {
|
||||
cswap512(&P1.z, &P2.z, choice)
|
||||
}
|
||||
|
||||
// A uniform Montgomery ladder. co is A coefficient of
|
||||
// x^3 + A*x^2 + x curve. k MUST be > 0
|
||||
// xMul implements point multiplication with left-to-right Montgomery
|
||||
// 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 xMul512(kP, P *point, co *coeff, k *fp) {
|
||||
// Non-constant time!
|
||||
func xMul(kP, P *point, co *coeff, k *fp) {
|
||||
var A24 coeff
|
||||
var Q point
|
||||
var j uint
|
||||
@ -107,16 +110,23 @@ func xMul512(kP, P *point, co *coeff, k *fp) {
|
||||
for i := j; i > 0; {
|
||||
i--
|
||||
bit := uint8(k[i>>6] >> (i & 63) & 1)
|
||||
swap := prevBit ^ bit
|
||||
prevBit = bit
|
||||
cswappoint(&Q, &R, swap)
|
||||
cswappoint(&Q, &R, prevBit^bit)
|
||||
xDblAdd(&Q, &R, &Q, &R, P, &A24)
|
||||
prevBit = bit
|
||||
}
|
||||
cswappoint(&Q, &R, uint8(k[0]&1))
|
||||
*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 Q, prod point
|
||||
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})
|
||||
|
||||
// TODO: Not constant time.
|
||||
for i := uint64(1); i < order>>1; i++ {
|
||||
// NOTE: Not constant time.
|
||||
for i := uint64(1); i < kernOrder>>1; i++ {
|
||||
if i >= 2 {
|
||||
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)
|
||||
subRdc(&t2, &t0, &t1)
|
||||
mulRdc(&Q.z, &Q.z, &t2)
|
||||
|
||||
}
|
||||
|
||||
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.z, &img.z, &Q.z)
|
||||
|
||||
// coEd.a^order and coEd.c^order
|
||||
modExpRdc64(&coEd.a, &coEd.a, order)
|
||||
modExpRdc64(&coEd.c, &coEd.c, order)
|
||||
// coEd.a^kernOrder and coEd.c^kernOrder
|
||||
modExpRdc64(&coEd.a, &coEd.a, kernOrder)
|
||||
modExpRdc64(&coEd.c, &coEd.c, kernOrder)
|
||||
|
||||
// prod^8
|
||||
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)
|
||||
}
|
||||
|
||||
// evaluates x^3 + Ax^2 + x
|
||||
// montEval evaluates x^3 + Ax^2 + x.
|
||||
func montEval(res, A, x *fp) {
|
||||
var t fp
|
||||
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Actual test implementation
|
||||
// Actual test implementation.
|
||||
func TestXAdd(t *testing.T) {
|
||||
var P, Q, PdQ point
|
||||
var PaQ point
|
||||
@ -180,14 +180,14 @@ func TestXMul(t *testing.T) {
|
||||
checkXMul := func() {
|
||||
var kP point
|
||||
|
||||
xMul512(&kP, &P, &co, &k)
|
||||
xMul(&kP, &P, &co, &k)
|
||||
retKP := toNormX(&kP)
|
||||
if expKP.Cmp(&retKP) != 0 {
|
||||
t.Errorf("\nExp: %s\nGot: %s", expKP.Text(16), retKP.Text(16))
|
||||
}
|
||||
|
||||
// Check if first and second argument can overlap
|
||||
xMul512(&P, &P, &co, &k)
|
||||
xMul(&P, &P, &co, &k)
|
||||
retKP = toNormX(&P)
|
||||
if expKP.Cmp(&retKP) != 0 {
|
||||
t.Errorf("\nExp: %s\nGot: %s", expKP.Text(16), retKP.Text(16))
|
||||
@ -261,13 +261,13 @@ func TestMappointHardcoded3(t *testing.T) {
|
||||
var expP = point{
|
||||
x: fp{0x91aba9b39f280495, 0xfbd8ea69d2990aeb, 0xb03e1b8ed7fe3dba, 0x3d30a41499f08998, 0xb15a42630de9c606, 0xa7dd487fef16f5c8, 0x8673948afed8e968, 0x57ecc8710004cd4d},
|
||||
z: fp{0xce8819869a942526, 0xb98ca2ff79ef8969, 0xd49c9703743a1812, 0x21dbb090f9152e03, 0xbabdcac831b1adea, 0x8cee90762baa2ddd, 0xa0dd2ddcef809d96, 0x1de2a8887a32f19b}}
|
||||
isom(&P, &A, &K, k)
|
||||
if !ceqFp(&P.x, &expP.x) || !ceqFp(&P.z, &expP.z) {
|
||||
xIso(&P, &A, &K, k)
|
||||
if !eqFp(&P.x, &expP.x) || !eqFp(&P.z, &expP.z) {
|
||||
normP := toNormX(&P)
|
||||
normPExp := toNormX(&expP)
|
||||
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])
|
||||
}
|
||||
}
|
||||
@ -291,13 +291,13 @@ func TestMappointHardcoded5(t *testing.T) {
|
||||
x: fp{0x3b75fc94b2a6df2d, 0x96d53dc9b0e867a0, 0x22e87202421d274e, 0x30a361440697ee1a, 0x8b52ee078bdbddcd, 0x64425d500e6b934d, 0xf47d1f568f6df391, 0x5d9d3607431395ab},
|
||||
z: fp{0x746e02dafa040976, 0xcd408f2cddbf3a8e, 0xf643354e0e13a93f, 0x7c39ed96ce9a5e29, 0xfcdf26f1a1a550ca, 0x2fc8aafc4ca0a559, 0x5d204a2b14cf19ba, 0xbd2c3406762f05d}}
|
||||
|
||||
isom(&P, &A, &K, k)
|
||||
if !ceqFp(&P.x, &expP.x) || !ceqFp(&P.z, &expP.z) {
|
||||
xIso(&P, &A, &K, k)
|
||||
if !eqFp(&P.x, &expP.x) || !eqFp(&P.z, &expP.z) {
|
||||
normP := toNormX(&P)
|
||||
normPExp := toNormX(&expP)
|
||||
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])
|
||||
}
|
||||
}
|
||||
@ -317,7 +317,7 @@ func BenchmarkXMul(b *testing.B) {
|
||||
k = fp{0x7A36C930A83EFBD5, 0xD0E80041ED0DDF9F, 0x5AA17134F1B8F877, 0x975711EC94168E51, 0xB3CAD962BED4BAC5, 0x3026DFDD7E4F5687, 0xE67F91AB8EC9C3AF, 0x34671D3FD8C317E7}
|
||||
|
||||
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")
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
isom(&P, &co, &kern, k)
|
||||
xIso(&P, &co, &kern, k)
|
||||
}
|
||||
}
|
||||
|
11
dh/csidh/doc.go
Arquivo normal
11
dh/csidh/doc.go
Arquivo normal
@ -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.
|
||||
var (
|
||||
// Signals support for BMI2 (MULX)
|
||||
hasBMI2 = cpu.X86.HasBMI2
|
||||
hasBMI2 = cpu.X86.HasBMI2 //nolint
|
||||
// Signals support for ADX and BMI2
|
||||
hasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX
|
||||
)
|
||||
@ -20,7 +20,7 @@ var (
|
||||
// Constant time select.
|
||||
// if pick == 0xFF..FF (out = in1)
|
||||
// if pick == 0 (out = in2)
|
||||
// else out is undefined
|
||||
// else out is undefined.
|
||||
func ctPick64(which uint64, in1, in2 uint64) uint64 {
|
||||
return (in1 & which) | (in2 & ^which)
|
||||
}
|
||||
@ -41,7 +41,6 @@ func mulGeneric(r, x, y *fp) {
|
||||
var c, q uint64
|
||||
|
||||
for i := 0; i < numWords-1; i++ {
|
||||
|
||||
q = ((x[i] * y[0]) + s[0]) * pNegInv[0]
|
||||
mul576(&t1, &p, q)
|
||||
mul576(&t2, y, x[i])
|
||||
@ -143,7 +142,7 @@ func addRdc(r, x, y *fp) {
|
||||
r[7] = ctPick64(w, r[7], t[7])
|
||||
}
|
||||
|
||||
// r = x - y
|
||||
// r = x - y.
|
||||
func sub512(r, x, y *fp) uint64 {
|
||||
var c uint64
|
||||
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[1] = *b // b ^ 1
|
||||
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.
|
||||
mulRdc(&precomp[i], &precomp[i/2], &precomp[i/2]) // sqr
|
||||
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[6] = ctPick64(w, r[6], t[6])
|
||||
r[7] = ctPick64(w, r[7], t[7])
|
||||
|
||||
}
|
||||
|
||||
// modExpRdc does modular exponentation of 512-bit number.
|
||||
@ -280,7 +278,7 @@ func (v *fp) isZero() bool {
|
||||
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 {
|
||||
var r uint64
|
||||
for i := range v {
|
||||
|
@ -4,6 +4,9 @@ package csidh
|
||||
|
||||
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) {
|
||||
var c, h, l uint64
|
||||
|
||||
@ -33,10 +36,14 @@ func mul512(r, m1 *fp, m2 uint64) {
|
||||
r[6], c = bits.Add64(l, c, 0)
|
||||
c = h + c
|
||||
|
||||
h, l = bits.Mul64(m2, m1[7])
|
||||
_, l = bits.Mul64(m2, m1[7])
|
||||
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) {
|
||||
var c, h, l uint64
|
||||
|
||||
@ -72,6 +79,9 @@ func mul576(r *[9]uint64, m1 *fp, m2 uint64) {
|
||||
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) {
|
||||
var tmp uint64
|
||||
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.
|
||||
// Returned result r is already reduced and in Montgomery domain.
|
||||
func mulRdc(r, x, y *fp) {
|
||||
|
@ -39,14 +39,13 @@ func testFp512Mul3Nominal(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check if mul512 produces result
|
||||
// z = x*y mod 2^512
|
||||
// z = x*y mod 2^512.
|
||||
func TestFp512Mul3_Nominal(t *testing.T) {
|
||||
hasBMI2 = false
|
||||
testFp512Mul3Nominal(t)
|
||||
|
||||
resetCPUFeatures()
|
||||
testFp512Mul3Nominal(t)
|
||||
|
||||
}
|
||||
|
||||
func TestAddRdcRandom(t *testing.T) {
|
||||
@ -78,26 +77,26 @@ func TestAddRdcNominal(t *testing.T) {
|
||||
|
||||
tmp := oneFp512
|
||||
addRdc(&res, &tmp, &p)
|
||||
if !ceq512(&res, &tmp) {
|
||||
if !eqFp(&res, &tmp) {
|
||||
t.Errorf("Wrong value\n%X", res)
|
||||
}
|
||||
|
||||
tmp = zeroFp512
|
||||
addRdc(&res, &p, &p)
|
||||
if !ceq512(&res, &p) {
|
||||
if !eqFp(&res, &p) {
|
||||
t.Errorf("Wrong value\n%X", res)
|
||||
}
|
||||
|
||||
tmp = fp{1, 1, 1, 1, 1, 1, 1, 1}
|
||||
addRdc(&res, &p, &tmp)
|
||||
if !ceq512(&res, &tmp) {
|
||||
if !eqFp(&res, &tmp) {
|
||||
t.Errorf("Wrong value\n%X", res)
|
||||
}
|
||||
|
||||
tmp = fp{1, 1, 1, 1, 1, 1, 1, 1}
|
||||
exp := fp{2, 2, 2, 2, 2, 2, 2, 2}
|
||||
addRdc(&res, &tmp, &tmp)
|
||||
if !ceq512(&res, &exp) {
|
||||
if !eqFp(&res, &exp) {
|
||||
t.Errorf("Wrong value\n%X", res)
|
||||
}
|
||||
}
|
||||
@ -168,19 +167,19 @@ func TestCswap(t *testing.T) {
|
||||
|
||||
arg1cpy := arg1
|
||||
cswap512(&arg1, &arg2, 0)
|
||||
if !ceq512(&arg1, &arg1cpy) {
|
||||
if !eqFp(&arg1, &arg1cpy) {
|
||||
t.Error("cswap swapped")
|
||||
}
|
||||
|
||||
arg1cpy = arg1
|
||||
cswap512(&arg1, &arg2, 1)
|
||||
if ceq512(&arg1, &arg1cpy) {
|
||||
if eqFp(&arg1, &arg1cpy) {
|
||||
t.Error("cswap didn't swapped")
|
||||
}
|
||||
|
||||
arg1cpy = arg1
|
||||
cswap512(&arg1, &arg2, 0xF2)
|
||||
if ceq512(&arg1, &arg1cpy) {
|
||||
if eqFp(&arg1, &arg1cpy) {
|
||||
t.Error("cswap didn't swapped")
|
||||
}
|
||||
}
|
||||
@ -191,7 +190,7 @@ func TestSubRdc(t *testing.T) {
|
||||
// 1 - 1 mod P
|
||||
tmp := oneFp512
|
||||
subRdc(&res, &tmp, &tmp)
|
||||
if !ceq512(&res, &zeroFp512) {
|
||||
if !eqFp(&res, &zeroFp512) {
|
||||
t.Errorf("Wrong value\n%X", res)
|
||||
}
|
||||
zero(&res)
|
||||
@ -201,7 +200,7 @@ func TestSubRdc(t *testing.T) {
|
||||
exp[0]--
|
||||
|
||||
subRdc(&res, &zeroFp512, &oneFp512)
|
||||
if !ceq512(&res, &exp) {
|
||||
if !eqFp(&res, &exp) {
|
||||
t.Errorf("Wrong value\n%X\n%X", res, exp)
|
||||
}
|
||||
zero(&res)
|
||||
@ -210,13 +209,13 @@ func TestSubRdc(t *testing.T) {
|
||||
pMinusOne := p
|
||||
pMinusOne[0]--
|
||||
subRdc(&res, &p, &pMinusOne)
|
||||
if !ceq512(&res, &oneFp512) {
|
||||
if !eqFp(&res, &oneFp512) {
|
||||
t.Errorf("Wrong value\n[%X != %X]", res, oneFp512)
|
||||
}
|
||||
zero(&res)
|
||||
|
||||
subRdc(&res, &p, &oneFp512)
|
||||
if !ceq512(&res, &pMinusOne) {
|
||||
if !eqFp(&res, &pMinusOne) {
|
||||
t.Errorf("Wrong value\n[%X != %X]", res, pMinusOne)
|
||||
}
|
||||
}
|
||||
@ -245,28 +244,28 @@ func testMulRdc(t *testing.T) {
|
||||
// 0*0
|
||||
tmp := zeroFp512
|
||||
mulRdc(&res, &tmp, &tmp)
|
||||
if !ceq512(&res, &tmp) {
|
||||
if !eqFp(&res, &tmp) {
|
||||
t.Errorf("Wrong value\n%X", res)
|
||||
}
|
||||
|
||||
// 1*m1 == m1
|
||||
zero(&res)
|
||||
mulRdc(&res, &m1, &one)
|
||||
if !ceq512(&res, &m1) {
|
||||
if !eqFp(&res, &m1) {
|
||||
t.Errorf("Wrong value\n%X", res)
|
||||
}
|
||||
|
||||
// m1*m2 < p
|
||||
zero(&res)
|
||||
mulRdc(&res, &m1, &m2)
|
||||
if !ceq512(&res, &m1m2) {
|
||||
if !eqFp(&res, &m1m2) {
|
||||
t.Errorf("Wrong value\n%X", res)
|
||||
}
|
||||
|
||||
// m1*m1 > p
|
||||
zero(&res)
|
||||
mulRdc(&res, &m1, &m1)
|
||||
if !ceq512(&res, &m1m1) {
|
||||
if !eqFp(&res, &m1m1) {
|
||||
t.Errorf("Wrong value\n%X", res)
|
||||
}
|
||||
}
|
||||
@ -300,13 +299,13 @@ func TestModExp(t *testing.T) {
|
||||
// Perform modexp with our implementation
|
||||
modExpRdc512(&resFp, &baseFp, &expFp)
|
||||
|
||||
if !ceq512(&resFp, &resFpExp) {
|
||||
if !eqFp(&resFp, &resFpExp) {
|
||||
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) {
|
||||
var n, nMont big.Int
|
||||
var pm1o2, rawP big.Int
|
||||
@ -318,7 +317,7 @@ func TestIsNonQuadRes(t *testing.T) {
|
||||
rawP.SetString("0x65b48e8f740f89bffc8ab0d15e3e4c4ab42d083aedc88c425afbfcc69322c9cda7aac6c567f35507516730cc1f0b4f25c2721bf457aca8351b81b90533c6c87b", 0)
|
||||
|
||||
// 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.Exp(&n, &pm1o2, &rawP)
|
||||
// exp == 1 iff n is quadratic non-residue
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
mrand "math/rand"
|
||||
)
|
||||
|
||||
// Commonly used variables
|
||||
var (
|
||||
// Number of interations
|
||||
numIter = 10
|
||||
@ -16,6 +15,8 @@ var (
|
||||
zeroFp512 = fp{}
|
||||
// One in fp
|
||||
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.
|
||||
@ -41,14 +42,14 @@ func fp2S(v fp) string {
|
||||
return str
|
||||
}
|
||||
|
||||
// zeroize fp
|
||||
// zeroize fp.
|
||||
func zero(v *fp) {
|
||||
for i := range *v {
|
||||
v[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// returns random value in a range (0,p)
|
||||
// returns random value in a range (0,p).
|
||||
func randomFp() fp {
|
||||
var u fp
|
||||
for i := 0; i < 8; i++ {
|
||||
@ -57,25 +58,8 @@ func randomFp() fp {
|
||||
return u
|
||||
}
|
||||
|
||||
// x<y: <0
|
||||
// x>y: >0
|
||||
// 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 {
|
||||
// return x==y for fp.
|
||||
func eqFp(l, r *fp) bool {
|
||||
for idx := range l {
|
||||
if l[idx] != r[idx] {
|
||||
return false
|
||||
@ -84,19 +68,14 @@ func ceqFp(l, r *fp) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// return x==y for point
|
||||
// return x==y for point.
|
||||
func ceqpoint(l, r *point) bool {
|
||||
return ceqFp(&l.x, &r.x) && ceqFp(&l.z, &r.z)
|
||||
}
|
||||
|
||||
// return x==y
|
||||
func ceq512(x, y *fp) bool {
|
||||
return cmp512(x, y) == 0
|
||||
return eqFp(&l.x, &r.x) && eqFp(&l.z, &r.z)
|
||||
}
|
||||
|
||||
// Converts src to big.Int. Function assumes that src is a slice of uint64
|
||||
// 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
|
||||
|
||||
dst.SetUint64(0)
|
||||
@ -105,7 +84,6 @@ func intSetU64(dst *big.Int, src []uint64) *big.Int {
|
||||
tmp.Lsh(&tmp, uint(i*64))
|
||||
dst.Add(dst, &tmp)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Converts src to an array of uint64 values encoded in little-endian
|
||||
@ -140,7 +118,7 @@ func toNormX(point *point) big.Int {
|
||||
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 {
|
||||
var tmp big.Int
|
||||
var ok bool
|
||||
|
Carregando…
Referência em uma nova issue
Block a user