@hwlt/era-connect 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -14
- package/bch/package.json +6 -0
- package/cosmos/package.json +6 -0
- package/dist/bch-CK6dKGQA.d.ts +74 -0
- package/dist/bch-CpLACx0j.cjs +139 -0
- package/dist/bch-CpLACx0j.cjs.map +1 -0
- package/dist/bch-DHsIVJqK.d.cts +74 -0
- package/dist/bch-dMESlQfv.js +134 -0
- package/dist/bch-dMESlQfv.js.map +1 -0
- package/dist/bch.cjs +13 -0
- package/dist/bch.d.cts +26 -0
- package/dist/bch.d.ts +26 -0
- package/dist/bch.js +4 -0
- package/dist/{btc-VyJKXq7d.js → btc-BmVgvvBd.js} +17 -8
- package/dist/btc-BmVgvvBd.js.map +1 -0
- package/dist/{btc-Fr6Jz4Fi.cjs → btc-BxNww6kW.cjs} +20 -11
- package/dist/btc-BxNww6kW.cjs.map +1 -0
- package/dist/{btc-DfQ0q79G.d.ts → btc-uzt0uC-Q.d.ts} +15 -4
- package/dist/{btc-Dn6_Y12c.d.cts → btc-wogJ4INA.d.cts} +15 -4
- package/dist/btc.cjs +2 -2
- package/dist/btc.d.cts +1 -1
- package/dist/btc.d.ts +1 -1
- package/dist/btc.js +2 -2
- package/dist/{cardano-yuOygqwp.js → cardano-BCT55gwf.js} +3 -2
- package/dist/{cardano-yuOygqwp.js.map → cardano-BCT55gwf.js.map} +1 -1
- package/dist/{cardano-DP6U_K1J.cjs → cardano-CzYswGzK.cjs} +5 -4
- package/dist/{cardano-DP6U_K1J.cjs.map → cardano-CzYswGzK.cjs.map} +1 -1
- package/dist/cardano.cjs +2 -2
- package/dist/cardano.js +2 -2
- package/dist/cashaddr-BIzawizX.js +134 -0
- package/dist/cashaddr-BIzawizX.js.map +1 -0
- package/dist/cashaddr-Ci0_8ITN.cjs +151 -0
- package/dist/cashaddr-Ci0_8ITN.cjs.map +1 -0
- package/dist/cosmos-BYrhIqRk.d.cts +77 -0
- package/dist/cosmos-DDsgtUki.cjs +113 -0
- package/dist/cosmos-DDsgtUki.cjs.map +1 -0
- package/dist/cosmos-DqyjA6lg.d.ts +77 -0
- package/dist/cosmos-jUHNxgWC.js +102 -0
- package/dist/cosmos-jUHNxgWC.js.map +1 -0
- package/dist/cosmos.cjs +10 -0
- package/dist/cosmos.d.cts +3 -0
- package/dist/cosmos.d.ts +3 -0
- package/dist/cosmos.js +3 -0
- package/dist/{derive-C4JdycUh.js → derive-00JUOkmn.js} +14 -3
- package/dist/derive-00JUOkmn.js.map +1 -0
- package/dist/{derive-CuILJRPT.cjs → derive-BuNsfWlg.cjs} +25 -2
- package/dist/derive-BuNsfWlg.cjs.map +1 -0
- package/dist/{evm-kJb3-oiR.js → evm-CI1cuZsp.js} +3 -2
- package/dist/{evm-kJb3-oiR.js.map → evm-CI1cuZsp.js.map} +1 -1
- package/dist/{evm-BHj_2OTG.cjs → evm-yfKOc2dy.cjs} +6 -5
- package/dist/{evm-BHj_2OTG.cjs.map → evm-yfKOc2dy.cjs.map} +1 -1
- package/dist/evm.cjs +2 -2
- package/dist/evm.js +2 -2
- package/dist/gzip-CLzDX7AZ.cjs +79 -0
- package/dist/gzip-CLzDX7AZ.cjs.map +1 -0
- package/dist/gzip-DyZLtgJJ.js +68 -0
- package/dist/gzip-DyZLtgJJ.js.map +1 -0
- package/dist/index.cjs +120 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -3
- package/dist/index.d.ts +50 -3
- package/dist/index.js +90 -9
- package/dist/index.js.map +1 -1
- package/dist/keypath-Bvv_cfHt.js +75 -0
- package/dist/keypath-Bvv_cfHt.js.map +1 -0
- package/dist/keypath-pzm_YIfN.cjs +116 -0
- package/dist/keypath-pzm_YIfN.cjs.map +1 -0
- package/dist/{messages-17Oup0-Z.js → messages--XbVef_k.js} +39 -3
- package/dist/messages--XbVef_k.js.map +1 -0
- package/dist/{messages-BzcdWlg1.cjs → messages-orAQ52CI.cjs} +44 -2
- package/dist/messages-orAQ52CI.cjs.map +1 -0
- package/dist/{shared-B8Wc7ViU.js → shared-Bbgejrus.js} +2 -73
- package/dist/shared-Bbgejrus.js.map +1 -0
- package/dist/{shared-nISrEktU.cjs → shared-Cu2yynP9.cjs} +13 -114
- package/dist/shared-Cu2yynP9.cjs.map +1 -0
- package/dist/{solana-DdEn24X4.cjs → solana-BoQBy0hu.cjs} +6 -5
- package/dist/{solana-DdEn24X4.cjs.map → solana-BoQBy0hu.cjs.map} +1 -1
- package/dist/{solana-C7JQEAec.js → solana-BukH3AI3.js} +3 -2
- package/dist/{solana-C7JQEAec.js.map → solana-BukH3AI3.js.map} +1 -1
- package/dist/solana.cjs +2 -2
- package/dist/solana.js +2 -2
- package/dist/sui-6WX6VPlW.d.cts +49 -0
- package/dist/sui-BtbPG6Xt.js +71 -0
- package/dist/sui-BtbPG6Xt.js.map +1 -0
- package/dist/sui-CYRn331O.cjs +82 -0
- package/dist/sui-CYRn331O.cjs.map +1 -0
- package/dist/sui-DI0ruW7E.d.ts +49 -0
- package/dist/sui.cjs +10 -0
- package/dist/sui.d.cts +3 -0
- package/dist/sui.d.ts +3 -0
- package/dist/sui.js +3 -0
- package/dist/{ton-5Uvi5ifg.js → ton-BSPKU5B9.js} +3 -2
- package/dist/{ton-5Uvi5ifg.js.map → ton-BSPKU5B9.js.map} +1 -1
- package/dist/{ton-DUJGXdGa.cjs → ton-CI2s9puH.cjs} +6 -5
- package/dist/{ton-DUJGXdGa.cjs.map → ton-CI2s9puH.cjs.map} +1 -1
- package/dist/ton.cjs +2 -2
- package/dist/ton.js +2 -2
- package/dist/{tron-Bo9HnvVE.js → tron-BpUEYTPT.js} +5 -67
- package/dist/tron-BpUEYTPT.js.map +1 -0
- package/dist/{tron-CQIEqjCA.cjs → tron-DYPOg5cm.cjs} +10 -72
- package/dist/{tron-Bo9HnvVE.js.map → tron-DYPOg5cm.cjs.map} +1 -1
- package/dist/tron.cjs +3 -3
- package/dist/tron.js +3 -3
- package/dist/verify.cjs +414 -24
- package/dist/verify.cjs.map +1 -1
- package/dist/verify.d.cts +120 -1
- package/dist/verify.d.ts +120 -1
- package/dist/verify.js +408 -24
- package/dist/verify.js.map +1 -1
- package/dist/xrp-BXAeK4iH.d.cts +32 -0
- package/dist/xrp-BrHXUnX5.cjs +52 -0
- package/dist/xrp-BrHXUnX5.cjs.map +1 -0
- package/dist/xrp-C8LJO5b-.js +47 -0
- package/dist/xrp-C8LJO5b-.js.map +1 -0
- package/dist/xrp-DqCXGYEk.d.ts +32 -0
- package/dist/xrp.cjs +9 -0
- package/dist/xrp.d.cts +3 -0
- package/dist/xrp.d.ts +3 -0
- package/dist/xrp.js +3 -0
- package/package.json +49 -1
- package/sui/package.json +6 -0
- package/xrp/package.json +6 -0
- package/dist/btc-Fr6Jz4Fi.cjs.map +0 -1
- package/dist/btc-VyJKXq7d.js.map +0 -1
- package/dist/derive-C4JdycUh.js.map +0 -1
- package/dist/derive-CuILJRPT.cjs.map +0 -1
- package/dist/messages-17Oup0-Z.js.map +0 -1
- package/dist/messages-BzcdWlg1.cjs.map +0 -1
- package/dist/shared-B8Wc7ViU.js.map +0 -1
- package/dist/shared-nISrEktU.cjs.map +0 -1
- package/dist/tron-CQIEqjCA.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tron-Bo9HnvVE.js","names":["UrValue"],"sources":["../src/tron-proto/gzip.ts","../src/chains/tron.ts"],"sourcesContent":["import { Gunzip, gzipSync } from 'fflate';\nimport { concatBytes } from '../core/bytes';\nimport { EraSdkError } from '../core/errors';\nimport { crc32 } from '../ur/crc32';\n\n/** Smallest possible gzip stream: 10-byte header + 8-byte trailer. */\nconst MIN_GZIP_BYTES = 18;\n\n/** Bytes fed to the inflater per step; bounds the overshoot past the cap. */\nconst SLICE_BYTES = 1024;\n\n/** Deterministic gzip (fixed level, zeroed mtime) for reproducible request bytes. */\nexport function gzipCompress(data: Uint8Array): Uint8Array {\n return gzipSync(data, { level: 9, mtime: 0 });\n}\n\n/**\n * Inflate with a hard output ceiling.\n *\n * A one-shot gunzip allocates the entire output before anyone can refuse it —\n * gzip reaches ~1000:1 in practice, so a few hundred scanned bytes could ask\n * for an arbitrary allocation. The decoder is therefore driven in slices and\n * the output counted as it arrives; the moment the total would pass the cap,\n * feeding stops and the reply is refused.\n *\n * The trailer's ISIZE (declared inflated length) is used twice: as a cheap\n * refusal of honest bombs before any work, and as a truncation check at the\n * end — an inflater hands back a partial buffer for a truncated stream\n * without erroring, and a genuine device reply always declares honestly.\n */\nexport function gunzipCapped(data: Uint8Array, maxOutputBytes: number): Uint8Array {\n if (data.length < MIN_GZIP_BYTES) {\n throw new EraSdkError('gzip-error', 'compressed payload is too short to be a gzip stream');\n }\n if (data[0] !== 0x1f || data[1] !== 0x8b) {\n throw new EraSdkError('gzip-error', 'compressed payload is not a gzip stream');\n }\n const n = data.length;\n const isize =\n (data[n - 4]! | (data[n - 3]! << 8) | (data[n - 2]! << 16) | (data[n - 1]! << 24)) >>> 0;\n if (isize > maxOutputBytes) {\n throw new EraSdkError(\n 'gzip-error',\n `compressed payload declares ${isize} bytes, over the ${maxOutputBytes} byte ceiling`,\n );\n }\n\n const chunks: Uint8Array[] = [];\n let total = 0;\n let overflowed = false;\n let malformed: string | null = null;\n\n const gunzip = new Gunzip((chunk) => {\n if (overflowed) return;\n if (total + chunk.length > maxOutputBytes) {\n overflowed = true;\n return;\n }\n chunks.push(chunk);\n total += chunk.length;\n });\n\n try {\n for (let offset = 0; offset < n && !overflowed; offset += SLICE_BYTES) {\n const end = Math.min(offset + SLICE_BYTES, n);\n const isLast = end === n;\n gunzip.push(data.slice(offset, end), isLast);\n }\n } catch (e) {\n malformed = (e as Error).message ?? 'inflate error';\n }\n\n if (overflowed) {\n throw new EraSdkError(\n 'gzip-error',\n `compressed payload inflates past the ${maxOutputBytes} byte ceiling`,\n );\n }\n if (malformed !== null) {\n throw new EraSdkError('gzip-error', `compressed payload is malformed: ${malformed}`);\n }\n const out = concatBytes(...chunks);\n if (out.length !== isize) {\n throw new EraSdkError(\n 'gzip-error',\n `compressed payload inflated to ${out.length} bytes but declares ${isize} — truncated or malformed`,\n );\n }\n // The trailer CRC32 (little-endian, bytes n-8..n-5) must cover the inflated\n // output. The streaming inflater does not verify it, and the reference\n // implementation's native decoder does — without this check a corrupted\n // stream, or a CONCATENATED multi-member stream (whose final member's CRC\n // cannot cover the whole output), would be accepted here and refused there.\n const declaredCrc =\n (data[n - 8]! | (data[n - 7]! << 8) | (data[n - 6]! << 16) | (data[n - 5]! << 24)) >>> 0;\n if (crc32(out) !== declaredCrc) {\n throw new EraSdkError('gzip-error', 'compressed payload is malformed: CRC mismatch');\n }\n return out;\n}\n","import { cborEncode } from '../cbor/encode';\nimport { asBytes, cbBytes, cbMap, cbText, mapGet } from '../cbor/model';\nimport { EraSdkError } from '../core/errors';\nimport { normalizeRequestId, uuidStringify } from '../core/rand';\nimport { normalizeXfp, parsePath, xfpToHex } from '../registry/keypath';\nimport { gunzipCapped, gzipCompress } from '../tron-proto/gzip';\nimport type { SignedTronTx, TronLatestBlock } from '../tron-proto/messages';\nimport {\n decodeSignResultProto,\n encodeSignRequestProto,\n splitSignedTronTx,\n} from '../tron-proto/messages';\nimport type { Ur } from '../ur/ur';\nimport { Ur as UrValue } from '../ur/ur';\nimport type { ChainContext, EraConnectConfig, ExpectedReply, SignRequest } from './shared';\nimport {\n makeSignRequest,\n requireReplyMap,\n requireUrType,\n resolveContext,\n resolveRequestId,\n toUr,\n} from './shared';\n\nexport type { TronLatestBlock } from '../tron-proto/messages';\n\nexport interface TronSignRequestProps {\n readonly requestId?: Uint8Array | string;\n /**\n * Serialized `Transaction.raw_data` — THE signing source of truth. The\n * device signs `sha256(rawData) = txID` and returns the transaction with\n * `raw_data` unmodified.\n */\n readonly rawData: Uint8Array;\n /** Full signing path, e.g. `m/44'/195'/0'/0/0`. */\n readonly path: string;\n readonly xfp: string | number;\n /**\n * Reference block context. Source it from a LIVE now-block query and pass\n * the FULL 64-hex block id.\n */\n readonly latestBlock: TronLatestBlock;\n /** On-device display only; safe to omit for opaque dApp transactions. */\n readonly display?: {\n readonly token?: string;\n readonly contractAddress?: string;\n readonly from?: string;\n readonly to?: string;\n readonly value?: string;\n readonly memo?: string;\n readonly fee?: number;\n readonly decimals?: number;\n };\n readonly timestamp?: number;\n readonly origin?: string;\n}\n\nexport interface TronSignatureResult {\n readonly requestId: Uint8Array;\n /** `sha256(raw_data)` hex, as computed by the device. */\n readonly txId: string;\n /** Hex of the fully assembled signed transaction — broadcast as-is. */\n readonly rawTx: string;\n /** The signed frame split into `raw_data` + signatures (65-byte r||s||recovery each). */\n readonly signedTx: SignedTronTx;\n}\n\n/**\n * Ceilings on the gzip blob a `keystone-sign-result` may carry. Tron is the\n * only chain whose reply is compressed, so it is the only one where a few\n * hundred scanned bytes can ask for an arbitrary allocation. Generous\n * multiples of the largest real device reply.\n */\nconst MAX_COMPRESSED_BYTES = 8 * 1024;\nconst MAX_INFLATED_BYTES = 64 * 1024;\n\nconst REPLY_TYPES = ['keystone-sign-result'] as const;\n\n/**\n * Tron signing rides the structured `keystone-sign-request` (6101) envelope —\n * a gzip-compressed protobuf inside CBOR `{1: gzip(protobuf), 2: origin}`.\n * The registry's generic `tron-sign-request` (5101) is NOT accepted by the\n * device and gets no response; do not emit it.\n */\nexport class TronChain {\n private readonly context: ChainContext;\n\n constructor(config?: EraConnectConfig) {\n this.context = resolveContext(config);\n }\n\n /** Build a `keystone-sign-request` (6101). Reply: `keystone-sign-result` (6102). */\n generateSignRequest(props: TronSignRequestProps): SignRequest<TronSignatureResult> {\n const requestId = resolveRequestId(this.context, props.requestId);\n parsePath(props.path); // validate shape; the wire carries the string form\n const xfp = normalizeXfp(props.xfp);\n if (props.rawData.length === 0) {\n throw new EraSdkError('invalid-props', 'rawData must not be empty');\n }\n if (!/^[0-9a-fA-F]{64}$/.test(props.latestBlock.hash)) {\n throw new EraSdkError(\n 'invalid-props',\n 'latestBlock.hash must be the FULL 64-hex block id (the device slices ref_block_hash from it)',\n );\n }\n\n const proto = encodeSignRequestProto({\n // Zero-padded to eight characters: the firmware parses this string with\n // a hex reader that yields 0 for anything shorter than 4 bytes, and a\n // zero fingerprint fails validation — a wallet whose fingerprint starts\n // with a zero byte (1 in 256) could not sign at all without the pad.\n xfpHex: xfpToHex(xfp),\n signId: uuidStringify(requestId),\n hdPath: props.path,\n timestamp: props.timestamp ?? 0,\n decimals: props.display?.decimals ?? 6,\n token: props.display?.token ?? '',\n contractAddress: props.display?.contractAddress,\n from: props.display?.from,\n to: props.display?.to,\n memo: props.display?.memo,\n value: props.display?.value,\n fee: props.display?.fee,\n latestBlock: props.latestBlock,\n rawData: props.rawData,\n });\n\n const ur = new UrValue(\n 'keystone-sign-request',\n cborEncode(\n cbMap([\n [1, cbBytes(gzipCompress(proto))],\n [2, cbText(props.origin ?? this.context.origin)],\n ]),\n ),\n );\n return makeSignRequest({\n ur,\n requestId,\n replyTypes: REPLY_TYPES,\n context: this.context,\n parse: (reply) => parseTronSignature(reply, requestId),\n });\n }\n\n /**\n * Parse a `keystone-sign-result` standalone. Tron carries the request id\n * INSIDE the protobuf (`signId`); passing `expect.requestId` is what makes\n * the echo check possible here — prefer `SignRequest.scanner().parse()`.\n */\n parseSignature(input: Ur | string, expect?: ExpectedReply): TronSignatureResult {\n return parseTronSignature(\n toUr(input),\n expect?.requestId === undefined ? undefined : normalizeRequestId(expect.requestId),\n );\n }\n}\n\nfunction parseTronSignature(\n ur: Ur,\n expectedRequestId: Uint8Array | undefined,\n): TronSignatureResult {\n requireUrType(ur, [...REPLY_TYPES], 'keystone-sign-result');\n const map = requireReplyMap(ur, 'keystone-sign-result');\n const compressed = asBytes(mapGet(map, 1));\n if (!compressed) {\n throw new EraSdkError('malformed-reply', 'keystone-sign-result is missing the payload (key 1)');\n }\n if (compressed.length > MAX_COMPRESSED_BYTES) {\n throw new EraSdkError(\n 'limit-exceeded',\n `keystone-sign-result payload is ${compressed.length} bytes, over the ${MAX_COMPRESSED_BYTES} byte ceiling`,\n );\n }\n const result = decodeSignResultProto(gunzipCapped(compressed, MAX_INFLATED_BYTES));\n\n // The signId echo is the ONLY anti-replay binding on this chain — the\n // device's own bytes are broadcast verbatim, so a stale reply that skipped\n // this check would finalize a payment the user did not approve now.\n if (expectedRequestId !== undefined) {\n const expected = uuidStringify(expectedRequestId).toLowerCase();\n if (result.signId.toLowerCase() !== expected) {\n throw new EraSdkError(\n 'request-id-mismatch',\n result.signId === ''\n ? 'keystone-sign-result does not echo the request id (signId)'\n : 'keystone-sign-result echoes a different request id — it answers another sign request, not this one',\n );\n }\n }\n if (result.rawTx === '') {\n throw new EraSdkError('malformed-reply', 'keystone-sign-result has no signed transaction');\n }\n const signedTx = splitSignedTronTx(result.rawTx);\n const requestId = expectedRequestId ?? signIdToBytes(result.signId);\n return { requestId, txId: result.txId, rawTx: result.rawTx, signedTx };\n}\n\nfunction signIdToBytes(signId: string): Uint8Array {\n try {\n return normalizeRequestId(signId);\n } catch {\n return new Uint8Array(16);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tron-DYPOg5cm.cjs","names":["resolveContext","resolveRequestId","normalizeXfp","EraSdkError","encodeSignRequestProto","xfpToHex","uuidStringify","UrValue","cborEncode","cbMap","cbBytes","gzipCompress","cbText","makeSignRequest","toUr","normalizeRequestId","requireReplyMap","asBytes","mapGet","decodeSignResultProto","gunzipCapped","splitSignedTronTx"],"sources":["../src/chains/tron.ts"],"sourcesContent":["import { cborEncode } from '../cbor/encode';\nimport { asBytes, cbBytes, cbMap, cbText, mapGet } from '../cbor/model';\nimport { EraSdkError } from '../core/errors';\nimport { normalizeRequestId, uuidStringify } from '../core/rand';\nimport { normalizeXfp, parsePath, xfpToHex } from '../registry/keypath';\nimport { gunzipCapped, gzipCompress } from '../tron-proto/gzip';\nimport type { SignedTronTx, TronLatestBlock } from '../tron-proto/messages';\nimport {\n decodeSignResultProto,\n encodeSignRequestProto,\n splitSignedTronTx,\n} from '../tron-proto/messages';\nimport type { Ur } from '../ur/ur';\nimport { Ur as UrValue } from '../ur/ur';\nimport type { ChainContext, EraConnectConfig, ExpectedReply, SignRequest } from './shared';\nimport {\n makeSignRequest,\n requireReplyMap,\n requireUrType,\n resolveContext,\n resolveRequestId,\n toUr,\n} from './shared';\n\nexport type { TronLatestBlock } from '../tron-proto/messages';\n\nexport interface TronSignRequestProps {\n readonly requestId?: Uint8Array | string;\n /**\n * Serialized `Transaction.raw_data` — THE signing source of truth. The\n * device signs `sha256(rawData) = txID` and returns the transaction with\n * `raw_data` unmodified.\n */\n readonly rawData: Uint8Array;\n /** Full signing path, e.g. `m/44'/195'/0'/0/0`. */\n readonly path: string;\n readonly xfp: string | number;\n /**\n * Reference block context. Source it from a LIVE now-block query and pass\n * the FULL 64-hex block id.\n */\n readonly latestBlock: TronLatestBlock;\n /** On-device display only; safe to omit for opaque dApp transactions. */\n readonly display?: {\n readonly token?: string;\n readonly contractAddress?: string;\n readonly from?: string;\n readonly to?: string;\n readonly value?: string;\n readonly memo?: string;\n readonly fee?: number;\n readonly decimals?: number;\n };\n readonly timestamp?: number;\n readonly origin?: string;\n}\n\nexport interface TronSignatureResult {\n readonly requestId: Uint8Array;\n /** `sha256(raw_data)` hex, as computed by the device. */\n readonly txId: string;\n /** Hex of the fully assembled signed transaction — broadcast as-is. */\n readonly rawTx: string;\n /** The signed frame split into `raw_data` + signatures (65-byte r||s||recovery each). */\n readonly signedTx: SignedTronTx;\n}\n\n/**\n * Ceilings on the gzip blob a `keystone-sign-result` may carry. Tron is the\n * only chain whose reply is compressed, so it is the only one where a few\n * hundred scanned bytes can ask for an arbitrary allocation. Generous\n * multiples of the largest real device reply.\n */\nconst MAX_COMPRESSED_BYTES = 8 * 1024;\nconst MAX_INFLATED_BYTES = 64 * 1024;\n\nconst REPLY_TYPES = ['keystone-sign-result'] as const;\n\n/**\n * Tron signing rides the structured `keystone-sign-request` (6101) envelope —\n * a gzip-compressed protobuf inside CBOR `{1: gzip(protobuf), 2: origin}`.\n * The registry's generic `tron-sign-request` (5101) is NOT accepted by the\n * device and gets no response; do not emit it.\n */\nexport class TronChain {\n private readonly context: ChainContext;\n\n constructor(config?: EraConnectConfig) {\n this.context = resolveContext(config);\n }\n\n /** Build a `keystone-sign-request` (6101). Reply: `keystone-sign-result` (6102). */\n generateSignRequest(props: TronSignRequestProps): SignRequest<TronSignatureResult> {\n const requestId = resolveRequestId(this.context, props.requestId);\n parsePath(props.path); // validate shape; the wire carries the string form\n const xfp = normalizeXfp(props.xfp);\n if (props.rawData.length === 0) {\n throw new EraSdkError('invalid-props', 'rawData must not be empty');\n }\n if (!/^[0-9a-fA-F]{64}$/.test(props.latestBlock.hash)) {\n throw new EraSdkError(\n 'invalid-props',\n 'latestBlock.hash must be the FULL 64-hex block id (the device slices ref_block_hash from it)',\n );\n }\n\n const proto = encodeSignRequestProto({\n // Zero-padded to eight characters: the firmware parses this string with\n // a hex reader that yields 0 for anything shorter than 4 bytes, and a\n // zero fingerprint fails validation — a wallet whose fingerprint starts\n // with a zero byte (1 in 256) could not sign at all without the pad.\n xfpHex: xfpToHex(xfp),\n signId: uuidStringify(requestId),\n hdPath: props.path,\n timestamp: props.timestamp ?? 0,\n decimals: props.display?.decimals ?? 6,\n token: props.display?.token ?? '',\n contractAddress: props.display?.contractAddress,\n from: props.display?.from,\n to: props.display?.to,\n memo: props.display?.memo,\n value: props.display?.value,\n fee: props.display?.fee,\n latestBlock: props.latestBlock,\n rawData: props.rawData,\n });\n\n const ur = new UrValue(\n 'keystone-sign-request',\n cborEncode(\n cbMap([\n [1, cbBytes(gzipCompress(proto))],\n [2, cbText(props.origin ?? this.context.origin)],\n ]),\n ),\n );\n return makeSignRequest({\n ur,\n requestId,\n replyTypes: REPLY_TYPES,\n context: this.context,\n parse: (reply) => parseTronSignature(reply, requestId),\n });\n }\n\n /**\n * Parse a `keystone-sign-result` standalone. Tron carries the request id\n * INSIDE the protobuf (`signId`); passing `expect.requestId` is what makes\n * the echo check possible here — prefer `SignRequest.scanner().parse()`.\n */\n parseSignature(input: Ur | string, expect?: ExpectedReply): TronSignatureResult {\n return parseTronSignature(\n toUr(input),\n expect?.requestId === undefined ? undefined : normalizeRequestId(expect.requestId),\n );\n }\n}\n\nfunction parseTronSignature(\n ur: Ur,\n expectedRequestId: Uint8Array | undefined,\n): TronSignatureResult {\n requireUrType(ur, [...REPLY_TYPES], 'keystone-sign-result');\n const map = requireReplyMap(ur, 'keystone-sign-result');\n const compressed = asBytes(mapGet(map, 1));\n if (!compressed) {\n throw new EraSdkError('malformed-reply', 'keystone-sign-result is missing the payload (key 1)');\n }\n if (compressed.length > MAX_COMPRESSED_BYTES) {\n throw new EraSdkError(\n 'limit-exceeded',\n `keystone-sign-result payload is ${compressed.length} bytes, over the ${MAX_COMPRESSED_BYTES} byte ceiling`,\n );\n }\n const result = decodeSignResultProto(gunzipCapped(compressed, MAX_INFLATED_BYTES));\n\n // The signId echo is the ONLY anti-replay binding on this chain — the\n // device's own bytes are broadcast verbatim, so a stale reply that skipped\n // this check would finalize a payment the user did not approve now.\n if (expectedRequestId !== undefined) {\n const expected = uuidStringify(expectedRequestId).toLowerCase();\n if (result.signId.toLowerCase() !== expected) {\n throw new EraSdkError(\n 'request-id-mismatch',\n result.signId === ''\n ? 'keystone-sign-result does not echo the request id (signId)'\n : 'keystone-sign-result echoes a different request id — it answers another sign request, not this one',\n );\n }\n }\n if (result.rawTx === '') {\n throw new EraSdkError('malformed-reply', 'keystone-sign-result has no signed transaction');\n }\n const signedTx = splitSignedTronTx(result.rawTx);\n const requestId = expectedRequestId ?? signIdToBytes(result.signId);\n return { requestId, txId: result.txId, rawTx: result.rawTx, signedTx };\n}\n\nfunction signIdToBytes(signId: string): Uint8Array {\n try {\n return normalizeRequestId(signId);\n } catch {\n return new Uint8Array(16);\n }\n}\n"],"mappings":"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"}
|
package/dist/tron.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_shared = require("./shared-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
2
|
+
const require_shared = require("./shared-Cu2yynP9.cjs");
|
|
3
|
+
const require_messages = require("./messages-orAQ52CI.cjs");
|
|
4
|
+
const require_tron = require("./tron-DYPOg5cm.cjs");
|
|
5
5
|
exports.AnimatedUr = require_shared.AnimatedUr;
|
|
6
6
|
exports.EraSdkError = require_shared.EraSdkError;
|
|
7
7
|
exports.TronChain = require_tron.TronChain;
|
package/dist/tron.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { K as EraSdkError, _ as Ur, d as UrScanner, f as AnimatedUr, u as TypedUrScanner } from "./shared-Bbgejrus.js";
|
|
2
|
+
import { i as splitSignedTronTx } from "./messages--XbVef_k.js";
|
|
3
|
+
import { t as TronChain } from "./tron-BpUEYTPT.js";
|
|
4
4
|
export { AnimatedUr, EraSdkError, TronChain, TypedUrScanner, Ur, UrScanner, splitSignedTronTx };
|
package/dist/verify.cjs
CHANGED
|
@@ -1,16 +1,237 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_shared = require("./shared-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const require_messages = require("./messages-
|
|
2
|
+
const require_shared = require("./shared-Cu2yynP9.cjs");
|
|
3
|
+
const require_keypath = require("./keypath-pzm_YIfN.cjs");
|
|
4
|
+
const require_cashaddr = require("./cashaddr-Ci0_8ITN.cjs");
|
|
5
|
+
const require_derive = require("./derive-BuNsfWlg.cjs");
|
|
6
|
+
const require_cardano = require("./cardano-CzYswGzK.cjs");
|
|
7
|
+
const require_messages = require("./messages-orAQ52CI.cjs");
|
|
8
|
+
const require_evm = require("./evm-yfKOc2dy.cjs");
|
|
9
|
+
const require_sui = require("./sui-CYRn331O.cjs");
|
|
10
|
+
const require_ton = require("./ton-CI2s9puH.cjs");
|
|
8
11
|
let _noble_curves_secp256k1 = require("@noble/curves/secp256k1");
|
|
12
|
+
let _noble_hashes_blake2b = require("@noble/hashes/blake2b");
|
|
13
|
+
let _noble_hashes_ripemd160 = require("@noble/hashes/ripemd160");
|
|
9
14
|
let _noble_hashes_sha2 = require("@noble/hashes/sha2");
|
|
10
15
|
let _noble_hashes_sha3 = require("@noble/hashes/sha3");
|
|
11
16
|
let _scure_base = require("@scure/base");
|
|
12
17
|
let _noble_curves_ed25519 = require("@noble/curves/ed25519");
|
|
13
|
-
|
|
18
|
+
//#region src/verify/result.ts
|
|
19
|
+
const verified = {
|
|
20
|
+
ok: true,
|
|
21
|
+
checked: true
|
|
22
|
+
};
|
|
23
|
+
const failed = (reason) => ({
|
|
24
|
+
ok: false,
|
|
25
|
+
reason
|
|
26
|
+
});
|
|
27
|
+
const unverifiable = (reason) => ({
|
|
28
|
+
ok: true,
|
|
29
|
+
checked: false,
|
|
30
|
+
reason
|
|
31
|
+
});
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/verify/bch.ts
|
|
34
|
+
const SIGHASH_FORKID_ALL = 65;
|
|
35
|
+
const BCH_TX_VERSION = 1;
|
|
36
|
+
const BCH_TX_LOCKTIME = 0;
|
|
37
|
+
const BCH_TX_SEQUENCE = 4294967293;
|
|
38
|
+
/** Hardened reader for the legacy (non-witness) transaction serialization. */
|
|
39
|
+
function decodeBchRawTx(rawTxHex) {
|
|
40
|
+
let bytes;
|
|
41
|
+
try {
|
|
42
|
+
bytes = require_shared.hexToBytes(rawTxHex);
|
|
43
|
+
} catch {
|
|
44
|
+
throw new require_shared.EraSdkError("malformed-reply", "signed transaction is not hex");
|
|
45
|
+
}
|
|
46
|
+
let offset = 0;
|
|
47
|
+
const need = (n) => {
|
|
48
|
+
if (offset + n > bytes.length) throw new require_shared.EraSdkError("malformed-reply", "signed transaction is truncated");
|
|
49
|
+
};
|
|
50
|
+
const readU32 = () => {
|
|
51
|
+
need(4);
|
|
52
|
+
const v = bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24;
|
|
53
|
+
offset += 4;
|
|
54
|
+
return v >>> 0;
|
|
55
|
+
};
|
|
56
|
+
const readU64 = () => {
|
|
57
|
+
need(8);
|
|
58
|
+
let v = 0n;
|
|
59
|
+
for (let i = 7; i >= 0; i--) v = v << 8n | BigInt(bytes[offset + i]);
|
|
60
|
+
offset += 8;
|
|
61
|
+
return v;
|
|
62
|
+
};
|
|
63
|
+
const readVarint = () => {
|
|
64
|
+
need(1);
|
|
65
|
+
const first = bytes[offset++];
|
|
66
|
+
if (first < 253) return first;
|
|
67
|
+
if (first === 253) {
|
|
68
|
+
need(2);
|
|
69
|
+
const v = bytes[offset] | bytes[offset + 1] << 8;
|
|
70
|
+
offset += 2;
|
|
71
|
+
return v;
|
|
72
|
+
}
|
|
73
|
+
throw new require_shared.EraSdkError("malformed-reply", "unreasonable varint in signed transaction");
|
|
74
|
+
};
|
|
75
|
+
const readSlice = (n) => {
|
|
76
|
+
need(n);
|
|
77
|
+
const s = bytes.subarray(offset, offset + n);
|
|
78
|
+
offset += n;
|
|
79
|
+
return s;
|
|
80
|
+
};
|
|
81
|
+
const version = readU32();
|
|
82
|
+
const inputCount = readVarint();
|
|
83
|
+
if (inputCount === 0 || inputCount > 1e3) throw new require_shared.EraSdkError("malformed-reply", "unreasonable input count in signed transaction");
|
|
84
|
+
const inputs = [];
|
|
85
|
+
for (let i = 0; i < inputCount; i++) {
|
|
86
|
+
const txidLE = readSlice(32);
|
|
87
|
+
const index = readU32();
|
|
88
|
+
const scriptSig = readSlice(readVarint());
|
|
89
|
+
const sequence = readU32();
|
|
90
|
+
inputs.push({
|
|
91
|
+
txidLE,
|
|
92
|
+
index,
|
|
93
|
+
scriptSig,
|
|
94
|
+
sequence
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const outputCount = readVarint();
|
|
98
|
+
if (outputCount === 0 || outputCount > 1e3) throw new require_shared.EraSdkError("malformed-reply", "unreasonable output count in signed transaction");
|
|
99
|
+
const outputs = [];
|
|
100
|
+
for (let i = 0; i < outputCount; i++) {
|
|
101
|
+
const value = readU64();
|
|
102
|
+
const script = readSlice(readVarint());
|
|
103
|
+
outputs.push({
|
|
104
|
+
value,
|
|
105
|
+
script
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
const locktime = readU32();
|
|
109
|
+
if (offset !== bytes.length) throw new require_shared.EraSdkError("malformed-reply", "trailing bytes after signed transaction");
|
|
110
|
+
return {
|
|
111
|
+
version,
|
|
112
|
+
inputs,
|
|
113
|
+
outputs,
|
|
114
|
+
locktime
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function sha256d(data) {
|
|
118
|
+
return (0, _noble_hashes_sha2.sha256)((0, _noble_hashes_sha2.sha256)(data));
|
|
119
|
+
}
|
|
120
|
+
function hash160(data) {
|
|
121
|
+
return (0, _noble_hashes_ripemd160.ripemd160)((0, _noble_hashes_sha2.sha256)(data));
|
|
122
|
+
}
|
|
123
|
+
function p2pkhScript(pubkeyHash) {
|
|
124
|
+
return require_shared.concatBytes(new Uint8Array([
|
|
125
|
+
118,
|
|
126
|
+
169,
|
|
127
|
+
20
|
|
128
|
+
]), pubkeyHash, new Uint8Array([136, 172]));
|
|
129
|
+
}
|
|
130
|
+
function p2shScript(scriptHash) {
|
|
131
|
+
return require_shared.concatBytes(new Uint8Array([169, 20]), scriptHash, new Uint8Array([135]));
|
|
132
|
+
}
|
|
133
|
+
function scriptForAddress(address) {
|
|
134
|
+
const decoded = require_cashaddr.decodeCashAddr(address);
|
|
135
|
+
return decoded.type === "p2pkh" ? p2pkhScript(decoded.hash) : p2shScript(decoded.hash);
|
|
136
|
+
}
|
|
137
|
+
function le32(value) {
|
|
138
|
+
return new Uint8Array([
|
|
139
|
+
value & 255,
|
|
140
|
+
value >>> 8 & 255,
|
|
141
|
+
value >>> 16 & 255,
|
|
142
|
+
value >>> 24 & 255
|
|
143
|
+
]);
|
|
144
|
+
}
|
|
145
|
+
function le64(value) {
|
|
146
|
+
const out = /* @__PURE__ */ new Uint8Array(8);
|
|
147
|
+
let v = value;
|
|
148
|
+
for (let i = 0; i < 8; i++) {
|
|
149
|
+
out[i] = Number(v & 255n);
|
|
150
|
+
v >>= 8n;
|
|
151
|
+
}
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
function varintBytes(value) {
|
|
155
|
+
if (value < 253) return new Uint8Array([value]);
|
|
156
|
+
return new Uint8Array([
|
|
157
|
+
253,
|
|
158
|
+
value & 255,
|
|
159
|
+
value >>> 8 & 255
|
|
160
|
+
]);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* BIP-143 sighash preimage with FORKID, exactly as consensus defines it:
|
|
164
|
+
* `version ‖ hashPrevouts ‖ hashSequence ‖ outpoint ‖ scriptCode ‖ value ‖
|
|
165
|
+
* sequence ‖ hashOutputs ‖ locktime ‖ hashType(LE)`, double-SHA256d.
|
|
166
|
+
*/
|
|
167
|
+
function computeBchSighash(args) {
|
|
168
|
+
const { tx, inputIndex, scriptCode, value } = args;
|
|
169
|
+
const hashType = args.hashType ?? SIGHASH_FORKID_ALL;
|
|
170
|
+
const input = tx.inputs[inputIndex];
|
|
171
|
+
if (!input) throw new require_shared.EraSdkError("invalid-props", "sighash input index out of range");
|
|
172
|
+
const hashPrevouts = sha256d(require_shared.concatBytes(...tx.inputs.map((i) => require_shared.concatBytes(i.txidLE, le32(i.index)))));
|
|
173
|
+
const hashSequence = sha256d(require_shared.concatBytes(...tx.inputs.map((i) => le32(i.sequence))));
|
|
174
|
+
const hashOutputs = sha256d(require_shared.concatBytes(...tx.outputs.map((o) => require_shared.concatBytes(le64(o.value), varintBytes(o.script.length), o.script))));
|
|
175
|
+
return sha256d(require_shared.concatBytes(le32(tx.version), hashPrevouts, hashSequence, input.txidLE, le32(input.index), varintBytes(scriptCode.length), scriptCode, le64(value), le32(input.sequence), hashOutputs, le32(tx.locktime), le32(hashType)));
|
|
176
|
+
}
|
|
177
|
+
function toBigintValue(value, label) {
|
|
178
|
+
const v = typeof value === "number" ? BigInt(value) : value;
|
|
179
|
+
if (v <= 0n) throw new require_shared.EraSdkError("invalid-props", `${label} must be positive`);
|
|
180
|
+
return v;
|
|
181
|
+
}
|
|
182
|
+
function toPublicKeyBytes(publicKey) {
|
|
183
|
+
return typeof publicKey === "string" ? require_shared.hexToBytes(publicKey) : publicKey;
|
|
184
|
+
}
|
|
185
|
+
function verifyBchSignedTx(args) {
|
|
186
|
+
try {
|
|
187
|
+
const tx = decodeBchRawTx(args.rawTx);
|
|
188
|
+
if (tx.version !== BCH_TX_VERSION || tx.locktime !== BCH_TX_LOCKTIME) return failed(`transaction parameters (version ${tx.version}, locktime ${tx.locktime}) are not the device signer's (1, 0)`);
|
|
189
|
+
for (let i = 0; i < tx.inputs.length; i++) if (tx.inputs[i].sequence !== BCH_TX_SEQUENCE) return failed(`input ${i} sequence is not the device signer's 0xfffffffd`);
|
|
190
|
+
if (tx.inputs.length !== args.inputs.length) return failed(`signed transaction has ${tx.inputs.length} inputs, the request had ${args.inputs.length}`);
|
|
191
|
+
if (tx.outputs.length !== args.outputs.length) return failed(`signed transaction has ${tx.outputs.length} outputs, the request had ${args.outputs.length}`);
|
|
192
|
+
for (let i = 0; i < args.outputs.length; i++) {
|
|
193
|
+
const requested = args.outputs[i];
|
|
194
|
+
const actual = tx.outputs[i];
|
|
195
|
+
if (actual.value !== toBigintValue(requested.value, `output ${i} value`)) return failed(`output ${i} value differs from the request`);
|
|
196
|
+
if (!require_shared.equalBytes(actual.script, scriptForAddress(requested.address))) return failed(`output ${i} does not pay the requested address`);
|
|
197
|
+
}
|
|
198
|
+
for (let i = 0; i < args.inputs.length; i++) {
|
|
199
|
+
const requested = args.inputs[i];
|
|
200
|
+
const actual = tx.inputs[i];
|
|
201
|
+
const txidLE = require_shared.hexToBytes(requested.txid).reverse();
|
|
202
|
+
if (!require_shared.equalBytes(actual.txidLE, txidLE) || actual.index !== requested.index) return failed(`input ${i} spends a different outpoint than the request named`);
|
|
203
|
+
const script = actual.scriptSig;
|
|
204
|
+
if (script.length < 2) return failed(`input ${i} has no signature`);
|
|
205
|
+
const sigLen = script[0];
|
|
206
|
+
if (sigLen < 9 || 1 + sigLen + 1 > script.length) return failed(`input ${i} scriptSig is not a signature push`);
|
|
207
|
+
const sigWithType = script.subarray(1, 1 + sigLen);
|
|
208
|
+
const pubLen = script[1 + sigLen];
|
|
209
|
+
if (pubLen !== 33 || 1 + sigLen + 1 + pubLen !== script.length) return failed(`input ${i} scriptSig does not end with a compressed public key push`);
|
|
210
|
+
const pubkey = script.subarray(1 + sigLen + 1);
|
|
211
|
+
if (!require_shared.equalBytes(pubkey, toPublicKeyBytes(requested.publicKey))) return failed(`input ${i} was signed with a different public key than the request named — the transaction cannot spend the requested UTXO`);
|
|
212
|
+
const hashType = sigWithType[sigWithType.length - 1];
|
|
213
|
+
if (hashType !== SIGHASH_FORKID_ALL) return failed(`input ${i} uses sighash 0x${hashType.toString(16)}, expected SIGHASH_ALL|FORKID (0x41)`);
|
|
214
|
+
const sighash = computeBchSighash({
|
|
215
|
+
tx,
|
|
216
|
+
inputIndex: i,
|
|
217
|
+
scriptCode: p2pkhScript(hash160(pubkey)),
|
|
218
|
+
value: toBigintValue(requested.value, `input ${i} value`)
|
|
219
|
+
});
|
|
220
|
+
const signature = _noble_curves_secp256k1.secp256k1.Signature.fromDER(sigWithType.subarray(0, sigWithType.length - 1)).toCompactRawBytes();
|
|
221
|
+
if (!_noble_curves_secp256k1.secp256k1.verify(signature, sighash, pubkey)) return failed(`input ${i} signature does not verify against the BIP-143 FORKID sighash`);
|
|
222
|
+
}
|
|
223
|
+
if (args.txId !== void 0) {
|
|
224
|
+
if (require_shared.bytesToHex(sha256d(require_shared.hexToBytes(args.rawTx)).reverse()) !== args.txId.toLowerCase()) return failed("reply txId does not match the hash of the signed transaction");
|
|
225
|
+
}
|
|
226
|
+
return verified;
|
|
227
|
+
} catch (e) {
|
|
228
|
+
return failed(message$1(e));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function message$1(e) {
|
|
232
|
+
return e instanceof require_shared.EraSdkError || e instanceof Error ? e.message : String(e);
|
|
233
|
+
}
|
|
234
|
+
//#endregion
|
|
14
235
|
//#region src/verify/psbt-reader.ts
|
|
15
236
|
const MAGIC = [
|
|
16
237
|
112,
|
|
@@ -149,21 +370,6 @@ function inputHas(psbt, index, keyType) {
|
|
|
149
370
|
return inputEntries(psbt, index, keyType).length > 0;
|
|
150
371
|
}
|
|
151
372
|
//#endregion
|
|
152
|
-
//#region src/verify/result.ts
|
|
153
|
-
const verified = {
|
|
154
|
-
ok: true,
|
|
155
|
-
checked: true
|
|
156
|
-
};
|
|
157
|
-
const failed = (reason) => ({
|
|
158
|
-
ok: false,
|
|
159
|
-
reason
|
|
160
|
-
});
|
|
161
|
-
const unverifiable = (reason) => ({
|
|
162
|
-
ok: true,
|
|
163
|
-
checked: false,
|
|
164
|
-
reason
|
|
165
|
-
});
|
|
166
|
-
//#endregion
|
|
167
373
|
//#region src/verify/btc.ts
|
|
168
374
|
/**
|
|
169
375
|
* The `crypto-psbt` reply carries NO request id — this comparison IS the
|
|
@@ -282,10 +488,10 @@ function verifyCardanoSignature(args) {
|
|
|
282
488
|
if (!ok) return failed("a witness signature does not verify against its own vkey");
|
|
283
489
|
}
|
|
284
490
|
if (args.account && args.signerPaths && args.signerPaths.length > 0) {
|
|
285
|
-
const accountLevels =
|
|
491
|
+
const accountLevels = require_keypath.parsePath(args.account.accountPath);
|
|
286
492
|
const expected = /* @__PURE__ */ new Map();
|
|
287
493
|
for (const path of new Set(args.signerPaths)) {
|
|
288
|
-
const levels =
|
|
494
|
+
const levels = require_keypath.parsePath(path);
|
|
289
495
|
if (levels.length !== accountLevels.length + 2 || !accountLevels.every((l, i) => levels[i].index === l.index && levels[i].hardened === l.hardened) || levels.slice(accountLevels.length).some((l) => l.hardened)) return failed(`signer path ${path} does not extend the account path with two soft components`);
|
|
290
496
|
const tail = levels.slice(accountLevels.length).map((l) => l.index);
|
|
291
497
|
const vkey = require_derive.cardanoSoftDerivePath(args.account.publicKey, args.account.chainCode, tail);
|
|
@@ -394,6 +600,21 @@ function skipItem(bytes, offset, depth) {
|
|
|
394
600
|
}
|
|
395
601
|
}
|
|
396
602
|
//#endregion
|
|
603
|
+
//#region src/verify/cosmos.ts
|
|
604
|
+
function verifyCosmosSignature(args) {
|
|
605
|
+
if (args.signature.length !== 64) return failed("signature must be 64 bytes (compact r||s)");
|
|
606
|
+
if (args.publicKey.length !== 33) return failed("publicKey must be 33 bytes (compressed)");
|
|
607
|
+
if (args.expectedPublicKey !== void 0 && !require_shared.equalBytes(args.publicKey, args.expectedPublicKey)) return failed("the reply public key is not the linked account key");
|
|
608
|
+
const digest = args.digest === "keccak256" ? (0, _noble_hashes_sha3.keccak_256)(args.signData) : (0, _noble_hashes_sha2.sha256)(args.signData);
|
|
609
|
+
let ok;
|
|
610
|
+
try {
|
|
611
|
+
ok = _noble_curves_secp256k1.secp256k1.verify(args.signature, digest, args.publicKey);
|
|
612
|
+
} catch (e) {
|
|
613
|
+
return failed(`Cosmos signature could not be checked: ${e.message}`);
|
|
614
|
+
}
|
|
615
|
+
return ok ? verified : failed("the signature does not belong to this account");
|
|
616
|
+
}
|
|
617
|
+
//#endregion
|
|
397
618
|
//#region src/verify/evm.ts
|
|
398
619
|
/** EIP-191: 0x19 || "Ethereum Signed Message:\n" || len(message). */
|
|
399
620
|
function personalSignDigest(message) {
|
|
@@ -449,6 +670,25 @@ function verifySolanaSignature(args) {
|
|
|
449
670
|
return ok ? verified : failed("the signature does not belong to this account");
|
|
450
671
|
}
|
|
451
672
|
//#endregion
|
|
673
|
+
//#region src/verify/sui.ts
|
|
674
|
+
/** BLAKE2b-256 of the intent message (or the given hash) + Ed25519 verification. */
|
|
675
|
+
function verifySuiSignature(args) {
|
|
676
|
+
let digest;
|
|
677
|
+
if (args.messageHash !== void 0) {
|
|
678
|
+
if (args.messageHash.length !== 32) return failed("messageHash must be 32 bytes");
|
|
679
|
+
digest = args.messageHash;
|
|
680
|
+
} else if (args.intentMessage !== void 0) digest = require_sui.suiIntentDigest(args.intentMessage);
|
|
681
|
+
else return failed("provide intentMessage or messageHash");
|
|
682
|
+
if (args.expectedPublicKey !== void 0 && !require_shared.equalBytes(args.publicKey, args.expectedPublicKey)) return failed("the reply public key is not the linked account key");
|
|
683
|
+
let ok;
|
|
684
|
+
try {
|
|
685
|
+
ok = _noble_curves_ed25519.ed25519.verify(args.signature, digest, args.publicKey);
|
|
686
|
+
} catch (e) {
|
|
687
|
+
return failed(`Sui signature could not be checked: ${e.message}`);
|
|
688
|
+
}
|
|
689
|
+
return ok ? verified : failed("the signature does not belong to this account");
|
|
690
|
+
}
|
|
691
|
+
//#endregion
|
|
452
692
|
//#region src/verify/ton-boc.ts
|
|
453
693
|
/**
|
|
454
694
|
* Minimal TON Bag-of-Cells reader + cell representation hash — exactly the
|
|
@@ -720,15 +960,165 @@ function compareWindow(repliedBytes, latestBlock) {
|
|
|
720
960
|
return verified;
|
|
721
961
|
}
|
|
722
962
|
//#endregion
|
|
963
|
+
//#region src/verify/xrp.ts
|
|
964
|
+
/**
|
|
965
|
+
* XRP has no request id — this check IS the binding. The signed binary is
|
|
966
|
+
* split into its canonical fields; `TxnSignature` is removed; the remainder
|
|
967
|
+
* (prefixed with the XRPL signing tag `STX\0`) is hashed with SHA-512-half
|
|
968
|
+
* and the DER signature is verified against `SigningPubKey`, which must also
|
|
969
|
+
* equal the key your request carried.
|
|
970
|
+
*
|
|
971
|
+
* The field walker covers the types Payment-class transactions use; a
|
|
972
|
+
* transaction carrying an exotic field type comes back `checked: false`
|
|
973
|
+
* rather than a false verdict.
|
|
974
|
+
*/
|
|
975
|
+
function verifyXrpSignature(args) {
|
|
976
|
+
let fields;
|
|
977
|
+
try {
|
|
978
|
+
fields = splitFields(args.signedTx);
|
|
979
|
+
} catch (e) {
|
|
980
|
+
const message = e.message;
|
|
981
|
+
if (message === "unsupported-field") return unverifiable("the transaction carries a field type this checker does not walk");
|
|
982
|
+
return failed(`the signed transaction is not readable: ${message}`);
|
|
983
|
+
}
|
|
984
|
+
const signingPubKey = fields.find((f) => f.header === 115);
|
|
985
|
+
const txnSignature = fields.find((f) => f.header === 116);
|
|
986
|
+
if (!signingPubKey || !txnSignature) return failed("the signed transaction is missing SigningPubKey or TxnSignature");
|
|
987
|
+
const expected = require_shared.hexToBytes(args.expectedSigningPubKey);
|
|
988
|
+
if (!require_shared.equalBytes(signingPubKey.value, expected)) return failed(`the transaction was signed with a different key (${require_shared.bytesToHex(signingPubKey.value)})`);
|
|
989
|
+
const payload = require_shared.concatBytes(new Uint8Array([
|
|
990
|
+
83,
|
|
991
|
+
84,
|
|
992
|
+
88,
|
|
993
|
+
0
|
|
994
|
+
]), ...fields.filter((f) => f.header !== 116).map((f) => f.raw));
|
|
995
|
+
const digest = (0, _noble_hashes_sha2.sha512)(payload).slice(0, 32);
|
|
996
|
+
let ok;
|
|
997
|
+
try {
|
|
998
|
+
ok = _noble_curves_secp256k1.secp256k1.verify(_noble_curves_secp256k1.secp256k1.Signature.fromDER(txnSignature.value).toCompactRawBytes(), digest, expected);
|
|
999
|
+
} catch (e) {
|
|
1000
|
+
return failed(`XRP signature could not be checked: ${e.message}`);
|
|
1001
|
+
}
|
|
1002
|
+
return ok ? verified : failed("the signature does not verify against SigningPubKey");
|
|
1003
|
+
}
|
|
1004
|
+
/** Split a canonical STObject into its top-level fields. */
|
|
1005
|
+
function splitFields(bytes) {
|
|
1006
|
+
const fields = [];
|
|
1007
|
+
let pos = 0;
|
|
1008
|
+
while (pos < bytes.length) {
|
|
1009
|
+
const field = parseField(bytes, pos);
|
|
1010
|
+
fields.push(field.field);
|
|
1011
|
+
pos = field.end;
|
|
1012
|
+
}
|
|
1013
|
+
return fields;
|
|
1014
|
+
}
|
|
1015
|
+
/** Parse ONE field at `pos`; returns the field and the offset past it. */
|
|
1016
|
+
function parseField(bytes, pos) {
|
|
1017
|
+
const start = pos;
|
|
1018
|
+
const first = bytes[pos++];
|
|
1019
|
+
if (first === void 0) throw new Error("truncated");
|
|
1020
|
+
let type = first >> 4;
|
|
1021
|
+
let fieldCode = first & 15;
|
|
1022
|
+
if (type === 0) {
|
|
1023
|
+
const t = bytes[pos++];
|
|
1024
|
+
if (t === void 0) throw new Error("truncated type");
|
|
1025
|
+
type = t;
|
|
1026
|
+
}
|
|
1027
|
+
if (fieldCode === 0) {
|
|
1028
|
+
const f = bytes[pos++];
|
|
1029
|
+
if (f === void 0) throw new Error("truncated field code");
|
|
1030
|
+
fieldCode = f;
|
|
1031
|
+
}
|
|
1032
|
+
let valueStart = pos;
|
|
1033
|
+
switch (type) {
|
|
1034
|
+
case 1:
|
|
1035
|
+
pos += 2;
|
|
1036
|
+
break;
|
|
1037
|
+
case 2:
|
|
1038
|
+
pos += 4;
|
|
1039
|
+
break;
|
|
1040
|
+
case 5:
|
|
1041
|
+
pos += 32;
|
|
1042
|
+
break;
|
|
1043
|
+
case 6: {
|
|
1044
|
+
const head = bytes[pos];
|
|
1045
|
+
if (head === void 0) throw new Error("truncated amount");
|
|
1046
|
+
pos += (head & 128) !== 0 ? 48 : 8;
|
|
1047
|
+
break;
|
|
1048
|
+
}
|
|
1049
|
+
case 7:
|
|
1050
|
+
case 8: {
|
|
1051
|
+
const vl = readVl(bytes, pos);
|
|
1052
|
+
valueStart = vl.next;
|
|
1053
|
+
pos = vl.next + vl.length;
|
|
1054
|
+
break;
|
|
1055
|
+
}
|
|
1056
|
+
case 14:
|
|
1057
|
+
while (bytes[pos] !== 225) {
|
|
1058
|
+
if (pos >= bytes.length) throw new Error("unterminated inner object");
|
|
1059
|
+
pos = parseField(bytes, pos).end;
|
|
1060
|
+
}
|
|
1061
|
+
pos += 1;
|
|
1062
|
+
break;
|
|
1063
|
+
case 15:
|
|
1064
|
+
while (bytes[pos] !== 241) {
|
|
1065
|
+
if (pos >= bytes.length) throw new Error("unterminated array");
|
|
1066
|
+
pos = parseField(bytes, pos).end;
|
|
1067
|
+
}
|
|
1068
|
+
pos += 1;
|
|
1069
|
+
break;
|
|
1070
|
+
default: throw new Error("unsupported-field");
|
|
1071
|
+
}
|
|
1072
|
+
if (pos > bytes.length) throw new Error("truncated field");
|
|
1073
|
+
return {
|
|
1074
|
+
field: {
|
|
1075
|
+
header: type << 4 | (fieldCode <= 15 ? fieldCode : 0),
|
|
1076
|
+
value: bytes.slice(valueStart, pos),
|
|
1077
|
+
raw: bytes.slice(start, pos)
|
|
1078
|
+
},
|
|
1079
|
+
end: pos
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
/** XRPL variable-length prefix. */
|
|
1083
|
+
function readVl(bytes, pos) {
|
|
1084
|
+
const b1 = bytes[pos];
|
|
1085
|
+
if (b1 === void 0) throw new Error("truncated length");
|
|
1086
|
+
if (b1 <= 192) return {
|
|
1087
|
+
length: b1,
|
|
1088
|
+
next: pos + 1
|
|
1089
|
+
};
|
|
1090
|
+
if (b1 <= 240) {
|
|
1091
|
+
const b2 = bytes[pos + 1];
|
|
1092
|
+
if (b2 === void 0) throw new Error("truncated length");
|
|
1093
|
+
return {
|
|
1094
|
+
length: 193 + (b1 - 193) * 256 + b2,
|
|
1095
|
+
next: pos + 2
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
const b2 = bytes[pos + 1];
|
|
1099
|
+
const b3 = bytes[pos + 2];
|
|
1100
|
+
if (b2 === void 0 || b3 === void 0) throw new Error("truncated length");
|
|
1101
|
+
return {
|
|
1102
|
+
length: 12481 + (b1 - 241) * 65536 + b2 * 256 + b3,
|
|
1103
|
+
next: pos + 3
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
//#endregion
|
|
723
1107
|
exports.PsbtInputType = PsbtInputType;
|
|
724
1108
|
exports.bocRootHash = bocRootHash;
|
|
1109
|
+
exports.computeBchSighash = computeBchSighash;
|
|
1110
|
+
exports.decodeBchRawTx = decodeBchRawTx;
|
|
725
1111
|
exports.parsePsbt = parsePsbt;
|
|
1112
|
+
exports.verifyBchSignedTx = verifyBchSignedTx;
|
|
726
1113
|
exports.verifyBtcMessageHeader = verifyBtcMessageHeader;
|
|
727
1114
|
exports.verifyCardanoSignature = verifyCardanoSignature;
|
|
1115
|
+
exports.verifyCosmosSignature = verifyCosmosSignature;
|
|
728
1116
|
exports.verifyEvmSignature = verifyEvmSignature;
|
|
729
1117
|
exports.verifySignedPsbt = verifySignedPsbt;
|
|
730
1118
|
exports.verifySolanaSignature = verifySolanaSignature;
|
|
1119
|
+
exports.verifySuiSignature = verifySuiSignature;
|
|
731
1120
|
exports.verifyTonSignature = verifyTonSignature;
|
|
732
1121
|
exports.verifyTronSignature = verifyTronSignature;
|
|
1122
|
+
exports.verifyXrpSignature = verifyXrpSignature;
|
|
733
1123
|
|
|
734
1124
|
//# sourceMappingURL=verify.cjs.map
|