UNPKG

cesr

Version:

[![NPM Version](https://img.shields.io/npm/v/cesr.svg?style=flat)](https://www.npmjs.com/package/cesr) [![NPM License](https://img.shields.io/npm/l/cesr.svg?style=flat)](https://github.com/lenkan/cesr-js/blob/main/LICENSE) [![CI](https://github.com/lenkan

139 lines (138 loc) 4.58 kB
import { IndexCode, IndexTableInit } from "./codes.js"; import { decodeBase64Int, encodeBase64Int } from "./encoding-base64.js"; import { encodeBinary, encodeText, decodeText, peekText, resolveQuadletCount, } from "./frame.js"; const Hards = {}; const Table = {}; for (const [key, value] of Object.entries(IndexTableInit)) { Hards[key.slice(0, 1)] = value.hs; Table[key] = { hs: value.hs, fs: value.fs ?? 0, os: value.os ?? 0, ls: value.ls ?? 0, ss: value.ss ?? 0, xs: value.xs ?? 0, }; } function lookup(input) { if (typeof input !== "string") { input = new TextDecoder().decode(input.slice(0, 4)); } if (input.length === 0) { throw new Error("Received empty input code for lookup"); } const hs = Hards[input.slice(0, 1)]; const hard = input.slice(0, hs ?? 4); const entry = Table[hard]; if (!entry) { throw new Error(`Code not found in Indexer table: ${hard}`); } return entry; } function resolveIndexerInit(frame, entry) { const ms = entry.ss - entry.os; const os = entry.os; const text = encodeBase64Int(frame.soft ?? 0, entry.ss); const index = decodeBase64Int(text.slice(0, ms)); const ondex = os > 0 ? decodeBase64Int(text.slice(ms)) : undefined; return { code: frame.code, raw: frame.raw || new Uint8Array(), index, ondex, }; } export class Indexer { code; index; ondex; raw; constructor(init) { this.index = init.index; this.ondex = init.ondex; this.code = init.code; this.raw = init.raw; } get quadlets() { return resolveQuadletCount(this); } get soft() { const entry = lookup(this.code); const ms = entry.ss - entry.os; const os = entry.os; const index = encodeBase64Int(this.index, ms); const ondex = os > 0 ? encodeBase64Int(this.ondex ?? 0, os) : ""; const soft = decodeBase64Int(index + ondex); return soft; } get size() { return lookup(this.code); } text() { return encodeText(this); } binary() { return encodeBinary(this); } static Code = IndexCode; static peek(input) { const entry = lookup(input); const result = peekText(input, entry); if (!result.frame) { return { n: result.n }; } return { frame: new Indexer(resolveIndexerInit(result.frame, entry)), n: result.n, }; } static parse(input) { const entry = lookup(input); const frame = decodeText(input, entry); return new Indexer(resolveIndexerInit(frame, entry)); } /** * Create a new Indexer frame. * * Note: It is recommended to use the helper methods in `Indexer.crypto` instead to ensure * the correct code is used for the signature type. * * @param code The Indexer code, see {@link Indexer.Code} * @param raw The raw signature bytes * @param index The main index of the signature * @param ondex The optional secondary index of the signature */ static from(code, raw, index, ondex) { return new Indexer({ code, raw, index, ondex }); } static crypto = { ed25519_sig(raw, index, ondex) { if (ondex !== undefined) { // TODO: Keripy also checks if index === ondex and then use Crt_Sig return Indexer.from(Indexer.Code.Ed25519_Big_Sig, raw, index, ondex); } if (index > 64) { return Indexer.from(Indexer.Code.Ed25519_Big_Crt_Sig, raw, index); } return Indexer.from(Indexer.Code.Ed25519_Sig, raw, index); }, ed448_sig(raw, index, ondex) { if (ondex !== undefined) { if (index > 64 || ondex > 64) { return Indexer.from(Indexer.Code.Ed448_Big_Sig, raw, index, ondex); } return Indexer.from(Indexer.Code.Ed448_Sig, raw, index, ondex); } if (index > 64) { return Indexer.from(Indexer.Code.Ed448_Big_Crt_Sig, raw, index); } return Indexer.from(Indexer.Code.Ed448_Crt_Sig, raw, index); }, ecdsa_256k1_sig(raw, index) { if (index > 64) { return Indexer.from(Indexer.Code.ECDSA_256r1_Big_Crt_Sig, raw, index); } return Indexer.from(Indexer.Code.ECDSA_256k1_Crt_Sig, raw, index); }, }; }