Source file src/crypto/internal/fips140/ecdsa/ecdsa_test.go

     1  // Copyright 2024 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ecdsa
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/internal/fips140/bigmod"
    10  	"crypto/rand"
    11  	"io"
    12  	"testing"
    13  )
    14  
    15  func TestRandomPoint(t *testing.T) {
    16  	t.Run("P-224", func(t *testing.T) { testRandomPoint(t, P224()) })
    17  	t.Run("P-256", func(t *testing.T) { testRandomPoint(t, P256()) })
    18  	t.Run("P-384", func(t *testing.T) { testRandomPoint(t, P384()) })
    19  	t.Run("P-521", func(t *testing.T) { testRandomPoint(t, P521()) })
    20  }
    21  
    22  func testRandomPoint[P Point[P]](t *testing.T, c *Curve[P]) {
    23  	t.Cleanup(func() { testingOnlyRejectionSamplingLooped = nil })
    24  	var loopCount int
    25  	testingOnlyRejectionSamplingLooped = func() { loopCount++ }
    26  
    27  	// A sequence of all ones will generate 2^N-1, which should be rejected.
    28  	// (Unless, for example, we are masking too many bits.)
    29  	r := io.MultiReader(bytes.NewReader(bytes.Repeat([]byte{0xff}, 100)), rand.Reader)
    30  	if k, p, err := randomPoint(c, func(b []byte) error {
    31  		_, err := r.Read(b)
    32  		return err
    33  	}); err != nil {
    34  		t.Fatal(err)
    35  	} else if k.IsZero() == 1 {
    36  		t.Error("k is zero")
    37  	} else if p.Bytes()[0] != 4 {
    38  		t.Error("p is infinity")
    39  	}
    40  	if loopCount == 0 {
    41  		t.Error("overflow was not rejected")
    42  	}
    43  	loopCount = 0
    44  
    45  	// A sequence of all zeroes will generate zero, which should be rejected.
    46  	r = io.MultiReader(bytes.NewReader(bytes.Repeat([]byte{0}, 100)), rand.Reader)
    47  	if k, p, err := randomPoint(c, func(b []byte) error {
    48  		_, err := r.Read(b)
    49  		return err
    50  	}); err != nil {
    51  		t.Fatal(err)
    52  	} else if k.IsZero() == 1 {
    53  		t.Error("k is zero")
    54  	} else if p.Bytes()[0] != 4 {
    55  		t.Error("p is infinity")
    56  	}
    57  	if loopCount == 0 {
    58  		t.Error("zero was not rejected")
    59  	}
    60  	loopCount = 0
    61  
    62  	// P-256 has a 2⁻³² chance of randomly hitting a rejection. For P-224 it's
    63  	// 2⁻¹¹², for P-384 it's 2⁻¹⁹⁴, and for P-521 it's 2⁻²⁶², so if we hit in
    64  	// tests, something is horribly wrong. (For example, we are masking the
    65  	// wrong bits.)
    66  	if c.curve == p256 {
    67  		return
    68  	}
    69  	if k, p, err := randomPoint(c, func(b []byte) error {
    70  		_, err := rand.Reader.Read(b)
    71  		return err
    72  	}); err != nil {
    73  		t.Fatal(err)
    74  	} else if k.IsZero() == 1 {
    75  		t.Error("k is zero")
    76  	} else if p.Bytes()[0] != 4 {
    77  		t.Error("p is infinity")
    78  	}
    79  	if loopCount > 0 {
    80  		t.Error("unexpected rejection")
    81  	}
    82  }
    83  
    84  func TestHashToNat(t *testing.T) {
    85  	t.Run("P-224", func(t *testing.T) { testHashToNat(t, P224()) })
    86  	t.Run("P-256", func(t *testing.T) { testHashToNat(t, P256()) })
    87  	t.Run("P-384", func(t *testing.T) { testHashToNat(t, P384()) })
    88  	t.Run("P-521", func(t *testing.T) { testHashToNat(t, P521()) })
    89  }
    90  
    91  func testHashToNat[P Point[P]](t *testing.T, c *Curve[P]) {
    92  	for l := 0; l < 600; l++ {
    93  		h := bytes.Repeat([]byte{0xff}, l)
    94  		hashToNat(c, bigmod.NewNat(), h)
    95  	}
    96  }
    97  

View as plain text