//! ML-DSA signature verification for binary upgrades.
//!
//! Provides quantum-resistant signature verification for auto-upgrade binaries
//! using FIPS 204 ML-DSA-65.
//!
//! ## Memory Constraint
//!
//! ML-DSA-65 signature verification requires the complete message in memory.
//! Unlike hash-based streaming verification (e.g., SHA-256), the ML-DSA algorithm
//! must process the entire binary at once. This means:
//!
//! - **Memory usage**: The entire binary is loaded into RAM for verification
//! - **Typical binaries**: 50-100MB for release builds, which is acceptable
//!   for modern systems (minimum 512MB RAM recommended)
//! - **No streaming**: Cannot verify signatures on files larger than available RAM
//!
//! This is an inherent property of FIPS 204 ML-DSA lattice-based signatures and
//! is accepted as a reasonable trade-off for post-quantum security.

use crate::error::{Error, Result};
use crate::logging::debug;
use saorsa_pqc::api::sig::{ml_dsa_65, MlDsaPublicKey, MlDsaSignature, MlDsaVariant};
use std::fs;
use std::path::Path;

/// Signing context for domain separation (prevents cross-protocol attacks).
pub const SIGNING_CONTEXT: &[u8] = b"ant-node-release-v1";

/// ML-DSA-65 signature size in bytes.
pub const SIGNATURE_SIZE: usize = 3309;

/// ML-DSA-65 public key size in bytes.
pub const PUBLIC_KEY_SIZE: usize = 1952;

