Skip to content

Commit

Permalink
Merge branch 'master' into feat_ledger_thorchain
Browse files Browse the repository at this point in the history
  • Loading branch information
kaladinlight committed Oct 18, 2023
2 parents 78a7581 + 6805444 commit 3ad7857
Showing 1 changed file with 19 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,65 +1,44 @@
/// <reference types="bip32/types/crypto" />

import * as core from "@shapeshiftoss/hdwallet-core";
import * as bip32crypto from "bip32/src/crypto";
import { createSHA512, pbkdf2 } from "hash-wasm";
import { TextEncoder } from "web-encoding";

import * as BIP32 from "../../core/bip32";
import * as BIP39 from "../../core/bip39";
import { safeBufferFrom } from "../../types";
import * as BIP32Engine from "./bip32";
import type { Seed as SeedType } from "../../core/bip32";
import type { Mnemonic as Bip39Mnemonic } from "../../core/bip39";
import { Seed } from "./bip32";
import { Revocable, revocable } from "./revocable";

export * from "../../core/bip39";

// Poor man's single-block PBKDF2 implementation
//TODO: get something better
function pbkdf2_sha512_singleblock(
password: string,
salt: Uint8Array,
iterations: number
): Uint8Array & { length: 64 } {
function be32Buf(index: number): Buffer {
const indexBE = Buffer.alloc(4);
indexBE.writeUInt32BE(index);
return indexBE;
}

const pwBuffer = safeBufferFrom(new TextEncoder().encode(password));

const out = bip32crypto.hmacSHA512(pwBuffer, core.compatibleBufferConcat([salt, be32Buf(1)])) as Buffer & {
length: 64;
};
let lastU = out;
for (let i = 2; i <= iterations; i++) {
const newU = bip32crypto.hmacSHA512(pwBuffer, lastU) as Buffer & { length: 64 };
for (let j = 0; j < out.length; j++) out[j] ^= newU[j];
lastU = newU;
}

return out;
}

export class Mnemonic extends Revocable(class {}) implements BIP39.Mnemonic {
export class Mnemonic extends Revocable(class {}) implements Bip39Mnemonic {
readonly #mnemonic: string;

protected constructor(mnemonic: string) {
super();
this.#mnemonic = mnemonic.normalize("NFKD");
}

static async create(mnemonic: string): Promise<BIP39.Mnemonic> {
static async create(mnemonic: string): Promise<Bip39Mnemonic> {
const obj = new Mnemonic(mnemonic);
return revocable(obj, (x) => obj.addRevoker(x));
}

async toSeed(passphrase?: string): Promise<BIP32.Seed> {
if (passphrase !== undefined && typeof passphrase !== "string") throw new Error("bad passphrase type");

async toSeed(passphrase?: string): Promise<SeedType> {
const mnemonic = this.#mnemonic;
const salt = new TextEncoder().encode(`mnemonic${passphrase ?? ""}`.normalize("NFKD"));

const out = await BIP32Engine.Seed.create(pbkdf2_sha512_singleblock(mnemonic, salt, 2048));
const out = await Seed.create(
Buffer.from(
await pbkdf2({
password: mnemonic,
salt,
iterations: 2048,
hashLength: 64,
hashFunction: createSHA512(),
outputType: "binary",
})
)
);
this.addRevoker(() => out.revoke?.());
return out;
}
Expand Down

0 comments on commit 3ad7857

Please sign in to comment.