Skip to content

Commit c75f9ff

Browse files
authored
Merge pull request #121 from sputn1ck/signmessage
signmessage: add signmessage cmd
2 parents cf4cabb + 3fbf8d0 commit c75f9ff

File tree

6 files changed

+122
-0
lines changed

6 files changed

+122
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ Available Commands:
429429
rescuefunding Rescue funds locked in a funding multisig output that never resulted in a proper channel; this is the command the initiator of the channel needs to run
430430
rescuetweakedkey Attempt to rescue funds locked in an address with a key that was affected by a specific bug in lnd
431431
showrootkey Extract and show the BIP32 HD root key from the 24 word lnd aezeed
432+
signmessage Sign a message with the nodes identity pubkey.
432433
signrescuefunding Rescue funds locked in a funding multisig output that never resulted in a proper channel; this is the command the remote node (the non-initiator) of the channel needs to run
433434
summary Compile a summary about the current state of channels
434435
sweeptimelock Sweep the force-closed state after the time lock has expired
@@ -488,6 +489,7 @@ Legend:
488489
| [rescueclosed](doc/chantools_rescueclosed.md) | :pencil: (:pushpin:) Rescue funds in a legacy (pre `STATIC_REMOTE_KEY`) channel output |
489490
| [rescuefunding](doc/chantools_rescuefunding.md) | :pencil: (:pushpin:) Rescue funds from a funding transaction. Deprecated, use [zombierecovery](doc/chantools_zombierecovery.md) instead |
490491
| [showrootkey](doc/chantools_showrootkey.md) | :pencil: Display the master root key (`xprv`) from your seed (DO NOT SHARE WITH ANYONE) |
492+
| [signmessage](doc/chantools_signmessage.md) | :pencil: Sign a message with the nodes identity pubkey. |
491493
| [signrescuefunding](doc/chantools_signrescuefunding.md) | :pencil: (:pushpin:) Sign to funds from a funding transaction. Deprecated, use [zombierecovery](doc/chantools_zombierecovery.md) instead |
492494
| [summary](doc/chantools_summary.md) | Create a summary of channel funds from a `channel.db` file |
493495
| [sweepremoteclosed](doc/chantools_sweepremoteclosed.md) | :pencil: Find channel funds from remotely force closed channels and sweep them |

cmd/chantools/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ func main() {
123123
newRescueFundingCommand(),
124124
newRescueTweakedKeyCommand(),
125125
newShowRootKeyCommand(),
126+
newSignMessageCommand(),
126127
newSignRescueFundingCommand(),
127128
newSummaryCommand(),
128129
newSweepTimeLockCommand(),

cmd/chantools/signmessage.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
6+
chantools_lnd "github.com/lightninglabs/chantools/lnd"
7+
"github.com/lightningnetwork/lnd/keychain"
8+
"github.com/spf13/cobra"
9+
"github.com/tv42/zbase32"
10+
)
11+
12+
var (
13+
signedMsgPrefix = []byte("Lightning Signed Message:")
14+
)
15+
16+
type signMessageCommand struct {
17+
Msg string
18+
19+
rootKey *rootKey
20+
cmd *cobra.Command
21+
}
22+
23+
func newSignMessageCommand() *cobra.Command {
24+
cc := &signMessageCommand{}
25+
cc.cmd = &cobra.Command{
26+
Use: "signmessage",
27+
Short: "Sign a message with the node's private key.",
28+
Long: `Sign msg with the resident node's private key.
29+
Returns the signature as a zbase32 string.`,
30+
Example: `chantools signmessage --msg=foobar`,
31+
RunE: cc.Execute,
32+
}
33+
cc.cmd.Flags().StringVar(
34+
&cc.Msg, "msg", "", "the message to sign",
35+
)
36+
37+
cc.rootKey = newRootKey(cc.cmd, "decrypting the backup")
38+
39+
return cc.cmd
40+
}
41+
42+
func (c *signMessageCommand) Execute(_ *cobra.Command, _ []string) error {
43+
if c.Msg == "" {
44+
return fmt.Errorf("please enter a valid msg")
45+
}
46+
47+
extendedKey, err := c.rootKey.read()
48+
if err != nil {
49+
return fmt.Errorf("error reading root key: %w", err)
50+
}
51+
52+
signer := &chantools_lnd.Signer{
53+
ExtendedKey: extendedKey,
54+
ChainParams: chainParams,
55+
}
56+
57+
// Create the key locator for the node key.
58+
keyLocator := keychain.KeyLocator{
59+
Family: keychain.KeyFamilyNodeKey,
60+
Index: 0,
61+
}
62+
63+
// Fetch the private key for node key.
64+
privKey, err := signer.FetchPrivKey(&keychain.KeyDescriptor{
65+
KeyLocator: keyLocator,
66+
})
67+
if err != nil {
68+
return err
69+
}
70+
71+
// Create a new signer.
72+
privKeyMsgSigner := keychain.NewPrivKeyMessageSigner(
73+
privKey, keyLocator,
74+
)
75+
76+
// Prepend the special lnd prefix.
77+
// See: https://github.com/lightningnetwork/lnd/blob/63e698ec4990e678089533561fd95cfd684b67db/rpcserver.go#L1576 .
78+
msg := []byte(c.Msg)
79+
msg = append(signedMsgPrefix, msg...)
80+
sigBytes, err := privKeyMsgSigner.SignMessageCompact(msg, true)
81+
if err != nil {
82+
return err
83+
}
84+
85+
// Encode the signature.
86+
sig := zbase32.EncodeToString(sigBytes)
87+
fmt.Println(sig)
88+
89+
return nil
90+
}

doc/chantools_signmessage.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
## chantools signmessage
2+
3+
Signs a message with the nodes key, results in the same signature as
4+
`lncli signmessage`
5+
6+
### Synopsis
7+
8+
```
9+
chantools signmessage [flags]
10+
```
11+
12+
### Examples
13+
14+
```
15+
chantools signmessage --msg=foobar
16+
```
17+
18+
### Options
19+
20+
```
21+
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
22+
-h, --help help for signmessage
23+
--msg string the message to sign
24+
--rootkey string BIP32 HD root key of the wallet to use for decrypting the backup; leave empty to prompt for lnd 24 word aezeed
25+
--single_hash single hash the msg instead of double hash (lnd default is false)
26+
```

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ require (
126126
github.com/stretchr/objx v0.5.0 // indirect
127127
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
128128
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
129+
github.com/tv42/zbase32 v0.0.0-20220222190657-f76a9fc892fa // indirect
129130
github.com/ulikunitz/xz v0.5.11 // indirect
130131
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
131132
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45
686686
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
687687
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA=
688688
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
689+
github.com/tv42/zbase32 v0.0.0-20220222190657-f76a9fc892fa h1:2EwhXkNkeMjX9iFYGWLPQLPhw9O58BhnYgtYKeqybcY=
690+
github.com/tv42/zbase32 v0.0.0-20220222190657-f76a9fc892fa/go.mod h1:is48sjgBanWcA5CQrPBu9Y5yABY/T2awj/zI65bq704=
689691
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
690692
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
691693
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=

0 commit comments

Comments
 (0)