import * as utils from '../../utils.js';
import { DerivationNonce, } from './interfaces.js';
import { SupportedKeyDerivationTypes } from '../module.js';
import { base64, crypto } from '../../utils.js';
import el from 'elliptic';
export class P256KeyDerivationStrategy {
    algorithmType;
    constructor(algorithmType) {
        this.algorithmType = algorithmType;
    }
    hydrate(masterKey, nonce) {
        return this.create(masterKey, nonce.salt);
    }
    async fromRaw(rawKey) {
        const ec = new el.ec(el.curves['p256']);
        const keyfrompriv = ec.keyFromPrivate(rawKey);
        const pubKey = new Uint8Array(keyfrompriv.getPublic(false, 'array')).slice(1);
        const xs = pubKey.slice(0, 32);
        const ys = pubKey.slice(32);
        const jwk = {
            kty: 'EC',
            crv: 'P-256',
            d: base64.bufToUrlBase64(rawKey),
            x: base64.bufToUrlBase64(xs),
            y: base64.bufToUrlBase64(ys),
        };
        const keyUsage = this.algorithmType === 'ECDH' ? ['deriveBits'] : ['sign'];
        const kid = await utils.jose.calculateJwkThumbprint(jwk, 'sha256');
        const cryptoKey = await crypto.subtle.importKey('jwk', jwk, { name: this.algorithmType, namedCurve: 'P-256' }, true, keyUsage);
        return new P256Key(cryptoKey, {
            ...jwk,
            kid,
        }, rawKey);
    }
    async create(masterKey, salt) {
        const rawMasterKey = await crypto.subtle.exportKey('raw', masterKey);
        const { secret, xs, ys } = await utils.generateP256Key(rawMasterKey, salt);
        const jwk = {
            kty: 'EC',
            crv: 'P-256',
            d: base64.bufToUrlBase64(secret),
            x: base64.bufToUrlBase64(xs),
            y: base64.bufToUrlBase64(ys),
        };
        const kid = await utils.jose.calculateJwkThumbprint(jwk, 'sha256');
        const keyUsage = this.algorithmType === 'ECDH' ? ['deriveBits'] : ['sign'];
        const cryptoKey = await crypto.subtle.importKey('jwk', jwk, { name: this.algorithmType, namedCurve: 'P-256' }, true, keyUsage);
        return new P256Key(cryptoKey, {
            ...jwk,
            kid,
        }, secret, new DerivationNonce(salt, 0));
    }
}
export class P256PublicKey {
    cryptoKey;
    constructor(cryptoKey) {
        this.cryptoKey = cryptoKey;
    }
    async getPublicKeyHex() {
        return utils.hex.bufToHex(await this.getPublicKeyBytes());
    }
    async getPublicKeyBytes() {
        const extractedKeyBytes = await crypto.subtle.exportKey('raw', this.cryptoKey);
        return new Uint8Array(extractedKeyBytes);
    }
    verify(signature, message) {
        return crypto.subtle.verify({
            hash: 'SHA-256',
            name: 'ECDSA',
        }, this.cryptoKey, signature, message);
    }
}
export class P256Key {
    key;
    jwk;
    secret;
    derivation_path;
    constructor(key, jwk, secret, derivation_path) {
        this.key = key;
        this.jwk = jwk;
        this.secret = secret;
        this.derivation_path = derivation_path;
    }
    async getPublicKeyBytes() {
        const pubKey = await this.getPublicKey();
        return await pubKey.getPublicKeyBytes();
    }
    async getPrivateKeyBytes() {
        const exportedRaw = await crypto.subtle.exportKey('raw', this.key);
        return new Uint8Array(exportedRaw);
    }
    async toJWK({ includePrivate }) {
        const jwk = { ...this.jwk };
        if (!includePrivate) {
            delete jwk.d;
        }
        return jwk;
    }
    async toCryptoKey() {
        return this.key;
    }
    async exportKeyInformation() {
        return {
            version: 1,
            curve: SupportedKeyDerivationTypes.P256_ECDSA,
            key: this.derivation_path
                ? {
                    type: 'derived',
                    from: 'master',
                    nonce: this.derivation_path.toString(),
                }
                : {
                    type: 'raw',
                    rawKeyHex: utils.hex.bufToHex(this.secret),
                },
            publicKey: utils.hex.bufToHex(await this.getPublicKeyBytes()),
            fingerprint: utils.hex.bufToHex(await this.getFingerprint()),
        };
    }
    async sign(message) {
        const signature = await crypto.subtle.sign({
            hash: 'SHA-256',
            name: 'ECDSA',
        }, this.key, message);
        return new Uint8Array(signature);
    }
    async verify(signature, message) {
        const pubKey = await this.getPublicKey();
        return Promise.resolve(pubKey.verify(signature, message));
    }
    getPath() {
        return this.derivation_path;
    }
    async getFingerprint() {
        const pubKey = await this.getPublicKey();
        return utils.sha256(await pubKey.getPublicKeyBytes());
    }
    async getPublicKey() {
        const jwkPrivate = Object.assign({}, this.jwk);
        // Delete secret P256 data, leaving only public information
        delete jwkPrivate.d;
        jwkPrivate.key_ops = ['verify'];
        const publicKey = await crypto.subtle.importKey('jwk', jwkPrivate, { name: 'ECDSA', namedCurve: 'P-256' }, true, [
            'verify',
        ]);
        return Promise.resolve(new P256PublicKey(publicKey));
    }
}
//# sourceMappingURL=p256ECDSA.js.map