cesr
Version:
[](https://www.npmjs.com/package/cesr) [](https://github.com/lenkan/cesr-js/blob/main/LICENSE) [ • 4.58 kB
JavaScript
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);
},
};
}