/// Embedded release signing public key (ML-DSA-65).
///
/// This key is used to verify signatures on released binaries.
/// The corresponding private key is held by authorized release signers.
/// Generated: 2026-03-24 22:03:22 UTC
const RELEASE_SIGNING_KEY: &[u8] = &[
    0x55, 0xed, 0xf3, 0xe1, 0xf8, 0xc6, 0xd3, 0xbf, 0x45, 0x89, 0x2c, 0x79, 0x6d, 0xdd, 0x23, 0x13,
    0xbe, 0xad, 0xd9, 0xdf, 0x8e, 0x4f, 0xf4, 0x3c, 0xb8, 0x63, 0x28, 0x79, 0x6e, 0x34, 0x84, 0xd3,
    0x7d, 0xfb, 0x1e, 0x10, 0x43, 0x43, 0x89, 0xe9, 0x21, 0xa1, 0x3c, 0xd4, 0xc0, 0x0b, 0x44, 0x5c,
    0x23, 0x99, 0xbd, 0x20, 0xd7, 0xb0, 0xac, 0x58, 0x8e, 0xed, 0xa2, 0x5a, 0x71, 0xd6, 0x6c, 0xf8,
    0x3f, 0xbe, 0x9c, 0x73, 0x6c, 0x3b, 0xc3, 0xb4, 0xc3, 0x77, 0x6d, 0x49, 0x92, 0x56, 0x6e, 0x84,
    0x66, 0x28, 0x73, 0xe4, 0xc5, 0xbb, 0x32, 0xb4, 0x3a, 0x33, 0x6c, 0x33, 0x77, 0x54, 0xc8, 0xc0,
    0x18, 0x71, 0x82, 0x6a, 0xf4, 0xf2, 0x10, 0xf4, 0xb7, 0xd1, 0x57, 0xc6, 0x1d, 0x36, 0xbb, 0x80,
    0x2b, 0xaf, 0xbd, 0x52, 0xa6, 0xcc, 0xd5, 0xa1, 0x63, 0x34, 0x0c, 0xbb, 0xc3, 0x83, 0x4d, 0xfc,
    0xeb, 0x8f, 0xf7, 0x28, 0x93, 0xcf, 0x67, 0x8c, 0x9c, 0xad, 0xc6, 0xf1, 0x0a, 0x95, 0x32, 0x7f,
    0x2b, 0x2c, 0x6c, 0x65, 0x2f, 0x8f, 0x29, 0x5b, 0x47, 0x64, 0x43, 0x90, 0x33, 0x7f, 0x82, 0x3c,
    0xe3, 0xec, 0x75, 0xdb, 0x3d, 0x6d, 0xe4, 0xc1, 0x42, 0x92, 0x80, 0x99, 0xdd, 0xd2, 0x10, 0xb4,
    0x91, 0x3e, 0x7a, 0xf6, 0xed, 0xd8, 0xa5, 0x1f, 0xe4, 0x07, 0xf0, 0x7b, 0x7b, 0x5e, 0x8e, 0x12,
    0xe6, 0x6e, 0x04, 0xe5, 0xa6, 0xf4, 0x24, 0x6a, 0x28, 0x18, 0x6b, 0x0a, 0x5a, 0x36, 0x5d, 0x46,
    0xe2, 0x22, 0xd7, 0x67, 0x29, 0x7b, 0xb9, 0x8e, 0x88, 0xd9, 0x76, 0x58, 0xc9, 0x12, 0xdf, 0xb6,
    0x97, 0x76, 0x21, 0xfa, 0xec, 0x6c, 0x67, 0xea, 0x63, 0xc8, 0x3b, 0xc3, 0xf6, 0x5c, 0xc0, 0x5e,
    0xf8, 0x08, 0x82, 0x63, 0xfc, 0xf9, 0x24, 0x2a, 0xf5, 0x20, 0x8c, 0x3c, 0xb7, 0xa8, 0x84, 0x8d,
    0x87, 0xd8, 0x03, 0x74, 0xc6, 0xb1, 0x32, 0x2b, 0xe8, 0xd9, 0x21, 0x86, 0xfb, 0x28, 0x13, 0x3b,
    0xe9, 0x4d, 0x99, 0x8f, 0xa3, 0x5c, 0x8c, 0xe0, 0xc6, 0xf3, 0x9b, 0x25, 0xcc, 0x11, 0x48, 0x39,
    0x50, 0x00, 0x3b, 0x0e, 0x1d, 0xb7, 0xd2, 0xca, 0x0f, 0x10, 0x08, 0xed, 0x65, 0xa6, 0x6f, 0xee,
    0x66, 0xd7, 0x68, 0x48, 0x0d, 0x9a, 0x73, 0xdf, 0x1c, 0x00, 0xcc, 0xbe, 0x86, 0xa6, 0x4f, 0x15,
    0x6b, 0xf3, 0x56, 0xbb, 0x0d, 0x93, 0xc3, 0x8d, 0xa8, 0x31, 0x84, 0x91, 0x13, 0x7b, 0x14, 0x10,
    0x60, 0x59, 0x18, 0x16, 0x08, 0xfd, 0x2d, 0x4d, 0x0c, 0xb2, 0x8c, 0x94, 0x6f, 0x7d, 0x81, 0xe9,
    0x43, 0x9f, 0xaa, 0x13, 0xc2, 0x03, 0xff, 0xe2, 0xa2, 0x06, 0x38, 0x3b, 0x9b, 0xce, 0x85, 0x23,
    0x80, 0xea, 0xa9, 0x92, 0x2f, 0x29, 0x15, 0xba, 0x68, 0x33, 0x6a, 0x0d, 0xbe, 0x11, 0x87, 0x61,
    0xf1, 0xd5, 0x59, 0x50, 0x70, 0x51, 0x91, 0x6d, 0x4a, 0x9e, 0x69, 0x7c, 0xdd, 0x23, 0x8f, 0xa6,
    0x4e, 0xa6, 0x81, 0xe7, 0xbc, 0x62, 0x40, 0x7c, 0x0b, 0xc0, 0xa2, 0xe1, 0xf8, 0x66, 0xc1, 0x82,
    0x4a, 0x72, 0xb3, 0xee, 0x45, 0x44, 0xc7, 0x7b, 0xb1, 0xce, 0xfd, 0x80, 0xa9, 0x20, 0x20, 0xe7,
    0xad, 0xdf, 0x9a, 0xa2, 0x86, 0xf3, 0x64, 0x93, 0xb2, 0xc9, 0xb1, 0x56, 0x5d, 0x66, 0x67, 0x9c,
    0x29, 0x23, 0x53, 0xc4, 0xc9, 0x85, 0xd1, 0xed, 0x84, 0x2b, 0xc4, 0xa9, 0x93, 0x1b, 0x8f, 0xd8,
    0xff, 0x1e, 0x2d, 0xa8, 0x3c, 0x27, 0x6c, 0xa5, 0x23, 0x2a, 0x5e, 0xd0, 0xcf, 0x11, 0xe2, 0x03,
    0x7b, 0xdb, 0xa0, 0x10, 0xde, 0x2e, 0xa9, 0x5b, 0x42, 0x77, 0xcf, 0xa4, 0xc8, 0xab, 0xbd, 0x67,
    0xa8, 0x88, 0x7b, 0x51, 0xe4, 0x39, 0xeb, 0x3e, 0x4e, 0x8f, 0xf1, 0x18, 0x83, 0x43, 0x43, 0x7e,
    0xd1, 0x58, 0x27, 0x60, 0x54, 0xd5, 0xa8, 0x30, 0x54, 0xa1, 0xd0, 0xdc, 0x94, 0xf0, 0x28, 0x8d,
    0x9c, 0xe4, 0x94, 0x1a, 0xcc, 0x87, 0xf7, 0xce, 0x4c, 0x63, 0x0d, 0xd0, 0x6d, 0x45, 0x20, 0x90,
    0x5c, 0x95, 0x3e, 0x3c, 0x2e, 0xd0, 0x35, 0x2c, 0x35, 0x49, 0x2c, 0x6a, 0x7e, 0x5d, 0x5d, 0xc8,
    0xaf, 0xb2, 0x96, 0x0b, 0x88, 0xb9, 0x2b, 0x33, 0x82, 0xa4, 0xc3, 0x81, 0xd3, 0xb9, 0x7e, 0x17,
    0xba, 0xa7, 0x57, 0x47, 0x4d, 0x33, 0x55, 0xeb, 0xa5, 0x51, 0xd7, 0xe7, 0xc9, 0x46, 0x95, 0x52,
    0x72, 0xb3, 0xb7, 0x57, 0x9b, 0xf6, 0x57, 0xff, 0x9d, 0xc5, 0x93, 0x4b, 0x05, 0x48, 0x41, 0x81,
    0x25, 0xfc, 0xd9, 0x9e, 0x56, 0x18, 0x36, 0x17, 0x74, 0x1f, 0x77, 0x41, 0x98, 0x3f, 0x9e, 0x20,
    0x74, 0x3d, 0x4e, 0xe3, 0xa0, 0xa0, 0x6b, 0x64, 0x38, 0xd7, 0xf7, 0x8c, 0xef, 0x01, 0x68, 0x82,
    0x53, 0x30, 0x0a, 0xb6, 0xd1, 0x81, 0xd1, 0x70, 0x3c, 0xea, 0x96, 0xd3, 0x89, 0x21, 0x0e, 0xbb,
    0x5a, 0x80, 0x51, 0x99, 0xeb, 0xef, 0x06, 0x85, 0xae, 0x8a, 0xfd, 0x23, 0x5a, 0x91, 0x3c, 0xe1,
    0x85, 0xed, 0xf5, 0xf0, 0x58, 0x88, 0xac, 0xd0, 0xe8, 0x83, 0xb6, 0x90, 0xf2, 0xe6, 0x76, 0x5c,
    0xcf, 0xd8, 0xba, 0xba, 0x88, 0xec, 0x0b, 0xd3, 0x77, 0x66, 0x30, 0x6e, 0xcc, 0x84, 0x29, 0xd3,
    0x5f, 0xdf, 0x6e, 0x5b, 0x7f, 0x9d, 0x97, 0xed, 0x25, 0x33, 0xc6, 0x93, 0x4e, 0x62, 0x62, 0x7e,
    0x00, 0x35, 0x20, 0x68, 0x4e, 0x85, 0x4a, 0xc1, 0xe0, 0x20, 0x2f, 0x80, 0x11, 0x2f, 0x33, 0xac,
    0xd3, 0x8d, 0x56, 0x71, 0xcc, 0xa6, 0xeb, 0xe1, 0x0e, 0x3f, 0xea, 0x46, 0x16, 0xc5, 0x5e, 0x84,
    0xbd, 0xad, 0x7a, 0x7a, 0x4a, 0x8c, 0x73, 0x66, 0xaa, 0x3e, 0xdc, 0xbe, 0x65, 0xa6, 0x5a, 0xed,
    0xc6, 0x32, 0xcb, 0xbb, 0x03, 0xb9, 0xfb, 0xf3, 0x7a, 0xdc, 0x71, 0x7b, 0x46, 0x86, 0x4d, 0x55,
    0xeb, 0x70, 0x05, 0xc9, 0x82, 0x03, 0xdf, 0x22, 0xa4, 0xfd, 0x25, 0xb1, 0x37, 0x3b, 0x90, 0x80,
    0x35, 0x45, 0xab, 0x66, 0x0e, 0x4c, 0xcf, 0x5f, 0x69, 0x2f, 0x7b, 0x09, 0x7d, 0x6a, 0xb1, 0x91,
    0x0d, 0x7e, 0xb4, 0xd4, 0xcb, 0x5f, 0xa3, 0xf3, 0x00, 0x73, 0x03, 0xbf, 0xc9, 0x6e, 0x9c, 0x48,
    0x9e, 0x1c, 0x3b, 0xb0, 0x1f, 0xab, 0xb6, 0xea, 0x72, 0x04, 0x9d, 0xec, 0x6c, 0xc9, 0xd2, 0xed,
    0x6f, 0x72, 0x19, 0x5c, 0x3a, 0xfc, 0x57, 0x68, 0xf6, 0x05, 0x88, 0xd8, 0xe6, 0x38, 0xd4, 0xe0,
    0x9c, 0xed, 0xa7, 0x38, 0xa9, 0xab, 0xd4, 0x79, 0xf0, 0x3e, 0x39, 0x32, 0xa3, 0x6b, 0x2a, 0x49,
    0x53, 0x12, 0xaf, 0x7f, 0x6d, 0x26, 0xf6, 0x16, 0x8c, 0x9d, 0xac, 0x0d, 0xf7, 0x33, 0xf4, 0x69,
    0xc9, 0x47, 0xec, 0xba, 0xac, 0x95, 0x7e, 0x7d, 0x41, 0xc0, 0xca, 0xce, 0xd5, 0xf8, 0x9e, 0x49,
    0xe0, 0x4d, 0xaa, 0x13, 0xea, 0x05, 0x3a, 0xf2, 0x71, 0x3b, 0xad, 0x8b, 0x16, 0xd7, 0x12, 0x07,
    0xea, 0xf6, 0x81, 0x09, 0x3f, 0x04, 0x20, 0x2f, 0xd5, 0x78, 0xd8, 0xc4, 0xee, 0xca, 0x9e, 0x43,
    0xe1, 0x5b, 0xe4, 0x21, 0xaf, 0xeb, 0xbf, 0xf8, 0x8c, 0x52, 0x1f, 0x3f, 0xb8, 0x8f, 0x3c, 0xfa,
    0x3c, 0x94, 0x81, 0x59, 0x53, 0x21, 0xd6, 0xf1, 0x3a, 0x9a, 0x7b, 0xd8, 0x18, 0xe9, 0xbd, 0x41,
    0xc4, 0x4a, 0x5c, 0x8a, 0x21, 0x2e, 0xda, 0x70, 0x32, 0xb7, 0xef, 0x49, 0x88, 0x38, 0xe3, 0x8d,
    0xd9, 0x53, 0xd1, 0xc2, 0x9c, 0xec, 0xf6, 0x76, 0x75, 0x0a, 0x31, 0x37, 0xba, 0xd2, 0xaa, 0x37,
    0xce, 0x30, 0x7a, 0x2b, 0xdb, 0xce, 0x44, 0x86, 0x6c, 0x20, 0x1a, 0x6c, 0xae, 0x0a, 0x20, 0xbb,
    0xfa, 0x6b, 0x04, 0x11, 0xdd, 0xfd, 0x89, 0x7a, 0xaf, 0x1f, 0x63, 0x85, 0x75, 0x78, 0x62, 0x77,
    0xa0, 0x13, 0x8e, 0x4c, 0x5b, 0x11, 0x06, 0xcf, 0x97, 0x28, 0x2d, 0x9a, 0xd1, 0x5c, 0xcd, 0x3e,
    0x0a, 0xc0, 0x42, 0x93, 0x60, 0xe2, 0x37, 0x1b, 0xf5, 0x68, 0x72, 0xd6, 0x8b, 0xd1, 0x78, 0xe4,
    0x1a, 0xa5, 0xbc, 0x7f, 0xd2, 0x6e, 0xfd, 0x3e, 0xdd, 0xca, 0x6f, 0x32, 0x7b, 0x19, 0x39, 0x48,
    0x88, 0x31, 0x10, 0x7f, 0xa6, 0x4d, 0xc9, 0xe3, 0x1d, 0x40, 0xe1, 0x11, 0xfc, 0xbc, 0x32, 0xa9,
    0x06, 0xde, 0x17, 0x29, 0x14, 0x50, 0x83, 0xdb, 0x54, 0x2c, 0x9e, 0x75, 0x4e, 0xf7, 0xee, 0xc4,
    0x8d, 0xc2, 0xf3, 0xf8, 0x03, 0x02, 0x0e, 0x4e, 0xc4, 0x42, 0xef, 0x5b, 0x3b, 0x37, 0x52, 0x2e,
    0x51, 0xf3, 0x72, 0x18, 0x32, 0x48, 0x42, 0xbe, 0xdf, 0xe2, 0x46, 0x49, 0x17, 0x77, 0xe4, 0x4e,
    0x5f, 0xda, 0x50, 0xda, 0xce, 0x30, 0x65, 0x3a, 0xf9, 0xef, 0xd4, 0x8b, 0x91, 0x88, 0xbb, 0xb9,
    0x69, 0x65, 0xaa, 0x3b, 0xe1, 0xd5, 0xf8, 0x0a, 0x2a, 0x8a, 0xc9, 0x67, 0x54, 0xd8, 0x54, 0x55,
    0x3e, 0xac, 0x9e, 0x9d, 0x73, 0x6a, 0x1f, 0x21, 0xe1, 0x2b, 0xaa, 0x87, 0x16, 0x40, 0xfc, 0x37,
    0xd8, 0xa9, 0xbc, 0x39, 0x72, 0x78, 0xfc, 0x9d, 0x6d, 0xe2, 0xd8, 0x5d, 0x30, 0xbb, 0xd4, 0x9b,
    0xbd, 0xf3, 0xeb, 0x64, 0x78, 0x4a, 0x63, 0x33, 0xe9, 0x95, 0x9c, 0xac, 0x94, 0xc1, 0xf8, 0xd9,
    0x2c, 0x25, 0x46, 0x92, 0x1a, 0xa5, 0x77, 0xca, 0x02, 0xaf, 0x97, 0x49, 0x24, 0x2f, 0xe6, 0x77,
    0x3a, 0x3d, 0x35, 0x05, 0x08, 0xd9, 0x90, 0x74, 0xb2, 0x28, 0x6e, 0xbd, 0x34, 0x85, 0xd5, 0x47,
    0x88, 0x5d, 0x36, 0xe8, 0x8c, 0xd1, 0x9b, 0x5d, 0x49, 0xa8, 0x94, 0x46, 0x22, 0xbd, 0x67, 0x19,
    0x77, 0x8f, 0xb7, 0xda, 0x17, 0x68, 0x49, 0xf0, 0xf5, 0x6d, 0x2a, 0xe4, 0x9b, 0x4c, 0x07, 0xac,
    0x91, 0xa6, 0x2d, 0x41, 0x6f, 0xf6, 0x40, 0xa7, 0xe9, 0xc4, 0x3e, 0x7c, 0xc3, 0xb6, 0x8b, 0xf5,
    0x0a, 0x47, 0x19, 0xd4, 0x86, 0x16, 0x40, 0x02, 0x5a, 0x9b, 0x6f, 0xe0, 0x83, 0x9b, 0x84, 0x61,
    0x28, 0x35, 0xdb, 0xa6, 0x22, 0xae, 0x67, 0x0c, 0x72, 0x5f, 0xd0, 0xdc, 0x9c, 0x8b, 0xca, 0xa5,
    0xc7, 0xed, 0x5c, 0xe0, 0xba, 0xe7, 0x57, 0xbb, 0xf3, 0xc2, 0xa4, 0x21, 0x16, 0x11, 0xe9, 0x5e,
    0x47, 0xdd, 0xb5, 0x88, 0x9c, 0x6a, 0x2c, 0xcc, 0x6b, 0x2c, 0x19, 0xbc, 0x52, 0x3f, 0xf5, 0x51,
    0x15, 0xcd, 0xae, 0x61, 0x1f, 0xca, 0x16, 0xfb, 0xd8, 0xd7, 0x20, 0x2f, 0xe4, 0xb9, 0xd4, 0x9a,
    0x8b, 0xf7, 0xa5, 0x03, 0x5d, 0x6b, 0xde, 0x57, 0x69, 0xef, 0x50, 0xff, 0xed, 0x2d, 0x41, 0x4f,
    0x5c, 0x87, 0x7a, 0x04, 0xce, 0x91, 0xf0, 0x23, 0x14, 0x20, 0x54, 0xae, 0x25, 0x6a, 0xea, 0x71,
    0xd2, 0x5c, 0x26, 0x3b, 0xc9, 0x75, 0xe4, 0x68, 0x92, 0x66, 0x63, 0x03, 0xa0, 0xf6, 0x9c, 0x46,
    0x48, 0x89, 0xe0, 0xad, 0x10, 0x4f, 0x35, 0x6f, 0x68, 0xb9, 0x63, 0xd0, 0x9c, 0xa6, 0xa6, 0x0e,
    0x93, 0x95, 0x63, 0xda, 0xea, 0x26, 0x27, 0xab, 0x10, 0x67, 0x6d, 0xe8, 0xc8, 0x4e, 0xc9, 0x9b,
    0x53, 0x96, 0xa8, 0x6f, 0x77, 0x71, 0x37, 0xef, 0xf6, 0x52, 0x51, 0x94, 0x7a, 0x3b, 0x8e, 0xf2,
    0x4c, 0x14, 0x21, 0x59, 0xc5, 0xe9, 0x85, 0x1a, 0xba, 0xf2, 0x98, 0xaf, 0x80, 0x01, 0xc4, 0x57,
    0x78, 0xde, 0x44, 0xa9, 0x0e, 0xc5, 0x31, 0x88, 0xe0, 0x65, 0x56, 0x8c, 0x16, 0xdb, 0x80, 0x89,
    0x63, 0xd5, 0xc2, 0x91, 0x7d, 0x90, 0x89, 0x7b, 0xfa, 0xa0, 0x2a, 0x55, 0xcc, 0x62, 0x20, 0xcb,
    0xcf, 0x89, 0x28, 0x8b, 0xa5, 0x70, 0x55, 0x69, 0x76, 0x30, 0xb0, 0xf0, 0x7e, 0x30, 0x64, 0x4c,
    0x7b, 0x4b, 0x41, 0xcf, 0x6f, 0x28, 0x8b, 0x99, 0x5f, 0x8a, 0xab, 0xf5, 0xfb, 0x45, 0xb6, 0xcd,
    0xca, 0xc9, 0x87, 0xb0, 0x83, 0x3e, 0xe3, 0x18, 0xce, 0xab, 0x6b, 0xd7, 0x57, 0x84, 0xd6, 0x43,
    0x1c, 0x10, 0xc2, 0xf2, 0x8b, 0xb4, 0xd2, 0xab, 0xd1, 0xca, 0x73, 0xc6, 0xc0, 0x72, 0xa7, 0x69,
    0x74, 0x02, 0x73, 0xf6, 0xa3, 0xe3, 0x9b, 0x6d, 0xc9, 0x01, 0x16, 0x95, 0x78, 0x9e, 0x17, 0x73,
    0x39, 0xca, 0x0a, 0xab, 0x03, 0x7c, 0x3b, 0xe9, 0x41, 0x69, 0x71, 0x47, 0xba, 0xc4, 0xc1, 0x34,
    0x9f, 0x47, 0x2b, 0xf2, 0x8e, 0x01, 0xf0, 0xe2, 0x86, 0x18, 0xb1, 0x80, 0x46, 0x06, 0x61, 0x42,
    0xd8, 0x25, 0x41, 0xe1, 0xd7, 0x17, 0x8b, 0xa3, 0x1f, 0x64, 0x91, 0x1f, 0x28, 0x82, 0x1a, 0x63,
    0x11, 0x68, 0xa7, 0x0f, 0x9a, 0x8c, 0xaf, 0x61, 0x18, 0x98, 0x31, 0x3a, 0x95, 0xe4, 0xf4, 0x73,
    0x8b, 0xf5, 0xb2, 0x1c, 0x19, 0xcb, 0x22, 0x77, 0x23, 0x07, 0x85, 0x80, 0xc9, 0x1c, 0x74, 0xee,
    0xbf, 0x97, 0x97, 0x60, 0x17, 0x29, 0x2a, 0x4c, 0x50, 0x64, 0x7e, 0xa0, 0x99, 0x13, 0x86, 0xa6,
    0x89, 0x3c, 0xd6, 0xd8, 0x9c, 0xef, 0x24, 0xe6, 0x92, 0xe9, 0x58, 0xc6, 0x38, 0x61, 0x86, 0x39,
    0xcf, 0xbe, 0x70, 0xf6, 0x5a, 0x69, 0x80, 0x6e, 0x80, 0xcb, 0x14, 0x6f, 0x9a, 0x26, 0x30, 0x28,
    0x3d, 0x32, 0x07, 0x41, 0x24, 0x9c, 0x84, 0xba, 0x4a, 0x67, 0x5f, 0xf0, 0x17, 0x28, 0x23, 0xfe,
    0x39, 0x39, 0x80, 0xb5, 0xac, 0x28, 0x53, 0x97, 0xdd, 0x0d, 0x5b, 0x55, 0xd4, 0x22, 0x81, 0x81,
    0x4d, 0xb4, 0x8b, 0x2b, 0x33, 0xad, 0x62, 0xd5, 0x8d, 0xfe, 0x39, 0xd4, 0xd8, 0xf1, 0x5d, 0x0f,
    0x19, 0x64, 0xbf, 0xac, 0x91, 0xf1, 0x92, 0x3c, 0x7f, 0x3a, 0xb8, 0xa6, 0xb5, 0xd7, 0x3a, 0x36,
    0xc8, 0x9c, 0x65, 0x1b, 0xa6, 0x2a, 0x98, 0x15, 0x96, 0x23, 0xd4, 0xe3, 0xa6, 0x07, 0x23, 0xa9,
    0xce, 0x16, 0x50, 0xb1, 0x97, 0xce, 0x69, 0x00, 0x68, 0x1a, 0xf8, 0x71, 0x88, 0x55, 0x5e, 0xf1,
    0xd9, 0x81, 0x64, 0x1c, 0x95, 0x2b, 0x68, 0xf9, 0xbe, 0x78, 0x9a, 0xbb, 0xf9, 0x2c, 0x7f, 0x6e,
    0xed, 0x66, 0xfd, 0x44, 0xaa, 0xfe, 0x96, 0x84, 0xde, 0xbc, 0x47, 0x78, 0xc4, 0x90, 0xb8, 0xe4,
    0xde, 0xb8, 0x3f, 0xaf, 0xc5, 0x05, 0xe6, 0x6e, 0x62, 0x4c, 0x43, 0x07, 0xbf, 0x06, 0x99, 0xf3,
    0x18, 0x38, 0x26, 0x3f, 0x87, 0xd7, 0x04, 0x0e, 0xa0, 0x0d, 0xbd, 0xf8, 0xda, 0x50, 0x24, 0xe9,
    0x46, 0x28, 0xbe, 0x70, 0x7f, 0x79, 0x25, 0xd1, 0x1a, 0xe6, 0x5e, 0x74, 0xe5, 0x2f, 0x5d, 0xd2,
    0xc2, 0x60, 0xe9, 0x6e, 0x15, 0x4c, 0x70, 0x40, 0x99, 0x88, 0xe0, 0x93, 0xfe, 0x36, 0x1e, 0x64,
    0x14, 0xa5, 0xcf, 0x35, 0xf2, 0xd2, 0xab, 0x8d, 0xf4, 0x1d, 0x29, 0xbd, 0xac, 0x08, 0xaf, 0xd6,
];

