1
0
mirror of https://github.com/henrydcase/nobs.git synced 2024-11-26 17:11:22 +00:00
nobs/dh/csidh/utils_test.go
Kris Kwiatkowski 7efbbf4745 cSIDH-511: (#26)
Implementation of Commutative Supersingular Isogeny Diffie Hellman,
based on "A faster way to CSIDH" paper (2018/782).

* For fast isogeny calculation, implementation converts a curve from
  Montgomery to Edwards. All calculations are done on Edwards curve
  and then converted back to Montgomery.
* As multiplication in a field Fp511 is most expensive operation
  the implementation contains multiple multiplications. It has
  most performant, assembly implementation which uses BMI2 and
  ADOX/ADCX instructions for modern CPUs. It also contains
  slower implementation which will run on older CPUs

* Benchmarks (Intel SkyLake):

  BenchmarkGeneratePrivate   	    6459	    172213 ns/op	       0 B/op	       0 allocs/op
  BenchmarkGenerateKeyPair   	      25	  45800356 ns/op	       0 B/op	       0 allocs/op
  BenchmarkValidate          	     297	   3915983 ns/op	       0 B/op	       0 allocs/op
  BenchmarkValidateRandom    	  184683	      6231 ns/op	       0 B/op	       0 allocs/op
  BenchmarkValidateGenerated 	      25	  48481306 ns/op	       0 B/op	       0 allocs/op
  BenchmarkDerive            	      19	  60928763 ns/op	       0 B/op	       0 allocs/op
  BenchmarkDeriveGenerated   	       8	 137342421 ns/op	       0 B/op	       0 allocs/op
  BenchmarkXMul              	    2311	    494267 ns/op	       1 B/op	       0 allocs/op
  BenchmarkXAdd              	 2396754	       501 ns/op	       0 B/op	       0 allocs/op
  BenchmarkXDbl              	 2072690	       571 ns/op	       0 B/op	       0 allocs/op
  BenchmarkIsom              	   78004	     15171 ns/op	       0 B/op	       0 allocs/op
  BenchmarkFp512Sub          	224635152	         5.33 ns/op	       0 B/op	       0 allocs/op
  BenchmarkFp512Mul          	246633255	         4.90 ns/op	       0 B/op	       0 allocs/op
  BenchmarkCSwap             	233228547	         5.10 ns/op	       0 B/op	       0 allocs/op
  BenchmarkAddRdc            	87348240	        12.6 ns/op	       0 B/op	       0 allocs/op
  BenchmarkSubRdc            	95112787	        11.7 ns/op	       0 B/op	       0 allocs/op
  BenchmarkModExpRdc         	   25436	     46878 ns/op	       0 B/op	       0 allocs/op
  BenchmarkMulBmiAsm         	19527573	        60.1 ns/op	       0 B/op	       0 allocs/op
  BenchmarkMulGeneric        	 7117650	       164 ns/op	       0 B/op	       0 allocs/op

* Go code has very similar performance when compared to C
  implementation.
  Results from sidh_torturer (4e2996e12d68364761064341cbe1d1b47efafe23)
  github.com:henrydcase/sidh-torture/csidh

  | TestName         |Go        | C        |
  |------------------|----------|----------|
  |TestSharedSecret  | 57.95774 | 57.91092 |
  |TestKeyGeneration | 62.23614 | 58.12980 |
  |TestSharedSecret  | 55.28988 | 57.23132 |
  |TestKeyGeneration | 61.68745 | 58.66396 |
  |TestSharedSecret  | 63.19408 | 58.64774 |
  |TestKeyGeneration | 62.34022 | 61.62539 |
  |TestSharedSecret  | 62.85453 | 68.74503 |
  |TestKeyGeneration | 52.58518 | 58.40115 |
  |TestSharedSecret  | 50.77081 | 61.91699 |
  |TestKeyGeneration | 59.91843 | 61.09266 |
  |TestSharedSecret  | 59.97962 | 62.98151 |
  |TestKeyGeneration | 64.57525 | 56.22863 |
  |TestSharedSecret  | 56.40521 | 55.77447 |
  |TestKeyGeneration | 67.85850 | 58.52604 |
  |TestSharedSecret  | 60.54290 | 65.14052 |
  |TestKeyGeneration | 65.45766 | 58.42823 |

  On average Go implementation is 2% faster.
2019-11-25 15:03:29 +00:00

157 lines
2.8 KiB
Go

package csidh
import (
"fmt"
"math/big"
mrand "math/rand"
)
// Commonly used variables
var (
// Number of interations
numIter = 10
// Modulus
modulus, _ = new(big.Int).SetString(fp2S(p), 16)
// Zero in fp
zeroFp512 = fp{}
// One in fp
oneFp512 = fp{1, 0, 0, 0, 0, 0, 0, 0}
)
// Converts dst to Montgomery if "toMont==true" or from Montgomery domain otherwise.
func toMont(dst *big.Int, toMont bool) {
var bigP, bigR big.Int
intSetU64(&bigP, p[:])
bigR.SetUint64(1)
bigR.Lsh(&bigR, 512)
if !toMont {
bigR.ModInverse(&bigR, &bigP)
}
dst.Mul(dst, &bigR)
dst.Mod(dst, &bigP)
}
func fp2S(v fp) string {
var str string
for i := 0; i < 8; i++ {
str = fmt.Sprintf("%016x", v[i]) + str
}
return str
}
// zeroize fp
func zero(v *fp) {
for i := range *v {
v[i] = 0
}
}
// returns random value in a range (0,p)
func randomFp() fp {
var u fp
for i := 0; i < 8; i++ {
u[i] = mrand.Uint64()
}
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 {
for idx := range l {
if l[idx] != r[idx] {
return false
}
}
return true
}
// 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
}
// 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 {
var tmp big.Int
dst.SetUint64(0)
for i := range src {
tmp.SetUint64(src[i])
tmp.Lsh(&tmp, uint(i*64))
dst.Add(dst, &tmp)
}
return dst
}
// Converts src to an array of uint64 values encoded in little-endian
// byte order.
func intGetU64(src *big.Int) []uint64 {
var tmp, mod big.Int
dst := make([]uint64, (src.BitLen()/64)+1)
u64 := uint64(0)
u64--
mod.SetUint64(u64)
for i := 0; i < (src.BitLen()/64)+1; i++ {
tmp.Set(src)
tmp.Rsh(&tmp, uint(i)*64)
tmp.And(&tmp, &mod)
dst[i] = tmp.Uint64()
}
return dst
}
// Returns projective coordinate X of normalized EC 'point' (point.x / point.z).
func toNormX(point *point) big.Int {
var bigP, bigDnt, bigDor big.Int
intSetU64(&bigP, p[:])
intSetU64(&bigDnt, point.x[:])
intSetU64(&bigDor, point.z[:])
bigDor.ModInverse(&bigDor, &bigP)
bigDnt.Mul(&bigDnt, &bigDor)
bigDnt.Mod(&bigDnt, &bigP)
return bigDnt
}
// Converts string to fp element in Montgomery domain of cSIDH-512
func toFp(num string) fp {
var tmp big.Int
var ok bool
var ret fp
_, ok = tmp.SetString(num, 0)
if !ok {
panic("Can't parse a number")
}
toMont(&tmp, true)
copy(ret[:], intGetU64(&tmp))
return ret
}