Files
crypto/curve25519/curve25519_test.go
T
Filippo Valsorda 3497b51f5e curve25519: replace field implementation with filippo.io/edwards25519
This imports the crypto/ed25519/internal/edwards25519/field package from
CL 276272, and uses it in x/crypto/curve25519.

The ScalarMult code was ported 1:1 from curve25519_generic.go.

                                old code lines     new code lines

Go                              896                463
Assembly (manually written)     1772 (1772)        362 (34)

43% performance loss on amd64, 33% loss on 386, and 45% gain on arm64.
Feels worth it to remove 1700 lines of manually written assembly.

Apple M1

name               old time/op  new time/op  delta
X25519Basepoint-8  85.0µs ± 1%  46.4µs ± 0%  -45.39%  (p=0.000 n=10+9)
X25519-8           84.4µs ± 0%  46.7µs ± 2%  -44.76%  (p=0.000 n=8+9)

Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz

name               old time/op  new time/op  delta
X25519Basepoint-4  42.6µs ± 1%  60.9µs ± 1%  +43.22%  (p=0.000 n=9+10)
X25519-4           42.5µs ± 1%  60.9µs ± 0%  +43.17%  (p=0.000 n=9+9)

Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz [GOARCH=386]

name               old time/op  new time/op  delta
X25519Basepoint-4   530µs ± 1%   703µs ± 1%  +32.81%  (p=0.000 n=10+10)
X25519-4            530µs ± 1%   706µs ± 1%  +33.18%  (p=0.000 n=10+10)

Change-Id: I1dc62a6a3a3e417a1366ff873c475087a0395124
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/315269
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>
Trust: Katie Hockman <katie@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>
2021-05-05 21:26:54 +00:00

141 lines
2.9 KiB
Go

// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package curve25519
import (
"bytes"
"crypto/rand"
"fmt"
"testing"
)
const expectedHex = "89161fde887b2b53de549af483940106ecc114d6982daa98256de23bdf77661a"
func TestX25519Basepoint(t *testing.T) {
x := make([]byte, 32)
x[0] = 1
for i := 0; i < 200; i++ {
var err error
x, err = X25519(x, Basepoint)
if err != nil {
t.Fatal(err)
}
}
result := fmt.Sprintf("%x", x)
if result != expectedHex {
t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
}
}
func TestLowOrderPoints(t *testing.T) {
scalar := make([]byte, ScalarSize)
if _, err := rand.Read(scalar); err != nil {
t.Fatal(err)
}
for i, p := range lowOrderPoints {
out, err := X25519(scalar, p)
if err == nil {
t.Errorf("%d: expected error, got nil", i)
}
if out != nil {
t.Errorf("%d: expected nil output, got %x", i, out)
}
}
}
func TestTestVectors(t *testing.T) {
t.Run("Legacy", func(t *testing.T) { testTestVectors(t, ScalarMult) })
t.Run("X25519", func(t *testing.T) {
testTestVectors(t, func(dst, scalar, point *[32]byte) {
out, err := X25519(scalar[:], point[:])
if err != nil {
t.Fatal(err)
}
copy(dst[:], out)
})
})
}
func testTestVectors(t *testing.T, scalarMult func(dst, scalar, point *[32]byte)) {
for _, tv := range testVectors {
var got [32]byte
scalarMult(&got, &tv.In, &tv.Base)
if !bytes.Equal(got[:], tv.Expect[:]) {
t.Logf(" in = %x", tv.In)
t.Logf(" base = %x", tv.Base)
t.Logf(" got = %x", got)
t.Logf("expect = %x", tv.Expect)
t.Fail()
}
}
}
// TestHighBitIgnored tests the following requirement in RFC 7748:
//
// When receiving such an array, implementations of X25519 (but not X448) MUST
// mask the most significant bit in the final byte.
//
// Regression test for issue #30095.
func TestHighBitIgnored(t *testing.T) {
var s, u [32]byte
rand.Read(s[:])
rand.Read(u[:])
var hi0, hi1 [32]byte
u[31] &= 0x7f
ScalarMult(&hi0, &s, &u)
u[31] |= 0x80
ScalarMult(&hi1, &s, &u)
if !bytes.Equal(hi0[:], hi1[:]) {
t.Errorf("high bit of group point should not affect result")
}
}
var benchmarkSink byte
func BenchmarkX25519Basepoint(b *testing.B) {
scalar := make([]byte, ScalarSize)
if _, err := rand.Read(scalar); err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
out, err := X25519(scalar, Basepoint)
if err != nil {
b.Fatal(err)
}
benchmarkSink ^= out[0]
}
}
func BenchmarkX25519(b *testing.B) {
scalar := make([]byte, ScalarSize)
if _, err := rand.Read(scalar); err != nil {
b.Fatal(err)
}
point, err := X25519(scalar, Basepoint)
if err != nil {
b.Fatal(err)
}
if _, err := rand.Read(scalar); err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
out, err := X25519(scalar, point)
if err != nil {
b.Fatal(err)
}
benchmarkSink ^= out[0]
}
}