Files
next.orly.dev/pkg/crypto/ec/secp256k1/modnscalar_test.go

1324 lines
44 KiB
Go

// Copyright (c) 2020-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
import (
"fmt"
"math/big"
"math/rand"
"reflect"
"testing"
"time"
"lol.mleku.dev/chk"
"next.orly.dev/pkg/encoders/hex"
"next.orly.dev/pkg/utils"
)
// SetHex interprets the provided hex string as a 256-bit big-endian unsigned
// integer (meaning it is truncated to the first 32 bytes), reduces it modulo
// the group order and sets the scalar to the result.
//
// This is NOT constant time.
//
// The scalar is returned to support chaining. This enables syntax like:
// s := new(ModNScalar).SetHex("0abc").Add(1) so that s = 0x0abc + 1
func (s *ModNScalar) SetHex(hexString string) *ModNScalar {
if len(hexString)%2 != 0 {
hexString = "0" + hexString
}
bytes, _ := hex.Dec(hexString)
s.SetByteSlice(bytes)
return s
}
// randModNScalar returns a mod N scalar created from a random value generated
// by the passed rng.
func randModNScalar(t *testing.T, rng *rand.Rand) *ModNScalar {
t.Helper()
var buf [32]byte
if _, err := rng.Read(buf[:]); chk.T(err) {
t.Fatalf("failed to read random: %v", err)
}
// Create and return a mod N scalar.
var modNVal ModNScalar
modNVal.SetBytes(&buf)
return &modNVal
}
// randIntAndModNScalar returns a big integer and mod N scalar both created from
// the same random value generated by the passed rng.
func randIntAndModNScalar(t *testing.T, rng *rand.Rand) (
*big.Int,
*ModNScalar,
) {
t.Helper()
var buf [32]byte
if _, err := rng.Read(buf[:]); chk.T(err) {
t.Fatalf("failed to read random: %v", err)
}
// Create and return both a big integer and a mod N scalar.
bigIntVal := new(big.Int).SetBytes(buf[:])
bigIntVal.Mod(bigIntVal, curveParams.N)
var modNVal ModNScalar
modNVal.SetBytes(&buf)
return bigIntVal, &modNVal
}
// TestModNScalarZero ensures that zeroing a scalar modulo the group order works
// as expected.
func TestModNScalarZero(t *testing.T) {
var s ModNScalar
s.SetHex("a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5")
s.Zero()
for idx, rawInt := range s.n {
if rawInt != 0 {
t.Errorf(
"internal integer at index #%d is not zero - got %d", idx,
rawInt,
)
}
}
}
// TestModNScalarIsZero ensures that checking if a scalar is zero via IsZero and
// IsZeroBit works as expected.
func TestModNScalarIsZero(t *testing.T) {
var s ModNScalar
if !s.IsZero() {
t.Errorf("new scalar is not zero - got %v (rawints %x)", s, s.n)
}
if s.IsZeroBit() != 1 {
t.Errorf("new scalar is not zero - got %v (rawints %x)", s, s.n)
}
s.SetInt(1)
if s.IsZero() {
t.Errorf("claims zero for nonzero scalar - got %v (rawints %x)", s, s.n)
}
if s.IsZeroBit() == 1 {
t.Errorf("claims zero for nonzero scalar - got %v (rawints %x)", s, s.n)
}
s.SetInt(0)
if !s.IsZero() {
t.Errorf("claims nonzero for zero scalar - got %v (rawints %x)", s, s.n)
}
if s.IsZeroBit() != 1 {
t.Errorf("claims nonzero for zero scalar - got %v (rawints %x)", s, s.n)
}
s.SetInt(1)
s.Zero()
if !s.IsZero() {
t.Errorf("claims nonzero for zero scalar - got %v (rawints %x)", s, s.n)
}
if s.IsZeroBit() != 1 {
t.Errorf("claims nonzero for zero scalar - got %v (rawints %x)", s, s.n)
}
}
// TestModNScalarSetInt ensures that setting a scalar to various native integers
// works as expected.
func TestModNScalarSetInt(t *testing.T) {
tests := []struct {
name string // test description
in uint32 // test value
expected [8]uint32 // expected raw ints
}{
{
name: "five",
in: 5,
expected: [8]uint32{5, 0, 0, 0, 0, 0, 0, 0},
}, {
name: "group order word zero",
in: orderWordZero,
expected: [8]uint32{orderWordZero, 0, 0, 0, 0, 0, 0, 0},
}, {
name: "group order word zero + 1",
in: orderWordZero + 1,
expected: [8]uint32{orderWordZero + 1, 0, 0, 0, 0, 0, 0, 0},
}, {
name: "2^32 - 1",
in: 4294967295,
expected: [8]uint32{4294967295, 0, 0, 0, 0, 0, 0, 0},
},
}
for _, test := range tests {
s := new(ModNScalar).SetInt(test.in)
if !reflect.DeepEqual(s.n, test.expected) {
t.Errorf(
"%s: wrong result\ngot: %v\nwant: %v", test.name, s.n,
test.expected,
)
continue
}
}
}
// TestModNScalarSetBytes ensures that setting a scalar to a 256-bit big-endian
// unsigned integer via both the slice and array methods works as expected for
// edge cases. Random cases are tested via the various other tests.
func TestModNScalarSetBytes(t *testing.T) {
tests := []struct {
name string // test description
in string // hex encoded test value
expected [8]uint32 // expected raw ints
overflow bool // expected overflow result
}{
{
name: "zero",
in: "00",
expected: [8]uint32{0, 0, 0, 0, 0, 0, 0, 0},
overflow: false,
}, {
name: "group order (aka 0)",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
expected: [8]uint32{0, 0, 0, 0, 0, 0, 0, 0},
overflow: true,
}, {
name: "group order - 1",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
expected: [8]uint32{
0xd0364140, 0xbfd25e8c, 0xaf48a03b, 0xbaaedce6,
0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff,
},
overflow: false,
}, {
name: "group order + 1 (aka 1, overflow in word zero)",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
expected: [8]uint32{1, 0, 0, 0, 0, 0, 0, 0},
overflow: true,
}, {
name: "group order word zero",
in: "d0364141",
expected: [8]uint32{0xd0364141, 0, 0, 0, 0, 0, 0, 0},
overflow: false,
}, {
name: "group order word zero and one",
in: "bfd25e8cd0364141",
expected: [8]uint32{0xd0364141, 0xbfd25e8c, 0, 0, 0, 0, 0, 0},
overflow: false,
}, {
name: "group order words zero, one, and two",
in: "af48a03bbfd25e8cd0364141",
expected: [8]uint32{
0xd0364141, 0xbfd25e8c, 0xaf48a03b, 0, 0, 0, 0, 0,
},
overflow: false,
}, {
name: "overflow in word one",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8dd0364141",
expected: [8]uint32{0, 1, 0, 0, 0, 0, 0, 0},
overflow: true,
}, {
name: "overflow in word two",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03cbfd25e8cd0364141",
expected: [8]uint32{0, 0, 1, 0, 0, 0, 0, 0},
overflow: true,
}, {
name: "overflow in word three",
in: "fffffffffffffffffffffffffffffffebaaedce7af48a03bbfd25e8cd0364141",
expected: [8]uint32{0, 0, 0, 1, 0, 0, 0, 0},
overflow: true,
}, {
name: "overflow in word four",
in: "ffffffffffffffffffffffffffffffffbaaedce6af48a03bbfd25e8cd0364141",
expected: [8]uint32{0, 0, 0, 0, 1, 0, 0, 0},
overflow: true,
}, {
name: "(group order - 1) * 2 NOT mod N, truncated >32 bytes",
in: "01fffffffffffffffffffffffffffffffd755db9cd5e9140777fa4bd19a06c8284",
expected: [8]uint32{
0x19a06c82, 0x777fa4bd, 0xcd5e9140, 0xfd755db9,
0xffffffff, 0xffffffff, 0xffffffff, 0x01ffffff,
},
overflow: false,
}, {
name: "alternating bits",
in: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
expected: [8]uint32{
0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5,
0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5,
},
overflow: false,
}, {
name: "alternating bits 2",
in: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
expected: [8]uint32{
0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
},
overflow: false,
},
}
for _, test := range tests {
inBytes := hexToBytes(test.in)
// Ensure setting the bytes via the slice method works as expected.
var s ModNScalar
overflow := s.SetByteSlice(inBytes)
if !reflect.DeepEqual(s.n, test.expected) {
t.Errorf(
"%s: unexpected result\ngot: %x\nwant: %x", test.name, s.n,
test.expected,
)
continue
}
// Ensure the setting the bytes via the slice method produces the
// expected overflow result.
if overflow != test.overflow {
t.Errorf(
"%s: unexpected overflow -- got: %v, want: %v", test.name,
overflow, test.overflow,
)
continue
}
// Ensure setting the bytes via the array method works as expected.
var s2 ModNScalar
var b32 [32]byte
truncatedInBytes := inBytes
if len(truncatedInBytes) > 32 {
truncatedInBytes = truncatedInBytes[:32]
}
copy(b32[32-len(truncatedInBytes):], truncatedInBytes)
overflow = s2.SetBytes(&b32) != 0
if !reflect.DeepEqual(s2.n, test.expected) {
t.Errorf(
"%s: unexpected result\ngot: %x\nwant: %x", test.name,
s2.n, test.expected,
)
continue
}
// Ensure the setting the bytes via the array method produces the
// expected overflow result.
if overflow != test.overflow {
t.Errorf(
"%s: unexpected overflow -- got: %v, want: %v", test.name,
overflow, test.overflow,
)
continue
}
}
}
// TestModNScalarBytes ensures that retrieving the bytes for a 256-bit
// big-endian unsigned integer via the various methods works as expected for
// edge cases. Random cases are tested via the various other tests.
func TestModNScalarBytes(t *testing.T) {
tests := []struct {
name string // test description
in string // hex encoded test value
expected string // expected hex encoded bytes
overflow bool // expected overflow result
}{
{
name: "zero",
in: "0",
expected: "0000000000000000000000000000000000000000000000000000000000000000",
}, {
name: "group order (aka 0)",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
expected: "0000000000000000000000000000000000000000000000000000000000000000",
}, {
name: "group order - 1",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
expected: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
}, {
name: "group order + 1 (aka 1, overflow in word zero)",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
expected: "0000000000000000000000000000000000000000000000000000000000000001",
}, {
name: "group order word zero",
in: "d0364141",
expected: "00000000000000000000000000000000000000000000000000000000d0364141",
}, {
name: "group order word zero and one",
in: "bfd25e8cd0364141",
expected: "000000000000000000000000000000000000000000000000bfd25e8cd0364141",
}, {
name: "group order words zero, one, and two",
in: "af48a03bbfd25e8cd0364141",
expected: "0000000000000000000000000000000000000000af48a03bbfd25e8cd0364141",
}, {
name: "overflow in word one",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8dd0364141",
expected: "0000000000000000000000000000000000000000000000000000000100000000",
}, {
name: "overflow in word two",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03cbfd25e8cd0364141",
expected: "0000000000000000000000000000000000000000000000010000000000000000",
}, {
name: "overflow in word three",
in: "fffffffffffffffffffffffffffffffebaaedce7af48a03bbfd25e8cd0364141",
expected: "0000000000000000000000000000000000000001000000000000000000000000",
}, {
name: "overflow in word four",
in: "ffffffffffffffffffffffffffffffffbaaedce6af48a03bbfd25e8cd0364141",
expected: "0000000000000000000000000000000100000000000000000000000000000000",
}, {
name: "alternating bits",
in: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
expected: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
}, {
name: "alternating bits 2",
in: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
expected: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
},
}
for _, test := range tests {
s := new(ModNScalar).SetHex(test.in)
expected := hexToBytes(test.expected)
// Ensure getting the bytes works as expected.
gotBytes := s.Bytes()
if !utils.FastEqual(gotBytes[:], expected) {
t.Errorf(
"%s: unexpected result\ngot: %x\nwant: %x", test.name,
gotBytes, expected,
)
continue
}
// Ensure getting the bytes directly into an array works as expected.
var b32 [32]byte
s.PutBytes(&b32)
if !utils.FastEqual(b32[:], expected) {
t.Errorf(
"%s: unexpected result\ngot: %x\nwant: %x", test.name,
b32, expected,
)
continue
}
// Ensure getting the bytes directly into a slice works as expected.
var buffer [64]byte
s.PutBytesUnchecked(buffer[:])
if !utils.FastEqual(buffer[:32], expected) {
t.Errorf(
"%s: unexpected result\ngot: %x\nwant: %x", test.name,
buffer[:32], expected,
)
continue
}
}
}
// TestModNScalarIsOdd ensures that checking if a scalar is odd works as
// expected.
func TestModNScalarIsOdd(t *testing.T) {
tests := []struct {
name string // test description
in string // hex encoded value
expected bool // expected oddness
}{
{
name: "zero",
in: "0",
expected: false,
}, {
name: "one",
in: "1",
expected: true,
}, {
name: "two",
in: "2",
expected: false,
}, {
name: "2^32 - 1",
in: "ffffffff",
expected: true,
}, {
name: "2^64 - 2",
in: "fffffffffffffffe",
expected: false,
}, {
name: "group order (aka 0)",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
expected: false,
}, {
name: "group order + 1 (aka 1)",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
expected: true,
},
}
for _, test := range tests {
result := new(ModNScalar).SetHex(test.in).IsOdd()
if result != test.expected {
t.Errorf(
"%s: wrong result -- got: %v, want: %v", test.name,
result, test.expected,
)
continue
}
}
}
// TestModNScalarEquals ensures that checking two scalars for equality works as
// expected for edge cases.
func TestModNScalarEquals(t *testing.T) {
tests := []struct {
name string // test description
in1 string // hex encoded value
in2 string // hex encoded value
expected bool // expected equality
}{
{
name: "0 == 0?",
in1: "0",
in2: "0",
expected: true,
}, {
name: "0 == 1?",
in1: "0",
in2: "1",
expected: false,
}, {
name: "1 == 0?",
in1: "1",
in2: "0",
expected: false,
}, {
name: "2^32 - 1 == 2^32 - 1?",
in1: "ffffffff",
in2: "ffffffff",
expected: true,
}, {
name: "2^64 - 1 == 2^64 - 2?",
in1: "ffffffffffffffff",
in2: "fffffffffffffffe",
expected: false,
}, {
name: "0 == group order?",
in1: "0",
in2: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
expected: true,
}, {
name: "1 == group order + 1?",
in1: "1",
in2: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
expected: true,
},
}
for _, test := range tests {
s1 := new(ModNScalar).SetHex(test.in1)
s2 := new(ModNScalar).SetHex(test.in2)
result := s1.Equals(s2)
if result != test.expected {
t.Errorf(
"%s: wrong result -- got: %v, want: %v", test.name, result,
test.expected,
)
continue
}
}
}
// TestModNScalarEqualsRandom ensures that scalars for random values works as
// expected.
func TestModNScalarEqualsRandom(t *testing.T) {
// Use a unique random seed each test instance and log it if the tests fail.
seed := time.Now().Unix()
rng := rand.New(rand.NewSource(seed))
defer func(t *testing.T, seed int64) {
if t.Failed() {
t.Logf("random seed: %d", seed)
}
}(t, seed)
for i := 0; i < 100; i++ {
// Ensure a randomly-generated scalar equals itself.
s := randModNScalar(t, rng)
if !s.Equals(s) {
t.Fatalf("failed equality check\nscalar in: %v", s)
}
// Flip a random bit in a random word and ensure it's no longer equal.
randomWord := rng.Int31n(int32(len(s.n)))
randomBit := uint32(1 << uint32(rng.Int31n(32)))
s2 := new(ModNScalar).Set(s)
s2.n[randomWord] ^= randomBit
if s2.Equals(s) {
t.Fatalf("failed inequality check\nscalar in: %v", s2)
}
}
}
// TestModNScalarAdd ensures that adding two scalars works as expected for edge
// cases.
func TestModNScalarAdd(t *testing.T) {
tests := []struct {
name string // test description
in1 string // first hex encoded test value
in2 string // second hex encoded test value
expected string // expected hex encoded bytes
}{
{
name: "zero + one",
in1: "0",
in2: "1",
expected: "1",
}, {
name: "one + zero",
in1: "1",
in2: "0",
expected: "1",
}, {
name: "group order (aka 0) + 1 (gets reduced, no overflow)",
in1: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
in2: "1",
expected: "1",
}, {
name: "group order - 1 + 1 (aka 0, overflow to prime)",
in1: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
in2: "1",
expected: "0",
}, {
name: "group order - 1 + 2 (aka 1, overflow in word zero)",
in1: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
in2: "2",
expected: "1",
}, {
name: "overflow in word one",
in1: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8bd0364141",
in2: "100000001",
expected: "1",
}, {
name: "overflow in word two",
in1: "fffffffffffffffffffffffffffffffebaaedce6af48a03abfd25e8cd0364141",
in2: "10000000000000001",
expected: "1",
}, {
name: "overflow in word three",
in1: "fffffffffffffffffffffffffffffffebaaedce5af48a03bbfd25e8cd0364141",
in2: "1000000000000000000000001",
expected: "1",
}, {
name: "overflow in word four",
in1: "fffffffffffffffffffffffffffffffdbaaedce6af48a03bbfd25e8cd0364141",
in2: "100000000000000000000000000000001",
expected: "1",
}, {
name: "overflow in word five",
in1: "fffffffffffffffffffffffefffffffebaaedce6af48a03bbfd25e8cd0364141",
in2: "10000000000000000000000000000000000000001",
expected: "1",
}, {
name: "overflow in word six",
in1: "fffffffffffffffefffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
in2: "1000000000000000000000000000000000000000000000001",
expected: "1",
}, {
name: "overflow in word seven",
in1: "fffffffefffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
in2: "100000000000000000000000000000000000000000000000000000001",
expected: "1",
}, {
name: "alternating bits",
in1: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
in2: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
expected: "14551231950b75fc4402da1732fc9bebe",
}, {
name: "alternating bits 2",
in1: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
in2: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
expected: "14551231950b75fc4402da1732fc9bebe",
},
}
for _, test := range tests {
// Parse test hex.
s1 := new(ModNScalar).SetHex(test.in1)
s2 := new(ModNScalar).SetHex(test.in2)
expected := new(ModNScalar).SetHex(test.expected)
// Ensure the result has the expected value.
s1.Add(s2)
if !s1.Equals(expected) {
t.Errorf(
"%s: unexpected result\ngot: %x\nwant: %x", test.name,
s1, expected,
)
continue
}
}
}
// TestModNScalarAddRandom ensures that adding two scalars together for random
// values works as expected by also performing the same operation with big ints
// and comparing the results.
func TestModNScalarAddRandom(t *testing.T) {
// Use a unique random seed each test instance and log it if the tests fail.
seed := time.Now().Unix()
rng := rand.New(rand.NewSource(seed))
defer func(t *testing.T, seed int64) {
if t.Failed() {
t.Logf("random seed: %d", seed)
}
}(t, seed)
for i := 0; i < 100; i++ {
// Generate two big integer and mod n scalar pairs.
bigIntVal1, modNVal1 := randIntAndModNScalar(t, rng)
bigIntVal2, modNVal2 := randIntAndModNScalar(t, rng)
// Calculate the sum of the values using big ints.
bigIntResult := new(big.Int).Add(bigIntVal1, bigIntVal2)
bigIntResult.Mod(bigIntResult, curveParams.N)
// Calculate the sum of the values using mod n scalars.
modNValResult := new(ModNScalar).Add2(modNVal1, modNVal2)
// Ensure they match.
bigIntResultHex := fmt.Sprintf("%064x", bigIntResult)
modNResultHex := fmt.Sprintf("%v", modNValResult)
if bigIntResultHex != modNResultHex {
t.Fatalf(
"mismatched add\nbig int in 1: %x\nbig int in 2: %x\n"+
"scalar in 1: %v\nscalar in 2: %v\nbig int result: %x\nscalar "+
"result %v", bigIntVal1, bigIntVal2, modNVal1, modNVal2,
bigIntResult, modNValResult,
)
}
}
}
// TestAccumulator96Add ensures that the internal 96-bit accumulator used by
// multiplication works as expected for overflow edge cases including overflow.
func TestAccumulator96Add(t *testing.T) {
tests := []struct {
name string // test description
start accumulator96 // starting value of accumulator
in uint64 // value to add to accumulator
expected accumulator96 // expected value of accumulator after addition
}{
{
name: "0 + 0 = 0",
start: accumulator96{[3]uint32{0, 0, 0}},
in: 0,
expected: accumulator96{[3]uint32{0, 0, 0}},
}, {
name: "overflow in word zero",
start: accumulator96{[3]uint32{0xffffffff, 0, 0}},
in: 1,
expected: accumulator96{[3]uint32{0, 1, 0}},
}, {
name: "overflow in word one",
start: accumulator96{[3]uint32{0, 0xffffffff, 0}},
in: 0x100000000,
expected: accumulator96{[3]uint32{0, 0, 1}},
}, {
name: "overflow in words one and two",
start: accumulator96{[3]uint32{0xffffffff, 0xffffffff, 0}},
in: 1,
expected: accumulator96{[3]uint32{0, 0, 1}},
}, {
// Start accumulator at 129127208455837319175 which is the result of
// 4294967295 * 4294967295 accumulated seven times.
name: "max result from eight adds of max uint32 multiplications",
start: accumulator96{[3]uint32{7, 4294967282, 6}},
in: 18446744065119617025,
expected: accumulator96{[3]uint32{8, 4294967280, 7}},
},
}
for _, test := range tests {
acc := test.start
acc.Add(test.in)
if acc.n != test.expected.n {
t.Errorf(
"%s: wrong result\ngot: %v\nwant: %v", test.name, acc.n,
test.expected.n,
)
}
}
}
// TestModNScalarMul ensures that multiplying two scalars together works as
// expected for edge cases.
func TestModNScalarMul(t *testing.T) {
tests := []struct {
name string // test description
in1 string // first hex encoded value
in2 string // second hex encoded value to multiply with
expected string // expected hex encoded value
}{
{
name: "zero * zero",
in1: "0",
in2: "0",
expected: "0",
}, {
name: "one * zero",
in1: "1",
in2: "0",
expected: "0",
}, {
name: "one * one",
in1: "1",
in2: "1",
expected: "1",
}, {
name: "(group order-1) * 2",
in1: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
in2: "2",
expected: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f",
}, {
name: "(group order-1) * (group order-1)",
in1: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
in2: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
expected: "1",
}, {
name: "slightly over group order",
in1: "7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1",
in2: "2",
expected: "1",
}, {
name: "group order (aka 0) * 3",
in1: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
in2: "3",
expected: "0",
}, {
name: "overflow in word eight",
in1: "100000000000000000000000000000000",
in2: "100000000000000000000000000000000",
expected: "14551231950b75fc4402da1732fc9bebf",
}, {
name: "overflow in word nine",
in1: "1000000000000000000000000000000000000",
in2: "1000000000000000000000000000000000000",
expected: "14551231950b75fc4402da1732fc9bebf00000000",
}, {
name: "overflow in word ten",
in1: "10000000000000000000000000000000000000000",
in2: "10000000000000000000000000000000000000000",
expected: "14551231950b75fc4402da1732fc9bebf0000000000000000",
}, {
name: "overflow in word eleven",
in1: "100000000000000000000000000000000000000000000",
in2: "100000000000000000000000000000000000000000000",
expected: "14551231950b75fc4402da1732fc9bebf000000000000000000000000",
}, {
name: "overflow in word twelve",
in1: "1000000000000000000000000000000000000000000000000",
in2: "1000000000000000000000000000000000000000000000000",
expected: "4551231950b75fc4402da1732fc9bec04551231950b75fc4402da1732fc9bebf",
}, {
name: "overflow in word thirteen",
in1: "10000000000000000000000000000000000000000000000000000",
in2: "10000000000000000000000000000000000000000000000000000",
expected: "50b75fc4402da1732fc9bec09d671cd51b343a1b66926b57d2a4c1c61536bda7",
}, {
name: "overflow in word fourteen",
in1: "100000000000000000000000000000000000000000000000000000000",
in2: "100000000000000000000000000000000000000000000000000000000",
expected: "402da1732fc9bec09d671cd581c69bc59509b0b074ec0aea8f564d667ec7eb3c",
}, {
name: "overflow in word fifteen",
in1: "1000000000000000000000000000000000000000000000000000000000000",
in2: "1000000000000000000000000000000000000000000000000000000000000",
expected: "2fc9bec09d671cd581c69bc5e697f5e41f12c33a0a7b6f4e3302b92ea029cecd",
}, {
name: "double overflow in internal accumulator",
in1: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
in2: "55555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c2",
expected: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b7f",
}, {
name: "alternating bits",
in1: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
in2: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
expected: "88edea3d29272800e7988455cfdf19b039dbfbb1c93b5b44a48c2ba462316838",
}, {
name: "alternating bits 2",
in1: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
in2: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
expected: "88edea3d29272800e7988455cfdf19b039dbfbb1c93b5b44a48c2ba462316838",
},
}
for _, test := range tests {
v1 := new(ModNScalar).SetHex(test.in1)
v2 := new(ModNScalar).SetHex(test.in2)
expected := new(ModNScalar).SetHex(test.expected)
// Ensure multiplying two other values produces the expected result.
result := new(ModNScalar).Mul2(v1, v2)
if !result.Equals(expected) {
t.Errorf(
"%s: wrong result\ngot: %v\nwant: %v", test.name, result,
expected,
)
continue
}
// Ensure self multiplying with another value also produces the expected
// result.
result2 := new(ModNScalar).Set(v1).Mul(v2)
if !result2.Equals(expected) {
t.Errorf(
"%s: wrong result\ngot: %v\nwant: %v", test.name, result2,
expected,
)
continue
}
}
}
// TestModNScalarMulRandom ensures that multiplying two scalars together for
// random values works as expected by also performing the same operation with
// big ints and comparing the results.
func TestModNScalarMulRandom(t *testing.T) {
// Use a unique random seed each test instance and log it if the tests fail.
seed := time.Now().Unix()
rng := rand.New(rand.NewSource(seed))
defer func(t *testing.T, seed int64) {
if t.Failed() {
t.Logf("random seed: %d", seed)
}
}(t, seed)
for i := 0; i < 100; i++ {
// Generate two big integer and mod n scalar pairs.
bigIntVal1, modNVal1 := randIntAndModNScalar(t, rng)
bigIntVal2, modNVal2 := randIntAndModNScalar(t, rng)
// Calculate the square of the value using big ints.
bigIntResult := new(big.Int).Mul(bigIntVal1, bigIntVal2)
bigIntResult.Mod(bigIntResult, curveParams.N)
// Calculate the square of the value using mod n scalar.
modNValResult := new(ModNScalar).Mul2(modNVal1, modNVal2)
// Ensure they match.
bigIntResultHex := fmt.Sprintf("%064x", bigIntResult)
modNResultHex := fmt.Sprintf("%v", modNValResult)
if bigIntResultHex != modNResultHex {
t.Fatalf(
"mismatched mul\nbig int in 1: %x\nbig int in 2: %x\n"+
"scalar in 1: %v\nscalar in 2: %v\nbig int result: %x\nscalar "+
"result %v", bigIntVal1, bigIntVal2, modNVal1, modNVal2,
bigIntResult, modNValResult,
)
}
}
}
// TestModNScalarSquare ensures that squaring scalars works as expected for edge
// cases.
func TestModNScalarSquare(t *testing.T) {
tests := []struct {
name string // test description
in string // hex encoded test value
expected string // expected hex encoded value
}{
{
name: "zero",
in: "0",
expected: "0",
}, {
name: "one",
in: "1",
expected: "1",
}, {
name: "over group order",
in: "0000000000000000000000000000000100000000000000000000000000000000",
expected: "000000000000000000000000000000014551231950b75fc4402da1732fc9bebf",
}, {
name: "group order - 1",
in: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
expected: "0000000000000000000000000000000000000000000000000000000000000001",
}, {
name: "overflow in word eight",
in: "100000000000000000000000000000000",
expected: "14551231950b75fc4402da1732fc9bebf",
}, {
name: "overflow in word nine",
in: "1000000000000000000000000000000000000",
expected: "14551231950b75fc4402da1732fc9bebf00000000",
}, {
name: "overflow in word ten",
in: "10000000000000000000000000000000000000000",
expected: "14551231950b75fc4402da1732fc9bebf0000000000000000",
}, {
name: "overflow in word eleven",
in: "100000000000000000000000000000000000000000000",
expected: "14551231950b75fc4402da1732fc9bebf000000000000000000000000",
}, {
name: "overflow in word twelve",
in: "1000000000000000000000000000000000000000000000000",
expected: "4551231950b75fc4402da1732fc9bec04551231950b75fc4402da1732fc9bebf",
}, {
name: "overflow in word thirteen",
in: "10000000000000000000000000000000000000000000000000000",
expected: "50b75fc4402da1732fc9bec09d671cd51b343a1b66926b57d2a4c1c61536bda7",
}, {
name: "overflow in word fourteen",
in: "100000000000000000000000000000000000000000000000000000000",
expected: "402da1732fc9bec09d671cd581c69bc59509b0b074ec0aea8f564d667ec7eb3c",
}, {
name: "overflow in word fifteen",
in: "1000000000000000000000000000000000000000000000000000000000000",
expected: "2fc9bec09d671cd581c69bc5e697f5e41f12c33a0a7b6f4e3302b92ea029cecd",
}, {
name: "alternating bits",
in: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
expected: "fb0982c5761d1eac534247f2a7c3af186a134d709b977ca88300faad5eafe9bc",
}, {
name: "alternating bits 2",
in: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
expected: "9081c595b95b2d17c424a546144b25488104c5889d914635bc9d1a51859e1c19",
},
}
for _, test := range tests {
v := new(ModNScalar).SetHex(test.in)
expected := new(ModNScalar).SetHex(test.expected)
// Ensure squaring another value produces the expected result.
result := new(ModNScalar).SquareVal(v)
if !result.Equals(expected) {
t.Errorf(
"%s: wrong result\ngot: %v\nwant: %v", test.name, result,
expected,
)
continue
}
// Ensure self squaring also produces the expected result.
result2 := new(ModNScalar).Set(v).Square()
if !result2.Equals(expected) {
t.Errorf(
"%s: wrong result\ngot: %v\nwant: %v", test.name, result2,
expected,
)
continue
}
}
}
// TestModNScalarSquareRandom ensures that squaring scalars for random values
// works as expected by also performing the same operation with big ints and
// comparing the results.
func TestModNScalarSquareRandom(t *testing.T) {
// Use a unique random seed each test instance and log it if the tests fail.
seed := time.Now().Unix()
rng := rand.New(rand.NewSource(seed))
defer func(t *testing.T, seed int64) {
if t.Failed() {
t.Logf("random seed: %d", seed)
}
}(t, seed)
for i := 0; i < 100; i++ {
// Generate big integer and mod n scalar with the same random value.
bigIntVal, modNVal := randIntAndModNScalar(t, rng)
// Calculate the square of the value using big ints.
bigIntResult := new(big.Int).Mul(bigIntVal, bigIntVal)
bigIntResult.Mod(bigIntResult, curveParams.N)
// Calculate the square of the value using mod n scalar.
modNValResult := new(ModNScalar).SquareVal(modNVal)
// Ensure they match.
bigIntResultHex := fmt.Sprintf("%064x", bigIntResult)
modNResultHex := fmt.Sprintf("%v", modNValResult)
if bigIntResultHex != modNResultHex {
t.Fatalf(
"mismatched square\nbig int in: %x\nscalar in: %v\n"+
"big int result: %x\nscalar result %v", bigIntVal, modNVal,
bigIntResult, modNValResult,
)
}
}
}
// TestModNScalarNegate ensures that negating scalars works as expected for edge
// cases.
func TestModNScalarNegate(t *testing.T) {
tests := []struct {
name string // test description
in string // hex encoded test value
expected string // hex encoded expected result
}{
{
name: "zero",
in: "0",
expected: "0",
}, {
name: "one",
in: "1",
expected: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
}, {
name: "negation in word one",
in: "0000000000000000000000000000000000000000000000000000000100000000",
expected: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8bd0364141",
}, {
name: "negation in word two",
in: "0000000000000000000000000000000000000000000000010000000000000000",
expected: "fffffffffffffffffffffffffffffffebaaedce6af48a03abfd25e8cd0364141",
}, {
name: "negation in word three",
in: "0000000000000000000000000000000000000001000000000000000000000000",
expected: "fffffffffffffffffffffffffffffffebaaedce5af48a03bbfd25e8cd0364141",
}, {
name: "negation in word four",
in: "0000000000000000000000000000000100000000000000000000000000000000",
expected: "fffffffffffffffffffffffffffffffdbaaedce6af48a03bbfd25e8cd0364141",
}, {
name: "negation in word five",
in: "0000000000000000000000010000000000000000000000000000000000000000",
expected: "fffffffffffffffffffffffefffffffebaaedce6af48a03bbfd25e8cd0364141",
}, {
name: "negation in word six",
in: "0000000000000001000000000000000000000000000000000000000000000000",
expected: "fffffffffffffffefffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
}, {
name: "negation in word seven",
in: "0000000100000000000000000000000000000000000000000000000000000000",
expected: "fffffffefffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
}, {
name: "alternating bits",
in: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
expected: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a591509374109a2fa961a2cb8e72a909b9c",
}, {
name: "alternating bits 2",
in: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
expected: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a46054828c54ee45e16578043275dbe6e7",
},
}
for _, test := range tests {
s := new(ModNScalar).SetHex(test.in)
expected := new(ModNScalar).SetHex(test.expected)
// Ensure negating another value produces the expected result.
result := new(ModNScalar).NegateVal(s)
if !result.Equals(expected) {
t.Errorf(
"%s: unexpected result -- got: %v, want: %v", test.name,
result, expected,
)
continue
}
// Ensure self negating also produces the expected result.
result2 := new(ModNScalar).Set(s).Negate()
if !result2.Equals(expected) {
t.Errorf(
"%s: unexpected result -- got: %v, want: %v", test.name,
result2, expected,
)
continue
}
}
}
// TestModNScalarNegateRandom ensures that negating scalars for random values
// works as expected by also performing the same operation with big ints and
// comparing the results.
func TestModNScalarNegateRandom(t *testing.T) {
// Use a unique random seed each test instance and log it if the tests fail.
seed := time.Now().Unix()
rng := rand.New(rand.NewSource(seed))
defer func(t *testing.T, seed int64) {
if t.Failed() {
t.Logf("random seed: %d", seed)
}
}(t, seed)
for i := 0; i < 100; i++ {
// Generate big integer and mod n scalar with the same random value.
bigIntVal, modNVal := randIntAndModNScalar(t, rng)
// Calculate the negation of the value using big ints.
bigIntResult := new(big.Int).Neg(bigIntVal)
bigIntResult.Mod(bigIntResult, curveParams.N)
// Calculate the negation of the value using mod n scalar.
modNValResult := new(ModNScalar).NegateVal(modNVal)
// Ensure they match.
bigIntResultHex := fmt.Sprintf("%064x", bigIntResult)
modNResultHex := fmt.Sprintf("%v", modNValResult)
if bigIntResultHex != modNResultHex {
t.Fatalf(
"mismatched negate\nbig int in: %x\nscalar in: %v\n"+
"big int result: %x\nscalar result %v", bigIntVal, modNVal,
bigIntResult, modNValResult,
)
}
}
}
// TestModNScalarInverseNonConst ensures that calculating the multiplicative
// inverse of scalars in *non-constant* time works as expected for edge cases.
func TestModNScalarInverseNonConst(t *testing.T) {
tests := []struct {
name string // test description
in string // hex encoded test value
expected string // hex encoded expected result
}{
{
name: "zero",
in: "0",
expected: "0",
}, {
name: "one",
in: "1",
expected: "1",
}, {
name: "inverse carry in word one",
in: "0000000000000000000000000000000000000000000000000000000100000000",
expected: "5588b13effffffffffffffffffffffff934e5b00ca8417bf50177f7ba415411a",
}, {
name: "inverse carry in word two",
in: "0000000000000000000000000000000000000000000000010000000000000000",
expected: "4b0dff665588b13effffffffffffffffa09f710af01555259d4ad302583de6dc",
}, {
name: "inverse carry in word three",
in: "0000000000000000000000000000000000000001000000000000000000000000",
expected: "34b9ec244b0dff665588b13effffffffbcff4127932a971a78274c9d74176b38",
}, {
name: "inverse carry in word four",
in: "0000000000000000000000000000000100000000000000000000000000000000",
expected: "50a51ac834b9ec244b0dff665588b13e9984d5b3cf80ef0fd6a23766a3ee9f22",
}, {
name: "inverse carry in word five",
in: "0000000000000000000000010000000000000000000000000000000000000000",
expected: "27cfab5e50a51ac834b9ec244b0dff6622f16e85b683d5a059bcd5a3b29d9dff",
}, {
name: "inverse carry in word six",
in: "0000000000000001000000000000000000000000000000000000000000000000",
expected: "897f30c127cfab5e50a51ac834b9ec239c53f268b4700c14f19b9499ac58d8ad",
}, {
name: "inverse carry in word seven",
in: "0000000100000000000000000000000000000000000000000000000000000000",
expected: "6494ef93897f30c127cfab5e50a51ac7b4e8f713e0cddd182234e907286ae6b3",
}, {
name: "alternating bits",
in: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
expected: "cb6086e560b8597a85c934e46f5b6e8a445bf3f0a88e4160d7fa8d83fd10338d",
}, {
name: "alternating bits 2",
in: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
expected: "9f864ca486a74eb5f546364d76d24aa93716dc78f84847aa6c1c09fca2707d77",
},
}
for _, test := range tests {
s := new(ModNScalar).SetHex(test.in)
expected := new(ModNScalar).SetHex(test.expected)
// Ensure calculating the multiplicative inverse of another value
// produces the expected result.
result := new(ModNScalar).InverseValNonConst(s)
if !result.Equals(expected) {
t.Errorf(
"%s: unexpected result -- got: %v, want: %v", test.name,
result, expected,
)
continue
}
// Ensure calculating the multiplicative inverse in place also produces
// the expected result.
result2 := new(ModNScalar).Set(s).InverseNonConst()
if !result2.Equals(expected) {
t.Errorf(
"%s: unexpected result -- got: %v, want: %v", test.name,
result2, expected,
)
continue
}
}
}
// TestModNScalarInverseNonConstRandom ensures that calculating the
// multiplicative inverse of scalars in *non-constant* time for random values
// works as expected by also performing the same operation with big ints and
// comparing the results.
func TestModNScalarInverseNonConstRandom(t *testing.T) {
// Use a unique random seed each test instance and log it if the tests fail.
seed := time.Now().Unix()
rng := rand.New(rand.NewSource(seed))
defer func(t *testing.T, seed int64) {
if t.Failed() {
t.Logf("random seed: %d", seed)
}
}(t, seed)
for i := 0; i < 100; i++ {
// Generate big integer and mod n scalar with the same random value.
bigIntVal, modNVal := randIntAndModNScalar(t, rng)
// Calculate the inverse of the value using big ints.
bigIntResult := new(big.Int).ModInverse(bigIntVal, curveParams.N)
// Calculate the inverse of the value using a mod n scalar.
modNValResult := new(ModNScalar).InverseValNonConst(modNVal)
// Ensure they match.
bigIntResultHex := fmt.Sprintf("%064x", bigIntResult)
modNResultHex := fmt.Sprintf("%v", modNValResult)
if bigIntResultHex != modNResultHex {
t.Fatalf(
"mismatched inverse\nbig int in: %x\nscalar in: %v\n"+
"big int result: %x\nscalar result %v", bigIntVal, modNVal,
bigIntResult, modNValResult,
)
}
}
}
// TestModNScalarIsOverHalfOrder ensures that scalars report whether or not they
// exceeed the half order works as expected for edge cases.
func TestModNScalarIsOverHalfOrder(t *testing.T) {
tests := []struct {
name string // test description
in string // hex encoded test value
expected bool // expected result
}{
{
name: "zero",
in: "0",
expected: false,
}, {
name: "one",
in: "1",
expected: false,
}, {
name: "group half order - 1",
in: "7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b209f",
expected: false,
}, {
name: "group half order",
in: "7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0",
expected: false,
}, {
name: "group half order + 1",
in: "7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1",
expected: true,
}, {
name: "over half order word one",
in: "7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f47681b20a0",
expected: true,
}, {
name: "over half order word two",
in: "7fffffffffffffffffffffffffffffff5d576e7357a4501edfe92f46681b20a0",
expected: true,
}, {
name: "over half order word three",
in: "7fffffffffffffffffffffffffffffff5d576e7457a4501ddfe92f46681b20a0",
expected: true,
}, {
name: "over half order word seven",
in: "8fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0",
expected: true,
},
}
for _, test := range tests {
result := new(ModNScalar).SetHex(test.in).IsOverHalfOrder()
if result != test.expected {
t.Errorf(
"%s: unexpected result -- got: %v, want: %v", test.name,
result, test.expected,
)
continue
}
}
}
// TestModNScalarIsOverHalfOrderRandom ensures that scalars report whether or
// not they exceeed the half order for random values works as expected by also
// performing the same operation with big ints and comparing the results.
func TestModNScalarIsOverHalfOrderRandom(t *testing.T) {
// Use a unique random seed each test instance and log it if the tests fail.
seed := time.Now().Unix()
rng := rand.New(rand.NewSource(seed))
defer func(t *testing.T, seed int64) {
if t.Failed() {
t.Logf("random seed: %d", seed)
}
}(t, seed)
bigHalfOrder := new(big.Int).Rsh(curveParams.N, 1)
for i := 0; i < 100; i++ {
// Generate big integer and mod n scalar with the same random value.
bigIntVal, modNVal := randIntAndModNScalar(t, rng)
// Determine the value exceeds the half order using big ints.
bigIntResult := bigIntVal.Cmp(bigHalfOrder) > 0
// Determine the value exceeds the half order using a mod n scalar.
modNValResult := modNVal.IsOverHalfOrder()
// Ensure they match.
if bigIntResult != modNValResult {
t.Fatalf(
"mismatched is over half order\nbig int in: %x\nscalar "+
"in: %v\nbig int result: %v\nscalar result %v", bigIntVal,
modNVal, bigIntResult, modNValResult,
)
}
}
}