"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
require("jest");
const crypto_1 = require("crypto");
const PrivateKey_1 = require("@wireio/sdk-core/chain/PrivateKey");
const PublicKey_1 = require("@wireio/sdk-core/chain/PublicKey");
const KeyType_1 = require("@wireio/sdk-core/chain/KeyType");
const Generate_1 = require("@wireio/sdk-core/crypto/Generate");
const GetPublic_1 = require("@wireio/sdk-core/crypto/GetPublic");
const Sign_1 = require("@wireio/sdk-core/crypto/Sign");
const Verify_1 = require("@wireio/sdk-core/crypto/Verify");
const Recover_1 = require("@wireio/sdk-core/crypto/Recover");
const SharedSecret_1 = require("@wireio/sdk-core/crypto/SharedSecret");
const Curves_1 = require("@wireio/sdk-core/crypto/Curves");
function sha256(data) {
    return new Uint8Array((0, crypto_1.createHash)("sha256").update(data).digest());
}
/** Convert SignatureParts to wire-format Uint8Array for low-level verify/recover. */
function sigPartsToBytes(parts) {
    if (parts.type === KeyType_1.KeyType.ED) {
        const buf = new Uint8Array(64);
        buf.set(parts.r, 0);
        buf.set(parts.s, 32);
        return buf;
    }
    const buf = new Uint8Array(65);
    buf[0] = parts.recid + 31;
    buf.set(parts.r, 1);
    buf.set(parts.s, 33);
    return buf;
}
describe("PrivateKey deterministic derivation", () => {
    const privKeyDigest = sha256("nathan");
    const privKey = PrivateKey_1.PrivateKey.regenerate(KeyType_1.KeyType.K1, privKeyDigest);
    const privKeyStr = privKey.toString();
    const privKeyWifStr = privKey.toWif();
    const pubKey = privKey.toPublic();
    const pubKeyStr = pubKey.toString();
    const pubKeyWifStr = pubKey.toLegacyString();
    test("regenerate from sha256('nathan') produces known public key", () => {
        expect(pubKeyWifStr).toBe("SYS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV");
    });
    test("private key string is PVT_K1_ format", () => {
        expect(privKeyStr).toMatch(/^PVT_K1_/);
    });
    test("private key WIF starts with 5", () => {
        expect(privKeyWifStr).toMatch(/^5/);
    });
    test("public key string is PUB_K1_ format", () => {
        expect(pubKeyStr).toMatch(/^PUB_K1_/);
    });
    test("private key roundtrips through WIF", () => {
        const restored = PrivateKey_1.PrivateKey.fromString(privKeyWifStr);
        expect(restored.data.array).toEqual(privKey.data.array);
        expect(restored.type).toBe(KeyType_1.KeyType.K1);
    });
    test("private key roundtrips through PVT string", () => {
        const restored = PrivateKey_1.PrivateKey.from(privKeyStr);
        expect(restored.data.array).toEqual(privKey.data.array);
    });
    test("public key roundtrips through string", () => {
        const restored = PublicKey_1.PublicKey.from(pubKeyStr);
        expect(restored.data.array).toEqual(pubKey.data.array);
        expect(restored.type).toBe(KeyType_1.KeyType.K1);
    });
    test("public key roundtrips through legacy string", () => {
        const restored = PublicKey_1.PublicKey.from(pubKeyWifStr);
        expect(restored.data.array).toEqual(pubKey.data.array);
    });
});
describe("PrivateKey sign and verify", () => {
    const message = new Uint8Array([0xde, 0xad, 0xbe, 0xef]);
    test("K1 sign/verify roundtrip", () => {
        const pvt = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.K1);
        const pub = pvt.toPublic();
        const sig = pvt.signMessage(message);
        expect(sig.verifyMessage(message, pub)).toBe(true);
    });
    test("K1 signature recovers correct public key", () => {
        const pvt = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.K1);
        const pub = pvt.toPublic();
        const sig = pvt.signMessage(message);
        const recovered = sig.recoverMessage(message);
        expect(recovered.data.array).toEqual(pub.data.array);
    });
    test("R1 sign/verify roundtrip", () => {
        const pvt = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.R1);
        const pub = pvt.toPublic();
        const sig = pvt.signMessage(message);
        expect(sig.verifyMessage(message, pub)).toBe(true);
    });
    test("EM key signs a message and produces a signature", () => {
        const pvt = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.EM);
        const sig = pvt.signMessage(message);
        expect(sig.type).toBe(KeyType_1.KeyType.EM);
        expect(sig.toString()).toMatch(/^SIG_EM_/);
    });
    test("ED sign/verify roundtrip", () => {
        const pvt = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.ED);
        const pub = pvt.toPublic();
        const sig = pvt.signMessage(message);
        expect(sig.verifyMessage(message, pub)).toBe(true);
    });
    test("verification fails with wrong public key", () => {
        const pvt1 = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.K1);
        const pvt2 = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.K1);
        const sig = pvt1.signMessage(message);
        expect(sig.verifyMessage(message, pvt2.toPublic())).toBe(false);
    });
    test("verification fails with wrong message", () => {
        const pvt = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.K1);
        const pub = pvt.toPublic();
        const sig = pvt.signMessage(message);
        const wrong = new Uint8Array([0xca, 0xfe, 0xba, 0xbe]);
        expect(sig.verifyMessage(wrong, pub)).toBe(false);
    });
});
describe("PrivateKey shared secret", () => {
    test("K1 ECDH shared secret is symmetric", () => {
        const a = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.K1);
        const b = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.K1);
        const secretAB = a.sharedSecret(b.toPublic());
        const secretBA = b.sharedSecret(a.toPublic());
        expect(secretAB.array).toEqual(secretBA.array);
    });
    test("R1 ECDH shared secret is symmetric", () => {
        const a = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.R1);
        const b = PrivateKey_1.PrivateKey.generate(KeyType_1.KeyType.R1);
        const secretAB = a.sharedSecret(b.toPublic());
        const secretBA = b.sharedSecret(a.toPublic());
        expect(secretAB.array).toEqual(secretBA.array);
    });
});
describe("crypto low-level functions", () => {
    describe("generate", () => {
        test("K1 produces 32 bytes", () => {
            expect((0, Generate_1.generate)(KeyType_1.KeyType.K1).length).toBe(32);
        });
        test("R1 produces 32 bytes", () => {
            expect((0, Generate_1.generate)(KeyType_1.KeyType.R1).length).toBe(32);
        });
        test("EM produces 32 bytes", () => {
            expect((0, Generate_1.generate)(KeyType_1.KeyType.EM).length).toBe(32);
        });
        test("ED produces 64 bytes", () => {
            expect((0, Generate_1.generate)(KeyType_1.KeyType.ED).length).toBe(64);
        });
    });
    describe("getPublic", () => {
        test("K1 compressed public key is 33 bytes", () => {
            const secret = (0, Generate_1.generate)(KeyType_1.KeyType.K1);
            const pub = (0, GetPublic_1.getPublic)(secret, KeyType_1.KeyType.K1);
            expect(pub.length).toBe(33);
            expect(pub[0] === 0x02 || pub[0] === 0x03).toBe(true);
        });
        test("ED public key is 32 bytes", () => {
            const secret = (0, Generate_1.generate)(KeyType_1.KeyType.ED);
            const pub = (0, GetPublic_1.getPublic)(secret, KeyType_1.KeyType.ED);
            expect(pub.length).toBe(32);
        });
    });
    describe("sign and verify (low-level)", () => {
        test("K1 sign then verify", () => {
            const secret = (0, Generate_1.generate)(KeyType_1.KeyType.K1);
            const pub = (0, GetPublic_1.getPublic)(secret, KeyType_1.KeyType.K1);
            const digest = sha256("test message");
            const parts = (0, Sign_1.sign)(secret, digest, KeyType_1.KeyType.K1);
            const sigBytes = sigPartsToBytes(parts);
            expect((0, Verify_1.verify)(sigBytes, digest, pub, KeyType_1.KeyType.K1)).toBe(true);
        });
        test("R1 sign then verify", () => {
            const secret = (0, Generate_1.generate)(KeyType_1.KeyType.R1);
            const pub = (0, GetPublic_1.getPublic)(secret, KeyType_1.KeyType.R1);
            const digest = sha256("test message");
            const parts = (0, Sign_1.sign)(secret, digest, KeyType_1.KeyType.R1);
            const sigBytes = sigPartsToBytes(parts);
            expect((0, Verify_1.verify)(sigBytes, digest, pub, KeyType_1.KeyType.R1)).toBe(true);
        });
        test("ED sign then verify", () => {
            const secret = (0, Generate_1.generate)(KeyType_1.KeyType.ED);
            const pub = (0, GetPublic_1.getPublic)(secret, KeyType_1.KeyType.ED);
            const msg = new Uint8Array([1, 2, 3, 4]);
            const parts = (0, Sign_1.sign)(secret, msg, KeyType_1.KeyType.ED);
            const sigBytes = sigPartsToBytes(parts);
            expect((0, Verify_1.verify)(sigBytes, msg, pub, KeyType_1.KeyType.ED)).toBe(true);
        });
    });
    describe("recover", () => {
        test("K1 recovers correct public key from signature", () => {
            const secret = (0, Generate_1.generate)(KeyType_1.KeyType.K1);
            const pub = (0, GetPublic_1.getPublic)(secret, KeyType_1.KeyType.K1);
            const digest = sha256("recover test");
            const parts = (0, Sign_1.sign)(secret, digest, KeyType_1.KeyType.K1);
            const sigBytes = sigPartsToBytes(parts);
            const recovered = (0, Recover_1.recover)(sigBytes, digest, KeyType_1.KeyType.K1);
            expect(recovered.data.array).toEqual(new Uint8Array(pub));
        });
    });
    describe("sharedSecret", () => {
        test("K1 ECDH produces consistent shared secret", () => {
            const a = (0, Generate_1.generate)(KeyType_1.KeyType.K1);
            const b = (0, Generate_1.generate)(KeyType_1.KeyType.K1);
            const pubA = (0, GetPublic_1.getPublic)(a, KeyType_1.KeyType.K1);
            const pubB = (0, GetPublic_1.getPublic)(b, KeyType_1.KeyType.K1);
            const sAB = (0, SharedSecret_1.sharedSecret)(a, pubB, KeyType_1.KeyType.K1);
            const sBA = (0, SharedSecret_1.sharedSecret)(b, pubA, KeyType_1.KeyType.K1);
            expect(sAB).toEqual(sBA);
        });
        test("ED throws for shared secret", () => {
            const a = (0, Generate_1.generate)(KeyType_1.KeyType.ED);
            const b = (0, Generate_1.generate)(KeyType_1.KeyType.ED);
            const pubB = (0, GetPublic_1.getPublic)(b, KeyType_1.KeyType.ED);
            expect(() => (0, SharedSecret_1.sharedSecret)(a, pubB, KeyType_1.KeyType.ED)).toThrow();
        });
    });
    describe("getCurve", () => {
        test("returns secp256k1 for K1", () => {
            const curve = (0, Curves_1.getCurve)(KeyType_1.KeyType.K1);
            expect(curve).toBeDefined();
        });
        test("returns p256 for R1", () => {
            const curve = (0, Curves_1.getCurve)(KeyType_1.KeyType.R1);
            expect(curve).toBeDefined();
        });
        test("returns secp256k1 for EM", () => {
            const curve = (0, Curves_1.getCurve)(KeyType_1.KeyType.EM);
            expect(curve).toBeDefined();
        });
        test("throws for ED", () => {
            expect(() => (0, Curves_1.getCurve)(KeyType_1.KeyType.ED)).toThrow();
        });
        test("caches curve instances", () => {
            const a = (0, Curves_1.getCurve)(KeyType_1.KeyType.K1);
            const b = (0, Curves_1.getCurve)(KeyType_1.KeyType.K1);
            expect(a).toBe(b);
        });
    });
});
//# sourceMappingURL=crypto.test.js.map