You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.7 KiB
139 lines
4.7 KiB
package ed25519strict_test
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"encoding/hex"
|
|
"slices"
|
|
"testing"
|
|
|
|
"g.activething.com/go/DateKeys/internal/ed25519strict"
|
|
"g.activething.com/go/DateKeys/internal/testkit"
|
|
)
|
|
|
|
// The table of the points of small order is what the arithmetic of testkit
|
|
// computes from the curve.
|
|
func TestSmallOrderTable(t *testing.T) {
|
|
var got, want [][32]byte
|
|
for _, p := range ed25519strict.SmallOrderPoints() {
|
|
got = append(got, p)
|
|
}
|
|
want = testkit.Ed25519Torsion()
|
|
cmp := func(a, b [32]byte) int { return slices.Compare(a[:], b[:]) }
|
|
slices.SortFunc(got, cmp)
|
|
slices.SortFunc(want, cmp)
|
|
if !slices.Equal(got, want) {
|
|
t.Fatalf("table %x, want %x", got, want)
|
|
}
|
|
}
|
|
|
|
func TestCanonical(t *testing.T) {
|
|
enc := func(s string) []byte {
|
|
b, err := hex.DecodeString(s)
|
|
if err != nil || len(b) != 32 {
|
|
t.Fatalf("bad test encoding %s", s)
|
|
}
|
|
return b
|
|
}
|
|
for _, c := range []struct {
|
|
name string
|
|
a string
|
|
want bool
|
|
}{
|
|
{"y = 0", "0000000000000000000000000000000000000000000000000000000000000000", true},
|
|
{"y = 0, sign set: x is not 0", "0000000000000000000000000000000000000000000000000000000000000080", true},
|
|
{"y = 1", "0100000000000000000000000000000000000000000000000000000000000000", true},
|
|
{"y = 1, sign set: x is 0", "0100000000000000000000000000000000000000000000000000000000000080", false},
|
|
{"y = p - 1", "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", true},
|
|
{"y = p - 1, sign set", "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", false},
|
|
{"y = p", "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", false},
|
|
{"y = 2^255 - 1", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", false},
|
|
{"y = p - 2, sign set", "ebffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", true},
|
|
} {
|
|
if got := ed25519strict.Canonical(enc(c.a)); got != c.want {
|
|
t.Errorf("%s: Canonical = %v, want %v", c.name, got, c.want)
|
|
}
|
|
}
|
|
if ed25519strict.Canonical(make([]byte, 31)) || ed25519strict.SmallOrder(make([]byte, 33)) {
|
|
t.Error("a length other than 32 is accepted")
|
|
}
|
|
}
|
|
|
|
// OnCurve is true on the base point, on the points of small order and on
|
|
// keys of the CSPRNG, and false on y = 2, which has no x. Over the first 4096
|
|
// values of y it agrees with the square root of testkit.
|
|
func TestOnCurve(t *testing.T) {
|
|
base, _ := hex.DecodeString("5866666666666666666666666666666666666666666666666666666666666666")
|
|
if !ed25519strict.OnCurve(base) {
|
|
t.Error("the base point is not on the curve")
|
|
}
|
|
for _, p := range ed25519strict.SmallOrderPoints() {
|
|
if !ed25519strict.OnCurve(p[:]) {
|
|
t.Errorf("%x, of small order, is not on the curve", p)
|
|
}
|
|
}
|
|
for range 32 {
|
|
pub, _, _ := ed25519.GenerateKey(nil)
|
|
if !ed25519strict.OnCurve(pub) {
|
|
t.Fatalf("a key of the CSPRNG %x is not on the curve", pub)
|
|
}
|
|
}
|
|
two := make([]byte, 32)
|
|
two[0] = 2
|
|
if ed25519strict.OnCurve(two) || ed25519strict.OnCurve(make([]byte, 31)) {
|
|
t.Error("y = 2, or 31 bytes, is on the curve")
|
|
}
|
|
for y := range 4096 {
|
|
a := make([]byte, 32)
|
|
a[0], a[1] = byte(y), byte(y>>8)
|
|
if got, want := ed25519strict.OnCurve(a), testkit.Ed25519Decodes(a); got != want {
|
|
t.Fatalf("y = %d: OnCurve %v, the square root %v", y, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// crypto/ed25519 accepts any message with A = 01 00…00, R the identity and S
|
|
// = 0; Verify does not, nor a key or a signature of another length.
|
|
func TestVerifyRejectsWhatStdlibAccepts(t *testing.T) {
|
|
a := make([]byte, 32)
|
|
a[0] = 1
|
|
sig := make([]byte, 64)
|
|
sig[0] = 1
|
|
msg := []byte("anything")
|
|
if !ed25519.Verify(a, msg, sig) {
|
|
t.Fatal("crypto/ed25519 no longer accepts the forgery: review the comment of the package")
|
|
}
|
|
if ed25519strict.Verify(a, msg, sig) {
|
|
t.Error("Verify accepts a key of small order")
|
|
}
|
|
pub, priv, _ := ed25519.GenerateKey(nil)
|
|
good := ed25519.Sign(priv, msg)
|
|
if !ed25519strict.Verify(pub, msg, good) {
|
|
t.Error("Verify rejects a valid signature")
|
|
}
|
|
if ed25519strict.Verify(pub[:31], msg, good) || ed25519strict.Verify(pub, msg, good[:63]) {
|
|
t.Error("Verify accepts another length")
|
|
}
|
|
}
|
|
|
|
// The committed vectors give their result.
|
|
func TestVectors(t *testing.T) {
|
|
var f testkit.Ed25519StrictFile
|
|
if err := testkit.ReadJSON("../../testdata/vectors/ed25519_strict.json", &f); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(f.Vectors) == 0 {
|
|
t.Fatal("no vectors")
|
|
}
|
|
for _, v := range f.Vectors {
|
|
msg, _ := hex.DecodeString(v.Message)
|
|
pub, _ := hex.DecodeString(v.PublicKey)
|
|
sig, _ := hex.DecodeString(v.Signature)
|
|
if got := ed25519strict.Verify(pub, msg, sig); got != v.Valid {
|
|
t.Errorf("%s: Verify = %v, want %v", v.Name, got, v.Valid)
|
|
}
|
|
if got := ed25519.Verify(pub, msg, sig); got != v.Stdlib {
|
|
t.Errorf("%s: crypto/ed25519 = %v, recorded %v", v.Name, got, v.Stdlib)
|
|
}
|
|
}
|
|
}
|