import { ed25519 } from '@noble/curves/ed25519.js';
import { hmac } from '@noble/hashes/hmac.js';
import { ripemd160 } from '@noble/hashes/legacy.js';
import { concatBytes, createView, utf8ToBytes } from '@noble/hashes/utils.js';
import { sha256, sha512 } from '@noble/hashes/sha2.js';
const HARDENED_OFFSET = 0x80000000;
const MASTER_SECRET = utf8ToBytes('ed25519 seed');
const ZERO = new Uint8Array([0]);
function assertBytes(bytes, length) {
    if (!(bytes instanceof Uint8Array)) {
        throw new TypeError('Ed25519HdKey: expected Uint8Array');
    }
    if (length !== undefined && bytes.length !== length) {
        throw new RangeError(`Ed25519HdKey: expected ${length} bytes, got ${bytes.length}`);
    }
}
function toU32(n) {
    if (!Number.isSafeInteger(n) || n < 0 || n > Math.pow(2, 32) - 1) {
        throw new Error(`Invalid number=${n}. Should be from 0 to 2 ** 32 - 1`);
    }
    const bytes = new Uint8Array(4);
    createView(bytes).setUint32(0, n, false);
    return bytes;
}
function fromU32(bytes) {
    return createView(bytes).getUint32(0, false);
}
function hash160(data) {
    return ripemd160(sha256(data));
}
/**
 * Minimal SLIP-0010 Ed25519 HD key derivation used by {@link HdIdentityVault}.
 */
export class Ed25519HdKey {
    static fromMasterSeed(seed) {
        assertBytes(seed);
        if (8 * seed.length < 128 || 8 * seed.length > 512) {
            throw new Error(`Ed25519HdKey: wrong seed length=${seed.length}. Should be between 128 and 512 bits; 256 bits is advised)`);
        }
        const digest = hmac(sha512, MASTER_SECRET, seed);
        return new Ed25519HdKey({
            chainCode: digest.slice(32),
            privateKey: digest.slice(0, 32),
        });
    }
    constructor({ chainCode, depth = 0, index = 0, parentFingerprint = 0, privateKey }) {
        assertBytes(privateKey, 32);
        assertBytes(chainCode, 32);
        if (depth === 0 && (parentFingerprint !== 0 || index !== 0)) {
            throw new Error('Ed25519HdKey: zero depth with non-zero index/parent fingerprint');
        }
        this.chainCode = chainCode;
        this.depth = depth;
        this.index = index;
        this.parentFingerprint = parentFingerprint;
        this.privateKey = privateKey;
    }
    get publicKeyRaw() {
        return ed25519.getPublicKey(this.privateKey);
    }
    get publicKey() {
        return concatBytes(ZERO, this.publicKeyRaw);
    }
    get fingerprint() {
        return fromU32(hash160(this.publicKey));
    }
    derive(path, forceHardened = false) {
        if (!/^[mM]'?/.test(path)) {
            throw new Error('Path must start with m or M');
        }
        if (/^[mM]'?$/.test(path)) {
            return this;
        }
        const parts = path.replace(/^[mM]'?\//, '').split('/');
        return parts.reduce((parent, part) => parent.deriveChild(Ed25519HdKey.parseChildIndex(part, forceHardened)), this);
    }
    deriveChild(index) {
        if (index < HARDENED_OFFSET) {
            throw new Error(`Non-hardened child derivation not possible for Ed25519 (index=${index})`);
        }
        const digest = hmac(sha512, this.chainCode, concatBytes(ZERO, this.privateKey, toU32(index)));
        return new Ed25519HdKey({
            chainCode: digest.slice(32),
            depth: this.depth + 1,
            index,
            parentFingerprint: this.fingerprint,
            privateKey: digest.slice(0, 32),
        });
    }
    static parseChildIndex(part, forceHardened) {
        const match = /^(\d+)('?)$/.exec(part);
        if ((match === null || match === void 0 ? void 0 : match.length) !== 3) {
            throw new Error(`Invalid child index: ${part}`);
        }
        let index = Number(match[1]);
        if (!Number.isSafeInteger(index) || index >= HARDENED_OFFSET) {
            throw new Error('Invalid index');
        }
        if (forceHardened || match[2] === '\'') {
            index += HARDENED_OFFSET;
        }
        return index;
    }
}
//# sourceMappingURL=ed25519-hd-key.js.map