/// Verify the ML-DSA signature on a binary file using the embedded release key.
///
/// # Arguments
///
/// * `binary_path` - Path to the binary to verify
/// * `signature` - The ML-DSA-65 signature bytes
///
/// # Errors
///
/// Returns an error if:
/// - The binary file cannot be read
/// - The signature format is invalid
/// - The signature verification fails
pub fn verify_binary_signature(binary_path: &Path, signature: &[u8]) -> Result<()> {
    let public_key = MlDsaPublicKey::from_bytes(MlDsaVariant::MlDsa65, RELEASE_SIGNING_KEY)
        .map_err(|e| Error::Crypto(format!("Invalid release key: {e}")))?;

    verify_binary_signature_with_key(binary_path, signature, &public_key)
}

/// Verify signature with an explicit public key.
///
/// This function is useful for testing and for cases where the public key
/// is provided externally rather than embedded in the binary.
///
/// # Arguments
///
/// * `binary_path` - Path to the binary to verify
/// * `signature` - The ML-DSA-65 signature bytes
/// * `public_key` - The public key to verify against
///
/// # Errors
///
/// Returns an error if:
/// - The binary file cannot be read
/// - The signature has an invalid size
/// - The signature format is invalid
/// - The signature verification fails
pub fn verify_binary_signature_with_key(
    binary_path: &Path,
    signature: &[u8],
    public_key: &MlDsaPublicKey,
) -> Result<()> {
    debug!("Verifying signature for: {}", binary_path.display());

    // Read binary content
    let binary_content = fs::read(binary_path).map_err(|e| {
        Error::Crypto(format!(
            "Failed to read binary '{}': {e}",
            binary_path.display()
        ))
    })?;

    // Validate signature size
    if signature.len() != SIGNATURE_SIZE {
        return Err(Error::Crypto(format!(
            "Invalid signature size: expected {SIGNATURE_SIZE}, got {}",
            signature.len()
        )));
    }

    // Parse signature
    let sig = MlDsaSignature::from_bytes(MlDsaVariant::MlDsa65, signature)
        .map_err(|e| Error::Crypto(format!("Invalid signature format: {e}")))?;

    // Verify with context
    let dsa = ml_dsa_65();
    let valid = dsa
        .verify_with_context(public_key, &binary_content, &sig, SIGNING_CONTEXT)
        .map_err(|e| Error::Crypto(format!("Signature verification error: {e}")))?;

    if valid {
        debug!("Signature verified successfully");
        Ok(())
    } else {
        Err(Error::Crypto(
            "Signature verification failed: invalid signature".to_string(),
        ))
    }
}

