package com.dangerousthings.aliro;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 * Tests for {@link CoseVerifier} — RFC 9052 COSE_Sign1 verification over
 * ECDSA P-256 + SHA-256, used to authenticate the Aliro Access Document
 * IssuerAuth signature.
 *
 * <p>Test vector generated once by harness/src/aliro_harness/issuer/cose.py
 * using a deterministic private key seed ("M2A.2-cose-verifier-test-key!!!_"
 * reduced mod n) and the literal payload "M2A.2 known-good payload".
 * Self-verified via verify_cose_sign1 before being copied here.
 *
 * <p>ECDSA k is randomised inside the python {@code cryptography} library;
 * regenerating the vector would produce a different signature. The hex
 * constants below are the canonical M2A.2 known-answer pair.
 */
class CoseVerifierTest {

    /** secp256r1 public key, uncompressed SEC1 (0x04 || X(32) || Y(32)). */
    private static final byte[] ISSUER_PUB_UNCOMP = hex(
        "04d28f7bbdb8bc7c4d1bbcb7b76e6bdffaa4994f978f316df8d5341bf164e36b82"
        + "76f90f72b5680bfd21901de452ea133f35ef44fd34e5b14ddb9a7e14ca700a0a");

    /**
     * COSE_Sign1 wire bytes (CBOR-encoded 4-element array) for the test
     * vector above. Layout:
     * <pre>
     *   [  0] 0x84            outer array(4)
     *   [  1] 0x43            protected bstr header (len 3)
     *   [  2..4] a1 01 26     {1: -7} → ES256 alg id
     *   [  5] 0xa1            unprotected map(1)
     *   [  6] 0x04            key 4 (kid)
     *   [  7] 0x48            bstr(8)
     *   [  8..15]             kid 01 02 03 04 05 06 07 08
     *   [ 16] 0x58            payload bstr 1-byte len
     *   [ 17] 0x18            len = 24
     *   [ 18..41]             "M2A.2 known-good payload" (24 bytes)
     *   [ 42] 0x58            sig bstr 1-byte len
     *   [ 43] 0x40            len = 64
     *   [ 44..107]            raw r||s ECDSA-P256 signature (64 bytes)
     * </pre>
     */
    private static final byte[] COSE_SIGN1_GOOD = hex(
        "8443a10126a1044801020304050607085818"
        + "4d32412e32206b6e6f776e2d676f6f64207061796c6f6164"
        + "5840"
        + "02e1c7996e16b3c47c020d7894f38f2c3850abc10a1a53dd56051c80412ba203"
        + "447598813bab380e0d286dc55985c24d123a7bc98f1f31419679d4f2dde0e916");

    @Test
    void verifyCoseSign1_validSignature_returnsTrue() {
        CoseVerifier verifier = new CoseVerifier();
        boolean ok = verifier.verifyCoseSign1(
            COSE_SIGN1_GOOD, (short) 0, (short) COSE_SIGN1_GOOD.length,
            ISSUER_PUB_UNCOMP, (short) 0);
        assertTrue(ok, "known-good COSE_Sign1 must verify against issuer pubkey");
    }

    @Test
    void verifyCoseSign1_tamperedPayload_returnsFalse() {
        // Flip one bit in the payload region (offset 25 = mid-payload).
        byte[] tampered = new byte[COSE_SIGN1_GOOD.length];
        System.arraycopy(COSE_SIGN1_GOOD, 0, tampered, 0, COSE_SIGN1_GOOD.length);
        tampered[25] ^= (byte) 0x01;

        CoseVerifier verifier = new CoseVerifier();
        boolean ok = verifier.verifyCoseSign1(
            tampered, (short) 0, (short) tampered.length,
            ISSUER_PUB_UNCOMP, (short) 0);
        assertFalse(ok, "tampered payload must NOT verify");
    }

    private static byte[] hex(String s) {
        s = s.replaceAll("\\s+", "");
        byte[] out = new byte[s.length() / 2];
        for (int i = 0; i < out.length; i++) {
            out[i] = (byte) Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16);
        }
        return out;
    }
}
