github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/crypto/elliptic/p224_test.go (about)

     1  // Copyright 2012 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 elliptic
     6  
     7  import (
     8  	"math/big"
     9  	"math/bits"
    10  	"math/rand"
    11  	"reflect"
    12  	"testing"
    13  	"testing/quick"
    14  )
    15  
    16  var toFromBigTests = []string{
    17  	"0",
    18  	"1",
    19  	"23",
    20  	"b70e0cb46bb4bf7f321390b94a03c1d356c01122343280d6105c1d21",
    21  	"706a46d476dcb76798e6046d89474788d164c18032d268fd10704fa6",
    22  }
    23  
    24  func p224AlternativeToBig(in *p224FieldElement) *big.Int {
    25  	ret := new(big.Int)
    26  	tmp := new(big.Int)
    27  
    28  	for i := len(in) - 1; i >= 0; i-- {
    29  		ret.Lsh(ret, 28)
    30  		tmp.SetInt64(int64(in[i]))
    31  		ret.Add(ret, tmp)
    32  	}
    33  	ret.Mod(ret, P224().Params().P)
    34  	return ret
    35  }
    36  
    37  func TestP224ToFromBig(t *testing.T) {
    38  	for i, test := range toFromBigTests {
    39  		n, _ := new(big.Int).SetString(test, 16)
    40  		var x p224FieldElement
    41  		p224FromBig(&x, n)
    42  		m := p224ToBig(&x)
    43  		if n.Cmp(m) != 0 {
    44  			t.Errorf("#%d: %x != %x", i, n, m)
    45  		}
    46  		q := p224AlternativeToBig(&x)
    47  		if n.Cmp(q) != 0 {
    48  			t.Errorf("#%d: %x != %x (alternative)", i, n, q)
    49  		}
    50  	}
    51  }
    52  
    53  // quickCheckConfig32 will make each quickcheck test run (32 * -quickchecks)
    54  // times. The default value of -quickchecks is 100.
    55  var quickCheckConfig32 = &quick.Config{MaxCountScale: 32}
    56  
    57  // weirdLimbs can be combined to generate a range of edge-case field elements.
    58  var weirdLimbs = [...]uint32{
    59  	0, 1, (1 << 29) - 1,
    60  	(1 << 12), (1 << 12) - 1,
    61  	(1 << 28), (1 << 28) - 1,
    62  }
    63  
    64  func generateLimb(rand *rand.Rand) uint32 {
    65  	const bottom29Bits = 0x1fffffff
    66  	n := rand.Intn(len(weirdLimbs) + 3)
    67  	switch n {
    68  	case len(weirdLimbs):
    69  		// Random value.
    70  		return uint32(rand.Int31n(1 << 29))
    71  	case len(weirdLimbs) + 1:
    72  		// Sum of two values.
    73  		k := generateLimb(rand) + generateLimb(rand)
    74  		return k & bottom29Bits
    75  	case len(weirdLimbs) + 2:
    76  		// Difference of two values.
    77  		k := generateLimb(rand) - generateLimb(rand)
    78  		return k & bottom29Bits
    79  	default:
    80  		return weirdLimbs[n]
    81  	}
    82  }
    83  
    84  func (p224FieldElement) Generate(rand *rand.Rand, size int) reflect.Value {
    85  	return reflect.ValueOf(p224FieldElement{
    86  		generateLimb(rand),
    87  		generateLimb(rand),
    88  		generateLimb(rand),
    89  		generateLimb(rand),
    90  		generateLimb(rand),
    91  		generateLimb(rand),
    92  		generateLimb(rand),
    93  		generateLimb(rand),
    94  	})
    95  }
    96  
    97  func isInBounds(x *p224FieldElement) bool {
    98  	return bits.Len32(x[0]) <= 29 &&
    99  		bits.Len32(x[1]) <= 29 &&
   100  		bits.Len32(x[2]) <= 29 &&
   101  		bits.Len32(x[3]) <= 29 &&
   102  		bits.Len32(x[4]) <= 29 &&
   103  		bits.Len32(x[5]) <= 29 &&
   104  		bits.Len32(x[6]) <= 29 &&
   105  		bits.Len32(x[7]) <= 29
   106  }
   107  
   108  func TestP224Mul(t *testing.T) {
   109  	mulMatchesBigInt := func(a, b, out p224FieldElement) bool {
   110  		var tmp p224LargeFieldElement
   111  		p224Mul(&out, &a, &b, &tmp)
   112  
   113  		exp := new(big.Int).Mul(p224AlternativeToBig(&a), p224AlternativeToBig(&b))
   114  		exp.Mod(exp, P224().Params().P)
   115  		got := p224AlternativeToBig(&out)
   116  		if exp.Cmp(got) != 0 || !isInBounds(&out) {
   117  			t.Logf("a = %x", a)
   118  			t.Logf("b = %x", b)
   119  			t.Logf("p224Mul(a, b) = %x = %v", out, got)
   120  			t.Logf("a * b = %v", exp)
   121  			return false
   122  		}
   123  
   124  		return true
   125  	}
   126  
   127  	a := p224FieldElement{0xfffffff, 0xfffffff, 0xf00ffff, 0x20f, 0x0, 0x0, 0x0, 0x0}
   128  	b := p224FieldElement{1, 0, 0, 0, 0, 0, 0, 0}
   129  	if !mulMatchesBigInt(a, b, p224FieldElement{}) {
   130  		t.Fail()
   131  	}
   132  
   133  	if err := quick.Check(mulMatchesBigInt, quickCheckConfig32); err != nil {
   134  		t.Error(err)
   135  	}
   136  }
   137  
   138  func TestP224Square(t *testing.T) {
   139  	squareMatchesBigInt := func(a, out p224FieldElement) bool {
   140  		var tmp p224LargeFieldElement
   141  		p224Square(&out, &a, &tmp)
   142  
   143  		exp := p224AlternativeToBig(&a)
   144  		exp.Mul(exp, exp)
   145  		exp.Mod(exp, P224().Params().P)
   146  		got := p224AlternativeToBig(&out)
   147  		if exp.Cmp(got) != 0 || !isInBounds(&out) {
   148  			t.Logf("a = %x", a)
   149  			t.Logf("p224Square(a, b) = %x = %v", out, got)
   150  			t.Logf("a * a = %v", exp)
   151  			return false
   152  		}
   153  
   154  		return true
   155  	}
   156  
   157  	if err := quick.Check(squareMatchesBigInt, quickCheckConfig32); err != nil {
   158  		t.Error(err)
   159  	}
   160  }
   161  
   162  func TestP224Add(t *testing.T) {
   163  	addMatchesBigInt := func(a, b, out p224FieldElement) bool {
   164  		p224Add(&out, &a, &b)
   165  
   166  		exp := new(big.Int).Add(p224AlternativeToBig(&a), p224AlternativeToBig(&b))
   167  		exp.Mod(exp, P224().Params().P)
   168  		got := p224AlternativeToBig(&out)
   169  		if exp.Cmp(got) != 0 {
   170  			t.Logf("a = %x", a)
   171  			t.Logf("b = %x", b)
   172  			t.Logf("p224Add(a, b) = %x = %v", out, got)
   173  			t.Logf("a + b = %v", exp)
   174  			return false
   175  		}
   176  
   177  		return true
   178  	}
   179  
   180  	if err := quick.Check(addMatchesBigInt, quickCheckConfig32); err != nil {
   181  		t.Error(err)
   182  	}
   183  }
   184  
   185  func TestP224Reduce(t *testing.T) {
   186  	reduceMatchesBigInt := func(a p224FieldElement) bool {
   187  		out := a
   188  		// TODO: generate higher values for functions like p224Reduce that are
   189  		// expected to work with higher input bounds.
   190  		p224Reduce(&out)
   191  
   192  		exp := p224AlternativeToBig(&a)
   193  		got := p224AlternativeToBig(&out)
   194  		if exp.Cmp(got) != 0 || !isInBounds(&out) {
   195  			t.Logf("a = %x = %v", a, exp)
   196  			t.Logf("p224Reduce(a) = %x = %v", out, got)
   197  			return false
   198  		}
   199  
   200  		return true
   201  	}
   202  
   203  	if err := quick.Check(reduceMatchesBigInt, quickCheckConfig32); err != nil {
   204  		t.Error(err)
   205  	}
   206  }
   207  
   208  func TestP224Contract(t *testing.T) {
   209  	contractMatchesBigInt := func(a, out p224FieldElement) bool {
   210  		p224Contract(&out, &a)
   211  
   212  		exp := p224AlternativeToBig(&a)
   213  		got := p224AlternativeToBig(&out)
   214  		if exp.Cmp(got) != 0 {
   215  			t.Logf("a = %x = %v", a, exp)
   216  			t.Logf("p224Contract(a) = %x = %v", out, got)
   217  			return false
   218  		}
   219  
   220  		// Check that out < P.
   221  		for i := range p224P {
   222  			k := 8 - i - 1
   223  			if out[k] > p224P[k] {
   224  				t.Logf("p224Contract(a) = %x", out)
   225  				return false
   226  			}
   227  			if out[k] < p224P[k] {
   228  				return true
   229  			}
   230  		}
   231  		t.Logf("p224Contract(a) = %x", out)
   232  		return false
   233  	}
   234  
   235  	if !contractMatchesBigInt(p224P, p224FieldElement{}) {
   236  		t.Error("p224Contract(p) is broken")
   237  	}
   238  	pMinus1 := p224FieldElement{0, 0, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
   239  	if !contractMatchesBigInt(pMinus1, p224FieldElement{}) {
   240  		t.Error("p224Contract(p - 1) is broken")
   241  	}
   242  	// Check that we can handle input above p, but lowest limb zero.
   243  	a := p224FieldElement{0, 1, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
   244  	if !contractMatchesBigInt(a, p224FieldElement{}) {
   245  		t.Error("p224Contract(p + 2²⁸) is broken")
   246  	}
   247  	// Check that we can handle input above p, but lowest three limbs zero.
   248  	b := p224FieldElement{0, 0, 0, 0xffff001, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
   249  	if !contractMatchesBigInt(b, p224FieldElement{}) {
   250  		t.Error("p224Contract(p + 2⁸⁴) is broken")
   251  	}
   252  
   253  	if err := quick.Check(contractMatchesBigInt, quickCheckConfig32); err != nil {
   254  		t.Error(err)
   255  	}
   256  }
   257  
   258  func TestP224IsZero(t *testing.T) {
   259  	if got := p224IsZero(&p224FieldElement{}); got != 1 {
   260  		t.Errorf("p224IsZero(0) = %d, expected 1", got)
   261  	}
   262  	if got := p224IsZero((*p224FieldElement)(&p224P)); got != 1 {
   263  		t.Errorf("p224IsZero(p) = %d, expected 1", got)
   264  	}
   265  	if got := p224IsZero(&p224FieldElement{1}); got != 0 {
   266  		t.Errorf("p224IsZero(1) = %d, expected 0", got)
   267  	}
   268  
   269  	isZeroMatchesBigInt := func(a p224FieldElement) bool {
   270  		isZero := p224IsZero(&a)
   271  
   272  		big := p224AlternativeToBig(&a)
   273  		if big.Sign() == 0 && isZero != 1 {
   274  			return false
   275  		}
   276  		if big.Sign() != 0 && isZero != 0 {
   277  			return false
   278  		}
   279  		return true
   280  	}
   281  
   282  	if err := quick.Check(isZeroMatchesBigInt, quickCheckConfig32); err != nil {
   283  		t.Error(err)
   284  	}
   285  }
   286  
   287  func TestP224Invert(t *testing.T) {
   288  	var out p224FieldElement
   289  
   290  	p224Invert(&out, &p224FieldElement{})
   291  	if got := p224IsZero(&out); got != 1 {
   292  		t.Errorf("p224Invert(0) = %x, expected 0", out)
   293  	}
   294  
   295  	p224Invert(&out, (*p224FieldElement)(&p224P))
   296  	if got := p224IsZero(&out); got != 1 {
   297  		t.Errorf("p224Invert(p) = %x, expected 0", out)
   298  	}
   299  
   300  	p224Invert(&out, &p224FieldElement{1})
   301  	p224Contract(&out, &out)
   302  	if out != (p224FieldElement{1}) {
   303  		t.Errorf("p224Invert(1) = %x, expected 1", out)
   304  	}
   305  
   306  	var tmp p224LargeFieldElement
   307  	a := p224FieldElement{1, 2, 3, 4, 5, 6, 7, 8}
   308  	p224Invert(&out, &a)
   309  	p224Mul(&out, &out, &a, &tmp)
   310  	p224Contract(&out, &out)
   311  	if out != (p224FieldElement{1}) {
   312  		t.Errorf("p224Invert(a) * a = %x, expected 1", out)
   313  	}
   314  }