TypeScript SeedBundle parsing and generation library.
- Git Repo - https://github.com/holochain/hcSeedBundle
- API Documentation - https://holochain.github.io/hcSeedBundle/
- Applications like Holochain have different requirements than classic blockchain system in terms of key management. Namely there is no need for read-only or hardened wallets (Holochain handles these concepts through capabilities and membranes).
- Applications like Holochain still have need of hierarchy and determinism in key (or in this case seed) derivation.
- Since we're using libsodium for hashing, signature, and encryption algorithms, let's use it for derivation as well.
- To be psychologically compatible with the Bitcoin "HD Wallet" spec, we will do away with the "context" part of sodium KDF by always setting it to
b"SeedBndl"
and focusing on thesubkey_id
and can declare a chain of subsequent derivations of a 32 byte seed in the formm/68/1/65/8
where we applysubkey_id
s 68, 1, 65, then 8 in turn.
import { UnlockedSeedBundle, seedBundleReady } from "@holochain/hc-seed-bundle";
// await library functions ready to call
await seedBundleReady;
// generate a new pure entropy master seed
const master = UnlockedSeedBundle.newRandom({
bundleType: "master",
});
// derive a device root seed from the master
const deviceRoot = master.derive(68, {
bundleType: "deviceRoot",
});
// clear our secrets
master.zero();
deviceRoot.zero();
import { UnlockedSeedBundle, SeedCipherPwHash, seedBundleReady, parseSecret } from "@holochain/hc-seed-bundle";
// await library functions ready to call
await seedBundleReady;
// generate a new pure entropy master seed
const master = UnlockedSeedBundle.newRandom({
bundleType: "master",
});
// we need the passphrase as a Uint8Array
const pw = new TextEncoder().encode("test-passphrase");
const encodedBytes = master.lock([new SeedCipherPwHash(parseSecret(pw), "minimum")]);
// -- if you want to regenerate for (decrypting) below:
// console.log(Buffer.from(encodedBytes).toString('base64'))
// clear our secrets
master.zero();
import {
UnlockedSeedBundle,
SeedCipherSecurityQuestions,
seedBundleReady,
parseSecret,
} from "@holochain/hc-seed-bundle";
// await library functions ready to call
await seedBundleReady;
// generate a new pure entropy master seed
const master = UnlockedSeedBundle.newRandom({
bundleType: "master",
});
// we need the answers as a Uint8Arrays
const pw = (pw: string) => parseSecret(new TextEncoder().encode(pw));
const encodedBytes = master.lock([
new SeedCipherSecurityQuestions(
["Favorite Color?", "Favorite Hair?", "Favorite Food?"],
[pw("blue"), pw("big"), pw("begal")],
"minimum",
),
]);
// clear our secrets
master.zero();
// await library functions ready to call
import { UnlockedSeedBundle, LockedSeedCipherPwHash, seedBundleReady, parseSecret } from "@holochain/hc-seed-bundle";
await seedBundleReady;
const encodedBytes = Buffer.from(
"k6VoY3NiMJGWonB3xBD5Ov1Vas4XnV1XPsf8ddCqzSAAAcQYkO36tg8NHoec02I7KtxfX+ZnmBzIz+SoxDFDNfr4/9811ugf18FiRSywOyVagFHIRTyrfV3jZLRt6W0r7WuepaQLjlFu4jgVMrd2xBOBqmJ1bmRsZVR5cGWmbWFzdGVy",
"base64",
);
// decode the SeedCiphers that will let us unlock this bundle
const cipherList = UnlockedSeedBundle.fromLocked(encodedBytes);
// the demo is encrypted with PwHash
if (!(cipherList[0] instanceof LockedSeedCipherPwHash)) {
throw new Error("Expecting PwHash");
}
// unlock with the passphrase
const pw = new TextEncoder().encode("test-passphrase");
const master = cipherList[0].unlock(parseSecret(pw));
// clear our secrets
master.zero();
bun install
To run:
bun run index.ts
This project was created using bun init
in bun v1.1.8. Bun is a fast all-in-one JavaScript runtime.