// TestSigCacheAddMaxEntriesZeroOrNegative tests that if a sigCache is created // with a max size <= 0, then no entries are added to the sigcache at all. func TestSigCacheAddMaxEntriesZeroOrNegative(t *testing.T) { // Create a sigcache that can hold up to 0 entries. sigCache := NewSigCache(0) // Generate a random sigCache entry triplet. msg1, sig1, key1, err := genRandomSig() if err != nil { t.Errorf("unable to generate random signature test data") } // Add the triplet to the signature cache. sigCache.Add(*msg1, sig1, key1) // The generated triplet should not be found. sig1Copy, _ := btcec.ParseSignature(sig1.Serialize(), btcec.S256()) key1Copy, _ := btcec.ParsePubKey(key1.SerializeCompressed(), btcec.S256()) if sigCache.Exists(*msg1, sig1Copy, key1Copy) { t.Errorf("previously added signature found in sigcache, but" + "shouldn't have been") } // There shouldn't be any entries in the sigCache. if len(sigCache.validSigs) != 0 { t.Errorf("%v items found in sigcache, no items should have"+ "been added", len(sigCache.validSigs)) } }
// TestSigCacheAddEvictEntry tests the eviction case where a new signature // triplet is added to a full signature cache which should trigger randomized // eviction, followed by adding the new element to the cache. func TestSigCacheAddEvictEntry(t *testing.T) { // Create a sigcache that can hold up to 100 entries. sigCacheSize := uint(100) sigCache := NewSigCache(sigCacheSize) // Fill the sigcache up with some random sig triplets. for i := uint(0); i < sigCacheSize; i++ { msg, sig, key, err := genRandomSig() if err != nil { t.Fatalf("unable to generate random signature test data") } sigCache.Add(*msg, sig, key) sigCopy, _ := btcec.ParseSignature(sig.Serialize(), btcec.S256()) keyCopy, _ := btcec.ParsePubKey(key.SerializeCompressed(), btcec.S256()) if !sigCache.Exists(*msg, sigCopy, keyCopy) { t.Errorf("previously added item not found in signature" + "cache") } } // The sigcache should now have sigCacheSize entries within it. if uint(len(sigCache.validSigs)) != sigCacheSize { t.Fatalf("sigcache should now have %v entries, instead it has %v", sigCacheSize, len(sigCache.validSigs)) } // Add a new entry, this should cause eviction of a randomly chosen // previous entry. msgNew, sigNew, keyNew, err := genRandomSig() if err != nil { t.Fatalf("unable to generate random signature test data") } sigCache.Add(*msgNew, sigNew, keyNew) // The sigcache should still have sigCache entries. if uint(len(sigCache.validSigs)) != sigCacheSize { t.Fatalf("sigcache should now have %v entries, instead it has %v", sigCacheSize, len(sigCache.validSigs)) } // The entry added above should be found within the sigcache. sigNewCopy, _ := btcec.ParseSignature(sigNew.Serialize(), btcec.S256()) keyNewCopy, _ := btcec.ParsePubKey(keyNew.SerializeCompressed(), btcec.S256()) if !sigCache.Exists(*msgNew, sigNewCopy, keyNewCopy) { t.Fatalf("previously added item not found in signature cache") } }
// This example demonstrates decrypting a message using a private key that is // first parsed from raw bytes. func Example_decryptMessage() { // Decode the hex-encoded private key. pkBytes, err := hex.DecodeString("a11b0a4e1a132305652ee7a8eb7848f6ad" + "5ea381e3ce20a2c086a2e388230811") if err != nil { fmt.Println(err) return } privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes) ciphertext, err := hex.DecodeString("35f644fbfb208bc71e57684c3c8b437402ca" + "002047a2f1b38aa1a8f1d5121778378414f708fe13ebf7b4a7bb74407288c1958969" + "00207cf4ac6057406e40f79961c973309a892732ae7a74ee96cd89823913b8b8d650" + "a44166dc61ea1c419d47077b748a9c06b8d57af72deb2819d98a9d503efc59fc8307" + "d14174f8b83354fac3ff56075162") // Try decrypting the message. plaintext, err := btcec.Decrypt(privKey, ciphertext) if err != nil { fmt.Println(err) return } fmt.Println(string(plaintext)) // Output: // test message }
func TestPubKeys(t *testing.T) { for _, test := range pubKeyTests { pk, err := btcec.ParsePubKey(test.key, btcec.S256()) if err != nil { if test.isValid { t.Errorf("%s pubkey failed when shouldn't %v", test.name, err) } continue } if !test.isValid { t.Errorf("%s counted as valid when it should fail", test.name) continue } var pkStr []byte switch test.format { case btcec.TstPubkeyUncompressed: pkStr = (*btcec.PublicKey)(pk).SerializeUncompressed() case btcec.TstPubkeyCompressed: pkStr = (*btcec.PublicKey)(pk).SerializeCompressed() case btcec.TstPubkeyHybrid: pkStr = (*btcec.PublicKey)(pk).SerializeHybrid() } if !bytes.Equal(test.key, pkStr) { t.Errorf("%s pubkey: serialized keys do not match.", test.name) spew.Dump(test.key) spew.Dump(pkStr) } } }
func TestScalarMult(t *testing.T) { // Strategy for this test: // Get a random exponent from the generator point at first // This creates a new point which is used in the next iteration // Use another random exponent on the new point. // We use BaseMult to verify by multiplying the previous exponent // and the new random exponent together (mod N) s256 := btcec.S256() x, y := s256.Gx, s256.Gy exponent := big.NewInt(1) for i := 0; i < 1024; i++ { data := make([]byte, 32) _, err := rand.Read(data) if err != nil { t.Fatalf("failed to read random data at %d", i) break } x, y = s256.ScalarMult(x, y, data) exponent.Mul(exponent, new(big.Int).SetBytes(data)) xWant, yWant := s256.ScalarBaseMult(exponent.Bytes()) if x.Cmp(xWant) != 0 || y.Cmp(yWant) != 0 { t.Fatalf("%d: bad output for %X: got (%X, %X), want (%X, %X)", i, data, x, y, xWant, yWant) break } } }
// This example demonstrates signing a message with a secp256k1 private key that // is first parsed form raw bytes and serializing the generated signature. func Example_signMessage() { // Decode a hex-encoded private key. pkBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2d4f87" + "20ee63e502ee2869afab7de234b80c") if err != nil { fmt.Println(err) return } privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes) // Sign a message using the private key. message := "test message" messageHash := wire.DoubleSha256([]byte(message)) signature, err := privKey.Sign(messageHash) if err != nil { fmt.Println(err) return } // Serialize and display the signature. fmt.Printf("Serialized Signature: %x\n", signature.Serialize()) // Verify the signature for the message using the public key. verified := signature.Verify(messageHash, pubKey) fmt.Printf("Signature Verified? %v\n", verified) // Output: // Serialized Signature: 304402201008e236fa8cd0f25df4482dddbb622e8a8b26ef0ba731719458de3ccd93805b022032f8ebe514ba5f672466eba334639282616bb3c2f0ab09998037513d1f9e3d6d // Signature Verified? true }
func TestPrivKeys(t *testing.T) { tests := []struct { name string key []byte }{ { name: "check curve", key: []byte{ 0xea, 0xf0, 0x2c, 0xa3, 0x48, 0xc5, 0x24, 0xe6, 0x39, 0x26, 0x55, 0xba, 0x4d, 0x29, 0x60, 0x3c, 0xd1, 0xa7, 0x34, 0x7d, 0x9d, 0x65, 0xcf, 0xe9, 0x3c, 0xe1, 0xeb, 0xff, 0xdc, 0xa2, 0x26, 0x94, }, }, } for _, test := range tests { priv, pub := btcec.PrivKeyFromBytes(btcec.S256(), test.key) _, err := btcec.ParsePubKey( pub.SerializeUncompressed(), btcec.S256()) if err != nil { t.Errorf("%s privkey: %v", test.name, err) continue } hash := []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9} sig, err := priv.Sign(hash) if err != nil { t.Errorf("%s could not sign: %v", test.name, err) continue } if !sig.Verify(hash, pub) { t.Errorf("%s could not verify: %v", test.name, err) continue } serializedKey := priv.Serialize() if !bytes.Equal(serializedKey, test.key) { t.Errorf("%s unexpected serialized bytes - got: %x, "+ "want: %x", test.name, serializedKey, test.key) } } }
// This example demonstrates encrypting a message for a public key that is first // parsed from raw bytes, then decrypting it using the corresponding private key. func Example_encryptMessage() { // Decode the hex-encoded pubkey of the recipient. pubKeyBytes, err := hex.DecodeString("04115c42e757b2efb7671c578530ec191a1" + "359381e6a71127a9d37c486fd30dae57e76dc58f693bd7e7010358ce6b165e483a29" + "21010db67ac11b1b51b651953d2") // uncompressed pubkey if err != nil { fmt.Println(err) return } pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256()) if err != nil { fmt.Println(err) return } // Encrypt a message decryptable by the private key corresponding to pubKey message := "test message" ciphertext, err := btcec.Encrypt(pubKey, []byte(message)) if err != nil { fmt.Println(err) return } // Decode the hex-encoded private key. pkBytes, err := hex.DecodeString("a11b0a4e1a132305652ee7a8eb7848f6ad" + "5ea381e3ce20a2c086a2e388230811") if err != nil { fmt.Println(err) return } // note that we already have corresponding pubKey privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes) // Try decrypting and verify if it's the same message. plaintext, err := btcec.Decrypt(privKey, ciphertext) if err != nil { fmt.Println(err) return } fmt.Println(string(plaintext)) // Output: // test message }
// TestSigCacheAddExists tests the ability to add, and later check the // existence of a signature triplet in the signature cache. func TestSigCacheAddExists(t *testing.T) { sigCache := NewSigCache(200) // Generate a random sigCache entry triplet. msg1, sig1, key1, err := genRandomSig() if err != nil { t.Errorf("unable to generate random signature test data") } // Add the triplet to the signature cache. sigCache.Add(*msg1, sig1, key1) // The previously added triplet should now be found within the sigcache. sig1Copy, _ := btcec.ParseSignature(sig1.Serialize(), btcec.S256()) key1Copy, _ := btcec.ParsePubKey(key1.SerializeCompressed(), btcec.S256()) if !sigCache.Exists(*msg1, sig1Copy, key1Copy) { t.Errorf("previously added item not found in signature cache") } }
func TestGenerateSharedSecret(t *testing.T) { privKey1, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("private key generation error: %s", err) return } privKey2, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("private key generation error: %s", err) return } secret1 := btcec.GenerateSharedSecret(privKey1, privKey2.PubKey()) secret2 := btcec.GenerateSharedSecret(privKey2, privKey1.PubKey()) if !bytes.Equal(secret1, secret2) { t.Errorf("ECDH failed, secrets mismatch - first: %x, second: %x", secret1, secret2) } }
func main() { fi, err := os.Create("secp256k1.go") if err != nil { log.Fatal(err) } defer fi.Close() // Compress the serialized byte points. serialized := btcec.S256().SerializedBytePoints() var compressed bytes.Buffer w := zlib.NewWriter(&compressed) if _, err := w.Write(serialized); err != nil { fmt.Println(err) os.Exit(1) } w.Close() // Encode the compressed byte points with base64. encoded := make([]byte, base64.StdEncoding.EncodedLen(compressed.Len())) base64.StdEncoding.Encode(encoded, compressed.Bytes()) fmt.Fprintln(fi, "// Copyright (c) 2015 The chrjen developers") fmt.Fprintln(fi, "// Use of this source code is governed by an ISC") fmt.Fprintln(fi, "// license that can be found in the LICENSE file.") fmt.Fprintln(fi) fmt.Fprintln(fi, "package btcec") fmt.Fprintln(fi) fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)") fmt.Fprintln(fi, "// DO NOT EDIT") fmt.Fprintln(fi) fmt.Fprintf(fi, "var secp256k1BytePoints = %q\n", string(encoded)) a1, b1, a2, b2 := btcec.S256().EndomorphismVectors() fmt.Println("The following values are the computed linearly " + "independent vectors needed to make use of the secp256k1 " + "endomorphism:") fmt.Printf("a1: %x\n", a1) fmt.Printf("b1: %x\n", b1) fmt.Printf("a2: %x\n", a2) fmt.Printf("b2: %x\n", b2) }
func TestSignCompact(t *testing.T) { for i := 0; i < 256; i++ { name := fmt.Sprintf("test %d", i) data := make([]byte, 32) _, err := rand.Read(data) if err != nil { t.Errorf("failed to read random data for %s", name) continue } compressed := i%2 != 0 testSignCompact(t, name, btcec.S256(), data, compressed) } }
// This example demonstrates verifying a secp256k1 signature against a public // key that is first parsed from raw bytes. The signature is also parsed from // raw bytes. func Example_verifySignature() { // Decode hex-encoded serialized public key. pubKeyBytes, err := hex.DecodeString("02a673638cb9587cb68ea08dbef685c" + "6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5") if err != nil { fmt.Println(err) return } pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256()) if err != nil { fmt.Println(err) return } // Decode hex-encoded serialized signature. sigBytes, err := hex.DecodeString("30450220090ebfb3690a0ff115bb1b38b" + "8b323a667b7653454f1bccb06d4bbdca42c2079022100ec95778b51e707" + "1cb1205f8bde9af6592fc978b0452dafe599481c46d6b2e479") if err != nil { fmt.Println(err) return } signature, err := btcec.ParseSignature(sigBytes, btcec.S256()) if err != nil { fmt.Println(err) return } // Verify the signature for the message using the public key. message := "test message" messageHash := wire.DoubleSha256([]byte(message)) verified := signature.Verify(messageHash, pubKey) fmt.Println("Signature Verified?", verified) // Output: // Signature Verified? true }
func TestSignatures(t *testing.T) { for _, test := range signatureTests { var err error if test.der { _, err = btcec.ParseDERSignature(test.sig, btcec.S256()) } else { _, err = btcec.ParseSignature(test.sig, btcec.S256()) } if err != nil { if test.isValid { t.Errorf("%s signature failed when shouldn't %v", test.name, err) } /* else { t.Errorf("%s got error %v", test.name, err) } */ continue } if !test.isValid { t.Errorf("%s counted as valid when it should fail", test.name) } } }
//TODO: test different curves as well? func TestBaseMult(t *testing.T) { s256 := btcec.S256() for i, e := range s256BaseMultTests { k, ok := new(big.Int).SetString(e.k, 16) if !ok { t.Errorf("%d: bad value for k: %s", i, e.k) } x, y := s256.ScalarBaseMult(k.Bytes()) if fmt.Sprintf("%X", x) != e.x || fmt.Sprintf("%X", y) != e.y { t.Errorf("%d: bad output for k=%s: got (%X, %X), want (%s, %s)", i, e.k, x, y, e.x, e.y) } if testing.Short() && i > 5 { break } } }
// genRandomSig returns a random message, a signature of the message under the // public key and the public key. This function is used to generate randomized // test data. func genRandomSig() (*wire.ShaHash, *btcec.Signature, *btcec.PublicKey, error) { privKey, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { return nil, nil, nil, err } var msgHash wire.ShaHash if _, err := rand.Read(msgHash[:]); err != nil { return nil, nil, nil, err } sig, err := privKey.Sign(msgHash[:]) if err != nil { return nil, nil, nil, err } return &msgHash, sig, privKey.PubKey(), nil }
func TestBaseMultVerify(t *testing.T) { s256 := btcec.S256() for bytes := 1; bytes < 40; bytes++ { for i := 0; i < 30; i++ { data := make([]byte, bytes) _, err := rand.Read(data) if err != nil { t.Errorf("failed to read random data for %d", i) continue } x, y := s256.ScalarBaseMult(data) xWant, yWant := s256.ScalarMult(s256.Gx, s256.Gy, data) if x.Cmp(xWant) != 0 || y.Cmp(yWant) != 0 { t.Errorf("%d: bad output for %X: got (%X, %X), want (%X, %X)", i, data, x, y, xWant, yWant) } if testing.Short() && i > 2 { break } } } }
// Test 2: Byte compatibility with Pyelliptic func TestCiphering(t *testing.T) { pb, _ := hex.DecodeString("fe38240982f313ae5afb3e904fb8215fb11af1200592b" + "fca26c96c4738e4bf8f") privkey, _ := btcec.PrivKeyFromBytes(btcec.S256(), pb) in := []byte("This is just a test.") out, _ := hex.DecodeString("b0d66e5adaa5ed4e2f0ca68e17b8f2fc02ca002009e3" + "3487e7fa4ab505cf34d98f131be7bd258391588ca7804acb30251e71a04e0020ecf" + "df0f84608f8add82d7353af780fbb28868c713b7813eb4d4e61f7b75d7534dd9856" + "9b0ba77cf14348fcff80fee10e11981f1b4be372d93923e9178972f69937ec850ed" + "6c3f11ff572ddd5b2bedf9f9c0b327c54da02a28fcdce1f8369ffec") dec, err := btcec.Decrypt(privkey, out) if err != nil { t.Fatal("failed to decrypt:", err) } if !bytes.Equal(in, dec) { t.Error("decrypted data doesn't match original") } }
// Test 1: Encryption and decryption func TestCipheringBasic(t *testing.T) { privkey, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Fatal("failed to generate private key") } in := []byte("Hey there dude. How are you doing? This is a test.") out, err := btcec.Encrypt(privkey.PubKey(), in) if err != nil { t.Fatal("failed to encrypt:", err) } dec, err := btcec.Decrypt(privkey, out) if err != nil { t.Fatal("failed to decrypt:", err) } if !bytes.Equal(in, dec) { t.Error("decrypted data doesn't match original") } }
func TestVectors(t *testing.T) { sha := sha1.New() for i, test := range testVectors { pub := btcec.PublicKey{ Curve: btcec.S256(), X: fromHex(test.Qx), Y: fromHex(test.Qy), } msg, _ := hex.DecodeString(test.msg) sha.Reset() sha.Write(msg) hashed := sha.Sum(nil) sig := btcec.Signature{R: fromHex(test.r), S: fromHex(test.s)} if f**k := sig.Verify(hashed, &pub); f**k != test.ok { //t.Errorf("%d: bad result %v %v", i, pub, hashed) t.Errorf("%d: bad result %v instead of %v", i, f**k, test.ok) } if testing.Short() { break } } }
func TestSignAndVerify(t *testing.T) { testSignAndVerify(t, btcec.S256(), "S256") }
func TestKeyGeneration(t *testing.T) { testKeyGeneration(t, btcec.S256(), "S256") }
func TestOnCurve(t *testing.T) { s256 := btcec.S256() if !s256.IsOnCurve(s256.Params().Gx, s256.Params().Gy) { t.Errorf("FAIL S256") } }
// TestDoubleJacobian tests doubling of points projected in Jacobian // coordinates. func TestDoubleJacobian(t *testing.T) { tests := []struct { x1, y1, z1 string // Coordinates (in hex) of point to double x3, y3, z3 string // Coordinates (in hex) of expected point }{ // Doubling a point at infinity is still infinity. { "0", "0", "0", "0", "0", "0", }, // Doubling with z1=1. { "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", "1", "ec9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee64f87c50c27", "b082b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd0755c8f2a", "16e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c1e594464", }, // Doubling with z1!=1. { "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee65073c50fabac", "2b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd125dc91cb988", "6e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c2e5944a11", }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Convert hex to field values. x1 := btcec.NewFieldVal().SetHex(test.x1) y1 := btcec.NewFieldVal().SetHex(test.y1) z1 := btcec.NewFieldVal().SetHex(test.z1) x3 := btcec.NewFieldVal().SetHex(test.x3) y3 := btcec.NewFieldVal().SetHex(test.y3) z3 := btcec.NewFieldVal().SetHex(test.z3) // Ensure the test data is using points that are actually on // the curve (or the point at infinity). if !z1.IsZero() && !btcec.S256().TstIsJacobianOnCurve(x1, y1, z1) { t.Errorf("#%d first point is not on the curve -- "+ "invalid test data", i) continue } if !z3.IsZero() && !btcec.S256().TstIsJacobianOnCurve(x3, y3, z3) { t.Errorf("#%d expected point is not on the curve -- "+ "invalid test data", i) continue } // Double the point. rx, ry, rz := btcec.NewFieldVal(), btcec.NewFieldVal(), btcec.NewFieldVal() btcec.S256().TstDoubleJacobian(x1, y1, z1, rx, ry, rz) // Ensure result matches expected. if !rx.Equals(x3) || !ry.Equals(y3) || !rz.Equals(z3) { t.Errorf("#%d wrong result\ngot: (%v, %v, %v)\n"+ "want: (%v, %v, %v)", i, rx, ry, rz, x3, y3, z3) continue } } }
// TestDoubleAffine tests doubling of points in affine coordinates. func TestDoubleAffine(t *testing.T) { tests := []struct { x1, y1 string // Coordinates (in hex) of point to double x3, y3 string // Coordinates (in hex) of expected point }{ // Doubling a point at infinity is still infinity. // 2*∞ = ∞ (point at infinity) { "0", "0", "0", "0", }, // Random points. { "e41387ffd8baaeeb43c2faa44e141b19790e8ac1f7ff43d480dc132230536f86", "1b88191d430f559896149c86cbcb703193105e3cf3213c0c3556399836a2b899", "88da47a089d333371bd798c548ef7caae76e737c1980b452d367b3cfe3082c19", "3b6f659b09a362821dfcfefdbfbc2e59b935ba081b6c249eb147b3c2100b1bc1", }, { "b3589b5d984f03ef7c80aeae444f919374799edf18d375cab10489a3009cff0c", "c26cf343875b3630e15bccc61202815b5d8f1fd11308934a584a5babe69db36a", "e193860172998751e527bb12563855602a227fc1f612523394da53b746bb2fb1", "2bfcf13d2f5ab8bb5c611fab5ebbed3dc2f057062b39a335224c22f090c04789", }, { "2b31a40fbebe3440d43ac28dba23eee71c62762c3fe3dbd88b4ab82dc6a82340", "9ba7deb02f5c010e217607fd49d58db78ec273371ea828b49891ce2fd74959a1", "2c8d5ef0d343b1a1a48aa336078eadda8481cb048d9305dc4fdf7ee5f65973a2", "bb4914ac729e26d3cd8f8dc8f702f3f4bb7e0e9c5ae43335f6e94c2de6c3dc95", }, { "61c64b760b51981fab54716d5078ab7dffc93730b1d1823477e27c51f6904c7a", "ef6eb16ea1a36af69d7f66524c75a3a5e84c13be8fbc2e811e0563c5405e49bd", "5f0dcdd2595f5ad83318a0f9da481039e36f135005420393e72dfca985b482f4", "a01c849b0837065c1cb481b0932c441f49d1cab1b4b9f355c35173d93f110ae0", }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Convert hex to field values. x1, y1 := fromHex(test.x1), fromHex(test.y1) x3, y3 := fromHex(test.x3), fromHex(test.y3) // Ensure the test data is using points that are actually on // the curve (or the point at infinity). if !(x1.Sign() == 0 && y1.Sign() == 0) && !btcec.S256().IsOnCurve(x1, y1) { t.Errorf("#%d first point is not on the curve -- "+ "invalid test data", i) continue } if !(x3.Sign() == 0 && y3.Sign() == 0) && !btcec.S256().IsOnCurve(x3, y3) { t.Errorf("#%d expected point is not on the curve -- "+ "invalid test data", i) continue } // Double the point. rx, ry := btcec.S256().Double(x1, y1) // Ensure result matches expected. if rx.Cmp(x3) != 00 || ry.Cmp(y3) != 0 { t.Errorf("#%d wrong result\ngot: (%x, %x)\n"+ "want: (%x, %x)", i, rx, ry, x3, y3) continue } } }
// TestAddAffine tests addition of points in affine coordinates. func TestAddAffine(t *testing.T) { tests := []struct { x1, y1 string // Coordinates (in hex) of first point to add x2, y2 string // Coordinates (in hex) of second point to add x3, y3 string // Coordinates (in hex) of expected point }{ // Addition with a point at infinity (left hand side). // ∞ + P = P { "0", "0", "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", }, // Addition with a point at infinity (right hand side). // P + ∞ = P { "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", "0", "0", "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", }, // Addition with different x values. { "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", "fd5b88c21d3143518d522cd2796f3d726793c88b3e05636bc829448e053fed69", "21cf4f6a5be5ff6380234c50424a970b1f7e718f5eb58f68198c108d642a137f", }, // Addition with same x opposite y. // P(x, y) + P(x, -y) = infinity { "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "f48e156428cf0276dc092da5856e182288d7569f97934a56fe44be60f0d359fd", "0", "0", }, // Addition with same point. // P(x, y) + P(x, y) = 2P { "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", "59477d88ae64a104dbb8d31ec4ce2d91b2fe50fa628fb6a064e22582196b365b", "938dc8c0f13d1e75c987cb1a220501bd614b0d3dd9eb5c639847e1240216e3b6", }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Convert hex to field values. x1, y1 := fromHex(test.x1), fromHex(test.y1) x2, y2 := fromHex(test.x2), fromHex(test.y2) x3, y3 := fromHex(test.x3), fromHex(test.y3) // Ensure the test data is using points that are actually on // the curve (or the point at infinity). if !(x1.Sign() == 0 && y1.Sign() == 0) && !btcec.S256().IsOnCurve(x1, y1) { t.Errorf("#%d first point is not on the curve -- "+ "invalid test data", i) continue } if !(x2.Sign() == 0 && y2.Sign() == 0) && !btcec.S256().IsOnCurve(x2, y2) { t.Errorf("#%d second point is not on the curve -- "+ "invalid test data", i) continue } if !(x3.Sign() == 0 && y3.Sign() == 0) && !btcec.S256().IsOnCurve(x3, y3) { t.Errorf("#%d expected point is not on the curve -- "+ "invalid test data", i) continue } // Add the two points. rx, ry := btcec.S256().Add(x1, y1, x2, y2) // Ensure result matches expected. if rx.Cmp(x3) != 00 || ry.Cmp(y3) != 0 { t.Errorf("#%d wrong result\ngot: (%x, %x)\n"+ "want: (%x, %x)", i, rx, ry, x3, y3) continue } } }
// TestAddJacobian tests addition of points projected in Jacobian coordinates. func TestAddJacobian(t *testing.T) { tests := []struct { x1, y1, z1 string // Coordinates (in hex) of first point to add x2, y2, z2 string // Coordinates (in hex) of second point to add x3, y3, z3 string // Coordinates (in hex) of expected point }{ // Addition with a point at infinity (left hand side). // ∞ + P = P { "0", "0", "0", "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", "1", "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", "1", }, // Addition with a point at infinity (right hand side). // P + ∞ = P { "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", "1", "0", "0", "0", "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", "1", }, // Addition with z1=z2=1 different x values. { "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", "1", "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", "1", "0cfbc7da1e569b334460788faae0286e68b3af7379d5504efc25e4dba16e46a6", "e205f79361bbe0346b037b4010985dbf4f9e1e955e7d0d14aca876bfa79aad87", "44a5646b446e3877a648d6d381370d9ef55a83b666ebce9df1b1d7d65b817b2f", }, // Addition with z1=z2=1 same x opposite y. // P(x, y, z) + P(x, -y, z) = infinity { "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", "1", "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "f48e156428cf0276dc092da5856e182288d7569f97934a56fe44be60f0d359fd", "1", "0", "0", "0", }, // Addition with z1=z2=1 same point. // P(x, y, z) + P(x, y, z) = 2P { "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", "1", "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", "1", "ec9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee64f87c50c27", "b082b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd0755c8f2a", "16e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c1e594464", }, // Addition with z1=z2 (!=1) different x values. { "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "5d2fe112c21891d440f65a98473cb626111f8a234d2cd82f22172e369f002147", "98e3386a0a622a35c4561ffb32308d8e1c6758e10ebb1b4ebd3d04b4eb0ecbe8", "2", "cfbc7da1e569b334460788faae0286e68b3af7379d5504efc25e4dba16e46a60", "817de4d86ef80d1ac0ded00426176fd3e787a5579f43452b2a1db021e6ac3778", "129591ad11b8e1de99235b4e04dc367bd56a0ed99baf3a77c6c75f5a6e05f08d", }, // Addition with z1=z2 (!=1) same x opposite y. // P(x, y, z) + P(x, -y, z) = infinity { "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "a470ab21467813b6e0496d2c2b70c11446bab4fcbc9a52b7f225f30e869aea9f", "2", "0", "0", "0", }, // Addition with z1=z2 (!=1) same point. // P(x, y, z) + P(x, y, z) = 2P { "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee65073c50fabac", "2b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd125dc91cb988", "6e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c2e5944a11", }, // Addition with z1!=z2 and z2=1 different x values. { "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", "131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", "1", "3ef1f68795a6ccd1181e23eab80a1b9a2cebdcde755413bf097936eb5b91b4f3", "0bef26c377c068d606f6802130bb7e9f3c3d2abcfa1a295950ed81133561cb04", "252b235a2371c3bd3246b69c09b86cf7aad41db3375e74ef8d8ebeb4dc0be11a", }, // Addition with z1!=z2 and z2=1 same x opposite y. // P(x, y, z) + P(x, -y, z) = infinity { "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "f48e156428cf0276dc092da5856e182288d7569f97934a56fe44be60f0d359fd", "1", "0", "0", "0", }, // Addition with z1!=z2 and z2=1 same point. // P(x, y, z) + P(x, y, z) = 2P { "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", "1", "9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee65073c50fabac", "2b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd125dc91cb988", "6e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c2e5944a11", }, // Addition with z1!=z2 and z2!=1 different x values. // P(x, y, z) + P(x, y, z) = 2P { "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "91abba6a34b7481d922a4bd6a04899d5a686f6cf6da4e66a0cb427fb25c04bd4", "03fede65e30b4e7576a2abefc963ddbf9fdccbf791b77c29beadefe49951f7d1", "3", "3f07081927fd3f6dadd4476614c89a09eba7f57c1c6c3b01fa2d64eac1eef31e", "949166e04ebc7fd95a9d77e5dfd88d1492ecffd189792e3944eb2b765e09e031", "eb8cba81bcffa4f44d75427506737e1f045f21e6d6f65543ee0e1d163540c931", }, // Addition with z1!=z2 and z2!=1 same x opposite y. // P(x, y, z) + P(x, -y, z) = infinity { "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "dcc3768780c74a0325e2851edad0dc8a566fa61a9e7fc4a34d13dcb509f99bc7", "cafc41904dd5428934f7d075129c8ba46eb622d4fc88d72cd1401452664add18", "3", "0", "0", "0", }, // Addition with z1!=z2 and z2!=1 same point. // P(x, y, z) + P(x, y, z) = 2P { "d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", "5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", "2", "dcc3768780c74a0325e2851edad0dc8a566fa61a9e7fc4a34d13dcb509f99bc7", "3503be6fb22abd76cb082f8aed63745b9149dd2b037728d32ebfebac99b51f17", "3", "9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee65073c50fabac", "2b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd125dc91cb988", "6e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c2e5944a11", }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Convert hex to field values. x1 := btcec.NewFieldVal().SetHex(test.x1) y1 := btcec.NewFieldVal().SetHex(test.y1) z1 := btcec.NewFieldVal().SetHex(test.z1) x2 := btcec.NewFieldVal().SetHex(test.x2) y2 := btcec.NewFieldVal().SetHex(test.y2) z2 := btcec.NewFieldVal().SetHex(test.z2) x3 := btcec.NewFieldVal().SetHex(test.x3) y3 := btcec.NewFieldVal().SetHex(test.y3) z3 := btcec.NewFieldVal().SetHex(test.z3) // Ensure the test data is using points that are actually on // the curve (or the point at infinity). if !z1.IsZero() && !btcec.S256().TstIsJacobianOnCurve(x1, y1, z1) { t.Errorf("#%d first point is not on the curve -- "+ "invalid test data", i) continue } if !z2.IsZero() && !btcec.S256().TstIsJacobianOnCurve(x2, y2, z2) { t.Errorf("#%d second point is not on the curve -- "+ "invalid test data", i) continue } if !z3.IsZero() && !btcec.S256().TstIsJacobianOnCurve(x3, y3, z3) { t.Errorf("#%d expected point is not on the curve -- "+ "invalid test data", i) continue } // Add the two points. rx, ry, rz := btcec.NewFieldVal(), btcec.NewFieldVal(), btcec.NewFieldVal() btcec.S256().TstAddJacobian(x1, y1, z1, x2, y2, z2, rx, ry, rz) // Ensure result matches expected. if !rx.Equals(x3) || !ry.Equals(y3) || !rz.Equals(z3) { t.Errorf("#%d wrong result\ngot: (%v, %v, %v)\n"+ "want: (%v, %v, %v)", i, rx, ry, rz, x3, y3, z3) continue } } }
func TestSignTxOutput(t *testing.T) { t.Parallel() // make key // make script based on key. // sign with magic pixie dust. hashTypes := []txscript.SigHashType{ txscript.SigHashOld, // no longer used but should act like all txscript.SigHashAll, txscript.SigHashNone, txscript.SigHashSingle, txscript.SigHashAll | txscript.SigHashAnyOneCanPay, txscript.SigHashNone | txscript.SigHashAnyOneCanPay, txscript.SigHashSingle | txscript.SigHashAnyOneCanPay, } tx := &wire.MsgTx{ Version: 1, TxIn: []*wire.TxIn{ &wire.TxIn{ PreviousOutPoint: wire.OutPoint{ Hash: wire.ShaHash{}, Index: 0, }, Sequence: 4294967295, }, &wire.TxIn{ PreviousOutPoint: wire.OutPoint{ Hash: wire.ShaHash{}, Index: 1, }, Sequence: 4294967295, }, &wire.TxIn{ PreviousOutPoint: wire.OutPoint{ Hash: wire.ShaHash{}, Index: 2, }, Sequence: 4294967295, }, }, TxOut: []*wire.TxOut{ &wire.TxOut{ Value: 1, }, &wire.TxOut{ Value: 2, }, &wire.TxOut{ Value: 3, }, }, LockTime: 0, } // Pay to Pubkey Hash (uncompressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), nil); err != nil { t.Error(err) break } } } // Pay to Pubkey Hash (uncompressed) (merging with correct) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), sigScript) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, pkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to Pubkey Hash (compressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), nil); err != nil { t.Error(err) break } } } // Pay to Pubkey Hash (compressed) with duplicate merge for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), sigScript) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, pkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to PubKey (uncompressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), nil); err != nil { t.Error(err) break } } } // Pay to PubKey (uncompressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), sigScript) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, pkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to PubKey (compressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), nil); err != nil { t.Error(err) break } } } // Pay to PubKey (compressed) with duplicate merge for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), sigScript) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, pkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // As before, but with p2sh now. // Pay to Pubkey Hash (uncompressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) break } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil); err != nil { t.Error(err) break } } } // Pay to Pubkey Hash (uncompressed) with duplicate merge for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) break } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to Pubkey Hash (compressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil); err != nil { t.Error(err) break } } } // Pay to Pubkey Hash (compressed) with duplicate merge for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to PubKey (uncompressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil); err != nil { t.Error(err) break } } } // Pay to PubKey (uncompressed) with duplicate merge for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to PubKey (compressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil); err != nil { t.Error(err) break } } } // Pay to PubKey (compressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Basic Multisig for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key1, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk1 := (*btcec.PublicKey)(&key1.PublicKey). SerializeCompressed() address1, err := btcutil.NewAddressPubKey(pk1, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } key2, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey 2 for %s: %v", msg, err) break } pk2 := (*btcec.PublicKey)(&key2.PublicKey). SerializeCompressed() address2, err := btcutil.NewAddressPubKey(pk2, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address 2 for %s: %v", msg, err) break } pkScript, err := txscript.MultiSigScript( []*btcutil.AddressPubKey{address1, address2}, 2) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address1.EncodeAddress(): {key1, true}, address2.EncodeAddress(): {key2, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil); err != nil { t.Error(err) break } } } // Two part multisig, sign with one key then the other. for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key1, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk1 := (*btcec.PublicKey)(&key1.PublicKey). SerializeCompressed() address1, err := btcutil.NewAddressPubKey(pk1, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } key2, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey 2 for %s: %v", msg, err) break } pk2 := (*btcec.PublicKey)(&key2.PublicKey). SerializeCompressed() address2, err := btcutil.NewAddressPubKey(pk2, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address 2 for %s: %v", msg, err) break } pkScript, err := txscript.MultiSigScript( []*btcutil.AddressPubKey{address1, address2}, 2) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address1.EncodeAddress(): {key1, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // Only 1 out of 2 signed, this *should* fail. if checkScripts(msg, tx, i, sigScript, scriptPkScript) == nil { t.Errorf("part signed script valid for %s", msg) break } // Sign with the other key and merge sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address2.EncodeAddress(): {key2, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), sigScript) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("fully signed script invalid for "+ "%s: %v", msg, err) break } } } // Two part multisig, sign with one key then both, check key dedup // correctly. for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key1, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk1 := (*btcec.PublicKey)(&key1.PublicKey). SerializeCompressed() address1, err := btcutil.NewAddressPubKey(pk1, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } key2, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey 2 for %s: %v", msg, err) break } pk2 := (*btcec.PublicKey)(&key2.PublicKey). SerializeCompressed() address2, err := btcutil.NewAddressPubKey(pk2, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address 2 for %s: %v", msg, err) break } pkScript, err := txscript.MultiSigScript( []*btcutil.AddressPubKey{address1, address2}, 2) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address1.EncodeAddress(): {key1, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // Only 1 out of 2 signed, this *should* fail. if checkScripts(msg, tx, i, sigScript, scriptPkScript) == nil { t.Errorf("part signed script valid for %s", msg) break } // Sign with the other key and merge sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address1.EncodeAddress(): {key1, true}, address2.EncodeAddress(): {key2, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), sigScript) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // Now we should pass. err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("fully signed script invalid for "+ "%s: %v", msg, err) break } } } }
// TestSignatureSerialize ensures that serializing signatures works as expected. func TestSignatureSerialize(t *testing.T) { tests := []struct { name string ecsig *btcec.Signature expected []byte }{ // signature from bitcoin blockchain tx // 0437cd7f8525ceed2324359c2d0ba26006d92d85 { "valid 1 - r and s most significant bits are zero", &btcec.Signature{ R: fromHex("4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41"), S: fromHex("181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09"), }, []byte{ 0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, }, }, // signature from bitcoin blockchain tx // cb00f8a0573b18faa8c4f467b049f5d202bf1101d9ef2633bc611be70376a4b4 { "valid 2 - r most significant bit is one", &btcec.Signature{ R: fromHex("0082235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3"), S: fromHex("24bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724"), }, []byte{ 0x30, 0x45, 0x02, 0x21, 0x00, 0x82, 0x23, 0x5e, 0x21, 0xa2, 0x30, 0x00, 0x22, 0x73, 0x8d, 0xab, 0xb8, 0xe1, 0xbb, 0xd9, 0xd1, 0x9c, 0xfb, 0x1e, 0x7a, 0xb8, 0xc3, 0x0a, 0x23, 0xb0, 0xaf, 0xbb, 0x8d, 0x17, 0x8a, 0xbc, 0xf3, 0x02, 0x20, 0x24, 0xbf, 0x68, 0xe2, 0x56, 0xc5, 0x34, 0xdd, 0xfa, 0xf9, 0x66, 0xbf, 0x90, 0x8d, 0xeb, 0x94, 0x43, 0x05, 0x59, 0x6f, 0x7b, 0xdc, 0xc3, 0x8d, 0x69, 0xac, 0xad, 0x7f, 0x9c, 0x86, 0x87, 0x24, }, }, // signature from bitcoin blockchain tx // fda204502a3345e08afd6af27377c052e77f1fefeaeb31bdd45f1e1237ca5470 { "valid 3 - s most significant bit is one", &btcec.Signature{ R: fromHex("1cadddc2838598fee7dc35a12b340c6bde8b389f7bfd19a1252a17c4b5ed2d71"), S: new(big.Int).Add(fromHex("00c1a251bbecb14b058a8bd77f65de87e51c47e95904f4c0e9d52eddc21c1415ac"), btcec.S256().N), }, []byte{ 0x30, 0x45, 0x02, 0x20, 0x1c, 0xad, 0xdd, 0xc2, 0x83, 0x85, 0x98, 0xfe, 0xe7, 0xdc, 0x35, 0xa1, 0x2b, 0x34, 0x0c, 0x6b, 0xde, 0x8b, 0x38, 0x9f, 0x7b, 0xfd, 0x19, 0xa1, 0x25, 0x2a, 0x17, 0xc4, 0xb5, 0xed, 0x2d, 0x71, 0x02, 0x21, 0x00, 0xc1, 0xa2, 0x51, 0xbb, 0xec, 0xb1, 0x4b, 0x05, 0x8a, 0x8b, 0xd7, 0x7f, 0x65, 0xde, 0x87, 0xe5, 0x1c, 0x47, 0xe9, 0x59, 0x04, 0xf4, 0xc0, 0xe9, 0xd5, 0x2e, 0xdd, 0xc2, 0x1c, 0x14, 0x15, 0xac, }, }, { "zero signature", &btcec.Signature{ R: big.NewInt(0), S: big.NewInt(0), }, []byte{0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00}, }, } for i, test := range tests { result := test.ecsig.Serialize() if !bytes.Equal(result, test.expected) { t.Errorf("Serialize #%d (%s) unexpected result:\n"+ "got: %x\nwant: %x", i, test.name, result, test.expected) } } }
func TestRFC6979(t *testing.T) { // Test vectors matching Trezor and CoreBitcoin implementations. // - https://github.com/trezor/trezor-crypto/blob/9fea8f8ab377dc514e40c6fd1f7c89a74c1d8dc6/tests.c#L432-L453 // - https://github.com/oleganza/CoreBitcoin/blob/e93dd71207861b5bf044415db5fa72405e7d8fbc/CoreBitcoin/BTCKey%2BTests.m#L23-L49 tests := []struct { key string msg string nonce string signature string }{ { "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", "sample", "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3", "3045022100af340daf02cc15c8d5d08d7735dfe6b98a474ed373bdb5fbecf7571be52b384202205009fb27f37034a9b24b707b7c6b79ca23ddef9e25f7282e8a797efe53a8f124", }, { // This signature hits the case when S is higher than halforder. // If S is not canonicalized (lowered by halforder), this test will fail. "0000000000000000000000000000000000000000000000000000000000000001", "Satoshi Nakamoto", "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15", "3045022100934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d802202442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5", }, { "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", "Satoshi Nakamoto", "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90", "3045022100fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d002206b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5", }, { "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", "Alan Turing", "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1", "304402207063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c022058dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea", }, { "0000000000000000000000000000000000000000000000000000000000000001", "All those moments will be lost in time, like tears in rain. Time to die...", "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3", "30450221008600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b0220547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21", }, { "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!", "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d", "3045022100b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b0220279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6", }, } for i, test := range tests { privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), decodeHex(test.key)) hash := fastsha256.Sum256([]byte(test.msg)) // Ensure deterministically generated nonce is the expected value. gotNonce := btcec.TstNonceRFC6979(privKey.D, hash[:]).Bytes() wantNonce := decodeHex(test.nonce) if !bytes.Equal(gotNonce, wantNonce) { t.Errorf("NonceRFC6979 #%d (%s): Nonce is incorrect: "+ "%x (expected %x)", i, test.msg, gotNonce, wantNonce) continue } // Ensure deterministically generated signature is the expected value. gotSig, err := privKey.Sign(hash[:]) if err != nil { t.Errorf("Sign #%d (%s): unexpected error: %v", i, test.msg, err) continue } gotSigBytes := gotSig.Serialize() wantSigBytes := decodeHex(test.signature) if !bytes.Equal(gotSigBytes, wantSigBytes) { t.Errorf("Sign #%d (%s): mismatched signature: %x "+ "(expected %x)", i, test.msg, gotSigBytes, wantSigBytes) continue } } }