mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
lightningd: add checkmessage JSON command.
I wanted to call it verifymessage, but then I read the LND API for that and wanted nothing to do with it! Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
neil saitug
parent
b81ed5be86
commit
1f0b86e575
@@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- JSON API: `listfunds` now lists a blockheight for confirmed transactions, and has `connected` and `state` fields for channels, like `listpeers`.
|
- JSON API: `listfunds` now lists a blockheight for confirmed transactions, and has `connected` and `state` fields for channels, like `listpeers`.
|
||||||
- JSON API: `fundchannel_start` now includes field `scriptpubkey`
|
- JSON API: `fundchannel_start` now includes field `scriptpubkey`
|
||||||
- JSON API: New method `listtransactions`
|
- JSON API: New method `listtransactions`
|
||||||
- JSON API: `signmessage` will now create a signature from your node on a message.
|
- JSON API: `signmessage` will now create a signature from your node on a message; `checkmessage` will verify it.
|
||||||
- Plugin: new notifications `sendpay_success` and `sendpay_failure`.
|
- Plugin: new notifications `sendpay_success` and `sendpay_failure`.
|
||||||
- Protocol: nodes now announce features in `node_announcement` broadcasts.
|
- Protocol: nodes now announce features in `node_announcement` broadcasts.
|
||||||
- Protocol: we now offer `option_gossip_queries_ex` for finegrained gossip control.
|
- Protocol: we now offer `option_gossip_queries_ex` for finegrained gossip control.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <common/bech32.h>
|
#include <common/bech32.h>
|
||||||
|
#include <common/hash_u5.h>
|
||||||
#include <common/json_helpers.h>
|
#include <common/json_helpers.h>
|
||||||
#include <common/jsonrpc_errors.h>
|
#include <common/jsonrpc_errors.h>
|
||||||
#include <common/param.h>
|
#include <common/param.h>
|
||||||
@@ -20,6 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
static const char*const zbase32_chars="ybndrfg8ejkmcpqxot1uwisza345h769";
|
static const char*const zbase32_chars="ybndrfg8ejkmcpqxot1uwisza345h769";
|
||||||
|
|
||||||
|
/* revchars: index into this table with the ASCII value of the char. The result is the value of that quintet. */
|
||||||
|
static const u8 zbase32_revchars[]={ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 18, 255, 25, 26, 27, 30, 29, 7, 31, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 24, 1, 12, 3, 8, 5, 6, 28, 21, 9, 10, 255, 11, 2, 16, 13, 14, 4, 22, 17, 19, 255, 20, 15, 0, 23, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, };
|
||||||
|
|
||||||
static const char *to_zbase32(const tal_t *ctx, const u8 *msg, size_t srclen)
|
static const char *to_zbase32(const tal_t *ctx, const u8 *msg, size_t srclen)
|
||||||
{
|
{
|
||||||
size_t outlen;
|
size_t outlen;
|
||||||
@@ -35,6 +39,28 @@ static const char *to_zbase32(const tal_t *ctx, const u8 *msg, size_t srclen)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const u8 *from_zbase32(const tal_t *ctx, const char *msg)
|
||||||
|
{
|
||||||
|
u5 *u5arr;
|
||||||
|
u8 *u8arr;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
u5arr = tal_arr(tmpctx, u5, strlen(msg));
|
||||||
|
for (size_t i = 0; i < tal_bytelen(u5arr); i++) {
|
||||||
|
u5arr[i] = zbase32_revchars[(unsigned char)msg[i]];
|
||||||
|
if (u5arr[i] > 31)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8arr = tal_arr(ctx, u8, (tal_bytelen(u5arr) * 5 + 7) / 8);
|
||||||
|
len = 0;
|
||||||
|
if (!bech32_convert_bits(u8arr, &len, 8,
|
||||||
|
u5arr, tal_bytelen(u5arr), 5, false))
|
||||||
|
return tal_free(u8arr);
|
||||||
|
assert(len == tal_bytelen(u8arr));
|
||||||
|
return u8arr;
|
||||||
|
}
|
||||||
|
|
||||||
static struct command_result *json_signmessage(struct command *cmd,
|
static struct command_result *json_signmessage(struct command *cmd,
|
||||||
const char *buffer,
|
const char *buffer,
|
||||||
const jsmntok_t *obj UNNEEDED,
|
const jsmntok_t *obj UNNEEDED,
|
||||||
@@ -94,3 +120,63 @@ static const struct json_command json_signmessage_cmd = {
|
|||||||
};
|
};
|
||||||
AUTODATA(json_command, &json_signmessage_cmd);
|
AUTODATA(json_command, &json_signmessage_cmd);
|
||||||
|
|
||||||
|
static struct command_result *json_checkmessage(struct command *cmd,
|
||||||
|
const char *buffer,
|
||||||
|
const jsmntok_t *obj UNNEEDED,
|
||||||
|
const jsmntok_t *params)
|
||||||
|
{
|
||||||
|
struct pubkey *pubkey, reckey;
|
||||||
|
const u8 *u8sig;
|
||||||
|
const char *message, *zb;
|
||||||
|
secp256k1_ecdsa_recoverable_signature rsig;
|
||||||
|
struct sha256_ctx sctx = SHA256_INIT;
|
||||||
|
struct sha256_double shad;
|
||||||
|
struct json_stream *response;
|
||||||
|
|
||||||
|
if (!param(cmd, buffer, params,
|
||||||
|
p_req("message", param_string, &message),
|
||||||
|
p_req("zbase", param_string, &zb),
|
||||||
|
p_req("pubkey", param_pubkey, &pubkey),
|
||||||
|
NULL))
|
||||||
|
return command_param_failed();
|
||||||
|
|
||||||
|
u8sig = from_zbase32(tmpctx, zb);
|
||||||
|
if (!u8sig)
|
||||||
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||||
|
"zbase is not valid zbase32");
|
||||||
|
|
||||||
|
if (tal_bytelen(u8sig) != 65)
|
||||||
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||||
|
"zbase is too %s",
|
||||||
|
tal_bytelen(u8sig) < 65 ? "short" : "long");
|
||||||
|
|
||||||
|
if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_ctx,
|
||||||
|
&rsig,
|
||||||
|
u8sig + 1,
|
||||||
|
u8sig[0] - 31))
|
||||||
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||||
|
"cannot parse zbase signature");
|
||||||
|
|
||||||
|
sha256_update(&sctx, "Lightning Signed Message:",
|
||||||
|
strlen("Lightning Signed Message:"));
|
||||||
|
sha256_update(&sctx, message, strlen(message));
|
||||||
|
sha256_double_done(&sctx, &shad);
|
||||||
|
|
||||||
|
response = json_stream_success(cmd);
|
||||||
|
if (!secp256k1_ecdsa_recover(secp256k1_ctx, &reckey.pubkey, &rsig,
|
||||||
|
shad.sha.u.u8)) {
|
||||||
|
json_add_bool(response, "verified", false);
|
||||||
|
} else {
|
||||||
|
json_add_bool(response, "verified", pubkey_eq(pubkey, &reckey));
|
||||||
|
}
|
||||||
|
return command_success(cmd, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct json_command json_checkmessage_cmd = {
|
||||||
|
"checkmessage",
|
||||||
|
"utility",
|
||||||
|
json_checkmessage,
|
||||||
|
"Verify a digital signature {zbase} of {message} signed with {pubkey}",
|
||||||
|
};
|
||||||
|
AUTODATA(json_command, &json_checkmessage_cmd);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user