@ledgerhq/hw-app-btc
Version:
Ledger Hardware Wallet Bitcoin Application API
67 lines (58 loc) • 1.76 kB
text/typescript
import type Transport from "@ledgerhq/hw-transport";
import bippath from "bip32-path";
import { MAX_SCRIPT_BLOCK } from "./constants";
export async function signMessage(
transport: Transport,
{
path,
messageHex,
}: {
path: string;
messageHex: string;
},
): Promise<{
v: number;
r: string;
s: string;
}> {
const paths = bippath.fromString(path).toPathArray();
const message = Buffer.from(messageHex, "hex");
let offset = 0;
while (offset !== message.length) {
const maxChunkSize =
offset === 0 ? MAX_SCRIPT_BLOCK - 1 - paths.length * 4 - 4 : MAX_SCRIPT_BLOCK;
const chunkSize =
offset + maxChunkSize > message.length ? message.length - offset : maxChunkSize;
const buffer = Buffer.alloc(offset === 0 ? 1 + paths.length * 4 + 2 + chunkSize : chunkSize);
if (offset === 0) {
buffer[0] = paths.length;
paths.forEach((element, index) => {
buffer.writeUInt32BE(element, 1 + 4 * index);
});
buffer.writeUInt16BE(message.length, 1 + 4 * paths.length);
message.copy(buffer, 1 + 4 * paths.length + 2, offset, offset + chunkSize);
} else {
message.copy(buffer, 0, offset, offset + chunkSize);
}
await transport.send(0xe0, 0x4e, 0x00, offset === 0 ? 0x01 : 0x80, buffer);
offset += chunkSize;
}
const res = await transport.send(0xe0, 0x4e, 0x80, 0x00, Buffer.from([0x00]));
const v = res[0] - 0x30;
let r: Buffer | string = res.slice(4, 4 + res[3]);
if (r[0] === 0) {
r = r.slice(1);
}
r = r.toString("hex");
offset = 4 + res[3] + 2;
let s: Buffer | string = res.slice(offset, offset + res[offset - 1]);
if (s[0] === 0) {
s = s.slice(1);
}
s = s.toString("hex");
return {
v,
r,
s,
};
}