Beispiel #1
0
// newHandshakeState returns a new instance of the handshake state initialized
// with the prologue and protocol name. If this is the respodner's handshake
// state, then the remotePub can be nil.
func newHandshakeState(initiator bool, prologue []byte,
	localPub *btcec.PrivateKey, remotePub *btcec.PublicKey) handshakeState {

	h := handshakeState{
		initiator:    initiator,
		localStatic:  localPub,
		remoteStatic: remotePub,
	}

	// Set the current chainking key and handshake digest to the hash of
	// the protocol name, and additionally mix in the prologue. If either
	// sides disagree about the prologue or protocol name, then the
	// handshake will fail.
	h.InitializeSymmetric([]byte(protocolName))
	h.mixHash(prologue)

	// In Noise_XK, then initiator should know the responder's static
	// public key, therefore we include the responder's static key in the
	// handshake digest. If the initiator gets this value wrong, then the
	// handshake will fail.
	if initiator {
		h.mixHash(remotePub.SerializeCompressed())
	} else {
		h.mixHash(localPub.PubKey().SerializeCompressed())
	}

	return h
}
Beispiel #2
0
// FetchOpenChannel returns all stored currently active/open channels
// associated with the target nodeID. In the case that no active channels are
// known to have been created with this node, then a zero-length slice is
// returned.
func (d *DB) FetchOpenChannels(nodeID *btcec.PublicKey) ([]*OpenChannel, error) {
	var channels []*OpenChannel
	err := d.store.View(func(tx *bolt.Tx) error {
		// Get the bucket dedicated to storing the meta-data for open
		// channels.
		openChanBucket := tx.Bucket(openChannelBucket)
		if openChanBucket == nil {
			return nil
		}

		// Within this top level bucket, fetch the bucket dedicated to storing
		// open channel data specific to the remote node.
		pub := nodeID.SerializeCompressed()
		nodeChanBucket := openChanBucket.Bucket(pub)
		if nodeChanBucket == nil {
			return nil
		}

		// Finally, we both of the necessary buckets retrieved, fetch
		// all the active channels related to this node.
		nodeChannels, err := d.fetchNodeChannels(openChanBucket,
			nodeChanBucket)
		if err != nil {
			return err
		}

		channels = nodeChannels
		return nil
	})

	return channels, err
}
Beispiel #3
0
// commitScriptToSelf constructs the public key script for the output on the
// commitment transaction paying to the "owner" of said commitment transaction.
// If the other party learns of the pre-image to the revocation hash, then they
// can claim all the settled funds in the channel, plus the unsettled funds.
//
// Possible Input Scripts:
//     REVOKE:     <sig> 1
//     SENDRSWEEP: <sig> 0
//
// Output Script:
//     OP_IF
//         <revokeKey> OP_CHECKSIG
//     OP_ELSE
//         <timeKey> OP_CHECKSIGVERIFY
//         <numRelativeBlocks> OP_CHECKSEQUENCEVERIFY
//     OP_ENDIF
func commitScriptToSelf(csvTimeout uint32, selfKey, revokeKey *btcec.PublicKey) ([]byte, error) {
	// This script is spendable under two conditions: either the 'csvTimeout'
	// has passed and we can redeem our funds, or they can produce a valid
	// signature with the revocation public key. The revocation public key
	// will *only* be known to the other party if we have divulged the
	// revocation hash, allowing them to homomorphically derive the proper
	// private key which corresponds to the revoke public key.
	builder := txscript.NewScriptBuilder()

	builder.AddOp(txscript.OP_IF)

	// If a valid signature using the revocation key is presented, then
	// allow an immediate spend provided the proper signature.
	builder.AddData(revokeKey.SerializeCompressed())
	builder.AddOp(txscript.OP_CHECKSIG)

	builder.AddOp(txscript.OP_ELSE)

	// Otherwise, we can re-claim our funds after a CSV delay of
	// 'csvTimeout' timeout blocks, and a valid signature.
	builder.AddData(selfKey.SerializeCompressed())
	builder.AddOp(txscript.OP_CHECKSIGVERIFY)
	builder.AddInt64(int64(csvTimeout))
	builder.AddOp(OP_CHECKSEQUENCEVERIFY)

	builder.AddOp(txscript.OP_ENDIF)

	return builder.Script()
}
Beispiel #4
0
// commitScriptUnencumbered constructs the public key script on the commitment
// transaction paying to the "other" party. The constructed output is a normal
// p2wkh output 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_0)
	builder.AddData(btcutil.Hash160(key.SerializeCompressed()))

	return builder.Script()
}
// computeBlindingFactor for the next hop given the ephemeral pubKey and
// sharedSecret for this hop. The blinding factor is computed as the
// sha-256(pubkey || sharedSecret).
func computeBlindingFactor(hopPubKey *btcec.PublicKey, hopSharedSecret []byte) [sha256.Size]byte {
	sha := sha256.New()
	sha.Write(hopPubKey.SerializeCompressed())
	sha.Write(hopSharedSecret)

	var hash [sha256.Size]byte
	copy(hash[:], sha.Sum(nil))
	return hash
}
Beispiel #6
0
// UnregisterLink requets the htlcSwitch to unregiser the new active link. An
// unregistered link will no longer be considered a candidate to forward
// HTLC's.
func (h *htlcSwitch) UnregisterLink(remotePub *btcec.PublicKey, chanPoint *wire.OutPoint) {
	done := make(chan struct{}, 1)
	rawPub := remotePub.SerializeCompressed()

	h.linkControl <- &unregisterLinkMsg{
		chanInterface: fastsha256.Sum256(rawPub),
		chanPoint:     chanPoint,
		remoteID:      rawPub,
		done:          done,
	}

	<-done
}
Beispiel #7
0
// fetchPrivKey attempts to retrieve the raw private key coresponding to the
// passed public key.
// TODO(roasbeef): alternatively can extract all the data pushes within the
// script, then attempt to match keys one by one
func (b *BtcWallet) fetchPrivKey(pub *btcec.PublicKey) (*btcec.PrivateKey, error) {
	hash160 := btcutil.Hash160(pub.SerializeCompressed())
	addr, err := btcutil.NewAddressWitnessPubKeyHash(hash160, b.netParams)
	if err != nil {
		return nil, err
	}

	walletddr, err := b.wallet.Manager.Address(addr)
	if err != nil {
		return nil, err
	}

	return walletddr.(waddrmgr.ManagedPubKeyAddress).PrivKey()
}
Beispiel #8
0
// deriveElkremRoot derives an elkrem root unique to a channel given the
// private key for our public key in the 2-of-2 multi-sig, and the remote
// node's multi-sig public key. The root is derived using the HKDF[1][2]
// instantiated with sha-256. The secret data used is our multi-sig private
// key, with the salt being the remote node's public key.
//
// [1]: https://eprint.iacr.org/2010/264.pdf
// [2]: https://tools.ietf.org/html/rfc5869
func deriveElkremRoot(elkremDerivationRoot *btcec.PrivateKey,
	localMultiSigKey *btcec.PublicKey,
	remoteMultiSigKey *btcec.PublicKey) wire.ShaHash {

	secret := elkremDerivationRoot.Serialize()
	salt := localMultiSigKey.SerializeCompressed()
	info := remoteMultiSigKey.SerializeCompressed()

	rootReader := hkdf.New(sha256.New, secret, salt, info)

	// It's safe to ignore the error her as we know for sure that we won't
	// be draining the HKDF past its available entropy horizon.
	// TODO(roasbeef): revisit...
	var elkremRoot wire.ShaHash
	rootReader.Read(elkremRoot[:])

	return elkremRoot
}
Beispiel #9
0
// FetchLinkNode attempts to lookup the data for a LinkNode based on a target
// identity public key. If a particular LinkNode for the passed identity public
// key cannot be found, then ErrNodeNotFound if returned.
func (db *DB) FetchLinkNode(identity *btcec.PublicKey) (*LinkNode, error) {
	var (
		node *LinkNode
		err  error
	)

	err = db.store.View(func(tx *bolt.Tx) error {
		// First fetch the bucket for storing node meta-data, bailing
		// out early if it hasn't been created yet.
		nodeMetaBucket := tx.Bucket(nodeInfoBucket)
		if nodeInfoBucket == nil {
			return fmt.Errorf("node bucket not created")
		}

		// If a link node for that particular public key cannot be
		// located, then exit early with a ErrNodeNotFound.
		pubKey := identity.SerializeCompressed()
		nodeBytes := nodeMetaBucket.Get(pubKey)
		if nodeBytes == nil {
			return ErrNodeNotFound
		}

		// Finally, decode an allocate a fresh LinkNode object to be
		// returned to the caller.
		nodeReader := bytes.NewReader(nodeBytes)
		node, err = deserializeLinkNode(nodeReader)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	return node, nil
}
Beispiel #10
0
// 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, addrType addressType) (*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())
	}

	var address btcutil.Address
	var err error

	switch addrType {
	// TODO(roasbeef): only use these types in the db?
	case adtChainNestedWitness:
		// For this address type we'l generate an address which is
		// backwards compatible to Bitcoin nodes running 0.6.0 onwards, but
		// allows us to take advantage of segwit's scripting improvments,
		// and malleability fixes.

		// First, we'll generate a normal p2wkh address from the pubkey hash.
		witAddr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, m.chainParams)
		if err != nil {
			return nil, err
		}

		// Next we'll generate the witness program which can be used as a
		// pkScript to pay to this generated address.
		witnessProgram, err := txscript.PayToAddrScript(witAddr)
		if err != nil {
			return nil, err
		}

		// Finally, we'll use the witness program itself as the pre-image
		// to a p2sh address. In order to spend, we first use the
		// witnessProgram as the sigScript, then present the proper
		// <sig, pubkey> pair as the witness.
		address, err = btcutil.NewAddressScriptHash(witnessProgram, m.chainParams)
		if err != nil {
			return nil, err
		}
	case adtImport:
		// TODO(roasbeef): truly proper?
		fallthrough
	case adtChain:
		address, err = btcutil.NewAddressPubKeyHash(pubKeyHash, m.chainParams)
		if err != nil {
			return nil, err
		}
	case adtChainWitness:
		address, err = btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, m.chainParams)
		if err != nil {
			return nil, err
		}
	}

	return &managedAddress{
		manager:          m,
		address:          address,
		account:          account,
		imported:         false,
		internal:         false,
		addrType:         addrType,
		compressed:       compressed,
		pubKey:           pubKey,
		privKeyEncrypted: nil,
		privKeyCT:        nil,
	}, nil
}
Beispiel #11
0
// receiverHTLCScript constructs the public key script for an incoming HTLC
// output payment for the receiver's version of the commitment transaction:
//
// Possible Input Scripts:
//    RECVR: <sig> <preimage> 1
//    REVOK: <sig> <preimage> 1 0
//    SENDR: <sig> 0 0
//
// OP_IF
//     //Receiver
//     OP_SIZE 32 OP_EQUALVERIFY
//     OP_SHA256
//     <payment hash> OP_EQUALVERIFY
//     <relative blockheight> OP_CHECKSEQUENCEVERIFY OP_DROP
//     <receiver key> OP_CHECKSIG
// OP_ELSE
//     //Sender
//     OP_IF
// 	//Revocation
//      OP_SHA256
// 	<revoke hash> OP_EQUALVERIFY
//     OP_ELSE
// 	//Refund
// 	<absolute blockehight> OP_CHECKLOCKTIMEVERIFY OP_DROP
//     OP_ENDIF
//     <sender key> OP_CHECKSIG
// OP_ENDIF
// TODO(roasbeef): go back to revocation keys in the HTLC outputs?
//  * also could combine pre-image with their key?
func receiverHTLCScript(absoluteTimeout, relativeTimeout uint32, senderKey,
	receiverKey *btcec.PublicKey, revokeHash, paymentHash []byte) ([]byte, error) {

	builder := txscript.NewScriptBuilder()

	// The receiver of the script will place a 1 as the first item of the
	// witness stack forcing Script execution to enter the "if" clause of
	// the main body of the script.
	builder.AddOp(txscript.OP_IF)

	// In this clause, the receiver can redeem the HTLC after a relative timeout.
	// This added delay gives the sender (at this time) an opportunity to
	// re-claim the pending HTLC in the event that the receiver
	// (at this time) broadcasts this old commitment transaction after it
	// has been revoked. Additionally, we require that the pre-image is
	// exactly 32-bytes in order to avoid undesirable redemption
	// asymmerties in the multi-hop scenario.
	builder.AddOp(txscript.OP_SIZE)
	builder.AddInt64(32)
	builder.AddOp(txscript.OP_EQUALVERIFY)
	builder.AddOp(txscript.OP_SHA256)
	builder.AddData(paymentHash)
	builder.AddOp(txscript.OP_EQUALVERIFY)
	builder.AddInt64(int64(relativeTimeout))
	builder.AddOp(OP_CHECKSEQUENCEVERIFY)
	builder.AddOp(txscript.OP_DROP)
	builder.AddData(receiverKey.SerializeCompressed())
	builder.AddOp(txscript.OP_CHECKSIG)

	// Otherwise, the sender will place a 0 as the first item of the
	// witness stack forcing exeuction to enter the "else" clause of the
	// main body of the script.
	builder.AddOp(txscript.OP_ELSE)

	// The sender will place a 1 as the second item of the witness stack
	// in the scenario that the receiver broadcasts an invalidated
	// commitment transaction, allowing the sender to sweep all the
	// receiver's funds.
	builder.AddOp(txscript.OP_IF)
	builder.AddOp(txscript.OP_SHA256)
	builder.AddData(revokeHash)
	builder.AddOp(txscript.OP_EQUALVERIFY)

	// If not, then the sender needs to wait for the HTLC timeout. This
	// clause may be executed if the receiver fails to present the r-value
	// in time. This prevents the pending funds from being locked up
	// indefinately.

	// The sender will place a 0 as the second item of the witness stack if
	// they wish to sweep the HTLC after an absolute refund timeout. This
	// time out clause prevents the pending funds from being locked up
	// indefinately.
	builder.AddOp(txscript.OP_ELSE)
	builder.AddInt64(int64(absoluteTimeout))
	builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
	builder.AddOp(txscript.OP_DROP)
	builder.AddOp(txscript.OP_ENDIF)

	// In either case, we also require a valid signature with the sender's
	// commitment private key.
	builder.AddData(senderKey.SerializeCompressed())
	builder.AddOp(txscript.OP_CHECKSIG)

	builder.AddOp(txscript.OP_ENDIF)

	return builder.Script()
}
Beispiel #12
0
// senderHTLCScript constructs the public key script for an outgoing HTLC
// output payment for the sender's version of the commitment transaction:
//
// Possible Input Scripts:
//    SENDR: <sig> 0
//    RECVR: <sig> <preimage> 0 1
//    REVOK: <sig  <preimage> 1 1
//     * receiver revoke
//
// OP_IF
//     //Receiver
//     OP_IF
// 	//Revoke
// 	<revocation hash>
//     OP_ELSE
// 	//Receive
// 	OP_SIZE 32 OP_EQUALVERIFY
// 	<payment hash>
//     OP_ENDIF
//     OP_SWAP
//     OP_SHA256 OP_EQUALVERIFY
//     <recv key> OP_CHECKSIG
// OP_ELSE
//     //Sender
//     <absolute blockheight> OP_CHECKLOCKTIMEVERIFY
//     <relative blockheight> OP_CHECKSEQUENCEVERIFY
//     OP_2DROP
//     <sendr key> OP_CHECKSIG
// OP_ENDIF
func senderHTLCScript(absoluteTimeout, relativeTimeout uint32, senderKey,
	receiverKey *btcec.PublicKey, revokeHash, paymentHash []byte) ([]byte, error) {

	builder := txscript.NewScriptBuilder()

	// The receiver of the HTLC places a 1 as the first item in the witness
	// stack, forcing Script execution to enter the "if" clause within the
	// main body of the script.
	builder.AddOp(txscript.OP_IF)

	// The receiver will place a 1 as the second item of the witness stack
	// in the case the sender broadcasts a revoked commitment transaction.
	// Executing this branch allows the receiver to claim the sender's
	// funds as a result of their contract violation.
	builder.AddOp(txscript.OP_IF)
	builder.AddData(revokeHash)

	// Alternatively, the receiver can place a 0 as the second item of the
	// witness stack if they wish to claim the HTLC with the proper
	// pre-image as normal. In order to prevent an over-sized pre-image
	// attack (which can create undesirable redemption asymmerties), we
	// strongly require that all HTLC pre-images are exactly 32 bytes.
	builder.AddOp(txscript.OP_ELSE)
	builder.AddOp(txscript.OP_SIZE)
	builder.AddInt64(32)
	builder.AddOp(txscript.OP_EQUALVERIFY)
	builder.AddData(paymentHash)
	builder.AddOp(txscript.OP_ENDIF)

	builder.AddOp(txscript.OP_SWAP)

	builder.AddOp(txscript.OP_SHA256)
	builder.AddOp(txscript.OP_EQUALVERIFY)

	// In either case, we require a valid signature by the receiver.
	builder.AddData(receiverKey.SerializeCompressed())
	builder.AddOp(txscript.OP_CHECKSIG)

	// Otherwise, the sender of the HTLC will place a 0 as the first item
	// of the witness stack in order to sweep the funds back after the HTLC
	// times out.
	builder.AddOp(txscript.OP_ELSE)

	// In this case, the sender will need to wait for an absolute HTLC
	// timeout, then afterwards a relative timeout before we claim re-claim
	// the unsettled funds. This delay gives the other party a chance to
	// present the pre-image to the revocation hash in the event that the
	// sender (at this time) broadcasts this commitment transaction after
	// it has been revoked.
	builder.AddInt64(int64(absoluteTimeout))
	builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
	builder.AddInt64(int64(relativeTimeout))
	builder.AddOp(OP_CHECKSEQUENCEVERIFY)
	builder.AddOp(txscript.OP_2DROP)
	builder.AddData(senderKey.SerializeCompressed())
	builder.AddOp(txscript.OP_CHECKSIG)

	builder.AddOp(txscript.OP_ENDIF)

	return builder.Script()
}