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  }