/// Verify a signature from a detached .sig file.
///
/// # Arguments
///
/// * `binary_path` - Path to the binary to verify
/// * `signature_path` - Path to the detached signature file
///
/// # Errors
///
/// Returns an error if the signature file cannot be read or verification fails.
pub fn verify_from_file(binary_path: &Path, signature_path: &Path) -> Result<()> {
    debug!(
        "Verifying {} with signature from {}",
        binary_path.display(),
        signature_path.display()
    );

    let signature = fs::read(signature_path)?;
    verify_binary_signature(binary_path, &signature)
}

/// Verify from file with explicit key.
///
/// # Arguments
///
/// * `binary_path` - Path to the binary to verify
/// * `signature_path` - Path to the detached signature file
/// * `public_key` - The public key to verify against
///
/// # Errors
///
/// Returns an error if the signature file cannot be read or verification fails.
pub fn verify_from_file_with_key(
    binary_path: &Path,
    signature_path: &Path,
    public_key: &MlDsaPublicKey,
) -> Result<()> {
    debug!(
        "Verifying {} with signature from {}",
        binary_path.display(),
        signature_path.display()
    );

    let signature = fs::read(signature_path)?;
    verify_binary_signature_with_key(binary_path, &signature, public_key)
}

#[cfg(test)]
#[allow(
    clippy::unwrap_used,
    clippy::expect_used,
    clippy::cast_possible_truncation,
    clippy::cast_sign_loss
)]
mod tests {
    use super::*;
    use saorsa_pqc::api::sig::ml_dsa_65;
    use std::io::Write;
    use tempfile::NamedTempFile;

