JSPM

  • Created
  • Published
  • Downloads 227
  • Score
    100M100P100Q71475F
  • License MPL-2.0

Utilities around Master Password Algorithm (Spectre.app, by Maarten Billemont) and crypto, using Noble and Scure by Paul Miller. Stateless accounts & passwords, 2fa, shamir secret sharing, crypto/bitcoin/nostr public and private keys, and more.

Package Exports

  • cryptils
  • cryptils/index.js
  • cryptils/index.ts
  • cryptils/node
  • cryptils/package.json

Readme

cryptils

Utilities around Spectre / Master Password Algorithm (by Maarten Billemont), implemented in TypeScript, using Noble & Scure cryptography by @paulmillr. Used for deriving stateless accounts & passwords, 2fa, shamir secret sharing, crypto/bitcoin/nostr public and private keys, and more.

Highlights

  • Don't store, derive! Derive passwords and keys from a master password and a name
  • Uses audited Noble & Scure cryptography by @paulmillr
  • TypeScript implementation of Spectre / Master Password Algorithm by Maarten Billemont
  • Stateless account & password derivation
  • Stateless Crypto, Bitcoin, Nostr public and private keys derivation
  • Support for Shamir Secret Sharing

Install

npm add cryptils
bun add cryptils
deno add npm:cryptils

Usage

import {
  bech32encode,
  deriveAccount,
  deriveCryptoAccount,
  deriveKeys,
  randomBytes,
  spectreV4,
  splitKeyToShares,
} from 'cryptils';

const usrName = 'wgw';
const passwd = 'secret master password';

// Derive password for `wgw` user on `twitter.com` and `github.com`,
const twitter = deriveAccount(usrName, passwd, 'twitter.com');
const github = deriveAccount(usrName, passwd, 'github.com');

// in addition to above, it uses the generated secret
// to derive crypto keys like ethereum address, bitcoin keys and nostr keys
const crypto_1 = deriveCryptoAccount(usrName, passwd, 'crypto.0');
const crypto_2 = deriveCryptoAccount(usrName, passwd, 'crypto.1');
const { secret: crypto_3_secret, ...crypto_3 } = spectreV4(usrName, passwd, 'crypto.2');

// deriveKeys is used inside `deriveCryptoKeys`, it's standalone function
const crypto_3_keys = deriveKeys(crypto_3_secret);

// Using Shamir Secret Sharing, split the secret into 3 keys and 5 shares
const crypto_3_keys_shares = await splitKeyToShares(crypto_3_secret, 3, 5);

const info = {
  twitter,
  github,
  crypto_1,
  crypto_2,
  crypto_3: { ...crypto_3, keys: crypto_3_keys, shares: crypto_3_keys_shares },
};

console.log();
console.log(JSON.stringify(info, null, 2));
console.log();

const rndSecret = randomBytes(32);
const otherKeys = deriveKeys(rndSecret);
console.log('other keys:', otherKeys);

// create Bitcoin bech32 bc1p address from a public key
const bc1p = bech32encode('bc', otherKeys.pubkey, true);
console.log('bc1p:', bc1p, bc1p === otherKeys.bitcoin);

Docs

declare type Options = { template?: string; hash?: any; iterations?: number };
declare type Result = { secret: Uint8Array; name: string; user: string; pass: string };
declare type Hex = string;

declare type Keys = {
  mnemonic: string;
  privkey: Hex;
  pubkey: Hex;
  npub: string; // npub1...abc
  nsec: string; // nsec1...abc
  nrepo: string; // nrepo1...abc
  ethereum: `0x${string}`; // 0x1987...abc
  bitcoin: string; // bc1p...abc
  litecoin: string; // ltc1p...abc
  vertcoin: string; // vtc1p...abc
};

declare function spectreV4(user: string, pass: string, name: string, options?: Options): Result;

declare function deriveKeys(secret: Uint8Array): Keys;
declare function deriveMnemonic(secret: string, size?: 16 | 32): string;

declare function deriveAccount(
  user: string,
  pass: string,
  name: string,
  options?: Options,
): Omit<Result, 'secret'>;

declare function deriveCryptoAccount(
  user: string,
  pass: string,
  name: string,
  options?: Options,
): Omit<Result, 'secret'> & Keys;

declare function bech32encode(
  prefix: string,
  key: Uint8Array | string,
  isAddr: boolean,
  limit: number,
): string;

declare function decryptWithSecret(ciphertext: string, key: Uint8Array | string): Promise<string>;
declare function encryptWithSecret(
  plaintext: Uint8Array | string,
  key: Uint8Array | string,
  salt?: Uint8Array,
): Promise<string>;

declare function privateKeyToEthereumAddress(key: Uint8Array | string): `0x${string}`;
declare function checksumEthereumAddress(address: string): `0x${string}`;

declare function combineSharesToKey(shares: string[]): Hex;
declare function splitKeyToShares(
  key: Uint8Array | string,
  threshold: number,
  shares: number,
): Hex[];

LICENSE

SPDX-License-Identifier: MPL-2.0