// newManagedAddressWithoutPrivKey returns a new managed address based on the // passed account, public key, and whether or not the public key should be // compressed. func newManagedAddressWithoutPrivKey(m *Manager, account uint32, pubKey *btcec.PublicKey, compressed bool) (*managedAddress, error) { // Create a pay-to-pubkey-hash address from the public key. var pubKeyHash []byte if compressed { pubKeyHash = btcutil.Hash160(pubKey.SerializeCompressed()) } else { pubKeyHash = btcutil.Hash160(pubKey.SerializeUncompressed()) } address, err := btcutil.NewAddressPubKeyHash(pubKeyHash, m.chainParams) if err != nil { return nil, err } return &managedAddress{ manager: m, address: address, account: account, imported: false, internal: false, compressed: compressed, pubKey: pubKey, privKeyEncrypted: nil, privKeyCT: nil, }, nil }
// authPKH... func (c *LNDConn) authPKH( myId *btcec.PrivateKey, theirPKH, localEphPubBytes []byte) error { if c.Authed { return fmt.Errorf("%s already authed", c.RemotePub) } if len(theirPKH) != 20 { return fmt.Errorf("remote PKH must be 20 bytes, got %d", len(theirPKH)) } // Send 53 bytes: our pubkey, and the remote's pubkey hash. var greetingMsg [53]byte copy(greetingMsg[:33], myId.PubKey().SerializeCompressed()) copy(greetingMsg[:33], theirPKH) if _, err := c.Conn.Write(greetingMsg[:]); err != nil { return err } // Wait for their response. // TODO(tadge): add timeout here // * NOTE(roasbeef): read timeout should be set on the underlying // net.Conn. resp := make([]byte, 53) if _, err := c.Conn.Read(resp); err != nil { return err } // Parse their long-term public key, and generate the DH proof. theirPub, err := btcec.ParsePubKey(resp[:33], btcec.S256()) if err != nil { return err } idDH := fastsha256.Sum256(btcec.GenerateSharedSecret(myId, theirPub)) fmt.Printf("made idDH %x\n", idDH) theirDHproof := btcutil.Hash160(append(localEphPubBytes, idDH[:]...)) // Verify that their DH proof matches the one we just generated. if bytes.Equal(resp[33:], theirDHproof) == false { return fmt.Errorf("Invalid DH proof %x", theirDHproof) } // If their DH proof checks out, then send our own. myDHproof := btcutil.Hash160(append(c.RemotePub.SerializeCompressed(), idDH[:]...)) if _, err = c.Conn.Write(myDHproof); err != nil { return err } // Proof sent, auth complete. c.RemotePub = theirPub theirAdr := btcutil.Hash160(theirPub.SerializeCompressed()) copy(c.RemoteLNId[:], theirAdr[:16]) c.Authed = true return nil }
func main() { name := "text/melange" rand, _ := hex.DecodeString("e4de61166713cf9e") hash := btcutil.Hash160(append(rand, []byte(name)...)) fmt.Println(hex.EncodeToString(hash)) }
func TestAddrIndexKeySerialization(t *testing.T) { var hash160Bytes [ripemd160.Size]byte fakeHash160 := btcutil.Hash160([]byte("testing")) copy(fakeHash160, hash160Bytes[:]) fakeIndex := txAddrIndex{ hash160: hash160Bytes, blkHeight: 1, txoffset: 5, txlen: 360, } serializedKey := addrIndexToKey(&fakeIndex) unpackedIndex := unpackTxIndex(serializedKey[22:]) if unpackedIndex.blkHeight != fakeIndex.blkHeight { t.Errorf("Incorrect block height. Unpack addr index key"+ "serialization failed. Expected %d, received %d", 1, unpackedIndex.blkHeight) } if unpackedIndex.txoffset != fakeIndex.txoffset { t.Errorf("Incorrect tx offset. Unpack addr index key"+ "serialization failed. Expected %d, received %d", 5, unpackedIndex.txoffset) } if unpackedIndex.txlen != fakeIndex.txlen { t.Errorf("Incorrect tx len. Unpack addr index key"+ "serialization failed. Expected %d, received %d", 360, unpackedIndex.txlen) } }
// addUsedAddr creates a deposit script for the given seriesID/branch/index, // ensures it is imported into the address manager and finaly adds the script // hash to our used addresses DB. It must be called with the manager unlocked. func (p *Pool) addUsedAddr(seriesID uint32, branch Branch, index Index) error { script, err := p.DepositScript(seriesID, branch, index) if err != nil { return err } // First ensure the address manager has our script. That way there's no way // to have it in the used addresses DB but not in the address manager. // TODO: Decide how far back we want the addr manager to rescan and set the // BlockStamp height according to that. _, err = p.manager.ImportScript(script, &waddrmgr.BlockStamp{}) if err != nil && err.(waddrmgr.ManagerError).ErrorCode != waddrmgr.ErrDuplicateAddress { return err } encryptedHash, err := p.manager.Encrypt(waddrmgr.CKTPublic, btcutil.Hash160(script)) if err != nil { return newError(ErrCrypto, "failed to encrypt script hash", err) } err = p.namespace.Update( func(tx walletdb.Tx) error { return putUsedAddrHash(tx, p.ID, seriesID, branch, index, encryptedHash) }) if err != nil { return newError(ErrDatabase, "failed to store used addr script hash", err) } return nil }
// TestFilterInsertKey ensures inserting public keys and addresses works as // expected. func TestFilterInsertKey(t *testing.T) { secret := "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C" wif, err := btcutil.DecodeWIF(secret) if err != nil { t.Errorf("TestFilterInsertKey DecodeWIF failed: %v", err) return } f := bloom.NewFilter(2, 0, 0.001, wire.BloomUpdateAll) f.Add(wif.SerializePubKey()) f.Add(btcutil.Hash160(wif.SerializePubKey())) want, err := hex.DecodeString("038fc16b080000000000000001") if err != nil { t.Errorf("TestFilterInsertWithTweak DecodeString failed: %v\n", err) return } got := bytes.NewBuffer(nil) err = f.MsgFilterLoad().BtcEncode(got, wire.ProtocolVersion) if err != nil { t.Errorf("TestFilterInsertWithTweak BtcDecode failed: %v\n", err) return } if !bytes.Equal(got.Bytes(), want) { t.Errorf("TestFilterInsertWithTweak failure: got %v want %v\n", got.Bytes(), want) return } }
// indexScriptPubKey indexes all data pushes greater than 8 bytes within the // passed SPK. Our "address" index is actually a hash160 index, where in the // ideal case the data push is either the hash160 of a publicKey (P2PKH) or // a Script (P2SH). func indexScriptPubKey(addrIndex database.BlockAddrIndex, scriptPubKey []byte, locInBlock *wire.TxLoc) error { dataPushes, err := txscript.PushedData(scriptPubKey) if err != nil { adxrLog.Tracef("Couldn't get pushes: %v", err) return err } for _, data := range dataPushes { // Only index pushes greater than 8 bytes. if len(data) < 8 { continue } var indexKey [ripemd160.Size]byte // A perfect little hash160. if len(data) <= 20 { copy(indexKey[:], data) // Otherwise, could be a payToPubKey or an OP_RETURN, so we'll // make a hash160 out of it. } else { copy(indexKey[:], btcutil.Hash160(data)) } addrIndex[indexKey] = append(addrIndex[indexKey], locInBlock) } return nil }
// scriptHashPkScript generates a pay-to-script-hash public key script paying // to the hash160 of the passed redeem script. func scriptHashPkScript(redeemScript []byte) ([]byte, error) { bldr := txscript.NewScriptBuilder() bldr.AddOp(txscript.OP_HASH160) bldr.AddData(btcutil.Hash160(redeemScript)) bldr.AddOp(txscript.OP_EQUAL) return bldr.Script() }
// authPubKey... func (c *LNDConn) authPubKey( myId *btcec.PrivateKey, remotePubBytes, localEphPubBytes []byte) error { if c.Authed { return fmt.Errorf("%s already authed", c.RemotePub) } // Since we already know their public key, we can immediately generate // the DH proof without an additional round-trip. theirPub, err := btcec.ParsePubKey(remotePubBytes, btcec.S256()) if err != nil { return err } theirPKH := btcutil.Hash160(remotePubBytes) idDH := fastsha256.Sum256(btcec.GenerateSharedSecret(myId, theirPub)) myDHproof := btcutil.Hash160(append(c.RemotePub.SerializeCompressed(), idDH[:]...)) // Send over the 73 byte authentication message: my pubkey, their // pubkey hash, DH proof. var authMsg [73]byte copy(authMsg[:33], myId.PubKey().SerializeCompressed()) copy(authMsg[33:], theirPKH) copy(authMsg[53:], myDHproof) if _, err = c.Conn.Write(authMsg[:]); err != nil { return nil } // Await, their response. They should send only the 20-byte DH proof. resp := make([]byte, 20) _, err = c.Conn.Read(resp) if err != nil { return err } // Verify that their proof matches our locally computed version. theirDHproof := btcutil.Hash160(append(localEphPubBytes, idDH[:]...)) if bytes.Equal(resp, theirDHproof) == false { return fmt.Errorf("invalid DH proof %x", theirDHproof) } // Proof checks out, auth complete. c.RemotePub = theirPub theirAdr := btcutil.Hash160(theirPub.SerializeCompressed()) copy(c.RemoteLNId[:], theirAdr[:16]) c.Authed = true return nil }
// commitScriptUnencumbered constructs the public key script on the commitment // transaction paying to the "other" party. This output is spendable // immediately, requiring no contestation period. func commitScriptUnencumbered(key *btcec.PublicKey) ([]byte, error) { // This script goes to the "other" party, and it spendable immediately. builder := txscript.NewScriptBuilder() builder.AddOp(txscript.OP_DUP) builder.AddOp(txscript.OP_HASH160) builder.AddData(btcutil.Hash160(key.SerializeCompressed())) builder.AddOp(txscript.OP_EQUALVERIFY) builder.AddOp(txscript.OP_CHECKSIG) return builder.Script() }
// newLnAddr... func newLnAddr(encodedAddr string) (*lnAddr, error) { // The format of an lnaddr is "<pubkey or pkh>@host" idHost := strings.Split(encodedAddr, "@") if len(idHost) != 2 { return nil, fmt.Errorf("invalid format for lnaddr string: %v", encodedAddr) } // Attempt to resolve the IP address, this handles parsing IPv6 zones, // and such. fmt.Println("host: ", idHost[1]) ipAddr, err := net.ResolveTCPAddr("tcp", idHost[1]) if err != nil { return nil, err } addr := &lnAddr{netAddr: ipAddr} idLen := len(idHost[0]) switch { // Is the ID a hex-encoded compressed public key? case idLen > 65 && idLen < 69: pubkeyBytes, err := hex.DecodeString(idHost[0]) if err != nil { return nil, err } addr.pubKey, err = btcec.ParsePubKey(pubkeyBytes, btcec.S256()) if err != nil { return nil, err } // got pubey, populate address from pubkey pkh := btcutil.Hash160(addr.pubKey.SerializeCompressed()) addr.bitcoinAddr, err = btcutil.NewAddressPubKeyHash(pkh, &chaincfg.TestNet3Params) if err != nil { return nil, err } // Is the ID a string encoded bitcoin address? case idLen > 33 && idLen < 37: addr.bitcoinAddr, err = btcutil.DecodeAddress(idHost[0], &chaincfg.TestNet3Params) if err != nil { return nil, err } default: return nil, fmt.Errorf("invalid address %s", idHost[0]) } // Finally, populate the lnid from the address. copy(addr.lnId[:], addr.bitcoinAddr.ScriptAddress()) return addr, nil }
// RevocationHash... func (c *ChannelUpdate) RevocationHash() ([]byte, error) { c.lnChannel.stateMtx.RLock() defer c.lnChannel.stateMtx.RUnlock() shachain := c.lnChannel.channelState.OurShaChain nextPreimage, err := shachain.GetHash(c.pendingUpdateNum) if err != nil { return nil, err } return btcutil.Hash160(nextPreimage[:]), nil }
// NewSphinxNode... func NewSphinxNode(nodeKey *btcec.PrivateKey, net *chaincfg.Params) *SphinxNode { var nodeID [securityParameter]byte copy(nodeID[:], btcutil.Hash160(nodeKey.PubKey().SerializeCompressed())) // Safe to ignore the error here, nodeID is 20 bytes. nodeAddr, _ := btcutil.NewAddressPubKeyHash(nodeID[:], net) return &SphinxNode{ nodeID: nodeID, nodeAddr: nodeAddr, lnKey: nodeKey, // TODO(roasbeef): replace instead with bloom filter? // * https://moderncrypto.org/mail-archive/messaging/2015/001911.html seenSecrets: make(map[[sharedSecretSize]byte]struct{}), } }
// generateAddr computes the associated bitcon address from the provided // public key. We compute ripemd160(sha256(b)) of the pubkey and then // shimmy the hashed bytes into btcsuite's AddressPubKeyHash type func generateAddr(pub *btcec.PublicKey) *btcutil.AddressPubKeyHash { net := &chaincfg.MainNetParams // Serialize the public key into bytes and then run ripemd160(sha256(b)) on it b := btcutil.Hash160(pub.SerializeCompressed()) // Convert the hashed public key into the btcsuite type so that the library // will handle the base58 encoding when we call addr.String() addr, err := btcutil.NewAddressPubKeyHash(b, net) if err != nil { log.Fatal(err) } return addr }
// Commit... func (c *ChannelUpdate) Commit(pastRevokePreimage []byte) error { c.lnChannel.stateMtx.Lock() defer c.lnChannel.stateMtx.Unlock() // First, ensure that the pre-image properly links into the shachain. theirShaChain := c.lnChannel.channelState.TheirShaChain var preImage [32]byte copy(preImage[:], pastRevokePreimage) if err := theirShaChain.AddNextHash(preImage); err != nil { return err } channelState := c.lnChannel.channelState // Finally, verify that that this is indeed the pre-image to the // revocation hash we were given earlier. if !bytes.Equal(btcutil.Hash160(pastRevokePreimage), channelState.TheirCurrentRevocation[:]) { return fmt.Errorf("pre-image hash does not match revocation") } // Store this current revocation in the channel state so we can // verify future channel updates. channelState.TheirCurrentRevocation = c.pendingRevocation // The channel update is now complete, roll over to the newest commitment // transaction. channelState.OurCommitTx = c.ourPendingCommitTx channelState.TheirCommitTx = c.theirPendingCommitTx channelState.NumUpdates = c.pendingUpdateNum // If this channel update involved deleting an HTLC, remove it from the // set of pending payments. if c.deletion { delete(c.lnChannel.pendingPayments, c.pendingDesc.RHash) } // TODO(roasbeef): db writes, checkpoints, and such // Return the updateTotem, allowing another update to be created now // that this pending update has been commited, and finalized. c.lnChannel.updateTotem <- struct{}{} return nil }
func (e *ElkremReceiver) FindPre( target [20]byte, timeHint uint32) (*[20]byte, error) { maxUint32 := uint32((1 << 32) - 1) minTime := uint32(500000000) hintRange := uint32((1 << 29) - 1) // a timeHint of 2^32 (4294967296) means we don't have a timeHint. if timeHint == maxUint32 { return nil, fmt.Errorf("no timeHint") } // valid timeHint range is 500M to 500M + 2^29 if timeHint < minTime || timeHint > minTime+hintRange { return nil, fmt.Errorf("timeHint %d out of range (500M - ~1G)", timeHint) } indexHint := uint64(timeHint - minTime) maxIndex := e.s[len(e.s)-1].i // highest index we have if indexHint > maxIndex { // we can't derive needed index return nil, fmt.Errorf("hint index %d greater than max index %d", indexHint, maxIndex) } // iterate though, adding 2^29 each time. // there is some redundancy here when you have a large number of guesses // to go through, so this could be optimized later. for guess := indexHint; guess < maxIndex; guess += uint64(hintRange) { sha, err := e.AtIndex(guess) // generate preimage if err != nil { return nil, err } var truncatedSha [20]byte copy(truncatedSha[:], sha.Bytes()) // copy into 20 byte array checkHash := btcutil.Hash160(truncatedSha[:]) // hash and compare if bytes.Equal(target[:], checkHash) { // matches hash, return return &truncatedSha, nil } } // got through the loop without finding anything. return nil, fmt.Errorf("Couldn't find preimage of %x. timeHint %d bad?", target, timeHint) }
// 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 }
// Deserialize an LNId from byte slice (on disk) // Note that this does not check any internal consistency, because on local // storage there's no point. Check separately if needed. // Also, old and probably needs to be changed / updated func (l *LNAdr) Deserialize(s []byte) error { b := bytes.NewBuffer(s) // Fail if on-disk LNId too short if b.Len() < 24 { // 24 is min lenght return fmt.Errorf("can't read LNId - too short") } // read indicator of pubkey or pubkeyhash x, err := b.ReadByte() if err != nil { return err } if x == 0xb0 { // for pubkey storage // read 33 bytes of pubkey l.PubKey, err = btcec.ParsePubKey(b.Next(33), btcec.S256()) if err != nil { return err } l.Base58Adr, err = btcutil.NewAddressPubKeyHash( btcutil.Hash160(l.PubKey.SerializeCompressed()), globalconfig.NetParams) if err != nil { return err } } else if x == 0xa0 { // for pubkeyhash storage l.Base58Adr, err = btcutil.NewAddressPubKeyHash( b.Next(20), globalconfig.NetParams) if err != nil { return err } } else { return fmt.Errorf("Unknown lnid indicator byte %x", x) } var nameLen, hostLen, endorseLen uint8 // read name length err = binary.Read(b, binary.BigEndian, &nameLen) if err != nil { return err } // if name non-zero, read name if nameLen > 0 { l.name = string(b.Next(int(nameLen))) } // read host length err = binary.Read(b, binary.BigEndian, &hostLen) if err != nil { return err } // if host non-zero, read host if hostLen > 0 { l.host = string(b.Next(int(hostLen))) } // read endorsement length err = binary.Read(b, binary.BigEndian, &endorseLen) if err != nil { return err } // if endorsement non-zero, read endorsement if endorseLen > 0 { l.endorsement = b.Next(int(endorseLen)) } return nil }
// Address converts the extended key to a standard bitcoin pay-to-pubkey-hash // address for the passed network. func (k *ExtendedKey) Address(net *chaincfg.Params) (*btcutil.AddressPubKeyHash, error) { pkHash := btcutil.Hash160(k.pubKeyBytes()) return btcutil.NewAddressPubKeyHash(pkHash, net) }
// Child returns a derived child extended key at the given index. When this // extended key is a private extended key (as determined by the IsPrivate // function), a private extended key will be derived. Otherwise, the derived // extended key will be also be a public extended key. // // When the index is greater to or equal than the HardenedKeyStart constant, the // derived extended key will be a hardened extended key. It is only possible to // derive a hardended extended key from a private extended key. Consequently, // this function will return ErrDeriveHardFromPublic if a hardened child // extended key is requested from a public extended key. // // A hardened extended key is useful since, as previously mentioned, it requires // a parent private extended key to derive. In other words, normal child // extended public keys can be derived from a parent public extended key (no // knowledge of the parent private key) whereas hardened extended keys may not // be. // // NOTE: There is an extremely small chance (< 1 in 2^127) the specific child // index does not derive to a usable child. The ErrInvalidChild error will be // returned if this should occur, and the caller is expected to ignore the // invalid child and simply increment to the next index. func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) { // There are four scenarios that could happen here: // 1) Private extended key -> Hardened child private extended key // 2) Private extended key -> Non-hardened child private extended key // 3) Public extended key -> Non-hardened child public extended key // 4) Public extended key -> Hardened child public extended key (INVALID!) // Case #4 is invalid, so error out early. // A hardened child extended key may not be created from a public // extended key. isChildHardened := i >= HardenedKeyStart if !k.isPrivate && isChildHardened { return nil, ErrDeriveHardFromPublic } // The data used to derive the child key depends on whether or not the // child is hardened per [BIP32]. // // For hardened children: // 0x00 || ser256(parentKey) || ser32(i) // // For normal children: // serP(parentPubKey) || ser32(i) keyLen := 33 data := make([]byte, keyLen+4) if isChildHardened { // Case #1. // When the child is a hardened child, the key is known to be a // private key due to the above early return. Pad it with a // leading zero as required by [BIP32] for deriving the child. copy(data[1:], k.key) } else { // Case #2 or #3. // This is either a public or private extended key, but in // either case, the data which is used to derive the child key // starts with the secp256k1 compressed public key bytes. copy(data, k.pubKeyBytes()) } binary.BigEndian.PutUint32(data[keyLen:], i) // Take the HMAC-SHA512 of the current key's chain code and the derived // data: // I = HMAC-SHA512(Key = chainCode, Data = data) hmac512 := hmac.New(sha512.New, k.chainCode) hmac512.Write(data) ilr := hmac512.Sum(nil) // Split "I" into two 32-byte sequences Il and Ir where: // Il = intermediate key used to derive the child // Ir = child chain code il := ilr[:len(ilr)/2] childChainCode := ilr[len(ilr)/2:] // Both derived public or private keys rely on treating the left 32-byte // sequence calculated above (Il) as a 256-bit integer that must be // within the valid range for a secp256k1 private key. There is a small // chance (< 1 in 2^127) this condition will not hold, and in that case, // a child extended key can't be created for this index and the caller // should simply increment to the next index. ilNum := new(big.Int).SetBytes(il) if ilNum.Cmp(btcec.S256().N) >= 0 || ilNum.Sign() == 0 { return nil, ErrInvalidChild } // The algorithm used to derive the child key depends on whether or not // a private or public child is being derived. // // For private children: // childKey = parse256(Il) + parentKey // // For public children: // childKey = serP(point(parse256(Il)) + parentKey) var isPrivate bool var childKey []byte if k.isPrivate { // Case #1 or #2. // Add the parent private key to the intermediate private key to // derive the final child key. // // childKey = parse256(Il) + parenKey keyNum := new(big.Int).SetBytes(k.key) ilNum.Add(ilNum, keyNum) ilNum.Mod(ilNum, btcec.S256().N) childKey = ilNum.Bytes() isPrivate = true } else { // Case #3. // Calculate the corresponding intermediate public key for // intermediate private key. ilx, ily := btcec.S256().ScalarBaseMult(il) if ilx.Sign() == 0 || ily.Sign() == 0 { return nil, ErrInvalidChild } // Convert the serialized compressed parent public key into X // and Y coordinates so it can be added to the intermediate // public key. pubKey, err := btcec.ParsePubKey(k.key, btcec.S256()) if err != nil { return nil, err } // Add the intermediate public key to the parent public key to // derive the final child key. // // childKey = serP(point(parse256(Il)) + parentKey) childX, childY := btcec.S256().Add(ilx, ily, pubKey.X, pubKey.Y) pk := btcec.PublicKey{Curve: btcec.S256(), X: childX, Y: childY} childKey = pk.SerializeCompressed() } // The fingerprint of the parent for the derived child is the first 4 // bytes of the RIPEMD160(SHA256(parentPubKey)). parentFP := btcutil.Hash160(k.pubKeyBytes())[:4] return newExtendedKey(k.version, childKey, childChainCode, parentFP, k.depth+1, i, isPrivate), nil }
// SettleHTLC... // R-VALUE, NEW REVOKE HASH // accept, sig func (lc *LightningChannel) SettleHTLC(rValue [20]byte, newRevocation [20]byte) (*ChannelUpdate, error) { // Grab the updateTotem, this acts as a barrier upholding the invariant // that only one channel update transaction should exist at any moment. // This aides in ensuring the channel updates are atomic, and consistent. <-lc.updateTotem // Find the matching payment descriptor, bailing out early if it // doesn't exist. var rHash PaymentHash copy(rHash[:], btcutil.Hash160(rValue[:])) payDesc, ok := lc.pendingPayments[rHash] if !ok { return nil, fmt.Errorf("r-hash for preimage not found") } chanUpdate := &ChannelUpdate{ pendingDesc: payDesc, deletion: true, pendingRevocation: newRevocation, lnChannel: lc, } // TODO(roasbeef): such copy pasta, make into func... // Get next revocation hash, updating the number of updates in the // channel as a result. chanUpdate.currentUpdateNum = lc.channelState.NumUpdates chanUpdate.pendingUpdateNum = lc.channelState.NumUpdates + 1 nextPreimage, err := lc.channelState.OurShaChain.GetHash(chanUpdate.pendingUpdateNum) if err != nil { return nil, err } copy(chanUpdate.pendingDesc.OurRevocation[:], btcutil.Hash160(nextPreimage[:])) // Re-calculate the amount of cleared funds for each side. var amountToUs, amountToThem btcutil.Amount if payDesc.PayToUs { amountToUs = lc.channelState.OurBalance + payDesc.Value amountToThem = lc.channelState.TheirBalance } else { amountToUs = lc.channelState.OurBalance amountToThem = lc.channelState.TheirBalance + payDesc.Value } // Create new commitment transactions that reflect the settlement of // this pending HTLC. ourNewCommitTx, theirNewCommitTx, err := createNewCommitmentTxns( lc.fundingTxIn, lc.channelState, chanUpdate, amountToUs, amountToThem, ) if err != nil { return nil, err } // Re-add all the HTLC's skipping over this newly settled payment. for paymentHash, paymentDesc := range lc.pendingPayments { if bytes.Equal(paymentHash[:], rHash[:]) { continue } if err := lc.addHTLC(ourNewCommitTx, theirNewCommitTx, paymentDesc); err != nil { return nil, err } } // Sort both transactions according to the agreed upon cannonical // ordering. This lets us skip sending the entire transaction over, // instead we'll just send signatures. txsort.InPlaceSort(ourNewCommitTx) txsort.InPlaceSort(theirNewCommitTx) // TODO(roasbeef): locktimes/sequence set // TODO(roasbeef): write checkpoint here... chanUpdate.ourPendingCommitTx = ourNewCommitTx chanUpdate.theirPendingCommitTx = theirNewCommitTx return chanUpdate, nil }
// AddHTLC... // 1. request R_Hash from receiver (only if single hop, would be out of band) // 2. propose HTLC // * timeout // * value // * r_hash // * next revocation hash // 3. they accept // * their next revocation hash // * their sig for our new commitment tx (verify correctness) // Can buld both new commitment txns at this point // 4. we give sigs // * our sigs for their new commitment tx // * the pre-image to our old commitment tx // 5. they complete // * the pre-image to their old commitment tx (verify is part of their chain, is pre-image) func (lc *LightningChannel) AddHTLC(timeout uint32, value btcutil.Amount, rHash, revocation PaymentHash, payToUs bool) (*ChannelUpdate, error) { // Grab the updateTotem, this acts as a barrier upholding the invariant // that only one channel update transaction should exist at any moment. // This aides in ensuring the channel updates are atomic, and consistent. <-lc.updateTotem chanUpdate := &ChannelUpdate{ pendingDesc: &PaymentDescriptor{ RHash: rHash, TheirRevocation: revocation, Timeout: timeout, Value: value, PayToUs: payToUs, }, pendingRevocation: revocation, lnChannel: lc, } // Get next revocation hash, updating the number of updates in the // channel as a result. chanUpdate.currentUpdateNum = lc.channelState.NumUpdates chanUpdate.pendingUpdateNum = lc.channelState.NumUpdates + 1 nextPreimage, err := lc.channelState.OurShaChain.GetHash(chanUpdate.pendingUpdateNum) if err != nil { return nil, err } copy(chanUpdate.pendingDesc.OurRevocation[:], btcutil.Hash160(nextPreimage[:])) // Re-calculate the amount of cleared funds for each side. var amountToUs, amountToThem btcutil.Amount if payToUs { amountToUs = lc.channelState.OurBalance amountToThem = lc.channelState.TheirBalance - value } else { amountToUs = lc.channelState.OurBalance - value amountToThem = lc.channelState.TheirBalance } // Re-create copies of the current commitment transactions to be updated. ourNewCommitTx, theirNewCommitTx, err := createNewCommitmentTxns( lc.fundingTxIn, lc.channelState, chanUpdate, amountToUs, amountToThem, ) if err != nil { return nil, err } // First, re-add all the old HTLCs. for _, paymentDesc := range lc.pendingPayments { if err := lc.addHTLC(ourNewCommitTx, theirNewCommitTx, paymentDesc); err != nil { return nil, err } } // Then add this new HTLC. if err := lc.addHTLC(ourNewCommitTx, theirNewCommitTx, chanUpdate.pendingDesc); err != nil { return nil, err } lc.pendingPayments[rHash] = chanUpdate.pendingDesc // TODO(roasbeef): check for dups? // Sort both transactions according to the agreed upon cannonical // ordering. This lets us skip sending the entire transaction over, // instead we'll just send signatures. txsort.InPlaceSort(ourNewCommitTx) txsort.InPlaceSort(theirNewCommitTx) // TODO(roasbeef): locktimes/sequence set // TODO(roasbeef): write checkpoint here... chanUpdate.ourPendingCommitTx = ourNewCommitTx chanUpdate.theirPendingCommitTx = theirNewCommitTx return chanUpdate, nil }
// CurrentRevocationHash... // TODO(roasbeef): *wire.ShaHash vs [wire.HashSize]byte ? func (h *HyperShaChain) CurrentRevocationHash() []byte { h.RLock() defer h.RUnlock() return btcutil.Hash160(h.lastHash[:]) }
// This example demonstrates manually creating and signing a redeem transaction. func ExampleSignTxOutput() { // Ordinarily the private key would come from whatever storage mechanism // is being used, but for this example just hard code it. privKeyBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2" + "d4f8720ee63e502ee2869afab7de234b80c") if err != nil { fmt.Println(err) return } privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed()) addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash, &chaincfg.MainNetParams) if err != nil { fmt.Println(err) return } // For this example, create a fake transaction that represents what // would ordinarily be the real transaction that is being spent. It // contains a single output that pays to address in the amount of 1 BTC. originTx := wire.NewMsgTx() prevOut := wire.NewOutPoint(&wire.ShaHash{}, ^uint32(0)) txIn := wire.NewTxIn(prevOut, []byte{txscript.OP_0, txscript.OP_0}) originTx.AddTxIn(txIn) pkScript, err := txscript.PayToAddrScript(addr) if err != nil { fmt.Println(err) return } txOut := wire.NewTxOut(100000000, pkScript) originTx.AddTxOut(txOut) originTxHash, err := originTx.TxSha() if err != nil { fmt.Println(err) return } // Create the transaction to redeem the fake transaction. redeemTx := wire.NewMsgTx() // Add the input(s) the redeeming transaction will spend. There is no // signature script at this point since it hasn't been created or signed // yet, hence nil is provided for it. prevOut = wire.NewOutPoint(&originTxHash, 0) txIn = wire.NewTxIn(prevOut, nil) redeemTx.AddTxIn(txIn) // Ordinarily this would contain that actual destination of the funds, // but for this example don't bother. txOut = wire.NewTxOut(0, nil) redeemTx.AddTxOut(txOut) // Sign the redeeming transaction. lookupKey := func(a btcutil.Address) (*btcec.PrivateKey, bool, error) { // Ordinarily this function would involve looking up the private // key for the provided address, but since the only thing being // signed in this example uses the address associated with the // private key from above, simply return it with the compressed // flag set since the address is using the associated compressed // public key. // // NOTE: If you want to prove the code is actually signing the // transaction properly, uncomment the following line which // intentionally returns an invalid key to sign with, which in // turn will result in a failure during the script execution // when verifying the signature. // // privKey.D.SetInt64(12345) // return privKey, true, nil } // Notice that the script database parameter is nil here since it isn't // used. It must be specified when pay-to-script-hash transactions are // being signed. sigScript, err := txscript.SignTxOutput(&chaincfg.MainNetParams, redeemTx, 0, originTx.TxOut[0].PkScript, txscript.SigHashAll, txscript.KeyClosure(lookupKey), nil, nil) if err != nil { fmt.Println(err) return } redeemTx.TxIn[0].SignatureScript = sigScript // Prove that the transaction has been validly signed by executing the // script pair. flags := txscript.ScriptBip16 | txscript.ScriptVerifyDERSignatures | txscript.ScriptStrictMultiSig | txscript.ScriptDiscourageUpgradableNops s, err := txscript.NewScript(redeemTx.TxIn[0].SignatureScript, originTx.TxOut[0].PkScript, 0, redeemTx, flags) if err != nil { fmt.Println(err) return } if err := s.Execute(); err != nil { fmt.Println(err) return } fmt.Println("Transaction successfully signed") // Output: // Transaction successfully signed }
func (p *Pool) addressFor(script []byte) (btcutil.Address, error) { scriptHash := btcutil.Hash160(script) return btcutil.NewAddressScriptHashFromHash(scriptHash, p.manager.ChainParams()) }
// 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 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 } } } }
// AuthListen... func (l *Listener) authenticateConnection( myId *btcec.PrivateKey, lnConn *LNDConn, localEphPubBytes []byte) error { var err error // TODO(roasbeef): should be using read/write clear here? slice := make([]byte, 73) n, err := lnConn.Conn.Read(slice) if err != nil { fmt.Printf("Read error: %s\n", err.Error()) return err } fmt.Printf("read %d bytes\n", n) authmsg := slice[:n] if len(authmsg) != 53 && len(authmsg) != 73 { return fmt.Errorf("got auth message of %d bytes, "+ "expect 53 or 73", len(authmsg)) } myPKH := btcutil.Hash160(l.longTermPriv.PubKey().SerializeCompressed()) if !bytes.Equal(myPKH, authmsg[33:53]) { return fmt.Errorf( "remote host asking for PKH %x, that's not me", authmsg[33:53]) } // do DH with id keys theirPub, err := btcec.ParsePubKey(authmsg[:33], btcec.S256()) if err != nil { return err } idDH := fastsha256.Sum256( btcec.GenerateSharedSecret(l.longTermPriv, theirPub), ) myDHproof := btcutil.Hash160( append(lnConn.RemotePub.SerializeCompressed(), idDH[:]...), ) theirDHproof := btcutil.Hash160(append(localEphPubBytes, idDH[:]...)) // If they already know our public key, then execute the fast path. // Verify their DH proof, and send our own. if len(authmsg) == 73 { // Verify their DH proof. if !bytes.Equal(authmsg[53:], theirDHproof) { return fmt.Errorf("invalid DH proof from %s", lnConn.RemoteAddr().String()) } // Their DH proof checks out, so send ours now. if _, err = lnConn.Conn.Write(myDHproof); err != nil { return err } } else { // Otherwise, they don't yet know our public key. So we'll send // it over to them, so we can both compute the DH proof. msg := append(l.longTermPriv.PubKey().SerializeCompressed(), myDHproof...) if _, err = lnConn.Conn.Write(msg); err != nil { return err } resp := make([]byte, 20) if _, err := lnConn.Conn.Read(resp); err != nil { return err } // Verify their DH proof. if bytes.Equal(resp, theirDHproof) == false { return fmt.Errorf("Invalid DH proof %x", theirDHproof) } } theirAdr := btcutil.Hash160(theirPub.SerializeCompressed()) copy(lnConn.RemoteLNId[:], theirAdr[:16]) lnConn.RemotePub = theirPub lnConn.Authed = true return nil }