// Copyright (c) 2013-2016 The btcsuite developers // Copyright (c) 2015-2022 The Decred developers // Copyright (c) 2013-2022 Dave Collins // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package secp256k1 import ( "bytes" "encoding/hex" "fmt" "math/big" "math/rand" "reflect" "testing" "time" ) // SetHex decodes the passed big-endian hex string into the internal field value // representation. Only the first 32-bytes are used. // // This is NOT constant time. // // The field value is returned to support chaining. This enables syntax like: // f := new(FieldVal).SetHex("0abc").Add(1) so that f = 0x0abc + 1 func (f *FieldVal) SetHex(hexString string) *FieldVal { if len(hexString)%2 != 0 { hexString = "0" + hexString } bytes, _ := hex.DecodeString(hexString) f.SetByteSlice(bytes) return f } // randFieldVal returns a field value created from a random value generated by // the passed rng. func randFieldVal(t *testing.T, rng *rand.Rand) *FieldVal { t.Helper() var buf [32]byte if _, err := rng.Read(buf[:]); err != nil { t.Fatalf("failed to read random: %v", err) } // Create and return a field value. var fv FieldVal fv.SetBytes(&buf) return &fv } // randIntAndFieldVal returns a big integer and a field value both created from // the same random value generated by the passed rng. func randIntAndFieldVal(t *testing.T, rng *rand.Rand) (*big.Int, *FieldVal) { t.Helper() var buf [32]byte if _, err := rng.Read(buf[:]); err != nil { t.Fatalf("failed to read random: %v", err) } // Create and return both a big integer and a field value. bigIntVal := new(big.Int).SetBytes(buf[:]) bigIntVal.Mod(bigIntVal, curveParams.N) var fv FieldVal fv.SetBytes(&buf) return bigIntVal, &fv } // TestFieldSetInt ensures that setting a field value to various native // integers works as expected. func TestFieldSetInt(t *testing.T) { tests := []struct { name string // test description in uint16 // test value expected [10]uint32 // expected raw ints }{{ name: "one", in: 1, expected: [10]uint32{1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { name: "five", in: 5, expected: [10]uint32{5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { name: "2^16 - 1", in: 65535, expected: [10]uint32{65535, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }} for _, test := range tests { f := new(FieldVal).SetInt(test.in) if !reflect.DeepEqual(f.n, test.expected) { t.Errorf("%s: wrong result\ngot: %v\nwant: %v", test.name, f.n, test.expected) continue } } } // 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 overflow bool // expected overflow result }{{ name: "zero", in: "00", expected: [10]uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, overflow: false, }, { name: "field prime", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", expected: [10]uint32{ 0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff, }, overflow: true, }, { name: "field prime - 1", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", expected: [10]uint32{ 0x03fffc2e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff, }, overflow: false, }, { name: "field prime + 1 (overflow in word zero)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", expected: [10]uint32{ 0x03fffc30, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff, }, overflow: true, }, { name: "field prime first 32 bits", in: "fffffc2f", expected: [10]uint32{ 0x03fffc2f, 0x00000003f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, overflow: false, }, { name: "field prime word zero", in: "03fffc2f", expected: [10]uint32{ 0x03fffc2f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, overflow: false, }, { name: "field prime first 64 bits", in: "fffffffefffffc2f", expected: [10]uint32{ 0x03fffc2f, 0x03ffffbf, 0x00000fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, overflow: false, }, { name: "field prime word zero and one", in: "0ffffefffffc2f", expected: [10]uint32{ 0x03fffc2f, 0x03ffffbf, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, overflow: false, }, { name: "field prime first 96 bits", in: "fffffffffffffffefffffc2f", expected: [10]uint32{ 0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x0003ffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, overflow: false, }, { name: "field prime word zero, one, and two", in: "3ffffffffffefffffc2f", expected: [10]uint32{ 0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, overflow: false, }, { name: "overflow in word one (prime + 1<<26)", in: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff03fffc2f", expected: [10]uint32{ 0x03fffc2f, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff, }, overflow: true, }, { 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, }, overflow: false, }, { name: "2^256 - 1", in: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: [10]uint32{ 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff, }, overflow: true, }, { name: "alternating bits", in: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5", expected: [10]uint32{ 0x01a5a5a5, 0x01696969, 0x025a5a5a, 0x02969696, 0x01a5a5a5, 0x01696969, 0x025a5a5a, 0x02969696, 0x01a5a5a5, 0x00296969, }, overflow: false, }, { name: "alternating bits 2", in: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a", expected: [10]uint32{ 0x025a5a5a, 0x02969696, 0x01a5a5a5, 0x01696969, 0x025a5a5a, 0x02969696, 0x01a5a5a5, 0x01696969, 0x025a5a5a, 0x00169696, }, overflow: false, }} for _, test := range tests { inBytes := hexToBytes(test.in) // Ensure setting the bytes via the slice method works as expected. var f FieldVal overflow := 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 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 f2 FieldVal var b32 [32]byte truncatedInBytes := inBytes if len(truncatedInBytes) > 32 { truncatedInBytes = truncatedInBytes[:32] } copy(b32[32-len(truncatedInBytes):], truncatedInBytes) overflow = f2.SetBytes(&b32) != 0 if !reflect.DeepEqual(f2.n, test.expected) { t.Errorf("%s: unexpected result\ngot: %x\nwant: %x", test.name, f2.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 } } } // TestFieldBytes 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 TestFieldBytes(t *testing.T) { tests := []struct { name string // test description in string // hex encoded test value expected string // expected hex encoded bytes }{{ name: "zero", in: "0", expected: "0000000000000000000000000000000000000000000000000000000000000000", }, { name: "field prime (aka 0)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", expected: "0000000000000000000000000000000000000000000000000000000000000000", }, { name: "field prime - 1", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", expected: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", }, { name: "field prime + 1 (aka 1, overflow in word zero)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", expected: "0000000000000000000000000000000000000000000000000000000000000001", }, { name: "field prime first 32 bits", in: "fffffc2f", expected: "00000000000000000000000000000000000000000000000000000000fffffc2f", }, { name: "field prime word zero", in: "03fffc2f", expected: "0000000000000000000000000000000000000000000000000000000003fffc2f", }, { name: "field prime first 64 bits", in: "fffffffefffffc2f", expected: "000000000000000000000000000000000000000000000000fffffffefffffc2f", }, { name: "field prime word zero and one", in: "0ffffefffffc2f", expected: "000000000000000000000000000000000000000000000000000ffffefffffc2f", }, { name: "field prime first 96 bits", in: "fffffffffffffffefffffc2f", expected: "0000000000000000000000000000000000000000fffffffffffffffefffffc2f", }, { name: "field prime word zero, one, and two", in: "3ffffffffffefffffc2f", expected: "000000000000000000000000000000000000000000003ffffffffffefffffc2f", }, { name: "overflow in word one (prime + 1<<26)", in: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff03fffc2f", expected: "0000000000000000000000000000000000000000000000000000000004000000", }, { name: "2^256 - 1", in: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "00000000000000000000000000000000000000000000000000000001000003d0", }, { name: "alternating bits", in: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5", expected: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5", }, { name: "alternating bits 2", in: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a", expected: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a", }} for _, test := range tests { f := new(FieldVal).SetHex(test.in).Normalize() expected := hexToBytes(test.expected) // Ensure getting the bytes works as expected. gotBytes := f.Bytes() if !bytes.Equal(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 f.PutBytes(&b32) if !bytes.Equal(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 f.PutBytesUnchecked(buffer[:]) if !bytes.Equal(buffer[:32], expected) { t.Errorf("%s: unexpected result\ngot: %x\nwant: %x", test.name, buffer[:32], expected) continue } } } // TestFieldZero ensures that zeroing a field value works as expected. func TestFieldZero(t *testing.T) { var f FieldVal f.SetHex("a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5") f.Zero() for idx, rawInt := range f.n { if rawInt != 0 { t.Errorf("internal integer at index #%d is not zero - got %d", idx, rawInt) } } } // TestFieldIsZero ensures that checking if a field is zero via IsZero and // IsZeroBit works as expected. func TestFieldIsZero(t *testing.T) { f := new(FieldVal) if !f.IsZero() { t.Errorf("new field value is not zero - got %v (rawints %x)", f, f.n) } if f.IsZeroBit() != 1 { t.Errorf("new field value is not zero - got %v (rawints %x)", f, f.n) } f.SetInt(1) if f.IsZero() { t.Errorf("claims zero for nonzero field - got %v (rawints %x)", f, f.n) } if f.IsZeroBit() == 1 { t.Errorf("claims zero for nonzero field - got %v (rawints %x)", f, f.n) } f.Zero() if !f.IsZero() { t.Errorf("claims nonzero for zero field - got %v (rawints %x)", f, f.n) } if f.IsZeroBit() != 1 { t.Errorf("claims nonzero for zero field - got %v (rawints %x)", f, f.n) } f.SetInt(1) f.Zero() if !f.IsZero() { t.Errorf("claims zero for nonzero field - got %v (rawints %x)", f, f.n) } if f.IsZeroBit() != 1 { t.Errorf("claims zero for nonzero field - got %v (rawints %x)", f, f.n) } } // TestFieldIsOne ensures that checking if a field is one via IsOne and IsOneBit // works as expected. func TestFieldIsOne(t *testing.T) { tests := []struct { name string // test description in string // hex encoded test value normalize bool // whether or not to normalize the test value expected bool // expected result }{{ name: "zero", in: "0", normalize: true, expected: false, }, { name: "one", in: "1", normalize: true, expected: true, }, { name: "secp256k1 prime NOT normalized (would be 0)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", normalize: false, expected: false, }, { name: "secp256k1 prime normalized (aka 0)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", normalize: true, expected: false, }, { name: "secp256k1 prime + 1 normalized (aka 1)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", normalize: true, expected: true, }, { name: "secp256k1 prime + 1 NOT normalized (would be 1)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", normalize: false, expected: false, }, { name: "2^26 (one bit in second internal field word", in: "4000000", normalize: false, expected: false, }, { name: "2^52 (one bit in third internal field word", in: "10000000000000", normalize: false, expected: false, }, { name: "2^78 (one bit in fourth internal field word", in: "40000000000000000000", normalize: false, expected: false, }, { name: "2^104 (one bit in fifth internal field word", in: "100000000000000000000000000", normalize: false, expected: false, }, { name: "2^130 (one bit in sixth internal field word", in: "400000000000000000000000000000000", normalize: false, expected: false, }, { name: "2^156 (one bit in seventh internal field word", in: "1000000000000000000000000000000000000000", normalize: false, expected: false, }, { name: "2^182 (one bit in eighth internal field word", in: "4000000000000000000000000000000000000000000000", normalize: false, expected: false, }, { name: "2^208 (one bit in ninth internal field word", in: "10000000000000000000000000000000000000000000000000000", normalize: false, expected: false, }, { name: "2^234 (one bit in tenth internal field word", in: "40000000000000000000000000000000000000000000000000000000000", normalize: false, expected: false, }} for _, test := range tests { f := new(FieldVal).SetHex(test.in) if test.normalize { f.Normalize() } result := f.IsOne() if result != test.expected { t.Errorf("%s: wrong result -- got: %v, want: %v", test.name, result, test.expected) continue } result2 := f.IsOneBit() == 1 if result2 != test.expected { t.Errorf("%s: wrong result -- got: %v, want: %v", test.name, result2, test.expected) continue } } } // TestFieldStringer ensures the stringer returns the appropriate hex string. func TestFieldStringer(t *testing.T) { tests := []struct { name string //test description in string // hex encoded test value expected string // expected result }{{ name: "zero", in: "0", expected: "0000000000000000000000000000000000000000000000000000000000000000", }, { name: "one", in: "1", expected: "0000000000000000000000000000000000000000000000000000000000000001", }, { name: "ten", in: "a", expected: "000000000000000000000000000000000000000000000000000000000000000a", }, { name: "eleven", in: "b", expected: "000000000000000000000000000000000000000000000000000000000000000b", }, { name: "twelve", in: "c", expected: "000000000000000000000000000000000000000000000000000000000000000c", }, { name: "thirteen", in: "d", expected: "000000000000000000000000000000000000000000000000000000000000000d", }, { name: "fourteen", in: "e", expected: "000000000000000000000000000000000000000000000000000000000000000e", }, { name: "fifteen", in: "f", expected: "000000000000000000000000000000000000000000000000000000000000000f", }, { name: "240", in: "f0", expected: "00000000000000000000000000000000000000000000000000000000000000f0", }, { name: "2^26 - 1", in: "3ffffff", expected: "0000000000000000000000000000000000000000000000000000000003ffffff", }, { name: "2^32 - 1", in: "ffffffff", expected: "00000000000000000000000000000000000000000000000000000000ffffffff", }, { name: "2^64 - 1", in: "ffffffffffffffff", expected: "000000000000000000000000000000000000000000000000ffffffffffffffff", }, { name: "2^96 - 1", in: "ffffffffffffffffffffffff", expected: "0000000000000000000000000000000000000000ffffffffffffffffffffffff", }, { name: "2^128 - 1", in: "ffffffffffffffffffffffffffffffff", expected: "00000000000000000000000000000000ffffffffffffffffffffffffffffffff", }, { name: "2^160 - 1", in: "ffffffffffffffffffffffffffffffffffffffff", expected: "000000000000000000000000ffffffffffffffffffffffffffffffffffffffff", }, { name: "2^192 - 1", in: "ffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff", }, { name: "2^224 - 1", in: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", }, { name: "2^256-4294968273 (the secp256k1 prime, so should result in 0)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", expected: "0000000000000000000000000000000000000000000000000000000000000000", }, { name: "2^256-4294968274 (the secp256k1 prime+1, so should result in 1)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", expected: "0000000000000000000000000000000000000000000000000000000000000001", }, { name: "invalid hex g", in: "g", expected: "0000000000000000000000000000000000000000000000000000000000000000", }, { name: "invalid hex 1h", in: "1h", expected: "0000000000000000000000000000000000000000000000000000000000000000", }, { name: "invalid hex i1", in: "i1", expected: "0000000000000000000000000000000000000000000000000000000000000000", }} for _, test := range tests { f := new(FieldVal).SetHex(test.in) result := f.String() if result != test.expected { t.Errorf("%s: wrong result\ngot: %v\nwant: %v", test.name, result, test.expected) continue } } } // TestFieldNormalize ensures that normalizing the internal field words works as // expected. func TestFieldNormalize(t *testing.T) { tests := []struct { name string // test description raw [10]uint32 // Intentionally denormalized value normalized [10]uint32 // Normalized form of the raw value }{{ name: "5", raw: [10]uint32{0x00000005, 0, 0, 0, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x00000005, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, { name: "2^26", raw: [10]uint32{0x04000000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x00000000, 0x1, 0, 0, 0, 0, 0, 0, 0, 0}, }, { name: "2^26 + 1", raw: [10]uint32{0x04000001, 0x0, 0, 0, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x00000001, 0x1, 0, 0, 0, 0, 0, 0, 0, 0}, }, { name: "2^32 - 1", raw: [10]uint32{0xffffffff, 0x00, 0, 0, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x03ffffff, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0}, }, { name: "2^32", raw: [10]uint32{0x04000000, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x00000000, 0x40, 0, 0, 0, 0, 0, 0, 0, 0}, }, { name: "2^32 + 1", raw: [10]uint32{0x04000001, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x00000001, 0x40, 0, 0, 0, 0, 0, 0, 0, 0}, }, { name: "2^64 - 1", raw: [10]uint32{0xffffffff, 0xffffffc0, 0xfc0, 0, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x03ffffff, 0x03ffffff, 0xfff, 0, 0, 0, 0, 0, 0, 0}, }, { name: "2^64", raw: [10]uint32{0x04000000, 0x03ffffff, 0x0fff, 0, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x00000000, 0x00000000, 0x1000, 0, 0, 0, 0, 0, 0, 0}, }, { name: "2^64 + 1", raw: [10]uint32{0x04000001, 0x03ffffff, 0x0fff, 0, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x00000001, 0x00000000, 0x1000, 0, 0, 0, 0, 0, 0, 0}, }, { name: "2^96 - 1", raw: [10]uint32{0xffffffff, 0xffffffc0, 0xffffffc0, 0x3ffc0, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x3ffff, 0, 0, 0, 0, 0, 0}, }, { name: "2^96", raw: [10]uint32{0x04000000, 0x03ffffff, 0x03ffffff, 0x3ffff, 0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x00000000, 0x00000000, 0x00000000, 0x40000, 0, 0, 0, 0, 0, 0}, }, { name: "2^128 - 1", raw: [10]uint32{0xffffffff, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffc0, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0xffffff, 0, 0, 0, 0, 0}, }, { name: "2^128", raw: [10]uint32{0x04000000, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x0ffffff, 0, 0, 0, 0, 0}, normalized: [10]uint32{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1000000, 0, 0, 0, 0, 0}, }, { name: "2^256 - 4294968273 (secp256k1 prime)", raw: [10]uint32{0xfffffc2f, 0xffffff80, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0}, normalized: [10]uint32{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000}, }, { // Value larger than P where both first and second words are larger than // P's first and second words name: "Value > P with 1st and 2nd words > P's 1st and 2nd words", raw: [10]uint32{0xfffffc30, 0xffffff86, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0}, normalized: [10]uint32{0x00000001, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000}, }, { // Value larger than P where only the second word is larger than P's // second word. name: "Value > P with 2nd word > P's 2nd word", raw: [10]uint32{0xfffffc2a, 0xffffff87, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0}, normalized: [10]uint32{0x03fffffb, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000}, }, { name: "2^256 - 1", raw: [10]uint32{0xffffffff, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0}, normalized: [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) name: "2^256 - 4294968273 (secp256k1 prime)", raw: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff}, normalized: [10]uint32{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }, { // Value 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) name: "2^256 - 4294968272 (secp256k1 prime + 1)", raw: [10]uint32{0x03fffc30, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff}, normalized: [10]uint32{0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }, { // Value 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) name: "2^256 - 4227859409 (secp256k1 prime + 0x4000000)", raw: [10]uint32{0x03fffc2f, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff}, normalized: [10]uint32{0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }, { // Value 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) name: "2^256 * 5 - ((4294968273 - (977+1)) * 4)", raw: [10]uint32{0x03ffffff, 0x03fffeff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x0013fffff}, normalized: [10]uint32{0x00001314, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000000}, }, { // Value 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. name: "Value > P with redux > P at mag 1 due to 1st word and carry to bit 256", raw: [10]uint32{0x03fffc30, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x07ffffff, 0x003fffff}, normalized: [10]uint32{0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001}, }, { // Value 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. name: "Value > P with redux > P at mag 1 due to 2nd word and carry to bit 256", raw: [10]uint32{0x03fffc2f, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x3ffffff, 0x07ffffff, 0x003fffff}, normalized: [10]uint32{0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000, 0x00000000, 0x00000001}, }, { // Value 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. name: "Value > P with redux > P at mag 1 due to 1st and 2nd words and carry to bit 256", raw: [10]uint32{0x03fffc30, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x07ffffff, 0x003fffff}, normalized: [10]uint32{0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001}, }, { // --------------------------------------------------------------------- // There are 3 main conditions that must be true if the final reduction // is needed after the initial reduction to magnitude 1 when there was // NOT a carry to bit 256 (in other words when the original value was < // 2^256): // 1) The final word of the reduced value is equal to the one of P // 2) The 3rd through 9th words are equal to those of P // 3) Either: // - The 2nd word is greater than the one of P; or // - The 2nd word is equal to that of P AND the 1st word is greater // // Therefore the eight possible combinations of those 3 main conditions // can be thought of in binary where each bit starting from the left // corresponds to the aforementioned conditions as such: // 000, 001, 010, 011, 100, 101, 110, 111 // // For example, combination 6 is when both conditons 1 and 2 are true, // but condition 3 is NOT true. // // The following tests hit each of these combinations and refer to each // by its decimal equivalent for ease of reference. // // NOTE: The final combination (7) is already tested above since it only // happens when the original value is already the normalized // representation of P. // --------------------------------------------------------------------- name: "Value < 2^256 final reduction combination 0", raw: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe}, normalized: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe}, }, { name: "Value < 2^256 final reduction combination 1 via 2nd word", raw: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe}, normalized: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe}, }, { name: "Value < 2^256 final reduction combination 1 via 1st word", raw: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe}, normalized: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe}, }, { name: "Value < 2^256 final reduction combination 2", raw: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe}, normalized: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe}, }, { name: "Value < 2^256 final reduction combination 3 via 2nd word", raw: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe}, normalized: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe}, }, { name: "Value < 2^256 final reduction combination 3 via 1st word", raw: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe}, normalized: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe}, }, { name: "Value < 2^256 final reduction combination 4", raw: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff}, normalized: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff}, }, { name: "Value < 2^256 final reduction combination 5 via 2nd word", raw: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff}, normalized: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff}, }, { name: "Value < 2^256 final reduction combination 5 via 1st word", raw: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff}, normalized: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff}, }, { name: "Value < 2^256 final reduction combination 6", raw: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff}, normalized: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff}, }} for _, test := range tests { f := new(FieldVal) f.n = test.raw f.Normalize() if !reflect.DeepEqual(f.n, test.normalized) { t.Errorf("%s: wrong normalized result\ngot: %x\nwant: %x", test.name, f.n, test.normalized) continue } } } // TestFieldIsOdd ensures that checking if a field value is odd via IsOdd and // IsOddBit works as expected. func TestFieldIsOdd(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: "secp256k1 prime (not normalized so should be incorrect result)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", expected: true, }, { name: "secp256k1 prime + 1 (not normalized so should be incorrect result)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", expected: false, }} for _, test := range tests { f := new(FieldVal).SetHex(test.in) result := f.IsOdd() if result != test.expected { t.Errorf("%s: wrong result -- got: %v, want: %v", test.name, result, test.expected) continue } result2 := f.IsOddBit() == 1 if result2 != test.expected { t.Errorf("%s: wrong result -- got: %v, want: %v", test.name, result2, test.expected) continue } } } // TestFieldEquals ensures that checking two field values for equality via // Equals works as expected. func TestFieldEquals(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 == prime (mod prime)?", in1: "0", in2: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", expected: true, }, { name: "1 == prime + 1 (mod prime)?", in1: "1", in2: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", expected: true, }} for _, 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("%s: wrong result -- got: %v, want: %v", test.name, result, test.expected) continue } } } // TestFieldNegate ensures that negating field values via Negate works as // expected. func TestFieldNegate(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: "secp256k1 prime (direct val in with 0 out)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", expected: "0", }, { name: "secp256k1 prime (0 in with direct val out)", in: "0", expected: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", }, { name: "1 -> secp256k1 prime - 1", in: "1", expected: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", }, { name: "secp256k1 prime - 1 -> 1", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", expected: "1", }, { name: "2 -> secp256k1 prime - 2", in: "2", expected: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", }, { name: "secp256k1 prime - 2 -> 2", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", expected: "2", }, { name: "random sampling #1", in: "b3d9aac9c5e43910b4385b53c7e78c21d4cd5f8e683c633aed04c233efc2e120", expected: "4c2655363a1bc6ef4bc7a4ac381873de2b32a07197c39cc512fb3dcb103d1b0f", }, { name: "random sampling #2", in: "f8a85984fee5a12a7c8dd08830d83423c937d77c379e4a958e447a25f407733f", expected: "757a67b011a5ed583722f77cf27cbdc36c82883c861b56a71bb85d90bf888f0", }, { name: "random sampling #3", in: "45ee6142a7fda884211e93352ed6cb2807800e419533be723a9548823ece8312", expected: "ba119ebd5802577bdee16ccad12934d7f87ff1be6acc418dc56ab77cc131791d", }, { name: "random sampling #4", in: "53c2a668f07e411a2e473e1c3b6dcb495dec1227af27673761d44afe5b43d22b", expected: "ac3d59970f81bee5d1b8c1e3c49234b6a213edd850d898c89e2bb500a4bc2a04", }} for _, test := range tests { f := new(FieldVal).SetHex(test.in).Normalize() expected := new(FieldVal).SetHex(test.expected).Normalize() // Ensure negating another value produces the expected result. result := new(FieldVal).NegateVal(f, 1).Normalize() 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 := f.Negate(1).Normalize() if !result2.Equals(expected) { t.Errorf("%s: unexpected result -- got: %v, want: %v", test.name, result2, expected) continue } } } // TestFieldAddInt ensures that adding an integer to field values via AddInt // works as expected. func TestFieldAddInt(t *testing.T) { tests := []struct { name string // test description in1 string // hex encoded value in2 uint16 // unsigned integer to add to the value above expected string // expected hex encoded value }{{ name: "zero + one", in1: "0", in2: 1, expected: "1", }, { name: "one + zero", in1: "1", in2: 0, expected: "1", }, { name: "one + one", in1: "1", in2: 1, expected: "2", }, { name: "secp256k1 prime-1 + 1", in1: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", in2: 1, expected: "0", }, { name: "secp256k1 prime + 1", in1: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", in2: 1, expected: "1", }, { name: "random sampling #1", in1: "ff95ad9315aff04ab4af0ce673620c7145dc85d03bab5ba4b09ca2c4dec2d6c1", in2: 0x10f, expected: "ff95ad9315aff04ab4af0ce673620c7145dc85d03bab5ba4b09ca2c4dec2d7d0", }, { name: "random sampling #2", in1: "44bdae6b772e7987941f1ba314e6a5b7804a4c12c00961b57d20f41deea9cecf", in2: 0x3196, expected: "44bdae6b772e7987941f1ba314e6a5b7804a4c12c00961b57d20f41deeaa0065", }, { name: "random sampling #3", in1: "88c3ecae67b591935fb1f6a9499c35315ffad766adca665c50b55f7105122c9c", in2: 0x966f, expected: "88c3ecae67b591935fb1f6a9499c35315ffad766adca665c50b55f710512c30b", }, { name: "random sampling #4", in1: "8523e9edf360ca32a95aae4e57fcde5a542b471d08a974d94ea0ee09a015e2a6", in2: 0xc54, expected: "8523e9edf360ca32a95aae4e57fcde5a542b471d08a974d94ea0ee09a015eefa", }} for _, 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("%s: wrong result -- got: %v -- want: %v", test.name, result, expected) continue } } } // TestFieldAdd ensures that adding two field values together via Add and Add2 // works as expected. func TestFieldAdd(t *testing.T) { tests := []struct { name string // test description in1 string // first hex encoded value in2 string // second hex encoded value to add expected string // expected hex encoded value }{{ name: "zero + one", in1: "0", in2: "1", expected: "1", }, { name: "one + zero", in1: "1", in2: "0", expected: "1", }, { name: "secp256k1 prime-1 + 1", in1: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", in2: "1", expected: "0", }, { name: "secp256k1 prime + 1", in1: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", in2: "1", expected: "1", }, { name: "random sampling #1", in1: "2b2012f975404e5065b4292fb8bed0a5d315eacf24c74d8b27e73bcc5430edcc", in2: "2c3cefa4e4753e8aeec6ac4c12d99da4d78accefda3b7885d4c6bab46c86db92", expected: "575d029e59b58cdb547ad57bcb986e4aaaa0b7beff02c610fcadf680c0b7c95e", }, { name: "random sampling #2", in1: "8131e8722fe59bb189692b96c9f38de92885730f1dd39ab025daffb94c97f79c", in2: "ff5454b765f0aab5f0977dcc629becc84cabeb9def48e79c6aadb2622c490fa9", expected: "80863d2995d646677a00a9632c8f7ab175315ead0d1c824c9088b21c78e10b16", }, { name: "random sampling #3", in1: "c7c95e93d0892b2b2cdd77e80eb646ea61be7a30ac7e097e9f843af73fad5c22", in2: "3afe6f91a74dfc1c7f15c34907ee981656c37236d946767dd53ccad9190e437c", expected: "2c7ce2577d72747abf33b3116a4df00b881ec6785c47ffc74c105d158bba36f", }, { name: "random sampling #4", in1: "fd1c26f6a23381e5d785ba889494ec059369b888ad8431cd67d8c934b580dbe1", in2: "a475aa5a31dcca90ef5b53c097d9133d6b7117474b41e7877bb199590fc0489c", expected: "a191d150d4104c76c6e10e492c6dff42fedacfcff8c61954e38a628ec541284e", }, { name: "random sampling #5", in1: "ad82b8d1cc136e23e9fd77fe2c7db1fe5a2ecbfcbde59ab3529758334f862d28", in2: "4d6a4e95d6d61f4f46b528bebe152d408fd741157a28f415639347a84f6f574b", expected: "faed0767a2e98d7330b2a0bcea92df3eea060d12380e8ec8b62a9fdb9ef58473", }, { name: "random sampling #6", in1: "f3f43a2540054a86e1df98547ec1c0e157b193e5350fb4a3c3ea214b228ac5e7", in2: "25706572592690ea3ddc951a1b48b504a4c83dc253756e1b96d56fdfb3199522", expected: "19649f97992bdb711fbc2d6e9a0a75e5fc79d1a7888522bf5abf912bd5a45eda", }, { name: "random sampling #7", in1: "6915bb94eef13ff1bb9b2633d997e13b9b1157c713363cc0e891416d6734f5b8", in2: "11f90d6ac6fe1c4e8900b1c85fb575c251ec31b9bc34b35ada0aea1c21eded22", expected: "7b0ec8ffb5ef5c40449bd7fc394d56fdecfd8980cf6af01bc29c2b898922e2da", }, { name: "random sampling #8", in1: "48b0c9eae622eed9335b747968544eb3e75cb2dc8128388f948aa30f88cabde4", in2: "0989882b52f85f9d524a3a3061a0e01f46d597839d2ba637320f4b9510c8d2d5", expected: "523a5216391b4e7685a5aea9c9f52ed32e324a601e53dec6c699eea4999390b9", }} for _, test := range tests { // Parse test hex. f1 := new(FieldVal).SetHex(test.in1).Normalize() f2 := new(FieldVal).SetHex(test.in2).Normalize() expected := new(FieldVal).SetHex(test.expected).Normalize() // Ensure adding the two values with the result going to another // variable produces the expected result. result := new(FieldVal).Add2(f1, f2).Normalize() if !result.Equals(expected) { t.Errorf("%s: unexpected result\ngot: %v\nwant: %v", test.name, result, expected) continue } // Ensure adding the value to an existing field value produces the // expected result. f1.Add(f2).Normalize() if !f1.Equals(expected) { t.Errorf("%s: unexpected result\ngot: %v\nwant: %v", test.name, f1, expected) continue } } } // TestFieldMulInt ensures that multiplying an integer to field values via // MulInt works as expected. func TestFieldMulInt(t *testing.T) { tests := []struct { name string // test description in1 string // hex encoded value in2 uint8 // unsigned integer to multiply with value above 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: "zero * one", in1: "0", in2: 1, expected: "0", }, { name: "one * one", in1: "1", in2: 1, expected: "1", }, { name: "secp256k1 prime-1 * 2", in1: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", in2: 2, expected: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", }, { name: "secp256k1 prime * 3", in1: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", in2: 3, expected: "0", }, { name: "secp256k1 prime-1 * 8", in1: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", in2: 8, expected: "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. name: "random sampling #1", in1: "b75674dc9180d306c692163ac5e089f7cef166af99645c0c23568ab6d967288a", in2: 6, expected: "4c06bd2b6904f228a76c8560a3433bced9a8681d985a2848d407404d186b0280", }, { name: "random sampling #2", in1: "54873298ac2b5ba8591c125ae54931f5ea72040aee07b208d6135476fb5b9c0e", in2: 3, expected: "fd9597ca048212f90b543710afdb95e1bf560c20ca17161a8239fd64f212d42a", }, { name: "random sampling #3", in1: "7c30fbd363a74c17e1198f56b090b59bbb6c8755a74927a6cba7a54843506401", in2: 5, expected: "6cf4eb20f2447c77657fccb172d38c0aa91ea4ac446dc641fa463a6b5091fba7", }, { name: "random sampling #3", in1: "fb4529be3e027a3d1587d8a500b72f2d312e3577340ef5175f96d113be4c2ceb", in2: 8, expected: "da294df1f013d1e8ac3ec52805b979698971abb9a077a8bafcb688a4f261820f", }} for _, 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("%s: wrong result -- got: %v -- want: %v", test.name, result, expected) continue } } } // TestFieldMul ensures that multiplying two field values via Mul and Mul2 works // as expected. func TestFieldMul(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: "zero * one", in1: "0", in2: "1", expected: "0", }, { name: "one * one", in1: "1", in2: "1", expected: "1", }, { name: "slightly over prime", in1: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff1ffff", in2: "1000", expected: "1ffff3d1", }, { name: "secp256k1 prime-1 * 2", in1: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", in2: "2", expected: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", }, { name: "secp256k1 prime * 3", in1: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", in2: "3", expected: "0", }, { name: "secp256k1 prime * 3", in1: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", in2: "8", expected: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc27", }, { name: "random sampling #1", in1: "cfb81753d5ef499a98ecc04c62cb7768c2e4f1740032946db1c12e405248137e", in2: "58f355ad27b4d75fb7db0442452e732c436c1f7c5a7c4e214fa9cc031426a7d3", expected: "1018cd2d7c2535235b71e18db9cd98027386328d2fa6a14b36ec663c4c87282b", }, { name: "random sampling #2", in1: "26e9d61d1cdf3920e9928e85fa3df3e7556ef9ab1d14ec56d8b4fc8ed37235bf", in2: "2dfc4bbe537afee979c644f8c97b31e58be5296d6dbc460091eae630c98511cf", expected: "da85f48da2dc371e223a1ae63bd30b7e7ee45ae9b189ac43ff357e9ef8cf107a", }, { name: "random sampling #3", in1: "5db64ed5afb71646c8b231585d5b2bf7e628590154e0854c4c29920b999ff351", in2: "279cfae5eea5d09ade8e6a7409182f9de40981bc31c84c3d3dfe1d933f152e9a", expected: "2c78fbae91792dd0b157abe3054920049b1879a7cc9d98cfda927d83be411b37", }, { name: "random sampling #4", in1: "b66dfc1f96820b07d2bdbd559c19319a3a73c97ceb7b3d662f4fe75ecb6819e6", in2: "bf774aba43e3e49eb63a6e18037d1118152568f1a3ac4ec8b89aeb6ff8008ae1", expected: "c4f016558ca8e950c21c3f7fc15f640293a979c7b01754ee7f8b3340d4902ebb", }} for _, test := range tests { f1 := new(FieldVal).SetHex(test.in1).Normalize() f2 := new(FieldVal).SetHex(test.in2).Normalize() expected := new(FieldVal).SetHex(test.expected).Normalize() // Ensure multiplying the two values with the result going to another // variable produces the expected result. result := new(FieldVal).Mul2(f1, f2).Normalize() if !result.Equals(expected) { t.Errorf("%s: unexpected result\ngot: %v\nwant: %v", test.name, result, expected) continue } // Ensure multiplying the value to an existing field value produces the // expected result. f1.Mul(f2).Normalize() if !f1.Equals(expected) { t.Errorf("%s: unexpected result\ngot: %v\nwant: %v", test.name, f1, expected) continue } } } // TestFieldSquare ensures that squaring field values via Square and SqualVal // works as expected. func TestFieldSquare(t *testing.T) { tests := []struct { name string // test description in string // hex encoded value expected string // expected hex encoded value }{{ name: "zero", in: "0", expected: "0", }, { name: "secp256k1 prime (direct val in with 0 out)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", expected: "0", }, { name: "secp256k1 prime (0 in with direct val out)", in: "0", expected: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", }, { name: "secp256k1 prime - 1", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", expected: "1", }, { name: "secp256k1 prime - 2", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", expected: "4", }, { name: "random sampling #1", in: "b0ba920360ea8436a216128047aab9766d8faf468895eb5090fc8241ec758896", expected: "133896b0b69fda8ce9f648b9a3af38f345290c9eea3cbd35bafcadf7c34653d3", }, { name: "random sampling #2", in: "c55d0d730b1d0285a1599995938b042a756e6e8857d390165ffab480af61cbd5", expected: "cd81758b3f5877cbe7e5b0a10cebfa73bcbf0957ca6453e63ee8954ab7780bee", }, { name: "random sampling #3", in: "e89c1f9a70d93651a1ba4bca5b78658f00de65a66014a25544d3365b0ab82324", expected: "39ffc7a43e5dbef78fd5d0354fb82c6d34f5a08735e34df29da14665b43aa1f", }, { name: "random sampling #4", in: "7dc26186079d22bcbe1614aa20ae627e62d72f9be7ad1e99cac0feb438956f05", expected: "bf86bcfc4edb3d81f916853adfda80c07c57745b008b60f560b1912f95bce8ae", }} for _, test := range tests { f := new(FieldVal).SetHex(test.in).Normalize() expected := new(FieldVal).SetHex(test.expected).Normalize() // Ensure squaring the value with the result going to another variable // produces the expected result. result := new(FieldVal).SquareVal(f).Normalize() if !result.Equals(expected) { t.Errorf("%s: unexpected result\ngot: %v\nwant: %v", test.name, result, expected) continue } // Ensure self squaring an existing field value produces the expected // result. f.Square().Normalize() if !f.Equals(expected) { t.Errorf("%s: unexpected result\ngot: %v\nwant: %v", test.name, f, expected) continue } } } // TestFieldSquareRoot ensures that calculating the square root of field values // via SquareRootVal works as expected for edge cases. func TestFieldSquareRoot(t *testing.T) { tests := []struct { name string // test description in string // hex encoded value valid bool // whether or not the value has a square root want string // expected hex encoded value }{{ name: "secp256k1 prime (as 0 in and out)", in: "0", valid: true, want: "0", }, { name: "secp256k1 prime (direct val with 0 out)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", valid: true, want: "0", }, { name: "secp256k1 prime (as 0 in direct val out)", in: "0", valid: true, want: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", }, { name: "secp256k1 prime-1", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", valid: false, want: "0000000000000000000000000000000000000000000000000000000000000001", }, { name: "secp256k1 prime-2", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", valid: false, want: "210c790573632359b1edb4302c117d8a132654692c3feeb7de3a86ac3f3b53f7", }, { name: "(secp256k1 prime-2)^2", in: "0000000000000000000000000000000000000000000000000000000000000004", valid: true, want: "0000000000000000000000000000000000000000000000000000000000000002", }, { name: "value 1", in: "0000000000000000000000000000000000000000000000000000000000000001", valid: true, want: "0000000000000000000000000000000000000000000000000000000000000001", }, { name: "value 2", in: "0000000000000000000000000000000000000000000000000000000000000002", valid: true, want: "210c790573632359b1edb4302c117d8a132654692c3feeb7de3a86ac3f3b53f7", }, { name: "random sampling 1", in: "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca", valid: false, want: "6a27dcfca440cf7930a967be533b9620e397f122787c53958aaa7da7ad3d89a4", }, { name: "square of random sampling 1", in: "f4a8c3738ace0a1c3abf77737ae737f07687b5e24c07a643398298bd96893a18", valid: true, want: "e90468feb8565338c9ab2b41dcc33b7478a31df5dedd2db0f8c2d641d77fa165", }, { name: "random sampling 2", in: "69d1323ce9f1f7b3bd3c7320b0d6311408e30281e273e39a0d8c7ee1c8257919", valid: true, want: "61f4a7348274a52d75dfe176b8e3aaff61c1c833b6678260ba73def0fb2ad148", }, { name: "random sampling 3", in: "e0debf988ae098ecda07d0b57713e97c6d213db19753e8c95aa12a2fc1cc5272", valid: false, want: "6e1cc9c311d33d901670135244f994b1ea39501f38002269b34ce231750cfbac", }, { name: "random sampling 4", in: "dcd394f91f74c2ba16aad74a22bb0ed47fe857774b8f2d6c09e28bfb14642878", valid: true, want: "72b22fe6f173f8bcb21898806142ed4c05428601256eafce5d36c1b08fb82bab", }} for _, test := range tests { input := new(FieldVal).SetHex(test.in).Normalize() want := new(FieldVal).SetHex(test.want).Normalize() // Calculate the square root and enusre the validity flag matches the // expected value. var result FieldVal isValid := result.SquareRootVal(input) if isValid != test.valid { t.Errorf("%s: mismatched validity -- got %v, want %v", test.name, isValid, test.valid) continue } // Ensure the calculated result matches the expected value. result.Normalize() if !result.Equals(want) { t.Errorf("%s: d wrong result\ngot: %v\nwant: %v", test.name, result, want) continue } } } // TestFieldSquareRootRandom ensures that calculating the square root for random // field values works as expected by also performing the same operation with big // ints and comparing the results. func TestFieldSquareRootRandom(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 field value with the same random value. bigIntVal, fVal := randIntAndFieldVal(t, rng) // Calculate the square root of the value using big ints. bigIntResult := new(big.Int).ModSqrt(bigIntVal, curveParams.P) bigIntHasSqrt := bigIntResult != nil // Calculate the square root of the value using a field value. var fValResult FieldVal fValHasSqrt := fValResult.SquareRootVal(fVal) // Ensure they match. if bigIntHasSqrt != fValHasSqrt { t.Fatalf("mismatched square root existence\nbig int in: %x\nfield "+ "in: %v\nbig int result: %v\nfield result %v", bigIntVal, fVal, bigIntHasSqrt, fValHasSqrt) } if !fValHasSqrt { continue } bigIntResultHex := fmt.Sprintf("%064x", bigIntResult) fieldValResultHex := fmt.Sprintf("%v", fValResult) if bigIntResultHex != fieldValResultHex { t.Fatalf("mismatched square root\nbig int in: %x\nfield in: %v\n"+ "big int result: %x\nfield result %v", bigIntVal, fVal, bigIntResult, fValResult) } } } // TestFieldInverse ensures that finding the multiplicative inverse via Inverse // works as expected. func TestFieldInverse(t *testing.T) { tests := []struct { name string // test description in string // hex encoded value expected string // expected hex encoded value }{{ name: "zero", in: "0", expected: "0", }, { name: "secp256k1 prime (direct val in with 0 out)", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", expected: "0", }, { name: "secp256k1 prime (0 in with direct val out)", in: "0", expected: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", }, { name: "secp256k1 prime - 1", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", expected: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", }, { name: "secp256k1 prime - 2", in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", expected: "7fffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffe17", }, { name: "random sampling #1", in: "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca", expected: "987aeb257b063df0c6d1334051c47092b6d8766c4bf10c463786d93f5bc54354", }, { name: "random sampling #2", in: "69d1323ce9f1f7b3bd3c7320b0d6311408e30281e273e39a0d8c7ee1c8257919", expected: "49340981fa9b8d3dad72de470b34f547ed9179c3953797d0943af67806f4bb6", }, { name: "random sampling #3", in: "e0debf988ae098ecda07d0b57713e97c6d213db19753e8c95aa12a2fc1cc5272", expected: "64f58077b68af5b656b413ea366863f7b2819f8d27375d9c4d9804135ca220c2", }, { name: "random sampling #4", in: "dcd394f91f74c2ba16aad74a22bb0ed47fe857774b8f2d6c09e28bfb14642878", expected: "fb848ec64d0be572a63c38fe83df5e7f3d032f60bf8c969ef67d36bf4ada22a9", }} for _, 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("%s: d wrong result\ngot: %v\nwant: %v", test.name, result, expected) continue } } } // TestFieldIsGtOrEqPrimeMinusOrder ensures that field values report whether or // not they are greater than or equal to the field prime minus the group order // as expected for edge cases. func TestFieldIsGtOrEqPrimeMinusOrder(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: "p - n - 1", in: "14551231950b75fc4402da1722fc9baed", expected: false, }, { name: "p - n", in: "14551231950b75fc4402da1722fc9baee", expected: true, }, { name: "p - n + 1", in: "14551231950b75fc4402da1722fc9baef", expected: true, }, { name: "over p - n word one", in: "14551231950b75fc4402da17233c9baee", expected: true, }, { name: "over p - n word two", in: "14551231950b75fc4403da1722fc9baee", expected: true, }, { name: "over p - n word three", in: "14551231950b79fc4402da1722fc9baee", expected: true, }, { name: "over p - n word four", in: "14551241950b75fc4402da1722fc9baee", expected: true, }, { name: "over p - n word five", in: "54551231950b75fc4402da1722fc9baee", expected: true, }, { name: "over p - n word six", in: "100000014551231950b75fc4402da1722fc9baee", expected: true, }, { name: "over p - n word seven", in: "000000000000000000400000000000014551231950b75fc4402da1722fc9baee", expected: true, }, { name: "over p - n word eight", in: "000000000001000000000000000000014551231950b75fc4402da1722fc9baee", expected: true, }, { name: "over p - n word nine", in: "000004000000000000000000000000014551231950b75fc4402da1722fc9baee", expected: true, }} for _, test := range tests { result := new(FieldVal).SetHex(test.in).IsGtOrEqPrimeMinusOrder() if result != test.expected { t.Errorf("%s: unexpected result -- got: %v, want: %v", test.name, result, test.expected) continue } } } // TestFieldIsGtOrEqPrimeMinusOrderRandom ensures that field values report // whether or not they are greater than or equal to the field prime minus the // group order as expected by also performing the same operation with big ints // and comparing the results. func TestFieldIsGtOrEqPrimeMinusOrderRandom(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) bigPMinusN := new(big.Int).Sub(curveParams.P, curveParams.N) for i := 0; i < 100; i++ { // Generate big integer and field value with the same random value. bigIntVal, fVal := randIntAndFieldVal(t, rng) // Determine the value is greater than or equal to the prime minus the // order using big ints. bigIntResult := bigIntVal.Cmp(bigPMinusN) >= 0 // Determine the value is greater than or equal to the prime minus the // order using a field value. fValResult := fVal.IsGtOrEqPrimeMinusOrder() // Ensure they match. if bigIntResult != fValResult { t.Fatalf("mismatched is gt or eq prime minus order\nbig int in: "+ "%x\nscalar in: %v\nbig int result: %v\nscalar result %v", bigIntVal, fVal, bigIntResult, fValResult) } } }