func BenchmarkPathPacketConstruction(b *testing.B) { route := make([]*btcec.PublicKey, NumMaxHops) for i := 0; i < NumMaxHops; i++ { privKey, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { b.Fatalf("unable to generate key: %v", privKey) } route[i] = privKey.PubKey() } var ( err error sphinxPacket *OnionPacket ) var hopPayloads [][]byte for i := 0; i < len(route); i++ { payload := bytes.Repeat([]byte{byte('A' + i)}, HopPayloadSize) hopPayloads = append(hopPayloads, payload) } d, _ := btcec.PrivKeyFromBytes(btcec.S256(), bytes.Repeat([]byte{'A'}, 32)) for i := 0; i < b.N; i++ { sphinxPacket, err = NewOnionPacket(route, d, hopPayloads, nil) if err != nil { b.Fatalf("unable to create packet: %v", err) } } s = sphinxPacket }
// TestSigCacheAddMaxEntriesZeroOrNegative tests that if a sigCache is created // with a max size <= 0, then no entries are added to the sigcache at all. func TestSigCacheAddMaxEntriesZeroOrNegative(t *testing.T) { // Create a sigcache that can hold up to 0 entries. sigCache := NewSigCache(0) // Generate a random sigCache entry triplet. msg1, sig1, key1, err := genRandomSig() if err != nil { t.Errorf("unable to generate random signature test data") } // Add the triplet to the signature cache. sigCache.Add(*msg1, sig1, key1) // The generated triplet should not be found. sig1Copy, _ := btcec.ParseSignature(sig1.Serialize(), btcec.S256()) key1Copy, _ := btcec.ParsePubKey(key1.SerializeCompressed(), btcec.S256()) if sigCache.Exists(*msg1, sig1Copy, key1Copy) { t.Errorf("previously added signature found in sigcache, but" + "shouldn't have been") } // There shouldn't be any entries in the sigCache. if len(sigCache.validSigs) != 0 { t.Errorf("%v items found in sigcache, no items should have"+ "been added", len(sigCache.validSigs)) } }
func fetchChanCommitKeys(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error { // Construct the key which stores the commitment keys: ckk || channelID. // TODO(roasbeef): factor into func var bc bytes.Buffer if err := writeOutpoint(&bc, channel.ChanID); err != nil { return err } commitKey := make([]byte, len(commitKeys)+bc.Len()) copy(commitKey[:3], commitKeys) copy(commitKey[3:], bc.Bytes()) var err error keyBytes := nodeChanBucket.Get(commitKey) channel.TheirCommitKey, err = btcec.ParsePubKey(keyBytes[:33], btcec.S256()) if err != nil { return err } channel.OurCommitKey, err = btcec.ParsePubKey(keyBytes[33:], btcec.S256()) if err != nil { return err } return nil }
// isPubKey returns whether or not the passed public key script is a standard // pay-to-pubkey script that pays to a valid compressed or uncompressed public // key along with the serialized pubkey it is paying to if it is. // // NOTE: This function ensures the public key is actually valid since the // compression algorithm requires valid pubkeys. It does not support hybrid // pubkeys. This means that even if the script has the correct form for a // pay-to-pubkey script, this function will only return true when it is paying // to a valid compressed or uncompressed pubkey. func isPubKey(script []byte) (bool, []byte) { // Pay-to-compressed-pubkey script. if len(script) == 35 && script[0] == txscript.OP_DATA_33 && script[34] == txscript.OP_CHECKSIG && (script[1] == 0x02 || script[1] == 0x03) { // Ensure the public key is valid. serializedPubKey := script[1:34] _, err := btcec.ParsePubKey(serializedPubKey, btcec.S256()) if err == nil { return true, serializedPubKey } } // Pay-to-uncompressed-pubkey script. if len(script) == 67 && script[0] == txscript.OP_DATA_65 && script[66] == txscript.OP_CHECKSIG && script[1] == 0x04 { // Ensure the public key is valid. serializedPubKey := script[1:66] _, err := btcec.ParsePubKey(serializedPubKey, btcec.S256()) if err == nil { return true, serializedPubKey } } return false, nil }
// DeriveRevocationPubkey derives the revocation public key given the // counter-party's commitment key, and revocation pre-image derived via a // pseudo-random-function. In the event that we (for some reason) broadcast a // revoked commitment transaction, then if the other party knows the revocation // pre-image, then they'll be able to derive the corresponding private key to // this private key by exploting the homomorphism in the elliptic curve group: // * https://en.wikipedia.org/wiki/Group_homomorphism#Homomorphisms_of_abelian_groups // // The derivation is performed as follows: // // revokeKey := commitKey + revokePoint // := G*k + G*h // := G * (k+h) // // Therefore, once we divulge the revocation pre-image, the remote peer is able to // compute the proper private key for the revokeKey by computing: // revokePriv := commitPriv + revokePreimge mod N // // Where N is the order of the sub-group. func DeriveRevocationPubkey(commitPubKey *btcec.PublicKey, revokePreimage []byte) *btcec.PublicKey { // First we need to convert the revocation hash into a point on the // elliptic curve. revokePointX, revokePointY := btcec.S256().ScalarBaseMult(revokePreimage) // Now that we have the revocation point, we add this to their commitment // public key in order to obtain the revocation public key. revokeX, revokeY := btcec.S256().Add(commitPubKey.X, commitPubKey.Y, revokePointX, revokePointY) return &btcec.PublicKey{X: revokeX, Y: revokeY} }
func establishTestConnection() (net.Conn, net.Conn, error) { // First, generate the long-term private keys both ends of the connection // within our test. localPriv, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { return nil, nil, err } remotePriv, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { return nil, nil, err } // Having a port of ":0" means a random port, and interface will be // chosen for our listener. addr := ":0" // Our listener will be local, and the connection remote. listener, err := NewListener(localPriv, addr) if err != nil { return nil, nil, err } defer listener.Close() netAddr := &lnwire.NetAddress{ IdentityKey: localPriv.PubKey(), Address: listener.Addr().(*net.TCPAddr), } // Initiate a connection with a separate goroutine, and listen with our // main one. If both errors are nil, then encryption+auth was succesful. errChan := make(chan error) connChan := make(chan net.Conn) go func() { conn, err := Dial(remotePriv, netAddr) errChan <- err connChan <- conn }() localConn, listenErr := listener.Accept() if listenErr != nil { return nil, nil, err } if dialErr := <-errChan; err != nil { return nil, nil, dialErr } remoteConn := <-connChan return localConn, remoteConn, nil }
func fetchChanFundingInfo(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error { var b bytes.Buffer if err := writeOutpoint(&b, channel.ChanID); err != nil { return err } fundTxnKey := make([]byte, len(fundingTxnKey)+b.Len()) copy(fundTxnKey[:3], fundingTxnKey) copy(fundTxnKey[3:], b.Bytes()) infoBytes := bytes.NewReader(nodeChanBucket.Get(fundTxnKey)) // TODO(roasbeef): can remove as channel ID *is* the funding point now. channel.FundingOutpoint = &wire.OutPoint{} if err := readOutpoint(infoBytes, channel.FundingOutpoint); err != nil { return err } ourKeyBytes, err := wire.ReadVarBytes(infoBytes, 0, 34, "") if err != nil { return err } channel.OurMultiSigKey, err = btcec.ParsePubKey(ourKeyBytes, btcec.S256()) if err != nil { return err } theirKeyBytes, err := wire.ReadVarBytes(infoBytes, 0, 34, "") if err != nil { return err } channel.TheirMultiSigKey, err = btcec.ParsePubKey(theirKeyBytes, btcec.S256()) if err != nil { return err } channel.FundingWitnessScript, err = wire.ReadVarBytes(infoBytes, 0, 520, "") if err != nil { return err } scratch := make([]byte, 8) if _, err := infoBytes.Read(scratch); err != nil { return err } unixSecs := byteOrder.Uint64(scratch) channel.CreationTime = time.Unix(int64(unixSecs), 0) return nil }
// TestSigCacheAddEvictEntry tests the eviction case where a new signature // triplet is added to a full signature cache which should trigger randomized // eviction, followed by adding the new element to the cache. func TestSigCacheAddEvictEntry(t *testing.T) { // Create a sigcache that can hold up to 100 entries. sigCacheSize := uint(100) sigCache := NewSigCache(sigCacheSize) // Fill the sigcache up with some random sig triplets. for i := uint(0); i < sigCacheSize; i++ { msg, sig, key, err := genRandomSig() if err != nil { t.Fatalf("unable to generate random signature test data") } sigCache.Add(*msg, sig, key) sigCopy, _ := btcec.ParseSignature(sig.Serialize(), btcec.S256()) keyCopy, _ := btcec.ParsePubKey(key.SerializeCompressed(), btcec.S256()) if !sigCache.Exists(*msg, sigCopy, keyCopy) { t.Errorf("previously added item not found in signature" + "cache") } } // The sigcache should now have sigCacheSize entries within it. if uint(len(sigCache.validSigs)) != sigCacheSize { t.Fatalf("sigcache should now have %v entries, instead it has %v", sigCacheSize, len(sigCache.validSigs)) } // Add a new entry, this should cause eviction of a randomly chosen // previous entry. msgNew, sigNew, keyNew, err := genRandomSig() if err != nil { t.Fatalf("unable to generate random signature test data") } sigCache.Add(*msgNew, sigNew, keyNew) // The sigcache should still have sigCache entries. if uint(len(sigCache.validSigs)) != sigCacheSize { t.Fatalf("sigcache should now have %v entries, instead it has %v", sigCacheSize, len(sigCache.validSigs)) } // The entry added above should be found within the sigcache. sigNewCopy, _ := btcec.ParseSignature(sigNew.Serialize(), btcec.S256()) keyNewCopy, _ := btcec.ParsePubKey(keyNew.SerializeCompressed(), btcec.S256()) if !sigCache.Exists(*msgNew, sigNewCopy, keyNewCopy) { t.Fatalf("previously added item not found in signature cache") } }
// PrivKey returns the private key for the address. It can fail if the address // manager is watching-only or locked, or the address does not have any keys. // // This is part of the ManagedPubKeyAddress interface implementation. func (a *managedAddress) PrivKey() (*btcec.PrivateKey, error) { // No private keys are available for a watching-only address manager. if a.manager.watchingOnly { return nil, managerError(ErrWatchingOnly, errWatchingOnly, nil) } a.manager.mtx.Lock() defer a.manager.mtx.Unlock() // Account manager must be unlocked to decrypt the private key. if a.manager.locked { return nil, managerError(ErrLocked, errLocked, nil) } // Decrypt the key as needed. Also, make sure it's a copy since the // private key stored in memory can be cleared at any time. Otherwise // the returned private key could be invalidated from under the caller. privKeyCopy, err := a.unlock(a.manager.cryptoKeyPriv) if err != nil { return nil, err } privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyCopy) zero.Bytes(privKeyCopy) return privKey, nil }
// This example demonstrates signing a message with a secp256k1 private key that // is first parsed form raw bytes and serializing the generated signature. func Example_signMessage() { // Decode a hex-encoded private key. pkBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2d4f87" + "20ee63e502ee2869afab7de234b80c") if err != nil { fmt.Println(err) return } privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes) // Sign a message using the private key. message := "test message" messageHash := chainhash.DoubleHashB([]byte(message)) signature, err := privKey.Sign(messageHash) if err != nil { fmt.Println(err) return } // Serialize and display the signature. fmt.Printf("Serialized Signature: %x\n", signature.Serialize()) // Verify the signature for the message using the public key. verified := signature.Verify(messageHash, pubKey) fmt.Printf("Signature Verified? %v\n", verified) // Output: // Serialized Signature: 304402201008e236fa8cd0f25df4482dddbb622e8a8b26ef0ba731719458de3ccd93805b022032f8ebe514ba5f672466eba334639282616bb3c2f0ab09998037513d1f9e3d6d // Signature Verified? true }
// This example demonstrates decrypting a message using a private key that is // first parsed from raw bytes. func Example_decryptMessage() { // Decode the hex-encoded private key. pkBytes, err := hex.DecodeString("a11b0a4e1a132305652ee7a8eb7848f6ad" + "5ea381e3ce20a2c086a2e388230811") if err != nil { fmt.Println(err) return } privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes) ciphertext, err := hex.DecodeString("35f644fbfb208bc71e57684c3c8b437402ca" + "002047a2f1b38aa1a8f1d5121778378414f708fe13ebf7b4a7bb74407288c1958969" + "00207cf4ac6057406e40f79961c973309a892732ae7a74ee96cd89823913b8b8d650" + "a44166dc61ea1c419d47077b748a9c06b8d57af72deb2819d98a9d503efc59fc8307" + "d14174f8b83354fac3ff56075162") // Try decrypting the message. plaintext, err := btcec.Decrypt(privKey, ciphertext) if err != nil { fmt.Println(err) return } fmt.Println(string(plaintext)) // Output: // test message }
// updateCommitTx signs, then sends an update to the remote peer adding a new // commitment to their commitment chain which includes all the latest updates // we've received+processed up to this point. func (p *peer) updateCommitTx(state *commitmentState) (bool, error) { sigTheirs, logIndexTheirs, err := state.channel.SignNextCommitment() if err == lnwallet.ErrNoWindow { peerLog.Tracef("revocation window exhausted, unable to send %v", len(state.pendingBatch)) return false, nil } else if err != nil { return false, err } parsedSig, err := btcec.ParseSignature(sigTheirs, btcec.S256()) if err != nil { return false, fmt.Errorf("unable to parse sig: %v", err) } commitSig := &lnwire.CommitSignature{ ChannelPoint: state.chanPoint, CommitSig: parsedSig, LogIndex: uint64(logIndexTheirs), } p.queueMsg(commitSig, nil) // Move all pending updates to the map of cleared HTLC's, clearing out // the set of pending updates. for _, update := range state.pendingBatch { // TODO(roasbeef): add parsed next-hop info to pending batch // for multi-hop forwarding state.clearedHTCLs[update.index] = update } state.logCommitTimer = nil state.pendingBatch = nil return true, nil }
// RecvActTwo processes the second packet (act two) sent from the responder to // the initiator. A succesful processing of this packet authenticates the // initiator to the responder. func (b *BrontideMachine) RecvActTwo(actTwo [ActTwoSize]byte) error { var ( err error e [33]byte p [16]byte ) copy(e[:], actTwo[:33]) copy(p[:], actTwo[33:]) // e b.remoteEphemeral, err = btcec.ParsePubKey(e[:], btcec.S256()) if err != nil { return err } b.mixHash(b.remoteEphemeral.SerializeCompressed()) // ee s := btcec.GenerateSharedSecret(b.localEphemeral, b.remoteEphemeral) b.mixKey(s) if _, err := b.DecryptAndHash(p[:]); err != nil { return err } return nil }
// Decode fully populates the target ForwardingMessage from the raw bytes // encoded within the io.Reader. In the case of any decoding errors, an error // will be returned. If the method successs, then the new OnionPacket is // ready to be processed by an instance of SphinxNode. func (f *OnionPacket) Decode(r io.Reader) error { var err error f.Header = &MixHeader{} var buf [1]byte if _, err := io.ReadFull(r, buf[:]); err != nil { return err } f.Header.Version = buf[0] var ephemeral [33]byte if _, err := io.ReadFull(r, ephemeral[:]); err != nil { return err } f.Header.EphemeralKey, err = btcec.ParsePubKey(ephemeral[:], btcec.S256()) if err != nil { return err } if _, err := io.ReadFull(r, f.Header.HeaderMAC[:]); err != nil { return err } if _, err := io.ReadFull(r, f.Header.RoutingInfo[:]); err != nil { return err } if _, err := io.ReadFull(r, f.Header.HopPayload[:]); err != nil { return err } return nil }
// RecvActThree processes the final act (act three) sent from the initiator to // the responder. After processing this act, the responder learns of the // initiators's static public key. Decryption of the static key serves to // authenticate the initiator to the responder. func (b *BrontideMachine) RecvActThree(actThree [ActThreeSize]byte) error { var ( err error s [33 + 16]byte p [16]byte ) copy(s[:], actThree[:33+16]) copy(p[:], actThree[33+16:]) // s remotePub, err := b.DecryptAndHash(s[:]) if err != nil { return err } b.remoteStatic, err = btcec.ParsePubKey(remotePub, btcec.S256()) if err != nil { return err } // se se := btcec.GenerateSharedSecret(b.localEphemeral, b.remoteStatic) b.mixKey(se) if _, err := b.DecryptAndHash(p[:]); err != nil { return err } // With the final ECDH operation complete, derive the session sending // and receiving keys. b.split() return nil }
// RecvActOne processes the act one packet sent by the initiator. The responder // executes the mirroed actions to that of the initiator extending the // handshake digest and deriving a new shared secret based on a ECDH with the // initiator's ephemeral key and reponder's static key. func (b *BrontideMachine) RecvActOne(actOne [ActOneSize]byte) error { var ( err error e [33]byte p [16]byte ) copy(e[:], actOne[:33]) copy(p[:], actOne[33:]) // e b.remoteEphemeral, err = btcec.ParsePubKey(e[:], btcec.S256()) if err != nil { return err } b.mixHash(b.remoteEphemeral.SerializeCompressed()) // es s := btcec.GenerateSharedSecret(b.localStatic, b.remoteEphemeral) b.mixKey(s) // If the initiator doesn't know our static key, then this operation // will fail. if _, err := b.DecryptAndHash(p[:]); err != nil { return err } return nil }
// GenActTwo generates the second packet (act two) to be sent from the // responder to the initiator. The packet for act two is identify to that of // act one, but then results in a different ECDH operation between the // initiator's and responder's ephemeral keys. // // <- e, ee func (b *BrontideMachine) GenActTwo() ([ActTwoSize]byte, error) { var ( err error actTwo [ActTwoSize]byte ) // e b.localEphemeral, err = btcec.NewPrivateKey(btcec.S256()) if err != nil { return actTwo, err } ephemeral := b.localEphemeral.PubKey().SerializeCompressed() b.mixHash(b.localEphemeral.PubKey().SerializeCompressed()) // ee s := btcec.GenerateSharedSecret(b.localEphemeral, b.remoteEphemeral) b.mixKey(s) authPayload := b.EncryptAndHash([]byte{}) copy(actTwo[:33], ephemeral) copy(actTwo[33:], authPayload) return actTwo, nil }
// executeCooperativeClose executes the initial phase of a user-executed // cooperative channel close. The channel state machine is transitioned to the // closing phase, then our half of the closing witness is sent over to the // remote peer. func (p *peer) executeCooperativeClose(channel *lnwallet.LightningChannel) (*wire.ShaHash, error) { // Shift the channel state machine into a 'closing' state. This // generates a signature for the closing tx, as well as a txid of the // closing tx itself, allowing us to watch the network to determine // when the remote node broadcasts the fully signed closing // transaction. sig, txid, err := channel.InitCooperativeClose() if err != nil { return nil, err } chanPoint := channel.ChannelPoint() peerLog.Infof("Executing cooperative closure of "+ "ChanPoint(%v) with peerID(%v), txid=%v", chanPoint, p.id, txid) // With our signature for the close tx generated, send the signature to // the remote peer instructing it to close this particular channel // point. // TODO(roasbeef): remove encoding redundancy closeSig, err := btcec.ParseSignature(sig, btcec.S256()) if err != nil { return nil, err } closeReq := lnwire.NewCloseRequest(chanPoint, closeSig) p.queueMsg(closeReq, nil) return txid, nil }
// handleFundingResponse processes a response to the workflow initiation sent // by the remote peer. This message then queues a message with the funding // outpoint, and a commitment signature to the remote peer. func (f *fundingManager) handleFundingResponse(fmsg *fundingResponseMsg) { msg := fmsg.msg sourcePeer := fmsg.peer f.resMtx.RLock() resCtx := f.activeReservations[fmsg.peer.id][msg.ChannelID] f.resMtx.RUnlock() fndgLog.Infof("Recv'd fundingResponse for pendingID(%v)", msg.ChannelID) // The remote node has responded with their portion of the channel // contribution. At this point, we can process their contribution which // allows us to construct and sign both the commitment transaction, and // the funding transaction. _, addrs, _, err := txscript.ExtractPkScriptAddrs(msg.DeliveryPkScript, activeNetParams.Params) if err != nil { fndgLog.Errorf("Unable to extract addresses from script: %v", err) resCtx.err <- err return } contribution := &lnwallet.ChannelContribution{ FundingAmount: 0, MultiSigKey: msg.ChannelDerivationPoint, CommitKey: msg.CommitmentKey, DeliveryAddress: addrs[0], RevocationKey: msg.RevocationKey, CsvDelay: msg.CsvDelay, } if err := resCtx.reservation.ProcessContribution(contribution); err != nil { fndgLog.Errorf("Unable to process contribution from %v: %v", sourcePeer, err) fmsg.peer.Disconnect() resCtx.err <- err return } // Now that we have their contribution, we can extract, then send over // both the funding out point and our signature for their version of // the commitment transaction to the remote peer. outPoint := resCtx.reservation.FundingOutpoint() _, sig := resCtx.reservation.OurSignatures() commitSig, err := btcec.ParseSignature(sig, btcec.S256()) if err != nil { fndgLog.Errorf("Unable to parse signature: %v", err) resCtx.err <- err return } // Register a new barrier for this channel to properly synchronize with // the peer's readHandler once the channel is open. fmsg.peer.barrierInits <- *outPoint fndgLog.Infof("Generated ChannelPoint(%v) for pendingID(%v)", outPoint, msg.ChannelID) revocationKey := resCtx.reservation.OurContribution().RevocationKey fundingComplete := lnwire.NewSingleFundingComplete(msg.ChannelID, outPoint, commitSig, revocationKey) sourcePeer.queueMsg(fundingComplete, nil) }
// This example demonstrates encrypting a message for a public key that is first // parsed from raw bytes, then decrypting it using the corresponding private key. func Example_encryptMessage() { // Decode the hex-encoded pubkey of the recipient. pubKeyBytes, err := hex.DecodeString("04115c42e757b2efb7671c578530ec191a1" + "359381e6a71127a9d37c486fd30dae57e76dc58f693bd7e7010358ce6b165e483a29" + "21010db67ac11b1b51b651953d2") // uncompressed pubkey if err != nil { fmt.Println(err) return } pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256()) if err != nil { fmt.Println(err) return } // Encrypt a message decryptable by the private key corresponding to pubKey message := "test message" ciphertext, err := btcec.Encrypt(pubKey, []byte(message)) if err != nil { fmt.Println(err) return } // Decode the hex-encoded private key. pkBytes, err := hex.DecodeString("a11b0a4e1a132305652ee7a8eb7848f6ad" + "5ea381e3ce20a2c086a2e388230811") if err != nil { fmt.Println(err) return } // note that we already have corresponding pubKey privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes) // Try decrypting and verify if it's the same message. plaintext, err := btcec.Decrypt(privKey, ciphertext) if err != nil { fmt.Println(err) return } fmt.Println(string(plaintext)) // Output: // test message }
// makeTestOutput creates an on-chain output paying to a freshly generated // p2pkh output with the specified amount. func makeTestOutput(r *rpctest.Harness, t *testing.T, amt btcutil.Amount) (*btcec.PrivateKey, *wire.OutPoint, []byte, error) { // Create a fresh key, then send some coins to an address spendable by // that key. key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { return nil, nil, nil, err } // Using the key created above, generate a pkScript which it's able to // spend. a, err := btcutil.NewAddressPubKey(key.PubKey().SerializeCompressed(), r.ActiveNet) if err != nil { return nil, nil, nil, err } selfAddrScript, err := txscript.PayToAddrScript(a.AddressPubKeyHash()) if err != nil { return nil, nil, nil, err } output := &wire.TxOut{PkScript: selfAddrScript, Value: 1e8} // Next, create and broadcast a transaction paying to the output. fundTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) if err != nil { return nil, nil, nil, err } txHash, err := r.Node.SendRawTransaction(fundTx, true) if err != nil { return nil, nil, nil, err } // The transaction created above should be included within the next // generated block. blockHash, err := r.Node.Generate(1) if err != nil { return nil, nil, nil, err } assertTxInBlock(r, t, blockHash[0], txHash) // Locate the output index of the coins spendable by the key we // generated above, this is needed in order to create a proper utxo for // this output. var outputIndex uint32 if bytes.Equal(fundTx.TxOut[0].PkScript, selfAddrScript) { outputIndex = 0 } else { outputIndex = 1 } utxo := &wire.OutPoint{ Hash: fundTx.TxHash(), Index: outputIndex, } return key, utxo, selfAddrScript, nil }
// OpenChannel attempts to open a singly funded channel specified in the // request to a remote peer. func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest, updateStream lnrpc.Lightning_OpenChannelServer) error { rpcsLog.Tracef("[openchannel] request to peerid(%v) "+ "allocation(us=%v, them=%v) numconfs=%v", in.TargetPeerId, in.LocalFundingAmount, in.RemoteFundingAmount, in.NumConfs) localFundingAmt := btcutil.Amount(in.LocalFundingAmount) remoteFundingAmt := btcutil.Amount(in.RemoteFundingAmount) nodepubKey, err := btcec.ParsePubKey(in.NodePubkey, btcec.S256()) if err != nil { return err } updateChan, errChan := r.server.OpenChannel(in.TargetPeerId, nodepubKey, localFundingAmt, remoteFundingAmt, in.NumConfs) var outpoint wire.OutPoint out: for { select { case err := <-errChan: rpcsLog.Errorf("unable to open channel to "+ "identityPub(%x) nor peerID(%v): %v", nodepubKey, in.TargetPeerId, err) return err case fundingUpdate := <-updateChan: rpcsLog.Tracef("[openchannel] sending update: %v", fundingUpdate) if err := updateStream.Send(fundingUpdate); err != nil { return err } // If a final channel open update is being sent, then // we can break out of our recv loop as we no longer // need to process any further updates. switch update := fundingUpdate.Update.(type) { case *lnrpc.OpenStatusUpdate_ChanOpen: chanPoint := update.ChanOpen.ChannelPoint h, _ := wire.NewShaHash(chanPoint.FundingTxid) outpoint = wire.OutPoint{ Hash: *h, Index: chanPoint.OutputIndex, } break out } case <-r.quit: return nil } } rpcsLog.Tracef("[openchannel] success peerid(%v), ChannelPoint(%v)", in.TargetPeerId, outpoint) return nil }
// TestSigCacheAddExists tests the ability to add, and later check the // existence of a signature triplet in the signature cache. func TestSigCacheAddExists(t *testing.T) { sigCache := NewSigCache(200) // Generate a random sigCache entry triplet. msg1, sig1, key1, err := genRandomSig() if err != nil { t.Errorf("unable to generate random signature test data") } // Add the triplet to the signature cache. sigCache.Add(*msg1, sig1, key1) // The previously added triplet should now be found within the sigcache. sig1Copy, _ := btcec.ParseSignature(sig1.Serialize(), btcec.S256()) key1Copy, _ := btcec.ParsePubKey(key1.SerializeCompressed(), btcec.S256()) if !sigCache.Exists(*msg1, sig1Copy, key1Copy) { t.Errorf("previously added item not found in signature cache") } }
// DeriveRevocationPrivKey derives the revocation private key given a node's // commitment private key, and the pre-image to a previously seen revocation // hash. Using this derived private key, a node is able to claim the output // within the commitment transaction of a node in the case that they broadcast // a previously revoked commitment transaction. // // The private key is derived as follwos: // revokePriv := commitPriv + revokePreimage mod N // // Where N is the order of the sub-group. func DeriveRevocationPrivKey(commitPrivKey *btcec.PrivateKey, revokePreimage []byte) *btcec.PrivateKey { // Convert the revocation pre-image into a scalar value so we can // manipulate it within the curve's defined finite field. revokeScalar := new(big.Int).SetBytes(revokePreimage) // To derive the revocation private key, we simply add the revocation // pre-image to the commitment private key. // // This works since: // P = G*a + G*b // = G*(a+b) // = G*p revokePriv := revokeScalar.Add(revokeScalar, commitPrivKey.D) revokePriv = revokePriv.Mod(revokePriv, btcec.S256().N) privRevoke, _ := btcec.PrivKeyFromBytes(btcec.S256(), revokePriv.Bytes()) return privRevoke }
func main() { fi, err := os.Create("secp256k1.go") if err != nil { log.Fatal(err) } defer fi.Close() // Compress the serialized byte points. serialized := btcec.S256().SerializedBytePoints() var compressed bytes.Buffer w := zlib.NewWriter(&compressed) if _, err := w.Write(serialized); err != nil { fmt.Println(err) os.Exit(1) } w.Close() // Encode the compressed byte points with base64. encoded := make([]byte, base64.StdEncoding.EncodedLen(compressed.Len())) base64.StdEncoding.Encode(encoded, compressed.Bytes()) fmt.Fprintln(fi, "// Copyright (c) 2015 The btcsuite developers") fmt.Fprintln(fi, "// Use of this source code is governed by an ISC") fmt.Fprintln(fi, "// license that can be found in the LICENSE file.") fmt.Fprintln(fi) fmt.Fprintln(fi, "package btcec") fmt.Fprintln(fi) fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)") fmt.Fprintln(fi, "// DO NOT EDIT") fmt.Fprintln(fi) fmt.Fprintf(fi, "var secp256k1BytePoints = %q\n", string(encoded)) a1, b1, a2, b2 := btcec.S256().EndomorphismVectors() fmt.Println("The following values are the computed linearly " + "independent vectors needed to make use of the secp256k1 " + "endomorphism:") fmt.Printf("a1: %x\n", a1) fmt.Printf("b1: %x\n", b1) fmt.Printf("a2: %x\n", a2) fmt.Printf("b2: %x\n", b2) }
// TestRevocationKeyDerivation tests that given a public key, and a revocation // hash, the homomorphic revocation public and private key derivation work // properly. func TestRevocationKeyDerivation(t *testing.T) { revocationPreimage := testHdSeed[:] priv, pub := btcec.PrivKeyFromBytes(btcec.S256(), testWalletPrivKey) revocationPub := DeriveRevocationPubkey(pub, revocationPreimage) revocationPriv := DeriveRevocationPrivKey(priv, revocationPreimage) x, y := btcec.S256().ScalarBaseMult(revocationPriv.D.Bytes()) derivedRevPub := &btcec.PublicKey{ Curve: btcec.S256(), X: x, Y: y, } // The the revocation public key derived from the original public key, // and the one derived from the private key should be identical. if !revocationPub.IsEqual(derivedRevPub) { t.Fatalf("derived public keys don't match!") } }
func newTestRoute(numHops int) ([]*Router, *OnionPacket, error) { nodes := make([]*Router, numHops) // Create numMaxHops random sphinx nodes. for i := 0; i < len(nodes); i++ { privKey, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { return nil, nil, fmt.Errorf("Unable to generate random "+ "key for sphinx node: %v", err) } nodes[i] = NewRouter(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].onionKey.PubKey() } var hopPayloads [][]byte for i := 0; i < len(nodes); i++ { payload := bytes.Repeat([]byte{byte('A' + i)}, HopPayloadSize) hopPayloads = append(hopPayloads, payload) } // 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. sessionKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), bytes.Repeat([]byte{'A'}, 32)) fwdMsg, err := NewOnionPacket(route, sessionKey, hopPayloads, nil) if err != nil { return nil, nil, fmt.Errorf("Unable to create forwarding "+ "message: %#v", err) } return nodes, fwdMsg, nil }
// This example demonstrates verifying a secp256k1 signature against a public // key that is first parsed from raw bytes. The signature is also parsed from // raw bytes. func Example_verifySignature() { // Decode hex-encoded serialized public key. pubKeyBytes, err := hex.DecodeString("02a673638cb9587cb68ea08dbef685c" + "6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5") if err != nil { fmt.Println(err) return } pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256()) if err != nil { fmt.Println(err) return } // Decode hex-encoded serialized signature. sigBytes, err := hex.DecodeString("30450220090ebfb3690a0ff115bb1b38b" + "8b323a667b7653454f1bccb06d4bbdca42c2079022100ec95778b51e707" + "1cb1205f8bde9af6592fc978b0452dafe599481c46d6b2e479") if err != nil { fmt.Println(err) return } signature, err := btcec.ParseSignature(sigBytes, btcec.S256()) if err != nil { fmt.Println(err) return } // Verify the signature for the message using the public key. message := "test message" messageHash := chainhash.DoubleHashB([]byte(message)) verified := signature.Verify(messageHash, pubKey) fmt.Println("Signature Verified?", verified) // Output: // Signature Verified? true }
// handleFundingComplete progresses the funding workflow when the daemon is on // the responding side of a single funder workflow. Once this message has been // processed, a signature is sent to the remote peer allowing it to broadcast // the funding transaction, progressing the workflow into the final stage. func (f *fundingManager) handleFundingComplete(fmsg *fundingCompleteMsg) { f.resMtx.RLock() resCtx := f.activeReservations[fmsg.peer.id][fmsg.msg.ChannelID] f.resMtx.RUnlock() // The channel initiator has responded with the funding outpoint of the // final funding transaction, as well as a signature for our version of // the commitment transaction. So at this point, we can validate the // inititator's commitment transaction, then send our own if it's valid. // TODO(roasbeef): make case (p vs P) consistent throughout fundingOut := fmsg.msg.FundingOutPoint chanID := fmsg.msg.ChannelID commitSig := fmsg.msg.CommitSignature.Serialize() fndgLog.Infof("completing pendingID(%v) with ChannelPoint(%v)", fmsg.msg.ChannelID, fundingOut, ) // Append a sighash type of SigHashAll to the signature as it's the // sighash type used implicitly within this type of channel for // commitment transactions. revokeKey := fmsg.msg.RevocationKey if err := resCtx.reservation.CompleteReservationSingle(revokeKey, fundingOut, commitSig); err != nil { // TODO(roasbeef): better error logging: peerID, channelID, etc. fndgLog.Errorf("unable to complete single reservation: %v", err) fmsg.peer.Disconnect() return } // With their signature for our version of the commitment transaction // verified, we can now send over our signature to the remote peer. // TODO(roasbeef): just have raw bytes in wire msg? avoids decoding // then decoding shortly afterwards. _, sig := resCtx.reservation.OurSignatures() ourCommitSig, err := btcec.ParseSignature(sig, btcec.S256()) if err != nil { fndgLog.Errorf("unable to parse signature: %v", err) return } // Register a new barrier for this channel to properly synchronize with // the peer's readHandler once the channel is open. fmsg.peer.barrierInits <- *fundingOut fndgLog.Infof("sending signComplete for pendingID(%v) over ChannelPoint(%v)", fmsg.msg.ChannelID, fundingOut) signComplete := lnwire.NewSingleFundingSignComplete(chanID, ourCommitSig) fmsg.peer.queueMsg(signComplete, nil) }
func deserializeLinkNode(r io.Reader) (*LinkNode, error) { var ( err error buf [8]byte ) node := &LinkNode{} if _, err := io.ReadFull(r, buf[:4]); err != nil { return nil, err } node.Network = wire.BitcoinNet(byteOrder.Uint32(buf[:4])) var pub [33]byte if _, err := io.ReadFull(r, pub[:]); err != nil { return nil, err } node.IdentityPub, err = btcec.ParsePubKey(pub[:], btcec.S256()) if err != nil { return nil, err } if _, err := io.ReadFull(r, buf[:]); err != nil { return nil, err } node.LastSeen = time.Unix(int64(byteOrder.Uint64(buf[:])), 0) if _, err := io.ReadFull(r, buf[:4]); err != nil { return nil, err } numAddrs := byteOrder.Uint32(buf[:4]) node.Addresses = make([]*net.TCPAddr, numAddrs) for i := uint32(0); i < numAddrs; i++ { addrString, err := wire.ReadVarString(r, 0) if err != nil { return nil, err } addr, err := net.ResolveTCPAddr("tcp", addrString) if err != nil { return nil, err } node.Addresses[i] = addr } return node, nil }