import { ed25519 as ed } from '@noble/curves/ed25519.js';
import { toString as uint8arrayToString } from 'uint8arrays/to-string';
import { withArrayBuffer } from 'uint8arrays/with-array-buffer';
import crypto from "../../webcrypto/index.js";
const PUBLIC_KEY_BYTE_LENGTH = 32;
const PRIVATE_KEY_BYTE_LENGTH = 64; // private key is actually 32 bytes but for historical reasons we concat private and public keys
const KEYS_BYTE_LENGTH = 32;
export { PUBLIC_KEY_BYTE_LENGTH as publicKeyLength };
export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength };
// memoize support result to skip additional awaits every time we use an ed key
let ed25519Supported;
const webCryptoEd25519SupportedPromise = (async () => {
    try {
        await crypto.get().subtle.generateKey({ name: 'Ed25519' }, true, ['sign', 'verify']);
        return true;
    }
    catch {
        return false;
    }
})();
export function generateKey() {
    // the actual private key (32 bytes)
    const privateKeyRaw = ed.utils.randomSecretKey();
    const publicKey = ed.getPublicKey(privateKeyRaw);
    // concatenated the public key to the private key
    const privateKey = concatKeys(privateKeyRaw, publicKey);
    return {
        privateKey,
        publicKey
    };
}
export function generateKeyFromSeed(seed) {
    if (seed.length !== KEYS_BYTE_LENGTH) {
        throw new TypeError('"seed" must be 32 bytes in length.');
    }
    else if (!(seed instanceof Uint8Array)) {
        throw new TypeError('"seed" must be a node.js Buffer, or Uint8Array.');
    }
    // based on node forges algorithm, the seed is used directly as private key
    const privateKeyRaw = seed;
    const publicKey = ed.getPublicKey(privateKeyRaw);
    const privateKey = concatKeys(privateKeyRaw, publicKey);
    return {
        privateKey,
        publicKey
    };
}
async function hashAndSignWebCrypto(privateKey, msg) {
    let privateKeyRaw;
    if (privateKey.length === PRIVATE_KEY_BYTE_LENGTH) {
        privateKeyRaw = privateKey.subarray(0, 32);
    }
    else {
        privateKeyRaw = privateKey;
    }
    const jwk = {
        crv: 'Ed25519',
        kty: 'OKP',
        x: uint8arrayToString(privateKey.subarray(32), 'base64url'),
        d: uint8arrayToString(privateKeyRaw, 'base64url'),
        ext: true,
        key_ops: ['sign']
    };
    const key = await crypto.get().subtle.importKey('jwk', jwk, { name: 'Ed25519' }, true, ['sign']);
    const sig = await crypto.get().subtle.sign({ name: 'Ed25519' }, key, withArrayBuffer(msg instanceof Uint8Array ? msg : msg.subarray()));
    return new Uint8Array(sig, 0, sig.byteLength);
}
export function hashAndSignNoble(privateKey, msg) {
    const privateKeyRaw = privateKey.subarray(0, KEYS_BYTE_LENGTH);
    return ed.sign(msg instanceof Uint8Array ? msg : msg.subarray(), privateKeyRaw);
}
export async function hashAndSign(privateKey, msg) {
    if (ed25519Supported == null) {
        ed25519Supported = await webCryptoEd25519SupportedPromise;
    }
    if (ed25519Supported) {
        return hashAndSignWebCrypto(privateKey, msg);
    }
    return hashAndSignNoble(privateKey, msg);
}
async function hashAndVerifyWebCrypto(publicKey, sig, msg) {
    if (publicKey.buffer instanceof ArrayBuffer) {
        const key = await crypto.get().subtle.importKey('raw', publicKey.buffer, { name: 'Ed25519' }, false, ['verify']);
        const isValid = await crypto.get().subtle.verify({ name: 'Ed25519' }, key, withArrayBuffer(sig), withArrayBuffer(msg instanceof Uint8Array ? msg : msg.subarray()));
        return isValid;
    }
    throw new TypeError('WebCrypto does not support SharedArrayBuffer for Ed25519 keys');
}
export function hashAndVerifyNoble(publicKey, sig, msg) {
    return ed.verify(sig, msg instanceof Uint8Array ? msg : msg.subarray(), publicKey);
}
export async function hashAndVerify(publicKey, sig, msg) {
    if (ed25519Supported == null) {
        ed25519Supported = await webCryptoEd25519SupportedPromise;
    }
    if (ed25519Supported) {
        return hashAndVerifyWebCrypto(publicKey, sig, msg);
    }
    return hashAndVerifyNoble(publicKey, sig, msg);
}
function concatKeys(privateKeyRaw, publicKey) {
    const privateKey = new Uint8Array(PRIVATE_KEY_BYTE_LENGTH);
    for (let i = 0; i < KEYS_BYTE_LENGTH; i++) {
        privateKey[i] = privateKeyRaw[i];
        privateKey[KEYS_BYTE_LENGTH + i] = publicKey[i];
    }
    return privateKey;
}
//# sourceMappingURL=index.browser.js.map