Source file src/crypto/internal/fips140test/nistec_ordinv_test.go

     1  // Copyright 2022 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 fipstest
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/elliptic"
    10  	"internal/byteorder"
    11  	"math/big"
    12  	"testing"
    13  )
    14  
    15  func bytesToLimbs(b []byte) [4]uint64 {
    16  	var l [4]uint64
    17  	l[0] = byteorder.BEUint64(b[24:])
    18  	l[1] = byteorder.BEUint64(b[16:])
    19  	l[2] = byteorder.BEUint64(b[8:])
    20  	l[3] = byteorder.BEUint64(b[:])
    21  	return l
    22  }
    23  
    24  func limbsToBytes(l [4]uint64) []byte {
    25  	b := make([]byte, 32)
    26  	byteorder.BEPutUint64(b[24:], l[0])
    27  	byteorder.BEPutUint64(b[16:], l[1])
    28  	byteorder.BEPutUint64(b[8:], l[2])
    29  	byteorder.BEPutUint64(b[:], l[3])
    30  	return b
    31  }
    32  
    33  func TestP256OrdInverse(t *testing.T) {
    34  	N := elliptic.P256().Params().N
    35  
    36  	// inv(0) is expected to be 0.
    37  	zero := make([]byte, 32)
    38  	k := bytesToLimbs(zero)
    39  	p256OrdInverse(t, &k)
    40  	if !bytes.Equal(limbsToBytes(k), zero) {
    41  		t.Error("unexpected output for inv(0)")
    42  	}
    43  
    44  	// inv(N) is also 0 mod N.
    45  	input := make([]byte, 32)
    46  	N.FillBytes(input)
    47  	k = bytesToLimbs(input)
    48  	p256OrdInverse(t, &k)
    49  	if !bytes.Equal(limbsToBytes(k), zero) {
    50  		t.Error("unexpected output for inv(N)")
    51  	}
    52  
    53  	// Check inv(1) and inv(N+1) against math/big
    54  	exp := new(big.Int).ModInverse(big.NewInt(1), N).FillBytes(make([]byte, 32))
    55  	big.NewInt(1).FillBytes(input)
    56  	k = bytesToLimbs(input)
    57  	p256OrdInverse(t, &k)
    58  	if !bytes.Equal(limbsToBytes(k), exp) {
    59  		t.Error("unexpected output for inv(1)")
    60  	}
    61  
    62  	new(big.Int).Add(N, big.NewInt(1)).FillBytes(input)
    63  	k = bytesToLimbs(input)
    64  	p256OrdInverse(t, &k)
    65  	if !bytes.Equal(limbsToBytes(k), exp) {
    66  		t.Error("unexpected output for inv(N+1)")
    67  	}
    68  
    69  	// Check inv(20) and inv(N+20) against math/big
    70  	exp = new(big.Int).ModInverse(big.NewInt(20), N).FillBytes(make([]byte, 32))
    71  	big.NewInt(20).FillBytes(input)
    72  	k = bytesToLimbs(input)
    73  	p256OrdInverse(t, &k)
    74  	if !bytes.Equal(limbsToBytes(k), exp) {
    75  		t.Error("unexpected output for inv(20)")
    76  	}
    77  
    78  	new(big.Int).Add(N, big.NewInt(20)).FillBytes(input)
    79  	k = bytesToLimbs(input)
    80  	p256OrdInverse(t, &k)
    81  	if !bytes.Equal(limbsToBytes(k), exp) {
    82  		t.Error("unexpected output for inv(N+20)")
    83  	}
    84  
    85  	// Check inv(2^256-1) against math/big
    86  	bigInput := new(big.Int).Lsh(big.NewInt(1), 256)
    87  	bigInput.Sub(bigInput, big.NewInt(1))
    88  	exp = new(big.Int).ModInverse(bigInput, N).FillBytes(make([]byte, 32))
    89  	bigInput.FillBytes(input)
    90  	k = bytesToLimbs(input)
    91  	p256OrdInverse(t, &k)
    92  	if !bytes.Equal(limbsToBytes(k), exp) {
    93  		t.Error("unexpected output for inv(2^256-1)")
    94  	}
    95  }
    96  

View as plain text