func GenerateKey() Secret { keys, _ := btcec.NewPrivateKey(btcec.S256()) pub := keys.PubKey().SerializeCompressed() priv := keys.Serialize() sin := GenerateSin(pub) return Secret{pub, priv, sin} }
func testKeyGeneration(t *testing.T, c *btcec.KoblitzCurve, tag string) { priv, err := btcec.NewPrivateKey(c) if err != nil { t.Errorf("%s: error: %s", tag, err) return } if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) { t.Errorf("%s: public key invalid: %s", tag, err) } }
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 generateKeyPair() (*btcec.PublicKey, *btcec.PrivateKey) { // Generate a private key, use the curve secpc256k1 and kill the program on // any errors priv, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { // There was an error. Log it and bail out log.Fatal(err) } return priv.PubKey(), priv }
func testSignCompact(t *testing.T, tag string, curve *btcec.KoblitzCurve, data []byte, isCompressed bool) { tmp, _ := btcec.NewPrivateKey(curve) priv := (*btcec.PrivateKey)(tmp) hashed := []byte("testing") sig, err := btcec.SignCompact(curve, priv, hashed, isCompressed) if err != nil { t.Errorf("%s: error signing: %s", tag, err) return } pk, wasCompressed, err := btcec.RecoverCompact(curve, sig, hashed) if err != nil { t.Errorf("%s: error recovering: %s", tag, err) return } if pk.X.Cmp(priv.X) != 0 || pk.Y.Cmp(priv.Y) != 0 { t.Errorf("%s: recovered pubkey doesn't match original "+ "(%v,%v) vs (%v,%v) ", tag, pk.X, pk.Y, priv.X, priv.Y) return } if wasCompressed != isCompressed { t.Errorf("%s: recovered pubkey doesn't match compressed state "+ "(%v vs %v)", tag, isCompressed, wasCompressed) return } // If we change the compressed bit we should get the same key back, // but the compressed flag should be reversed. if isCompressed { sig[0] -= 4 } else { sig[0] += 4 } pk, wasCompressed, err = btcec.RecoverCompact(curve, sig, hashed) if err != nil { t.Errorf("%s: error recovering (2): %s", tag, err) return } if pk.X.Cmp(priv.X) != 0 || pk.Y.Cmp(priv.Y) != 0 { t.Errorf("%s: recovered pubkey (2) doesn't match original "+ "(%v,%v) vs (%v,%v) ", tag, pk.X, pk.Y, priv.X, priv.Y) return } if wasCompressed == isCompressed { t.Errorf("%s: recovered pubkey doesn't match reversed "+ "compressed state (%v vs %v)", tag, isCompressed, wasCompressed) return } }
// GenerateKeyPair creates a random public/private key pair. func GenerateKeyPair() (*SecretKey, *PublicKey, error) { sk_s, err := btcec.NewPrivateKey(S256) if err != nil { return nil, nil, err } // Serialize the key pair sk := newSecretKeyInt(sk_s.D) pk := newPublicKeyCoords(sk_s.X, sk_s.Y) sk_s.D.SetUint64(0) return sk, pk, nil }
//All BitPay clients use a PEM file to store the private and public keys. func GeneratePem() string { priv, _ := btcec.NewPrivateKey(btcec.S256()) pub := priv.PubKey() ecd := pub.ToECDSA() oid := asn1.ObjectIdentifier{1, 3, 132, 0, 10} curve := btcec.S256() der, _ := asn1.Marshal(ecPrivateKey{ Version: 1, PrivateKey: priv.D.Bytes(), NamedCurveOID: oid, PublicKey: asn1.BitString{Bytes: elliptic.Marshal(curve, ecd.X, ecd.Y)}, }) blck := pem.Block{Type: "EC PRIVATE KEY", Bytes: der} pm := pem.EncodeToMemory(&blck) return string(pm) }
// createCipherConn.... func (l *Listener) createCipherConn(lnConn *LNDConn) (*btcec.PrivateKey, error) { var err error var theirEphPubBytes []byte // First, read and deserialize their ephemeral public key. theirEphPubBytes, err = readClear(lnConn.Conn) if err != nil { return nil, err } if len(theirEphPubBytes) != 33 { return nil, fmt.Errorf("Got invalid %d byte eph pubkey %x\n", len(theirEphPubBytes), theirEphPubBytes) } theirEphPub, err := btcec.ParsePubKey(theirEphPubBytes, btcec.S256()) if err != nil { return nil, err } // Once we've parsed and verified their key, generate, and send own // ephemeral key pair for use within this session. myEph, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { return nil, err } if _, err := writeClear(lnConn.Conn, myEph.PubKey().SerializeCompressed()); err != nil { return nil, err } // Now that we have both keys, do non-interactive diffie with ephemeral // pubkeys, sha256 for good luck. sessionKey := fastsha256.Sum256( btcec.GenerateSharedSecret(myEph, theirEphPub), ) lnConn.chachaStream, err = chacha20poly1305.New(sessionKey[:]) // display private key for debug only fmt.Printf("made session key %x\n", sessionKey) lnConn.remoteNonceInt = 1 << 63 lnConn.myNonceInt = 0 lnConn.RemotePub = theirEphPub lnConn.Authed = false return myEph, nil }
// genRandomSig returns a random message, public key, and a signature of the // message under 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 testSignAndVerify(t *testing.T, c *btcec.KoblitzCurve, tag string) { priv, _ := btcec.NewPrivateKey(c) pub := priv.PubKey() hashed := []byte("testing") sig, err := priv.Sign(hashed) if err != nil { t.Errorf("%s: error signing: %s", tag, err) return } if !sig.Verify(hashed, pub) { t.Errorf("%s: Verify failed", tag) } hashed[0] ^= 0xff if sig.Verify(hashed, pub) { t.Errorf("%s: Verify always works!", tag) } }
// 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 TestSignTxOutput(t *testing.T) { t.Parallel() // make key // make script based on key. // sign with magic pixie dust. hashTypes := []SigHashType{ SigHashOld, // no longer used but should act like all SigHashAll, SigHashNone, SigHashSingle, SigHashAll | SigHashAnyOneCanPay, SigHashNone | SigHashAnyOneCanPay, SigHashSingle | SigHashAnyOneCanPay, } tx := &wire.MsgTx{ Version: 1, TxIn: []*wire.TxIn{ { PreviousOutPoint: wire.OutPoint{ Hash: chainhash.Hash{}, Index: 0, }, Sequence: 4294967295, }, { PreviousOutPoint: wire.OutPoint{ Hash: chainhash.Hash{}, Index: 1, }, Sequence: 4294967295, }, { PreviousOutPoint: wire.OutPoint{ Hash: chainhash.Hash{}, Index: 2, }, Sequence: 4294967295, }, }, TxOut: []*wire.TxOut{ { Value: 1, }, { Value: 2, }, { 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 := 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 := PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := 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 = 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 := 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 := PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := 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 = 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 := 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 := PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := 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 = 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 := 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 := PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := 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 = 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 := 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 := 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 := 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 := PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := 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 = 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 := 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 := 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 := 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 := PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := 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 = 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 := 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 := 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 := 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 := PayToAddrScript(scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := 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 = 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 := 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 := 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 := 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 := PayToAddrScript(scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := 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 = 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 := 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 := 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 := 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 := PayToAddrScript(scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := 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 = 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 := 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 := PayToAddrScript(scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := 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 = 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 } } } }
// Dial... func (c *Conn) Dial(address string, remoteId []byte) error { var err error if c.conn != nil { return fmt.Errorf("connection already established") } // Before dialing out to the remote host, verify that `remoteId` is either // a pubkey or a pubkey hash. if len(remoteId) != 33 && len(remoteId) != 20 { return fmt.Errorf("must supply either remote pubkey or " + "pubkey hash") } // First, open the TCP connection itself. c.conn, err = net.Dial("tcp", address) if err != nil { return err } // Calc remote LNId; need this for creating pbx connections just because // LNid is in the struct does not mean it's authed! if len(remoteId) == 20 { copy(c.remoteLNId[:], remoteId[:16]) } else { theirAdr := btcutil.Hash160(remoteId) copy(c.remoteLNId[:], theirAdr[:16]) } // Make up an ephemeral keypair for this session. ourEphemeralPriv, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { return err } ourEphemeralPub := ourEphemeralPriv.PubKey() // Sned 1. Send my ephemeral pubkey. Can add version bits. if _, err = writeClear(c.conn, ourEphemeralPub.SerializeCompressed()); err != nil { return err } // Read, then deserialize their ephemeral public key. theirEphPubBytes, err := readClear(c.conn) if err != nil { return err } theirEphPub, err := btcec.ParsePubKey(theirEphPubBytes, btcec.S256()) if err != nil { return err } // Do non-interactive diffie with ephemeral pubkeys. Sha256 for good // luck. sessionKey := fastsha256.Sum256( btcec.GenerateSharedSecret(ourEphemeralPriv, theirEphPub), ) // Now that we've derive the session key, we can initialize the // chacha20poly1305 AEAD instance which will be used for the remainder of // the session. c.chachaStream, err = chacha20poly1305.New(sessionKey[:]) if err != nil { return err } // display private key for debug only fmt.Printf("made session key %x\n", sessionKey) c.myNonceInt = 1 << 63 c.remoteNonceInt = 0 c.remotePub = theirEphPub c.authed = false // Session is now open and confidential but not yet authenticated... // So auth! if len(remoteId) == 20 { // Only know pubkey hash (20 bytes). err = c.authPKH(remoteId, ourEphemeralPub.SerializeCompressed()) } else { // Must be 33 byte pubkey. err = c.authPubKey(remoteId, ourEphemeralPub.SerializeCompressed()) } if err != nil { return err } return nil }
func TestSphinxCorrectness(t *testing.T) { nodes := make([]*SphinxNode, numMaxHops) // Create numMaxHops random sphinx nodes. for i := 0; i < len(nodes); i++ { privKey, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Fatalf("Unable to generate random key for sphinx node: %v", err) } nodes[i] = NewSphinxNode(privKey, &chaincfg.MainNetParams) } // Gather all the pub keys in the path. route := make([]*btcec.PublicKey, len(nodes)) for i := 0; i < len(nodes); i++ { route[i] = nodes[i].lnKey.PubKey() } // Generate a forwarding message to route to the final node via the // generated intermdiates nodes above. // Destination should be Hash160, adding padding so parsing still works. dest := append([]byte("roasbeef"), bytes.Repeat([]byte{0}, securityParameter-8)...) fwdMsg, err := NewForwardingMessage(route, dest, []byte("testing")) if err != nil { t.Fatalf("Unable to create forwarding message: %#v", err) } // Now simulate the message propagating through the mix net eventually // reaching the final destination. for i := 0; i < len(nodes); i++ { hop := nodes[i] fmt.Printf("Processing at hop: %v \n", i) processAction, err := hop.ProcessForwardingMessage(fwdMsg) if err != nil { t.Fatalf("Node %v was unabled to process the forwarding message: %v", i, err) } // If this is the last hop on the path, the node should // recognize that it's the exit node. if i == len(nodes)-1 { if processAction.action != ExitNode { t.Fatalf("Processing error, node %v is the last hop in"+ "the path, yet it doesn't recognize so", i) } // The original destination address and message should // now be fully decrypted. if !bytes.Equal(dest, processAction.destAddr) { t.Fatalf("Destination address parsed incorrectly at final destination!"+ " Should be %v, is instead %v", hex.EncodeToString(dest), hex.EncodeToString(processAction.destAddr)) } if !bytes.HasPrefix(processAction.destMsg, []byte("testing")) { t.Fatalf("Final message parsed incorrectly at final destination!"+ "Should be %v, is instead %v", []byte("testing"), processAction.destMsg) } } else { // If this isn't the last node in the path, then the returned // action should indicate that there are more hops to go. if processAction.action != MoreHops { t.Fatalf("Processing error, node %v is not the final"+ " hop, yet thinks it is.", i) } // The next hop should have been parsed as node[i+1]. parsedNextHop := processAction.nextHop[:] if !bytes.Equal(parsedNextHop, nodes[i+1].nodeID[:]) { t.Fatalf("Processing error, next hop parsed incorrectly."+ " next hop shoud be %v, was instead parsed as %v", hex.EncodeToString(nodes[i+1].nodeID[:]), hex.EncodeToString(parsedNextHop)) } fwdMsg = processAction.fwdMsg } } }
// TestCheckPkScriptStandard tests the checkPkScriptStandard API. func TestCheckPkScriptStandard(t *testing.T) { var pubKeys [][]byte for i := 0; i < 4; i++ { pk, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Fatalf("TestCheckPkScriptStandard NewPrivateKey failed: %v", err) return } pubKeys = append(pubKeys, pk.PubKey().SerializeCompressed()) } tests := []struct { name string // test description. script *txscript.ScriptBuilder isStandard bool }{ { "key1 and key2", txscript.NewScriptBuilder().AddOp(txscript.OP_2). AddData(pubKeys[0]).AddData(pubKeys[1]). AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG), true, }, { "key1 or key2", txscript.NewScriptBuilder().AddOp(txscript.OP_1). AddData(pubKeys[0]).AddData(pubKeys[1]). AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG), true, }, { "escrow", txscript.NewScriptBuilder().AddOp(txscript.OP_2). AddData(pubKeys[0]).AddData(pubKeys[1]). AddData(pubKeys[2]). AddOp(txscript.OP_3).AddOp(txscript.OP_CHECKMULTISIG), true, }, { "one of four", txscript.NewScriptBuilder().AddOp(txscript.OP_1). AddData(pubKeys[0]).AddData(pubKeys[1]). AddData(pubKeys[2]).AddData(pubKeys[3]). AddOp(txscript.OP_4).AddOp(txscript.OP_CHECKMULTISIG), false, }, { "malformed1", txscript.NewScriptBuilder().AddOp(txscript.OP_3). AddData(pubKeys[0]).AddData(pubKeys[1]). AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG), false, }, { "malformed2", txscript.NewScriptBuilder().AddOp(txscript.OP_2). AddData(pubKeys[0]).AddData(pubKeys[1]). AddOp(txscript.OP_3).AddOp(txscript.OP_CHECKMULTISIG), false, }, { "malformed3", txscript.NewScriptBuilder().AddOp(txscript.OP_0). AddData(pubKeys[0]).AddData(pubKeys[1]). AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG), false, }, { "malformed4", txscript.NewScriptBuilder().AddOp(txscript.OP_1). AddData(pubKeys[0]).AddData(pubKeys[1]). AddOp(txscript.OP_0).AddOp(txscript.OP_CHECKMULTISIG), false, }, { "malformed5", txscript.NewScriptBuilder().AddOp(txscript.OP_1). AddData(pubKeys[0]).AddData(pubKeys[1]). AddOp(txscript.OP_CHECKMULTISIG), false, }, { "malformed6", txscript.NewScriptBuilder().AddOp(txscript.OP_1). AddData(pubKeys[0]).AddData(pubKeys[1]), false, }, } for _, test := range tests { script, err := test.script.Script() if err != nil { t.Fatalf("TestCheckPkScriptStandard test '%s' "+ "failed: %v", test.name, err) continue } scriptClass := txscript.GetScriptClass(script) got := checkPkScriptStandard(script, scriptClass) if (test.isStandard && got != nil) || (!test.isStandard && got == nil) { t.Fatalf("TestCheckPkScriptStandard test '%s' failed", test.name) return } } }
func TestConnectionCorrectness(t *testing.T) { // First, generate the long-term private keys both ends of the connection // within our test. localPriv, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Fatalf("unable to generate local priv key: %v", err) } remotePriv, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Fatalf("unable to generate remote priv key: %v", err) } // Having a port of "0" means a random port will be chosen for our // listener. addr := "127.0.0.1:0" // Our listener will be local, and the connection remote. listener, err := NewListener(localPriv, addr) if err != nil { t.Fatalf("unable to create listener: %v", err) } conn := NewConn(remotePriv, nil) var wg sync.WaitGroup var dialErr error // Initiate a connection with a separate goroutine, and listen with our // main one. If both errors are nil, then encryption+auth was succesful. wg.Add(1) go func() { dialErr = conn.Dial(listener.Addr().String(), localPriv.PubKey().SerializeCompressed()) wg.Done() }() localConn, listenErr := listener.Accept() if listenErr != nil { t.Fatalf("unable to accept connection: %v", listenErr) } wg.Wait() if dialErr != nil { t.Fatalf("unable to establish connection: %v", dialErr) } // Test out some message full-message reads. for i := 0; i < 10; i++ { msg := []byte("hello" + string(i)) if _, err := conn.Write(msg); err != nil { t.Fatalf("remote conn failed to write: %v", err) } readBuf := make([]byte, len(msg)) if _, err := localConn.Read(readBuf); err != nil { t.Fatalf("local conn failed to read: %v", err) } if !bytes.Equal(readBuf, msg) { t.Fatalf("messages don't match, %v vs %v", string(readBuf), string(msg)) } } // Now try incremental message reads. This simulates first writing a // message header, then a message body. outMsg := []byte("hello world") fmt.Println("write") if _, err := conn.Write(outMsg); err != nil { t.Fatalf("remote conn failed to write: %v", err) } readBuf := make([]byte, len(outMsg)) if _, err := localConn.Read(readBuf[:len(outMsg)/2]); err != nil { t.Fatalf("local conn failed to read: %v", err) } if _, err := localConn.Read(readBuf[len(outMsg)/2:]); err != nil { t.Fatalf("local conn failed to read: %v", err) } if !bytes.Equal(outMsg, readBuf) { t.Fatalf("messages don't match, %v vs %v", string(readBuf), string(outMsg)) } }
// NewMixHeader creates a new mix header which is capable of obliviously // routing a message through the mix-net path outline by 'paymentPath' // to a final node indicated by 'identifier' housing a message addressed to // 'dest'. This function returns the created mix header along with a derived // shared secret for each node in the path. func NewMixHeader(dest LightningAddress, identifier [securityParameter]byte, paymentPath []*btcec.PublicKey) (*MixHeader, [][sharedSecretSize]byte, error) { // Each hop performs ECDH with our ephemeral key pair to arrive at a // shared secret. Additionally, each hop randomizes the group element // for the next hop by multiplying it by the blinding factor. This way // we only need to transmit a single group element, and hops can't link // a session back to us if they have several nodes in the path. numHops := len(paymentPath) hopEphemeralPubKeys := make([]*btcec.PublicKey, numHops) hopSharedSecrets := make([][sha256.Size]byte, numHops) hopBlindingFactors := make([][sha256.Size]byte, numHops) // Generate a new ephemeral key to use for ECDH for this session. sessionKey, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { return nil, nil, err } // Compute the triplet for the first hop outside of the main loop. // Within the loop each new triplet will be computed recursively based // off of the blinding factor of the last hop. hopEphemeralPubKeys[0] = sessionKey.PubKey() hopSharedSecrets[0] = sha256.Sum256(btcec.GenerateSharedSecret(sessionKey, paymentPath[0])) hopBlindingFactors[0] = computeBlindingFactor(hopEphemeralPubKeys[0], hopSharedSecrets[0][:]) // Now recursively compute the ephemeral ECDH pub keys, the shared // secret, and blinding factor for each hop. for i := 1; i <= numHops-1; i++ { // a_{n} = a_{n-1} x c_{n-1} -> (Y_prev_pub_key x prevBlindingFactor) hopEphemeralPubKeys[i] = blindGroupElement(hopEphemeralPubKeys[i-1], hopBlindingFactors[i-1][:]) // s_{n} = sha256( y_{n} x c_{n-1} ) -> // (Y_their_pub_key x x_our_priv) x all prev blinding factors yToX := blindGroupElement(paymentPath[i], sessionKey.D.Bytes()) hopSharedSecrets[i] = sha256.Sum256(multiScalarMult(yToX, hopBlindingFactors[:i]).X.Bytes()) // TODO(roasbeef): prob don't need to store all blinding factors, only the prev... // b_{n} = sha256(a_{n} || s_{n}) hopBlindingFactors[i] = computeBlindingFactor(hopEphemeralPubKeys[i], hopSharedSecrets[i][:]) } // Generate the padding, called "filler strings" in the paper. filler := generateHeaderPadding(numHops, hopSharedSecrets) // First we generate the routing info + MAC for the very last hop. mixHeader := make([]byte, 0, routingInfoSize) mixHeader = append(mixHeader, dest...) mixHeader = append(mixHeader, identifier[:]...) mixHeader = append(mixHeader, bytes.Repeat([]byte{0}, ((2*(numMaxHops-numHops)+2)*securityParameter-len(dest)))...) // Encrypt the header for the final hop with the shared secret the // destination will eventually derive, then pad the message out to full // size with the "random" filler bytes. streamBytes := generateCipherStream(generateKey("rho", hopSharedSecrets[numHops-1]), numStreamBytes) xor(mixHeader, mixHeader, streamBytes[:(2*(numMaxHops-numHops)+3)*securityParameter]) mixHeader = append(mixHeader, filler...) // Calculate a MAC over the encrypted mix header for the last hop // (including the filler bytes), using the same shared secret key as // used for encryption above. headerMac := calcMac(generateKey("mu", hopSharedSecrets[numHops-1]), mixHeader) // Now we compute the routing information for each hop, along with a // MAC of the routing info using the shared key for that hop. for i := numHops - 2; i >= 0; i-- { // The next hop from the point of view of the current hop. Node // ID's are currently the hash160 of a node's pubKey serialized // in compressed format. nodeID := btcutil.Hash160(paymentPath[i+1].SerializeCompressed()) var b bytes.Buffer b.Write(nodeID) // MAC for mix header. b.Write(headerMac[:]) // Mix header itself. b.Write(mixHeader[:(2*numMaxHops-1)*securityParameter]) streamBytes := generateCipherStream(generateKey("rho", hopSharedSecrets[i]), numStreamBytes) xor(mixHeader, b.Bytes(), streamBytes[:(2*numMaxHops+1)*securityParameter]) headerMac = calcMac(generateKey("mu", hopSharedSecrets[i]), mixHeader) } var r [routingInfoSize]byte copy(r[:], mixHeader) header := &MixHeader{ EphemeralKey: hopEphemeralPubKeys[0], RoutingInfo: r, HeaderMAC: headerMac, } return header, hopSharedSecrets, nil }
func TestCipheringErrors(t *testing.T) { privkey, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Fatal("failed to generate private key") } tests1 := []struct { ciphertext []byte // input ciphertext }{ {bytes.Repeat([]byte{0x00}, 133)}, // errInputTooShort {bytes.Repeat([]byte{0x00}, 134)}, // errUnsupportedCurve {bytes.Repeat([]byte{0x02, 0xCA}, 134)}, // errInvalidXLength {bytes.Repeat([]byte{0x02, 0xCA, 0x00, 0x20}, 134)}, // errInvalidYLength {[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // IV 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xCA, 0x00, 0x20, // curve and X length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // X 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, // Y length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Y 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ciphertext 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // MAC 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }}, // invalid pubkey {[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // IV 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xCA, 0x00, 0x20, // curve and X length 0x11, 0x5C, 0x42, 0xE7, 0x57, 0xB2, 0xEF, 0xB7, // X 0x67, 0x1C, 0x57, 0x85, 0x30, 0xEC, 0x19, 0x1A, 0x13, 0x59, 0x38, 0x1E, 0x6A, 0x71, 0x12, 0x7A, 0x9D, 0x37, 0xC4, 0x86, 0xFD, 0x30, 0xDA, 0xE5, 0x00, 0x20, // Y length 0x7E, 0x76, 0xDC, 0x58, 0xF6, 0x93, 0xBD, 0x7E, // Y 0x70, 0x10, 0x35, 0x8C, 0xE6, 0xB1, 0x65, 0xE4, 0x83, 0xA2, 0x92, 0x10, 0x10, 0xDB, 0x67, 0xAC, 0x11, 0xB1, 0xB5, 0x1B, 0x65, 0x19, 0x53, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ciphertext // padding not aligned to 16 bytes 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // MAC 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }}, // errInvalidPadding {[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // IV 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xCA, 0x00, 0x20, // curve and X length 0x11, 0x5C, 0x42, 0xE7, 0x57, 0xB2, 0xEF, 0xB7, // X 0x67, 0x1C, 0x57, 0x85, 0x30, 0xEC, 0x19, 0x1A, 0x13, 0x59, 0x38, 0x1E, 0x6A, 0x71, 0x12, 0x7A, 0x9D, 0x37, 0xC4, 0x86, 0xFD, 0x30, 0xDA, 0xE5, 0x00, 0x20, // Y length 0x7E, 0x76, 0xDC, 0x58, 0xF6, 0x93, 0xBD, 0x7E, // Y 0x70, 0x10, 0x35, 0x8C, 0xE6, 0xB1, 0x65, 0xE4, 0x83, 0xA2, 0x92, 0x10, 0x10, 0xDB, 0x67, 0xAC, 0x11, 0xB1, 0xB5, 0x1B, 0x65, 0x19, 0x53, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ciphertext 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // MAC 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }}, // ErrInvalidMAC } for i, test := range tests1 { _, err = btcec.Decrypt(privkey, test.ciphertext) if err == nil { t.Errorf("Decrypt #%d did not get error", i) } } // test error from removePKCSPadding tests2 := []struct { in []byte // input data }{ {bytes.Repeat([]byte{0x11}, 17)}, {bytes.Repeat([]byte{0x07}, 15)}, } for i, test := range tests2 { _, err = btcec.TstRemovePKCSPadding(test.in) if err == nil { t.Errorf("removePKCSPadding #%d did not get error", i) } } }
func GeneratePrivateKey() *btcec.PrivateKey { priv, _ := btcec.NewPrivateKey(btcec.S256()) return priv }
func TestImportPrivateKey(t *testing.T) { createHeight := int32(100) createdAt := makeBS(createHeight) w, err := New(dummyDir, "A wallet for testing.", []byte("banana"), tstNetParams, createdAt) if err != nil { t.Error("Error creating new wallet: " + err.Error()) return } if err = w.Unlock([]byte("banana")); err != nil { t.Errorf("Can't unlock original wallet: %v", err) return } pk, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Error("Error generating private key: " + err.Error()) return } // verify that the entire wallet's sync height matches the // expected createHeight. if _, h := w.SyncedTo(); h != createHeight { t.Errorf("Initial sync height %v does not match expected %v.", h, createHeight) return } // import priv key wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), tstNetParams, false) if err != nil { t.Fatal(err) } importHeight := int32(50) importedAt := makeBS(importHeight) address, err := w.ImportPrivateKey(wif, importedAt) if err != nil { t.Error("importing private key: " + err.Error()) return } addr, err := w.Address(address) if err != nil { t.Error("privkey just imported missing: " + err.Error()) return } pka := addr.(PubKeyAddress) // lookup address pk2, err := pka.PrivKey() if err != nil { t.Error("error looking up key: " + err.Error()) } if !reflect.DeepEqual(pk, pk2) { t.Error("original and looked-up private keys do not match.") return } // verify that the sync height now match the (smaller) import height. if _, h := w.SyncedTo(); h != importHeight { t.Errorf("After import sync height %v does not match expected %v.", h, importHeight) return } // serialise and deseralise and check still there. // Test (de)serialization of wallet. buf := new(bytes.Buffer) _, err = w.WriteTo(buf) if err != nil { t.Errorf("Cannot write wallet: %v", err) return } w2 := new(Store) _, err = w2.ReadFrom(buf) if err != nil { t.Errorf("Cannot read wallet: %v", err) return } // Verify that the sync height match expected after the reserialization. if _, h := w2.SyncedTo(); h != importHeight { t.Errorf("After reserialization sync height %v does not match expected %v.", h, importHeight) return } // Mark imported address as partially synced with a block somewhere inbetween // the import height and the chain height. partialHeight := (createHeight-importHeight)/2 + importHeight if err := w2.SetSyncStatus(address, PartialSync(partialHeight)); err != nil { t.Errorf("Cannot mark address partially synced: %v", err) return } if _, h := w2.SyncedTo(); h != partialHeight { t.Errorf("After address partial sync, sync height %v does not match expected %v.", h, partialHeight) return } // Test serialization with the partial sync. buf.Reset() _, err = w2.WriteTo(buf) if err != nil { t.Errorf("Cannot write wallet: %v", err) return } w3 := new(Store) _, err = w3.ReadFrom(buf) if err != nil { t.Errorf("Cannot read wallet: %v", err) return } // Test correct partial height after serialization. if _, h := w3.SyncedTo(); h != partialHeight { t.Errorf("After address partial sync and reserialization, sync height %v does not match expected %v.", h, partialHeight) return } // Mark imported address as not synced at all, and verify sync height is now // the import height. if err := w3.SetSyncStatus(address, Unsynced(0)); err != nil { t.Errorf("Cannot mark address synced: %v", err) return } if _, h := w3.SyncedTo(); h != importHeight { t.Errorf("After address unsync, sync height %v does not match expected %v.", h, importHeight) return } // Mark imported address as synced with the recently-seen blocks, and verify // that the sync height now equals the most recent block (the one at wallet // creation). if err := w3.SetSyncStatus(address, FullSync{}); err != nil { t.Errorf("Cannot mark address synced: %v", err) return } if _, h := w3.SyncedTo(); h != createHeight { t.Errorf("After address sync, sync height %v does not match expected %v.", h, createHeight) return } if err = w3.Unlock([]byte("banana")); err != nil { t.Errorf("Can't unlock deserialised wallet: %v", err) return } addr3, err := w3.Address(address) if err != nil { t.Error("privkey in deserialised wallet missing : " + err.Error()) return } pka3 := addr3.(PubKeyAddress) // lookup address pk2, err = pka3.PrivKey() if err != nil { t.Error("error looking up key in deserialized wallet: " + err.Error()) } if !reflect.DeepEqual(pk, pk2) { t.Error("original and deserialized private keys do not match.") return } }