lncli: add sign/verify message with an address

adds the functionality in the lncli walletkit to sign and verify a
message with a single address. Signing works only with lnd default
wallet account. Verifying signature on messages with external addresses
is also supported.
This commit is contained in:
ziggie 2022-12-03 16:44:43 +01:00
parent 39b77edca1
commit 5edf64f4c5
No known key found for this signature in database
GPG Key ID: 1AFF9C4DCED6D666

View File

@ -52,6 +52,8 @@ var (
Usage: "Interact with wallet addresses.", Usage: "Interact with wallet addresses.",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
listAddressesCommand, listAddressesCommand,
signMessageWithAddrCommand,
verifyMessageWithAddrCommand,
}, },
} }
) )
@ -1193,6 +1195,200 @@ func listAddresses(ctx *cli.Context) error {
return nil return nil
} }
var signMessageWithAddrCommand = cli.Command{
Name: "signmessage",
Usage: "Sign a message with the private key of the provided " +
"address.",
ArgsUsage: "address msg",
Description: `
Sign a message with the private key of the specified address, and
return the signature. Signing is solely done in the ECDSA compact
signature format. This is also done when signing with a P2TR address
meaning that the private key of the P2TR address (internal key) is used
to sign the provided message with the ECDSA format. Only addresses are
accepted which are owned by the internal lnd wallet.
`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "address",
Usage: "specify the address which private key " +
"will be used to sign the message",
},
cli.StringFlag{
Name: "msg",
Usage: "the message to sign for",
},
},
Action: actionDecorator(signMessageWithAddr),
}
func signMessageWithAddr(ctx *cli.Context) error {
ctxc := getContext()
// Display the command's help message if we do not have the expected
// number of arguments/flags.
if ctx.NArg() > 2 || ctx.NumFlags() > 2 {
return cli.ShowCommandHelp(ctx, "signmessagewithaddr")
}
walletClient, cleanUp := getWalletClient(ctx)
defer cleanUp()
var (
args = ctx.Args()
addr string
msg []byte
)
switch {
case ctx.IsSet("address"):
addr = ctx.String("address")
case ctx.Args().Present():
addr = args.First()
args = args.Tail()
default:
return fmt.Errorf("address argument missing")
}
switch {
case ctx.IsSet("msg"):
msg = []byte(ctx.String("msg"))
case ctx.Args().Present():
msg = []byte(args.First())
args = args.Tail()
default:
return fmt.Errorf("msg argument missing")
}
resp, err := walletClient.SignMessageWithAddr(
ctxc,
&walletrpc.SignMessageWithAddrRequest{
Msg: msg,
Addr: addr,
},
)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}
var verifyMessageWithAddrCommand = cli.Command{
Name: "verifymessage",
Usage: "Verify a message signed with the private key of the " +
"provided address.",
ArgsUsage: "address sig msg",
Description: `
Verify a message signed with the signature of the public key
of the provided address. The signature must be in compact ECDSA format
The verification is independent whether the address belongs to the
wallet or not. This is achieved by only accepting ECDSA compacted
signatures. When verifying a signature with a taproot address, the
signature still has to be in the ECDSA compact format and no tapscript
has to be included in the P2TR address.
Supports address types P2PKH, P2WKH, NP2WKH, P2TR.
Besides whether the signature is valid or not, the recoverd public key
of the compact ECDSA signature is returned.
`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "address",
Usage: "specify the address which corresponding" +
"public key will be used",
},
cli.StringFlag{
Name: "sig",
Usage: "the base64 encoded compact signature " +
"of the message",
},
cli.StringFlag{
Name: "msg",
Usage: "the message to sign",
},
},
Action: actionDecorator(verifyMessageWithAddr),
}
func verifyMessageWithAddr(ctx *cli.Context) error {
ctxc := getContext()
// Display the command's help message if we do not have the expected
// number of arguments/flags.
if ctx.NArg() > 3 || ctx.NumFlags() > 3 {
return cli.ShowCommandHelp(ctx, "signmessagewithaddr")
}
walletClient, cleanUp := getWalletClient(ctx)
defer cleanUp()
var (
args = ctx.Args()
addr string
sig string
msg []byte
)
switch {
case ctx.IsSet("address"):
addr = ctx.String("address")
case args.Present():
addr = args.First()
args = args.Tail()
default:
return fmt.Errorf("address argument missing")
}
switch {
case ctx.IsSet("sig"):
sig = ctx.String("sig")
case ctx.Args().Present():
sig = args.First()
args = args.Tail()
default:
return fmt.Errorf("sig argument missing")
}
switch {
case ctx.IsSet("msg"):
msg = []byte(ctx.String("msg"))
case ctx.Args().Present():
msg = []byte(args.First())
args = args.Tail()
default:
return fmt.Errorf("msg argument missing")
}
resp, err := walletClient.VerifyMessageWithAddr(
ctxc,
&walletrpc.VerifyMessageWithAddrRequest{
Msg: msg,
Signature: sig,
Addr: addr,
},
)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}
var importAccountCommand = cli.Command{ var importAccountCommand = cli.Command{
Name: "import", Name: "import",
Usage: "Import an on-chain account into the wallet through its " + Usage: "Import an on-chain account into the wallet through its " +