lbcd/btcec/field_test.go
Anirudha Bose d28c7167a5 btcec: Avoid panic in fieldVal.SetByteSlice for large inputs
The implementation has been adapted from the dcrec module in dcrd. The
bug was initially fixed in decred/dcrd@3d9cda1 while transitioning to a
constant time algorithm. A large set of test vectors were subsequently
added in decred/dcrd@8c6b52d.

The function signature has been preserved for backwards compatibility.
This means that returning whether the value has overflowed, and the
corresponding test vectors have not been backported.

This fixes  and closes a previous attempt to fix the bug in .
2020-07-13 09:43:36 -04:00

1121 lines
37 KiB
Go

// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2013-2016 Dave Collins
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcec
import (
"crypto/rand"
"encoding/hex"
"fmt"
"reflect"
"testing"
)
// TestSetInt ensures that setting a field value to various native integers
// works as expected.
func TestSetInt(t *testing.T) {
tests := []struct {
in uint
raw [10]uint32
}{
{5, [10]uint32{5, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
// 2^26
{67108864, [10]uint32{67108864, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
// 2^26 + 1
{67108865, [10]uint32{67108865, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
// 2^32 - 1
{4294967295, [10]uint32{4294967295, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetInt(test.in)
if !reflect.DeepEqual(f.n, test.raw) {
t.Errorf("fieldVal.Set #%d wrong result\ngot: %v\n"+
"want: %v", i, f.n, test.raw)
continue
}
}
}
// TestZero ensures that zeroing a field value zero works as expected.
func TestZero(t *testing.T) {
f := new(fieldVal).SetInt(2)
f.Zero()
for idx, rawInt := range f.n {
if rawInt != 0 {
t.Errorf("internal field integer at index #%d is not "+
"zero - got %d", idx, rawInt)
}
}
}
// TestIsZero ensures that checking if a field IsZero works as expected.
func TestIsZero(t *testing.T) {
f := new(fieldVal)
if !f.IsZero() {
t.Errorf("new field value is not zero - got %v (rawints %x)", f,
f.n)
}
f.SetInt(1)
if f.IsZero() {
t.Errorf("field claims it's zero when it's not - got %v "+
"(raw rawints %x)", f, f.n)
}
f.Zero()
if !f.IsZero() {
t.Errorf("field claims it's not zero when it is - got %v "+
"(raw rawints %x)", f, f.n)
}
}
// TestStringer ensures the stringer returns the appropriate hex string.
func TestStringer(t *testing.T) {
tests := []struct {
in string
expected string
}{
{"0", "0000000000000000000000000000000000000000000000000000000000000000"},
{"1", "0000000000000000000000000000000000000000000000000000000000000001"},
{"a", "000000000000000000000000000000000000000000000000000000000000000a"},
{"b", "000000000000000000000000000000000000000000000000000000000000000b"},
{"c", "000000000000000000000000000000000000000000000000000000000000000c"},
{"d", "000000000000000000000000000000000000000000000000000000000000000d"},
{"e", "000000000000000000000000000000000000000000000000000000000000000e"},
{"f", "000000000000000000000000000000000000000000000000000000000000000f"},
{"f0", "00000000000000000000000000000000000000000000000000000000000000f0"},
// 2^26-1
{
"3ffffff",
"0000000000000000000000000000000000000000000000000000000003ffffff",
},
// 2^32-1
{
"ffffffff",
"00000000000000000000000000000000000000000000000000000000ffffffff",
},
// 2^64-1
{
"ffffffffffffffff",
"000000000000000000000000000000000000000000000000ffffffffffffffff",
},
// 2^96-1
{
"ffffffffffffffffffffffff",
"0000000000000000000000000000000000000000ffffffffffffffffffffffff",
},
// 2^128-1
{
"ffffffffffffffffffffffffffffffff",
"00000000000000000000000000000000ffffffffffffffffffffffffffffffff",
},
// 2^160-1
{
"ffffffffffffffffffffffffffffffffffffffff",
"000000000000000000000000ffffffffffffffffffffffffffffffffffffffff",
},
// 2^192-1
{
"ffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff",
},
// 2^224-1
{
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
},
// 2^256-4294968273 (the btcec prime, so should result in 0)
{
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
"0000000000000000000000000000000000000000000000000000000000000000",
},
// 2^256-4294968274 (the secp256k1 prime+1, so should result in 1)
{
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
"0000000000000000000000000000000000000000000000000000000000000001",
},
// Invalid hex
{"g", "0000000000000000000000000000000000000000000000000000000000000000"},
{"1h", "0000000000000000000000000000000000000000000000000000000000000000"},
{"i1", "0000000000000000000000000000000000000000000000000000000000000000"},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in)
result := f.String()
if result != test.expected {
t.Errorf("fieldVal.String #%d wrong result\ngot: %v\n"+
"want: %v", i, result, test.expected)
continue
}
}
}
// TestNormalize ensures that normalizing the internal field words works as
// expected.
func TestNormalize(t *testing.T) {
tests := []struct {
raw [10]uint32 // Intentionally denormalized value
normalized [10]uint32 // Normalized form of the raw value
}{
{
[10]uint32{0x00000005, 0, 0, 0, 0, 0, 0, 0, 0, 0},
[10]uint32{0x00000005, 0, 0, 0, 0, 0, 0, 0, 0, 0},
},
// 2^26
{
[10]uint32{0x04000000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0},
[10]uint32{0x00000000, 0x1, 0, 0, 0, 0, 0, 0, 0, 0},
},
// 2^26 + 1
{
[10]uint32{0x04000001, 0x0, 0, 0, 0, 0, 0, 0, 0, 0},
[10]uint32{0x00000001, 0x1, 0, 0, 0, 0, 0, 0, 0, 0},
},
// 2^32 - 1
{
[10]uint32{0xffffffff, 0x00, 0, 0, 0, 0, 0, 0, 0, 0},
[10]uint32{0x03ffffff, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0},
},
// 2^32
{
[10]uint32{0x04000000, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0},
[10]uint32{0x00000000, 0x40, 0, 0, 0, 0, 0, 0, 0, 0},
},
// 2^32 + 1
{
[10]uint32{0x04000001, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0},
[10]uint32{0x00000001, 0x40, 0, 0, 0, 0, 0, 0, 0, 0},
},
// 2^64 - 1
{
[10]uint32{0xffffffff, 0xffffffc0, 0xfc0, 0, 0, 0, 0, 0, 0, 0},
[10]uint32{0x03ffffff, 0x03ffffff, 0xfff, 0, 0, 0, 0, 0, 0, 0},
},
// 2^64
{
[10]uint32{0x04000000, 0x03ffffff, 0x0fff, 0, 0, 0, 0, 0, 0, 0},
[10]uint32{0x00000000, 0x00000000, 0x1000, 0, 0, 0, 0, 0, 0, 0},
},
// 2^64 + 1
{
[10]uint32{0x04000001, 0x03ffffff, 0x0fff, 0, 0, 0, 0, 0, 0, 0},
[10]uint32{0x00000001, 0x00000000, 0x1000, 0, 0, 0, 0, 0, 0, 0},
},
// 2^96 - 1
{
[10]uint32{0xffffffff, 0xffffffc0, 0xffffffc0, 0x3ffc0, 0, 0, 0, 0, 0, 0},
[10]uint32{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x3ffff, 0, 0, 0, 0, 0, 0},
},
// 2^96
{
[10]uint32{0x04000000, 0x03ffffff, 0x03ffffff, 0x3ffff, 0, 0, 0, 0, 0, 0},
[10]uint32{0x00000000, 0x00000000, 0x00000000, 0x40000, 0, 0, 0, 0, 0, 0},
},
// 2^128 - 1
{
[10]uint32{0xffffffff, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffc0, 0, 0, 0, 0, 0},
[10]uint32{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0xffffff, 0, 0, 0, 0, 0},
},
// 2^128
{
[10]uint32{0x04000000, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x0ffffff, 0, 0, 0, 0, 0},
[10]uint32{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1000000, 0, 0, 0, 0, 0},
},
// 2^256 - 4294968273 (secp256k1 prime)
{
[10]uint32{0xfffffc2f, 0xffffff80, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0},
[10]uint32{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000},
},
// Prime larger than P where both first and second words are larger
// than P's first and second words
{
[10]uint32{0xfffffc30, 0xffffff86, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0},
[10]uint32{0x00000001, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000},
},
// Prime larger than P where only the second word is larger
// than P's second words.
{
[10]uint32{0xfffffc2a, 0xffffff87, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0},
[10]uint32{0x03fffffb, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000},
},
// 2^256 - 1
{
[10]uint32{0xffffffff, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0},
[10]uint32{0x000003d0, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000},
},
// Prime with field representation such that the initial
// reduction does not result in a carry to bit 256.
//
// 2^256 - 4294968273 (secp256k1 prime)
{
[10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff},
[10]uint32{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
},
// Prime larger than P that reduces to a value which is still
// larger than P when it has a magnitude of 1 due to its first
// word and does not result in a carry to bit 256.
//
// 2^256 - 4294968272 (secp256k1 prime + 1)
{
[10]uint32{0x03fffc30, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff},
[10]uint32{0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
},
// Prime larger than P that reduces to a value which is still
// larger than P when it has a magnitude of 1 due to its second
// word and does not result in a carry to bit 256.
//
// 2^256 - 4227859409 (secp256k1 prime + 0x4000000)
{
[10]uint32{0x03fffc2f, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff},
[10]uint32{0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
},
// Prime larger than P that reduces to a value which is still
// larger than P when it has a magnitude of 1 due to a carry to
// bit 256, but would not be without the carry. These values
// come from the fact that P is 2^256 - 4294968273 and 977 is
// the low order word in the internal field representation.
//
// 2^256 * 5 - ((4294968273 - (977+1)) * 4)
{
[10]uint32{0x03ffffff, 0x03fffeff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x0013fffff},
[10]uint32{0x00001314, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000000},
},
// Prime larger than P that reduces to a value which is still
// larger than P when it has a magnitude of 1 due to both a
// carry to bit 256 and the first word.
{
[10]uint32{0x03fffc30, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x07ffffff, 0x003fffff},
[10]uint32{0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001},
},
// Prime larger than P that reduces to a value which is still
// larger than P when it has a magnitude of 1 due to both a
// carry to bit 256 and the second word.
//
{
[10]uint32{0x03fffc2f, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x3ffffff, 0x07ffffff, 0x003fffff},
[10]uint32{0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000, 0x00000000, 0x00000001},
},
// Prime larger than P that reduces to a value which is still
// larger than P when it has a magnitude of 1 due to a carry to
// bit 256 and the first and second words.
//
{
[10]uint32{0x03fffc30, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x07ffffff, 0x003fffff},
[10]uint32{0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001},
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal)
f.n = test.raw
f.Normalize()
if !reflect.DeepEqual(f.n, test.normalized) {
t.Errorf("fieldVal.Normalize #%d wrong result\n"+
"got: %x\nwant: %x", i, f.n, test.normalized)
continue
}
}
}
// TestIsOdd ensures that checking if a field value IsOdd works as expected.
func TestIsOdd(t *testing.T) {
tests := []struct {
in string // hex encoded value
expected bool // expected oddness
}{
{"0", false},
{"1", true},
{"2", false},
// 2^32 - 1
{"ffffffff", true},
// 2^64 - 2
{"fffffffffffffffe", false},
// secp256k1 prime
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", true},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in)
result := f.IsOdd()
if result != test.expected {
t.Errorf("fieldVal.IsOdd #%d wrong result\n"+
"got: %v\nwant: %v", i, result, test.expected)
continue
}
}
}
// TestEquals ensures that checking two field values for equality via Equals
// works as expected.
func TestEquals(t *testing.T) {
tests := []struct {
in1 string // hex encoded value
in2 string // hex encoded value
expected bool // expected equality
}{
{"0", "0", true},
{"0", "1", false},
{"1", "0", false},
// 2^32 - 1 == 2^32 - 1?
{"ffffffff", "ffffffff", true},
// 2^64 - 1 == 2^64 - 2?
{"ffffffffffffffff", "fffffffffffffffe", false},
// 0 == prime (mod prime)?
{"0", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", true},
// 1 == prime+1 (mod prime)?
{"1", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", true},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in1).Normalize()
f2 := new(fieldVal).SetHex(test.in2).Normalize()
result := f.Equals(f2)
if result != test.expected {
t.Errorf("fieldVal.Equals #%d wrong result\n"+
"got: %v\nwant: %v", i, result, test.expected)
continue
}
}
}
// TestNegate ensures that negating field values via Negate works as expected.
func TestNegate(t *testing.T) {
tests := []struct {
in string // hex encoded value
expected string // expected hex encoded value
}{
// secp256k1 prime (aka 0)
{"0", "0"},
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "0"},
{"0", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"},
// secp256k1 prime-1
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", "1"},
{"1", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e"},
// secp256k1 prime-2
{"2", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d"},
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", "2"},
// Random sampling
{
"b3d9aac9c5e43910b4385b53c7e78c21d4cd5f8e683c633aed04c233efc2e120",
"4c2655363a1bc6ef4bc7a4ac381873de2b32a07197c39cc512fb3dcb103d1b0f",
},
{
"f8a85984fee5a12a7c8dd08830d83423c937d77c379e4a958e447a25f407733f",
"757a67b011a5ed583722f77cf27cbdc36c82883c861b56a71bb85d90bf888f0",
},
{
"45ee6142a7fda884211e93352ed6cb2807800e419533be723a9548823ece8312",
"ba119ebd5802577bdee16ccad12934d7f87ff1be6acc418dc56ab77cc131791d",
},
{
"53c2a668f07e411a2e473e1c3b6dcb495dec1227af27673761d44afe5b43d22b",
"ac3d59970f81bee5d1b8c1e3c49234b6a213edd850d898c89e2bb500a4bc2a04",
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in).Normalize()
expected := new(fieldVal).SetHex(test.expected).Normalize()
result := f.Negate(1).Normalize()
if !result.Equals(expected) {
t.Errorf("fieldVal.Negate #%d wrong result\n"+
"got: %v\nwant: %v", i, result, expected)
continue
}
}
}
// TestAddInt ensures that adding an integer to field values via AddInt works as
// expected.
func TestAddInt(t *testing.T) {
tests := []struct {
in1 string // hex encoded value
in2 uint // unsigned integer to add to the value above
expected string // expected hex encoded value
}{
{"0", 1, "1"},
{"1", 0, "1"},
{"1", 1, "2"},
// secp256k1 prime-1 + 1
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", 1, "0"},
// secp256k1 prime + 1
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", 1, "1"},
// Random samples.
{
"ff95ad9315aff04ab4af0ce673620c7145dc85d03bab5ba4b09ca2c4dec2d6c1",
0x10f,
"ff95ad9315aff04ab4af0ce673620c7145dc85d03bab5ba4b09ca2c4dec2d7d0",
},
{
"44bdae6b772e7987941f1ba314e6a5b7804a4c12c00961b57d20f41deea9cecf",
0x2cf11d41,
"44bdae6b772e7987941f1ba314e6a5b7804a4c12c00961b57d20f41e1b9aec10",
},
{
"88c3ecae67b591935fb1f6a9499c35315ffad766adca665c50b55f7105122c9c",
0x4829aa2d,
"88c3ecae67b591935fb1f6a9499c35315ffad766adca665c50b55f714d3bd6c9",
},
{
"8523e9edf360ca32a95aae4e57fcde5a542b471d08a974d94ea0ee09a015e2a6",
0xa21265a5,
"8523e9edf360ca32a95aae4e57fcde5a542b471d08a974d94ea0ee0a4228484b",
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in1).Normalize()
expected := new(fieldVal).SetHex(test.expected).Normalize()
result := f.AddInt(test.in2).Normalize()
if !result.Equals(expected) {
t.Errorf("fieldVal.AddInt #%d wrong result\n"+
"got: %v\nwant: %v", i, result, expected)
continue
}
}
}
// TestAdd ensures that adding two field values together via Add works as
// expected.
func TestAdd(t *testing.T) {
tests := []struct {
in1 string // first hex encoded value
in2 string // second hex encoded value to add
expected string // expected hex encoded value
}{
{"0", "1", "1"},
{"1", "0", "1"},
{"1", "1", "2"},
// secp256k1 prime-1 + 1
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", "1", "0"},
// secp256k1 prime + 1
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "1", "1"},
// Random samples.
{
"2b2012f975404e5065b4292fb8bed0a5d315eacf24c74d8b27e73bcc5430edcc",
"2c3cefa4e4753e8aeec6ac4c12d99da4d78accefda3b7885d4c6bab46c86db92",
"575d029e59b58cdb547ad57bcb986e4aaaa0b7beff02c610fcadf680c0b7c95e",
},
{
"8131e8722fe59bb189692b96c9f38de92885730f1dd39ab025daffb94c97f79c",
"ff5454b765f0aab5f0977dcc629becc84cabeb9def48e79c6aadb2622c490fa9",
"80863d2995d646677a00a9632c8f7ab175315ead0d1c824c9088b21c78e10b16",
},
{
"c7c95e93d0892b2b2cdd77e80eb646ea61be7a30ac7e097e9f843af73fad5c22",
"3afe6f91a74dfc1c7f15c34907ee981656c37236d946767dd53ccad9190e437c",
"02c7ce2577d72747abf33b3116a4df00b881ec6785c47ffc74c105d158bba36f",
},
{
"fd1c26f6a23381e5d785ba889494ec059369b888ad8431cd67d8c934b580dbe1",
"a475aa5a31dcca90ef5b53c097d9133d6b7117474b41e7877bb199590fc0489c",
"a191d150d4104c76c6e10e492c6dff42fedacfcff8c61954e38a628ec541284e",
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in1).Normalize()
f2 := new(fieldVal).SetHex(test.in2).Normalize()
expected := new(fieldVal).SetHex(test.expected).Normalize()
result := f.Add(f2).Normalize()
if !result.Equals(expected) {
t.Errorf("fieldVal.Add #%d wrong result\n"+
"got: %v\nwant: %v", i, result, expected)
continue
}
}
}
// TestAdd2 ensures that adding two field values together via Add2 works as
// expected.
func TestAdd2(t *testing.T) {
tests := []struct {
in1 string // first hex encoded value
in2 string // second hex encoded value to add
expected string // expected hex encoded value
}{
{"0", "1", "1"},
{"1", "0", "1"},
{"1", "1", "2"},
// secp256k1 prime-1 + 1
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", "1", "0"},
// secp256k1 prime + 1
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "1", "1"},
// close but over the secp256k1 prime
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000", "f1ffff000", "1ffff3d1"},
// Random samples.
{
"ad82b8d1cc136e23e9fd77fe2c7db1fe5a2ecbfcbde59ab3529758334f862d28",
"4d6a4e95d6d61f4f46b528bebe152d408fd741157a28f415639347a84f6f574b",
"faed0767a2e98d7330b2a0bcea92df3eea060d12380e8ec8b62a9fdb9ef58473",
},
{
"f3f43a2540054a86e1df98547ec1c0e157b193e5350fb4a3c3ea214b228ac5e7",
"25706572592690ea3ddc951a1b48b504a4c83dc253756e1b96d56fdfb3199522",
"19649f97992bdb711fbc2d6e9a0a75e5fc79d1a7888522bf5abf912bd5a45eda",
},
{
"6915bb94eef13ff1bb9b2633d997e13b9b1157c713363cc0e891416d6734f5b8",
"11f90d6ac6fe1c4e8900b1c85fb575c251ec31b9bc34b35ada0aea1c21eded22",
"7b0ec8ffb5ef5c40449bd7fc394d56fdecfd8980cf6af01bc29c2b898922e2da",
},
{
"48b0c9eae622eed9335b747968544eb3e75cb2dc8128388f948aa30f88cabde4",
"0989882b52f85f9d524a3a3061a0e01f46d597839d2ba637320f4b9510c8d2d5",
"523a5216391b4e7685a5aea9c9f52ed32e324a601e53dec6c699eea4999390b9",
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in1).Normalize()
f2 := new(fieldVal).SetHex(test.in2).Normalize()
expected := new(fieldVal).SetHex(test.expected).Normalize()
result := f.Add2(f, f2).Normalize()
if !result.Equals(expected) {
t.Errorf("fieldVal.Add2 #%d wrong result\n"+
"got: %v\nwant: %v", i, result, expected)
continue
}
}
}
// TestMulInt ensures that adding an integer to field values via MulInt works as
// expected.
func TestMulInt(t *testing.T) {
tests := []struct {
in1 string // hex encoded value
in2 uint // unsigned integer to multiply with value above
expected string // expected hex encoded value
}{
{"0", 0, "0"},
{"1", 0, "0"},
{"0", 1, "0"},
{"1", 1, "1"},
// secp256k1 prime-1 * 2
{
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e",
2,
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d",
},
// secp256k1 prime * 3
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", 3, "0"},
// secp256k1 prime-1 * 8
{
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e",
8,
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc27",
},
// Random samples for first value. The second value is limited
// to 8 since that is the maximum int used in the elliptic curve
// calculations.
{
"b75674dc9180d306c692163ac5e089f7cef166af99645c0c23568ab6d967288a",
6,
"4c06bd2b6904f228a76c8560a3433bced9a8681d985a2848d407404d186b0280",
},
{
"54873298ac2b5ba8591c125ae54931f5ea72040aee07b208d6135476fb5b9c0e",
3,
"fd9597ca048212f90b543710afdb95e1bf560c20ca17161a8239fd64f212d42a",
},
{
"7c30fbd363a74c17e1198f56b090b59bbb6c8755a74927a6cba7a54843506401",
5,
"6cf4eb20f2447c77657fccb172d38c0aa91ea4ac446dc641fa463a6b5091fba7",
},
{
"fb4529be3e027a3d1587d8a500b72f2d312e3577340ef5175f96d113be4c2ceb",
8,
"da294df1f013d1e8ac3ec52805b979698971abb9a077a8bafcb688a4f261820f",
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in1).Normalize()
expected := new(fieldVal).SetHex(test.expected).Normalize()
result := f.MulInt(test.in2).Normalize()
if !result.Equals(expected) {
t.Errorf("fieldVal.MulInt #%d wrong result\n"+
"got: %v\nwant: %v", i, result, expected)
continue
}
}
}
// TestMul ensures that multiplying two field valuess via Mul works as expected.
func TestMul(t *testing.T) {
tests := []struct {
in1 string // first hex encoded value
in2 string // second hex encoded value to multiply with
expected string // expected hex encoded value
}{
{"0", "0", "0"},
{"1", "0", "0"},
{"0", "1", "0"},
{"1", "1", "1"},
// slightly over prime
{
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff1ffff",
"1000",
"1ffff3d1",
},
// secp256k1 prime-1 * 2
{
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e",
"2",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d",
},
// secp256k1 prime * 3
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "3", "0"},
// secp256k1 prime-1 * 8
{
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e",
"8",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc27",
},
// Random samples.
{
"cfb81753d5ef499a98ecc04c62cb7768c2e4f1740032946db1c12e405248137e",
"58f355ad27b4d75fb7db0442452e732c436c1f7c5a7c4e214fa9cc031426a7d3",
"1018cd2d7c2535235b71e18db9cd98027386328d2fa6a14b36ec663c4c87282b",
},
{
"26e9d61d1cdf3920e9928e85fa3df3e7556ef9ab1d14ec56d8b4fc8ed37235bf",
"2dfc4bbe537afee979c644f8c97b31e58be5296d6dbc460091eae630c98511cf",
"da85f48da2dc371e223a1ae63bd30b7e7ee45ae9b189ac43ff357e9ef8cf107a",
},
{
"5db64ed5afb71646c8b231585d5b2bf7e628590154e0854c4c29920b999ff351",
"279cfae5eea5d09ade8e6a7409182f9de40981bc31c84c3d3dfe1d933f152e9a",
"2c78fbae91792dd0b157abe3054920049b1879a7cc9d98cfda927d83be411b37",
},
{
"b66dfc1f96820b07d2bdbd559c19319a3a73c97ceb7b3d662f4fe75ecb6819e6",
"bf774aba43e3e49eb63a6e18037d1118152568f1a3ac4ec8b89aeb6ff8008ae1",
"c4f016558ca8e950c21c3f7fc15f640293a979c7b01754ee7f8b3340d4902ebb",
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in1).Normalize()
f2 := new(fieldVal).SetHex(test.in2).Normalize()
expected := new(fieldVal).SetHex(test.expected).Normalize()
result := f.Mul(f2).Normalize()
if !result.Equals(expected) {
t.Errorf("fieldVal.Mul #%d wrong result\n"+
"got: %v\nwant: %v", i, result, expected)
continue
}
}
}
// TestSquare ensures that squaring field values via Square works as expected.
func TestSquare(t *testing.T) {
tests := []struct {
in string // hex encoded value
expected string // expected hex encoded value
}{
// secp256k1 prime (aka 0)
{"0", "0"},
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "0"},
{"0", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"},
// secp256k1 prime-1
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", "1"},
// secp256k1 prime-2
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", "4"},
// Random sampling
{
"b0ba920360ea8436a216128047aab9766d8faf468895eb5090fc8241ec758896",
"133896b0b69fda8ce9f648b9a3af38f345290c9eea3cbd35bafcadf7c34653d3",
},
{
"c55d0d730b1d0285a1599995938b042a756e6e8857d390165ffab480af61cbd5",
"cd81758b3f5877cbe7e5b0a10cebfa73bcbf0957ca6453e63ee8954ab7780bee",
},
{
"e89c1f9a70d93651a1ba4bca5b78658f00de65a66014a25544d3365b0ab82324",
"39ffc7a43e5dbef78fd5d0354fb82c6d34f5a08735e34df29da14665b43aa1f",
},
{
"7dc26186079d22bcbe1614aa20ae627e62d72f9be7ad1e99cac0feb438956f05",
"bf86bcfc4edb3d81f916853adfda80c07c57745b008b60f560b1912f95bce8ae",
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in).Normalize()
expected := new(fieldVal).SetHex(test.expected).Normalize()
result := f.Square().Normalize()
if !result.Equals(expected) {
t.Errorf("fieldVal.Square #%d wrong result\n"+
"got: %v\nwant: %v", i, result, expected)
continue
}
}
}
// TestInverse ensures that finding the multiplicative inverse via Inverse works
// as expected.
func TestInverse(t *testing.T) {
tests := []struct {
in string // hex encoded value
expected string // expected hex encoded value
}{
// secp256k1 prime (aka 0)
{"0", "0"},
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "0"},
{"0", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"},
// secp256k1 prime-1
{
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e",
},
// secp256k1 prime-2
{
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d",
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffe17",
},
// Random sampling
{
"16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca",
"987aeb257b063df0c6d1334051c47092b6d8766c4bf10c463786d93f5bc54354",
},
{
"69d1323ce9f1f7b3bd3c7320b0d6311408e30281e273e39a0d8c7ee1c8257919",
"49340981fa9b8d3dad72de470b34f547ed9179c3953797d0943af67806f4bb6",
},
{
"e0debf988ae098ecda07d0b57713e97c6d213db19753e8c95aa12a2fc1cc5272",
"64f58077b68af5b656b413ea366863f7b2819f8d27375d9c4d9804135ca220c2",
},
{
"dcd394f91f74c2ba16aad74a22bb0ed47fe857774b8f2d6c09e28bfb14642878",
"fb848ec64d0be572a63c38fe83df5e7f3d032f60bf8c969ef67d36bf4ada22a9",
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
f := new(fieldVal).SetHex(test.in).Normalize()
expected := new(fieldVal).SetHex(test.expected).Normalize()
result := f.Inverse().Normalize()
if !result.Equals(expected) {
t.Errorf("fieldVal.Inverse #%d wrong result\n"+
"got: %v\nwant: %v", i, result, expected)
continue
}
}
}
// randFieldVal returns a random, normalized element in the field.
func randFieldVal(t *testing.T) fieldVal {
var b [32]byte
if _, err := rand.Read(b[:]); err != nil {
t.Fatalf("unable to create random element: %v", err)
}
var x fieldVal
return *x.SetBytes(&b).Normalize()
}
type sqrtTest struct {
name string
in string
expected string
}
// TestSqrt asserts that a fieldVal properly computes the square root modulo the
// sep256k1 prime.
func TestSqrt(t *testing.T) {
var tests []sqrtTest
// No valid root exists for the negative of a square.
for i := uint(9); i > 0; i-- {
var (
x fieldVal
s fieldVal // x^2 mod p
n fieldVal // -x^2 mod p
)
x.SetInt(i)
s.SquareVal(&x).Normalize()
n.NegateVal(&s, 1).Normalize()
tests = append(tests, sqrtTest{
name: fmt.Sprintf("-%d", i),
in: fmt.Sprintf("%x", *n.Bytes()),
})
}
// A root should exist for true squares.
for i := uint(0); i < 10; i++ {
var (
x fieldVal
s fieldVal // x^2 mod p
)
x.SetInt(i)
s.SquareVal(&x).Normalize()
tests = append(tests, sqrtTest{
name: fmt.Sprintf("%d", i),
in: fmt.Sprintf("%x", *s.Bytes()),
expected: fmt.Sprintf("%x", *x.Bytes()),
})
}
// Compute a non-square element, by negating if it has a root.
ns := randFieldVal(t)
if new(fieldVal).SqrtVal(&ns).Square().Equals(&ns) {
ns.Negate(1).Normalize()
}
// For large random field values, test that:
// 1) its square has a valid root.
// 2) the negative of its square has no root.
// 3) the product of its square with a non-square has no root.
for i := 0; i < 10; i++ {
var (
x fieldVal
s fieldVal // x^2 mod p
n fieldVal // -x^2 mod p
m fieldVal // ns*x^2 mod p
)
x = randFieldVal(t)
s.SquareVal(&x).Normalize()
n.NegateVal(&s, 1).Normalize()
m.Mul2(&s, &ns).Normalize()
// A root should exist for true squares.
tests = append(tests, sqrtTest{
name: fmt.Sprintf("%x", *s.Bytes()),
in: fmt.Sprintf("%x", *s.Bytes()),
expected: fmt.Sprintf("%x", *x.Bytes()),
})
// No valid root exists for the negative of a square.
tests = append(tests, sqrtTest{
name: fmt.Sprintf("-%x", *s.Bytes()),
in: fmt.Sprintf("%x", *n.Bytes()),
})
// No root should be computed for product of a square and
// non-square.
tests = append(tests, sqrtTest{
name: fmt.Sprintf("ns*%x", *s.Bytes()),
in: fmt.Sprintf("%x", *m.Bytes()),
})
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
testSqrt(t, test)
})
}
}
func testSqrt(t *testing.T, test sqrtTest) {
var (
f fieldVal
root fieldVal
rootNeg fieldVal
)
f.SetHex(test.in).Normalize()
// Compute sqrt(f) and its negative.
root.SqrtVal(&f).Normalize()
rootNeg.NegateVal(&root, 1).Normalize()
switch {
// If we expect a square root, verify that either the computed square
// root is +/- the expected value.
case len(test.expected) > 0:
var expected fieldVal
expected.SetHex(test.expected).Normalize()
if !root.Equals(&expected) && !rootNeg.Equals(&expected) {
t.Fatalf("fieldVal.Sqrt incorrect root\n"+
"got: %v\ngot_neg: %v\nwant: %v",
root, rootNeg, expected)
}
// Otherwise, we expect this input not to have a square root.
default:
if root.Square().Equals(&f) || rootNeg.Square().Equals(&f) {
t.Fatalf("fieldVal.Sqrt root should not exist\n"+
"got: %v\ngot_neg: %v", root, rootNeg)
}
}
}
// TestFieldSetBytes ensures that setting a field value 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 TestFieldSetBytes(t *testing.T) {
tests := []struct {
name string // test description
in string // hex encoded test value
expected [10]uint32 // expected raw ints
}{{
name: "zero",
in: "00",
expected: [10]uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}, {
name: "field prime",
in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
expected: [10]uint32{
0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff,
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff,
},
}, {
name: "field prime - 1",
in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e",
expected: [10]uint32{
0x03fffc2e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff,
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff,
},
}, {
name: "field prime + 1 (overflow in word zero)",
in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
expected: [10]uint32{
0x03fffc30, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff,
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff,
},
}, {
name: "field prime first 32 bits",
in: "fffffc2f",
expected: [10]uint32{
0x03fffc2f, 0x00000003f, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
},
}, {
name: "field prime word zero",
in: "03fffc2f",
expected: [10]uint32{
0x03fffc2f, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
},
}, {
name: "field prime first 64 bits",
in: "fffffffefffffc2f",
expected: [10]uint32{
0x03fffc2f, 0x03ffffbf, 0x00000fff, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
},
}, {
name: "field prime word zero and one",
in: "0ffffefffffc2f",
expected: [10]uint32{
0x03fffc2f, 0x03ffffbf, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
},
}, {
name: "field prime first 96 bits",
in: "fffffffffffffffefffffc2f",
expected: [10]uint32{
0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x0003ffff, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
},
}, {
name: "field prime word zero, one, and two",
in: "3ffffffffffefffffc2f",
expected: [10]uint32{
0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
},
}, {
name: "overflow in word one (prime + 1<<26)",
in: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff03fffc2f",
expected: [10]uint32{
0x03fffc2f, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff,
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff,
},
}, {
name: "(field prime - 1) * 2 NOT mod P, truncated >32 bytes",
in: "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffff85c",
expected: [10]uint32{
0x01fffff8, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x00007fff,
},
}, {
name: "2^256 - 1",
in: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
expected: [10]uint32{
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff,
},
}, {
name: "alternating bits",
in: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
expected: [10]uint32{
0x01a5a5a5, 0x01696969, 0x025a5a5a, 0x02969696, 0x01a5a5a5,
0x01696969, 0x025a5a5a, 0x02969696, 0x01a5a5a5, 0x00296969,
},
}, {
name: "alternating bits 2",
in: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
expected: [10]uint32{
0x025a5a5a, 0x02969696, 0x01a5a5a5, 0x01696969, 0x025a5a5a,
0x02969696, 0x01a5a5a5, 0x01696969, 0x025a5a5a, 0x00169696,
},
}}
for _, test := range tests {
inBytes := hexToBytes(test.in)
// Ensure setting the bytes via the slice method works as expected.
var f fieldVal
f.SetByteSlice(inBytes)
if !reflect.DeepEqual(f.n, test.expected) {
t.Errorf("%s: unexpected result\ngot: %x\nwant: %x", test.name, f.n,
test.expected)
continue
}
// Ensure setting the bytes via the array method works as expected.
var f2 fieldVal
var b32 [32]byte
truncatedInBytes := inBytes
if len(truncatedInBytes) > 32 {
truncatedInBytes = truncatedInBytes[:32]
}
copy(b32[32-len(truncatedInBytes):], truncatedInBytes)
f2.SetBytes(&b32)
if !reflect.DeepEqual(f2.n, test.expected) {
t.Errorf("%s: unexpected result\ngot: %x\nwant: %x", test.name,
f2.n, test.expected)
continue
}
}
}
// hexToBytes converts the passed hex string into bytes and will panic if there
// is an error. This is only provided for the hard-coded constants so errors in
// the source code can be detected. It will only (and must only) be called with
// hard-coded values.
func hexToBytes(s string) []byte {
b, err := hex.DecodeString(s)
if err != nil {
panic("invalid hex in source file: " + s)
}
return b
}