github.com/cloudflare/circl@v1.5.0/sign/ed448/ed448_test.go (about) 1 package ed448_test 2 3 import ( 4 "bytes" 5 "crypto" 6 "crypto/rand" 7 "errors" 8 "fmt" 9 "testing" 10 11 "github.com/cloudflare/circl/internal/test" 12 "github.com/cloudflare/circl/sign/ed448" 13 ) 14 15 type zeroReader struct{} 16 17 func (zeroReader) Read(buf []byte) (int, error) { 18 for i := range buf { 19 buf[i] = 0 20 } 21 return len(buf), nil 22 } 23 24 func TestEqual(t *testing.T) { 25 public, private, _ := ed448.GenerateKey(rand.Reader) 26 27 if !public.Equal(public) { 28 t.Errorf("public key is not equal to itself: %q", public) 29 } 30 if !public.Equal(crypto.Signer(private).Public()) { 31 t.Errorf("private.Public() is not Equal to public: %q", public) 32 } 33 if !private.Equal(private) { 34 t.Errorf("private key is not equal to itself: %q", private) 35 } 36 37 otherPub, otherPriv, _ := ed448.GenerateKey(rand.Reader) 38 if public.Equal(otherPub) { 39 t.Errorf("different public keys are Equal") 40 } 41 if private.Equal(otherPriv) { 42 t.Errorf("different private keys are Equal") 43 } 44 } 45 46 func TestWrongPublicKey(t *testing.T) { 47 wrongPublicKeys := [...][ed448.PublicKeySize]byte{ 48 { // y = p 49 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 50 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 51 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 52 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 53 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 54 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 55 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 56 }, 57 { // y > p 58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 62 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 63 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 64 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 65 }, 66 { // x^2 = u/v = (y^2-1)/(dy^2-1) is not a quadratic residue 67 0xa4, 0x8b, 0xae, 0x31, 0x1b, 0x3a, 0xe5, 0x62, 68 0x3d, 0x6f, 0x2d, 0xbe, 0x8b, 0xb4, 0xd3, 0x21, 69 0x0f, 0x04, 0x0a, 0x7e, 0xf2, 0x25, 0x87, 0xc3, 70 0xc0, 0x1e, 0xe1, 0xf4, 0x6d, 0xc7, 0x28, 0x8f, 71 0x8b, 0xb9, 0x9f, 0x3d, 0x02, 0xb0, 0xc0, 0xa8, 72 0xe7, 0xe3, 0x4f, 0xb2, 0x82, 0x64, 0x98, 0x4a, 73 0x84, 0x73, 0xd7, 0x57, 0x6a, 0x39, 0x90, 0xa3, 74 }, 75 { // y = 1 and x^2 = u/v = 0, and the sign of X is 1 76 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 83 }, 84 { // y = -1 and x^2 = u/v = 0, and the sign of X is 1 85 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 86 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 87 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 88 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 89 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 90 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 91 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 92 }, 93 } 94 sig := (&[ed448.SignatureSize]byte{})[:] 95 for _, public := range wrongPublicKeys { 96 got := ed448.Verify(public[:], []byte(""), sig, "") 97 want := false 98 if got != want { 99 test.ReportError(t, got, want, public) 100 } 101 } 102 } 103 104 func TestSigner(t *testing.T) { 105 seed := (&[ed448.SeedSize]byte{})[:] 106 _, _ = rand.Read(seed) 107 key := ed448.NewKeyFromSeed(seed) 108 109 priv := key.Seed() 110 if !bytes.Equal(seed, priv) { 111 got := priv 112 want := seed 113 test.ReportError(t, got, want) 114 } 115 116 signer := crypto.Signer(key) 117 ops := crypto.Hash(0) 118 msg := make([]byte, 16) 119 _, _ = rand.Read(msg) 120 sig, err := signer.Sign(nil, msg, ops) 121 if err != nil { 122 got := err 123 var want error 124 test.ReportError(t, got, want) 125 } 126 if len(sig) != ed448.SignatureSize { 127 got := len(sig) 128 want := ed448.SignatureSize 129 test.ReportError(t, got, want) 130 } 131 132 for _, o := range []ed448.SignerOptions{ 133 {Scheme: ed448.ED448, Hash: crypto.Hash(0), Context: ""}, 134 {Scheme: ed448.ED448, Hash: crypto.Hash(0), Context: "non-empty"}, 135 {Scheme: ed448.ED448Ph, Hash: crypto.Hash(0), Context: ""}, 136 {Scheme: ed448.ED448Ph, Hash: crypto.Hash(0), Context: "non-empty"}, 137 } { 138 testSigner(t, key, o) 139 } 140 } 141 142 func testSigner(t *testing.T, signer crypto.Signer, ops ed448.SignerOptions) { 143 msg := make([]byte, 64) 144 _, _ = rand.Read(msg) 145 146 sig, err := signer.Sign(nil, msg, ops) 147 if err != nil { 148 got := err 149 var want error 150 test.ReportError(t, got, want, ops) 151 } 152 153 if len(sig) != ed448.SignatureSize { 154 got := len(sig) 155 want := ed448.SignatureSize 156 test.ReportError(t, got, want, ops) 157 } 158 159 pubSigner, ok := signer.Public().(ed448.PublicKey) 160 if !ok { 161 got := ok 162 want := true 163 test.ReportError(t, got, want, ops) 164 } 165 166 got := ed448.VerifyAny(pubSigner, msg, sig, ops) 167 want := true 168 if got != want { 169 test.ReportError(t, got, want, ops) 170 } 171 } 172 173 type badReader struct{} 174 175 func (badReader) Read([]byte) (n int, err error) { return 0, errors.New("cannot read") } 176 177 func TestErrors(t *testing.T) { 178 t.Run("badHash", func(t *testing.T) { 179 var msg [16]byte 180 ops := crypto.SHA224 181 _, priv, _ := ed448.GenerateKey(nil) 182 _, got := priv.Sign(nil, msg[:], ops) 183 want := errors.New("ed448: bad hash algorithm") 184 if got.Error() != want.Error() { 185 test.ReportError(t, got, want) 186 } 187 }) 188 t.Run("badReader", func(t *testing.T) { 189 _, _, got := ed448.GenerateKey(badReader{}) 190 want := errors.New("cannot read") 191 if got.Error() != want.Error() { 192 test.ReportError(t, got, want) 193 } 194 }) 195 t.Run("wrongSeedSize", func(t *testing.T) { 196 var seed [256]byte 197 var want error 198 got := test.CheckPanic(func() { ed448.NewKeyFromSeed(seed[:]) }) 199 if got != want { 200 test.ReportError(t, got, want) 201 } 202 }) 203 t.Run("bigContext", func(t *testing.T) { 204 var msg [16]byte 205 var ctx [256]byte 206 var want error 207 _, priv, _ := ed448.GenerateKey(nil) 208 got := test.CheckPanic(func() { ed448.Sign(priv, msg[:], string(ctx[:])) }) 209 if got != want { 210 test.ReportError(t, got, want) 211 } 212 }) 213 } 214 215 func BenchmarkKeyGeneration(b *testing.B) { 216 var zero zeroReader 217 for i := 0; i < b.N; i++ { 218 if _, _, err := ed448.GenerateKey(zero); err != nil { 219 b.Fatal(err) 220 } 221 } 222 } 223 224 func BenchmarkNewKeyFromSeed(b *testing.B) { 225 seed := make([]byte, ed448.SeedSize) 226 b.ReportAllocs() 227 for i := 0; i < b.N; i++ { 228 _ = ed448.NewKeyFromSeed(seed) 229 } 230 } 231 232 func BenchmarkSigning(b *testing.B) { 233 var zero zeroReader 234 _, priv, err := ed448.GenerateKey(zero) 235 if err != nil { 236 b.Fatal(err) 237 } 238 message := []byte("Hello, world!") 239 ctx := "a context string" 240 b.ReportAllocs() 241 b.ResetTimer() 242 for i := 0; i < b.N; i++ { 243 ed448.Sign(priv, message, ctx) 244 } 245 } 246 247 func BenchmarkVerification(b *testing.B) { 248 var zero zeroReader 249 pub, priv, err := ed448.GenerateKey(zero) 250 if err != nil { 251 b.Fatal(err) 252 } 253 message := []byte("Hello, world!") 254 ctx := "a context string" 255 signature := ed448.Sign(priv, message, ctx) 256 b.ResetTimer() 257 for i := 0; i < b.N; i++ { 258 ed448.Verify(pub, message, signature, ctx) 259 } 260 } 261 262 func BenchmarkEd448Ph(b *testing.B) { 263 msg := make([]byte, 128) 264 _, _ = rand.Read(msg) 265 266 b.Run("Sign", func(b *testing.B) { 267 _, key, _ := ed448.GenerateKey(rand.Reader) 268 ctx := "" 269 b.ResetTimer() 270 for i := 0; i < b.N; i++ { 271 _ = ed448.SignPh(key, msg, ctx) 272 } 273 }) 274 b.Run("Verify", func(b *testing.B) { 275 pub, priv, _ := ed448.GenerateKey(rand.Reader) 276 ctx := "" 277 sig := ed448.SignPh(priv, msg, ctx) 278 b.ResetTimer() 279 for i := 0; i < b.N; i++ { 280 ed448.VerifyPh(pub, msg, sig, ctx) 281 } 282 }) 283 } 284 285 func Example_ed448() { 286 // import "github.com/cloudflare/circl/sign/ed448" 287 // import "crypto/rand" 288 289 // Generating Alice's key pair 290 pub, priv, err := ed448.GenerateKey(rand.Reader) 291 if err != nil { 292 panic("error on generating keys") 293 } 294 295 // Alice signs a message. 296 message := []byte("A message to be signed") 297 ctx := "This is a context string" 298 signature := ed448.Sign(priv, message, ctx) 299 300 // Anyone can verify the signature using Alice's public key. 301 ok := ed448.Verify(pub, message, signature, ctx) 302 fmt.Println(ok) 303 // Output: true 304 } 305 306 func ExampleSignPh() { 307 // import "github.com/cloudflare/circl/sign/ed448" 308 // import "crypto/rand" 309 310 // Generating Alice's key pair 311 pub, priv, err := ed448.GenerateKey(rand.Reader) 312 if err != nil { 313 panic("error on generating keys") 314 } 315 316 // Alice signs a message. 317 message := []byte("A message to be signed") 318 ctx := "This is a context string" 319 signature := ed448.SignPh(priv, message, ctx) 320 321 // Anyone can verify the signature using Alice's public key. 322 ok := ed448.VerifyPh(pub, message, signature, ctx) 323 fmt.Println(ok) 324 // Output: true 325 }