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) } } }