    /// Test 1: Valid signature verification
    #[test]
    fn test_verify_valid_signature() {
        let dsa = ml_dsa_65();
        let (public_key, secret_key) = dsa.generate_keypair().unwrap();
        let binary_content = b"test binary content for signing";

        let mut file = NamedTempFile::new().unwrap();
        file.write_all(binary_content).unwrap();

        let signature = dsa
            .sign_with_context(&secret_key, binary_content, SIGNING_CONTEXT)
            .unwrap();

        let result =
            verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &public_key);
        assert!(result.is_ok(), "Valid signature should verify: {result:?}");
    }

    /// Test 2: Invalid signature rejected
    #[test]
    fn test_reject_invalid_signature() {
        let dsa = ml_dsa_65();
        let (public_key, _) = dsa.generate_keypair().unwrap();
        let binary_content = b"test binary content";

        let mut file = NamedTempFile::new().unwrap();
        file.write_all(binary_content).unwrap();

        // All-zero signature is invalid
        let invalid_sig = vec![0u8; SIGNATURE_SIZE];

        let result = verify_binary_signature_with_key(file.path(), &invalid_sig, &public_key);
        assert!(result.is_err(), "Invalid signature should be rejected");
    }

    /// Test 3: Wrong key rejected
    #[test]
    fn test_reject_wrong_key() {
        let dsa = ml_dsa_65();
        let (_, secret_key) = dsa.generate_keypair().unwrap();
        let (wrong_key, _) = dsa.generate_keypair().unwrap();
        let binary_content = b"test binary content";

        let mut file = NamedTempFile::new().unwrap();
        file.write_all(binary_content).unwrap();

        let signature = dsa
            .sign_with_context(&secret_key, binary_content, SIGNING_CONTEXT)
            .unwrap();

        let result =
            verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &wrong_key);
        assert!(result.is_err(), "Wrong key should fail verification");
    }

    /// Test 4: Modified binary rejected
    #[test]
    fn test_reject_modified_binary() {
        let dsa = ml_dsa_65();
        let (public_key, secret_key) = dsa.generate_keypair().unwrap();
        let original_content = b"original binary content";

        // Sign the original content
        let signature = dsa
            .sign_with_context(&secret_key, original_content, SIGNING_CONTEXT)
            .unwrap();

        // Write modified content to file
        let mut file = NamedTempFile::new().unwrap();
        file.write_all(b"MODIFIED binary content").unwrap();

        let result =
            verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &public_key);
        assert!(result.is_err(), "Modified binary should fail verification");
    }

    /// Test 5: Malformed signature rejected
    #[test]
    fn test_reject_malformed_signature() {
        let dsa = ml_dsa_65();
        let (public_key, _) = dsa.generate_keypair().unwrap();
        let binary_content = b"test content";

        let mut file = NamedTempFile::new().unwrap();
        file.write_all(binary_content).unwrap();

        // Too short signature
        let short_sig = vec![0u8; 100];

        let result = verify_binary_signature_with_key(file.path(), &short_sig, &public_key);
        assert!(result.is_err(), "Malformed signature should be rejected");
        assert!(
            result
                .unwrap_err()
                .to_string()
                .contains("Invalid signature size"),
            "Error should mention invalid size"
        );
    }

    /// Test 6: Empty file handling
    #[test]
    fn test_empty_file() {
        let dsa = ml_dsa_65();
        let (public_key, secret_key) = dsa.generate_keypair().unwrap();
        let empty_content: &[u8] = b"";

        let mut file = NamedTempFile::new().unwrap();
        file.write_all(empty_content).unwrap();

        let signature = dsa
            .sign_with_context(&secret_key, empty_content, SIGNING_CONTEXT)
            .unwrap();

        let result =
            verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &public_key);
        assert!(result.is_ok(), "Empty file should verify: {result:?}");
    }

    /// Test 7: Non-existent file
    #[test]
    fn test_nonexistent_file() {
        let dsa = ml_dsa_65();
        let (public_key, _) = dsa.generate_keypair().unwrap();
        let path = Path::new("/nonexistent/path/to/binary");
        let sig = vec![0u8; SIGNATURE_SIZE];

        let result = verify_binary_signature_with_key(path, &sig, &public_key);
        assert!(result.is_err(), "Non-existent file should fail");
    }

    /// Test 8: Context binding (cross-protocol attack prevention)
    #[test]
    fn test_wrong_context_rejected() {
        let dsa = ml_dsa_65();
        let (public_key, secret_key) = dsa.generate_keypair().unwrap();
        let content = b"binary content";

        let mut file = NamedTempFile::new().unwrap();
        file.write_all(content).unwrap();

        // Sign with wrong context
        let signature = dsa
            .sign_with_context(&secret_key, content, b"wrong-context-string")
            .unwrap();

        // Verify with correct context should fail
        let result =
            verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &public_key);
        assert!(
            result.is_err(),
            "Wrong context should fail verification: {result:?}"
        );
    }

    /// Test 9: Verify from detached .sig file
    #[test]
    fn test_verify_from_sig_file() {
        let dsa = ml_dsa_65();
        let (public_key, secret_key) = dsa.generate_keypair().unwrap();
        let content = b"binary content for sig file test";

        let mut binary_file = NamedTempFile::new().unwrap();
        binary_file.write_all(content).unwrap();

        let signature = dsa
            .sign_with_context(&secret_key, content, SIGNING_CONTEXT)
            .unwrap();

        let mut sig_file = NamedTempFile::new().unwrap();
        sig_file.write_all(&signature.to_bytes()).unwrap();

        let result = verify_from_file_with_key(binary_file.path(), sig_file.path(), &public_key);
        assert!(
            result.is_ok(),
            "Detached sig file verification should succeed: {result:?}"
        );
    }

    /// Test 10: Large binary file
    #[test]
    fn test_large_binary() {
        let dsa = ml_dsa_65();
        let (public_key, secret_key) = dsa.generate_keypair().unwrap();

        // Create 1MB of test content
        let large_content: Vec<u8> = (0..1_000_000).map(|i| (i % 256) as u8).collect();

        let mut file = NamedTempFile::new().unwrap();
        file.write_all(&large_content).unwrap();

        let signature = dsa
            .sign_with_context(&secret_key, &large_content, SIGNING_CONTEXT)
            .unwrap();

        let result =
            verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &public_key);
        assert!(result.is_ok(), "Large binary should verify: {result:?}");
    }

    /// Test: Embedded release key is properly configured
    #[test]
    fn test_release_key_configured() {
        // Verify the embedded key has correct size
        assert_eq!(
            RELEASE_SIGNING_KEY.len(),
            PUBLIC_KEY_SIZE,
            "Embedded release key should be {PUBLIC_KEY_SIZE} bytes"
        );

        // Verify the key can be parsed
        let result = MlDsaPublicKey::from_bytes(MlDsaVariant::MlDsa65, RELEASE_SIGNING_KEY);
        assert!(
            result.is_ok(),
            "Embedded release key should be valid ML-DSA-65 public key"
        );
    }

    /// Test: Invalid signature rejected with embedded key
    #[test]
    fn test_embedded_key_rejects_invalid_signature() {
        let content = b"test binary content";

        let mut file = NamedTempFile::new().unwrap();
        file.write_all(content).unwrap();

        // All-zero signature should be rejected
        let invalid_sig = vec![0u8; SIGNATURE_SIZE];

        let result = verify_binary_signature(file.path(), &invalid_sig);
        assert!(result.is_err(), "Invalid signature should be rejected");
    }
}
