UNPKG

@zondax/ledger-filecoin

Version:

Node API for Filecoin App (Ledger Nano S/X)

277 lines (218 loc) 9.17 kB
/* eslint-disable no-console */ import FilecoinApp from "index.js"; import TransportNodeHid from "@ledgerhq/hw-transport-node-hid"; import { expect, test } from "jest"; import secp256k1 from "secp256k1/elliptic"; import { ERROR_CODE, PKLEN } from "../src/common"; import { getDigest } from "./utils"; test("get version", async () => { const transport = await TransportNodeHid.create(); try { const app = new FilecoinApp(transport); const resp = await app.getVersion(); console.log(resp); expect(resp.return_code).toEqual(ERROR_CODE.NoError); expect(resp.error_message).toEqual("No errors"); expect(resp).toHaveProperty("test_mode"); expect(resp).toHaveProperty("major"); expect(resp).toHaveProperty("minor"); expect(resp).toHaveProperty("patch"); expect(resp.test_mode).toEqual(false); } finally { transport.close(); } }); test("getAddressAndPubKey", async () => { const transport = await TransportNodeHid.create(); try { const app = new FilecoinApp(transport); const path = "m/44'/461'/5'/0/3"; const resp = await app.getAddressAndPubKey(path); console.log(resp); expect(resp.return_code).toEqual(ERROR_CODE.NoError); expect(resp.error_message).toEqual("No errors"); expect(resp).toHaveProperty("addrByte"); expect(resp).toHaveProperty("addrString"); expect(resp).toHaveProperty("compressed_pk"); expect(resp.compressed_pk.length).toEqual(PKLEN); expect(resp.compressed_pk.toString("hex")).toEqual( "0425d0dbeedb2053e690a58e9456363158836b1361f30dba0332f440558fa803d056042b50d0e70e4a2940428e82c7cea54259d65254aed4663e4d0cffd649f4fb", ); expect(resp.addrString).toEqual("f1mk3zcefvlgpay4f32c5vmruk5gqig6dumc7pz6q"); } finally { transport.close(); } }); test("showAddressAndPubKey", async () => { // noinspection ES6ModulesDependencies jest.setTimeout(60000); const transport = await TransportNodeHid.create(); try { const app = new FilecoinApp(transport); const path = "m/44'/461'/5'/0/3"; const resp = await app.showAddressAndPubKey(path); console.log(resp); expect(resp.return_code).toEqual(0x9000); expect(resp.error_message).toEqual("No errors"); expect(resp).toHaveProperty("addrByte"); expect(resp).toHaveProperty("addrString"); expect(resp).toHaveProperty("compressed_pk"); expect(resp.compressed_pk.length).toEqual(PKLEN); expect(resp.compressed_pk.toString("hex")).toEqual( "0425d0dbeedb2053e690a58e9456363158836b1361f30dba0332f440558fa803d056042b50d0e70e4a2940428e82c7cea54259d65254aed4663e4d0cffd649f4fb", ); expect(resp.addrString).toEqual("f1mk3zcefvlgpay4f32c5vmruk5gqig6dumc7pz6q"); } finally { transport.close(); } }); test("getAddressAndPubKeyTestnet", async () => { // noinspection ES6ModulesDependencies jest.setTimeout(60000); const transport = await TransportNodeHid.create(); try { const app = new FilecoinApp(transport); const path = "m/44'/1'/0'/0/0"; const resp = await app.getAddressAndPubKey(path); console.log(resp); expect(resp.return_code).toEqual(0x9000); expect(resp.error_message).toEqual("No errors"); expect(resp).toHaveProperty("addrByte"); expect(resp).toHaveProperty("addrString"); expect(resp).toHaveProperty("compressed_pk"); expect(resp.compressed_pk.length).toEqual(PKLEN); expect(resp.compressed_pk.toString("hex")).toEqual( "0431fef770d890c1ee4f38efd0a24dfd5e2687416a3e7718035e380f0d0489ce176b91fba5c922bf5683e65df00a29df31c326c72160d0ece7c3a543dedfb605aa", ); expect(resp.addrString).toEqual("t156h5dzekdyhrusjrb3dhlpdhpi4vifduelwsr4y"); } finally { transport.close(); } }); test("appInfo", async () => { const transport = await TransportNodeHid.create(); try { const app = new FilecoinApp(transport); const resp = await app.appInfo(); console.log(resp); expect(resp.return_code).toEqual(ERROR_CODE.NoError); expect(resp.error_message).toEqual("No errors"); expect(resp).toHaveProperty("appName"); expect(resp).toHaveProperty("appVersion"); expect(resp).toHaveProperty("flagLen"); expect(resp).toHaveProperty("flagsValue"); expect(resp).toHaveProperty("flag_recovery"); expect(resp).toHaveProperty("flag_signed_mcu_code"); expect(resp).toHaveProperty("flag_onboarded"); expect(resp).toHaveProperty("flag_pin_validated"); } finally { transport.close(); } }); test("deviceInfo", async () => { const transport = await TransportNodeHid.create(); try { const app = new FilecoinApp(transport); const resp = await app.deviceInfo(); console.log(resp); expect(resp.return_code).toEqual(ERROR_CODE.NoError); expect(resp.error_message).toEqual("No errors"); expect(resp).toHaveProperty("targetId"); expect(resp).toHaveProperty("seVersion"); expect(resp).toHaveProperty("flag"); expect(resp).toHaveProperty("mcuVersion"); } finally { transport.close(); } }); test("sign_and_verify", async () => { // noinspection ES6ModulesDependencies jest.setTimeout(60000); const transport = await TransportNodeHid.create(); try { const app = new FilecoinApp(transport); // Derivation path. First 3 items are automatically hardened! const path = "m/44'/461'/0'/0/0"; const message = Buffer.from( "8a0058310396a1a3e4ea7a14d49985e661b22401d44fed402d1d0925b243c923589c0fbc7e32cd04e29ed78d15d37d3aaa3fe6da3358310386b454258c589475f7d16f5aac018a79f6c1169d20fc33921dd8b5ce1cac6c348f90a3603624f6aeb91b64518c2e80950144000186a01961a8430009c44200000040", "hex", ); const responsePk = await app.getAddressAndPubKey(path); const responseSign = await app.sign(path, message); expect(responsePk.return_code).toEqual(ERROR_CODE.NoError); expect(responsePk.error_message).toEqual("No errors"); expect(responseSign.return_code).toEqual(ERROR_CODE.NoError); expect(responseSign.error_message).toEqual("No errors"); // Calculate message digest const msgDigest = getDigest(message); // Check signature is valid const signatureDER = responseSign.signature_der; const signature = secp256k1.signatureImport(signatureDER); // Check compact signatures const sigBuf = Buffer.from(signature); const sigCompBuf = Buffer.from(responseSign.signature_compact.slice(0, 64)); expect(sigBuf).toEqual(sigCompBuf); const signatureOk = secp256k1.ecdsaVerify(signature, msgDigest, responsePk.compressed_pk); expect(signatureOk).toEqual(true); } finally { transport.close(); } }); test("sign_and_verify_testnet", async () => { // noinspection ES6ModulesDependencies jest.setTimeout(60000); const transport = await TransportNodeHid.create(); try { const app = new FilecoinApp(transport); // Derivation path. First 3 items are automatically hardened! const path = "m/44'/1'/0'/0/0"; const message = Buffer.from( "8a0055019f4c34943e4b92f4542bed08af54be955629fc6f5501ef8fd1e48a1e0f1a49310ec675bc677a3954147400430003e81903e84200014200010040", "hex", ); const responsePk = await app.getAddressAndPubKey(path); const responseSign = await app.sign(path, message); expect(responsePk.return_code).toEqual(ERROR_CODE.NoError); expect(responsePk.error_message).toEqual("No errors"); expect(responseSign.return_code).toEqual(ERROR_CODE.NoError); expect(responseSign.error_message).toEqual("No errors"); // Calculate message digest const msgDigest = getDigest(message); console.log(`Digest: ${msgDigest.toString("hex")}`); // Check signature is valid const signatureDER = responseSign.signature_der; const signature = secp256k1.signatureImport(signatureDER); console.log(`DER : ${responseSign.signature_der.toString("hex")}`); // Check compact signatures const sigBuf = Buffer.from(signature); const sigCompBuf = Buffer.from(responseSign.signature_compact.slice(0, 64)); console.log(`compact : ${Buffer.from(responseSign.signature_compact).toString("hex")}`); expect(sigBuf).toEqual(sigCompBuf); const signatureOk = secp256k1.ecdsaVerify(signature, msgDigest, responsePk.compressed_pk); expect(signatureOk).toEqual(true); console.log(`compact : ${responseSign.signature_compact.toString("base64")}`); // Prepare curl command } finally { transport.close(); } }); test("sign_invalid", async () => { // noinspection ES6ModulesDependencies jest.setTimeout(60000); const transport = await TransportNodeHid.create(); try { const app = new FilecoinApp(transport); const path = "m/44'/461'/0'/0/0"; let invalidMessage = Buffer.from( "88315501fd1d0f4dfcd7e99afcb99a8326b7dc459d32c6285501b882619d46558f3d9e316d11b48dcf211327025a0144000186a0430009c4430061a80040", "hex", ); invalidMessage += "1"; const responseSign = await app.sign(path, invalidMessage); console.log(responseSign); expect(responseSign.return_code).toEqual(0x6984); expect(responseSign.error_message).toEqual("Data is invalid : Unexpected data type"); } finally { transport.close(); } });