@iacobus/hd
Version:
Hierarchical Deterministic Symmetric Keys.
72 lines (71 loc) • 3 kB
JavaScript
/**
* @fileoverview Provides functionality for parsing derivation paths and schemas.
* @module
* @author Jacob V. B. Haap <iacobus.xyz>
* @license MIT
*/
import { getIndex } from "./utils.js";
/** defaultSchema is the default derivation path schema */
export const defaultSchema = "m / application: any / purpose: any / context: any / index: num";
/** defaultPath is the default derivation path. */
export const defaultPath = "m/42/0/1/0";
/**
* newSchema parses a new derivation path schema from a given string.
* @example
* const str: string = "m / application: any / purpose: any / context: any / index: num";
* const schema = newSchema(str);
*/
export function newSchema(str) {
const segments = str.split(" / ");
if (segments.length > 256) {
throw new RangeError(`schema cannot exceed 256 segments, got "${segments.length}"`);
}
if (segments[0] !== "m") {
throw new SyntaxError(`schema must begin with "m", got "${segments[0]}"`);
}
const allowed = new Set(["str", "num", "any"]); // Allow strings, numbers, or either
const result = []; // Allocate array for the parsed schema
for (const segment of segments.slice(1)) {
const [label, type] = segment.split(":").map(s => s.trim()); // Separate the label and the type
if (!label || !type) {
throw new SyntaxError(`invalid segment in schema, "${segment}"`);
}
if (!allowed.has(type)) {
throw new TypeError(`invalid type "${type}" for label "${label} in schema"`);
}
result.push([label, type]); // Add the label and type to the parsed results
}
return result; // Return parsed schema
}
/**
* newPath parses a new derivation path from a given hash, string, and schema.
* @example
* const path = newPath(h, "m/42/0/1/0", schema);
*/
export function newPath(h, str, schema) {
const pathArray = str.split("/");
const [root, ...indices] = pathArray;
if (root != "m") {
throw new SyntaxError(`derivation path must begin with "m", got "${root}"`);
}
if (indices.length > schema.length) {
throw new RangeError(`too many indices in derivation path: got "${indices.length}", expected "${schema.length}"`);
}
const result = []; // Allocate array for the parsed path
for (let i = 0; i < indices.length; i++) {
const [label, type] = schema[i]; // Get label and type for the current index from the schema
let index;
try {
index = getIndex(h, indices[i], type); // Parse the current index, enforcing the type from the schema
}
catch (error) {
if (error instanceof Error) {
const IndexError = error.constructor;
throw new IndexError(`derivation path position ${i} label "${label}", ${error.message}`);
}
throw error;
}
result.push(index); // Add the parsed index to the result
}
return result; // Return the parsed derivation path
}