#![allow(dead_code)]
use super::super::super::apr_args::{AprSignArgs, AprVerifySigArgs};
use super::super::super::commands::{CliError, CliResult, CommandResult};
#[cfg(feature = "format-signing")]
use super::emit_output;
#[cfg(feature = "format-signing")]
use std::fs;
pub(in super::super) fn run_sign(
args: &AprSignArgs,
global: &super::super::super::args::Args,
) -> CliResult<CommandResult> {
#[cfg(not(feature = "format-signing"))]
{
let _ = (args, global);
Err(CliError::InvalidArgument(
"apr sign requires --features format-signing".to_string(),
))
}
#[cfg(feature = "format-signing")]
{
use ed25519_dalek::Signer;
let key_bytes = fs::read(&args.key)
.map_err(|e| CliError::InvalidArgument(format!("Failed to read key file: {e}")))?;
if key_bytes.len() < 32 {
return Err(CliError::InvalidArgument(format!(
"Key file too small: {} bytes (need 32)",
key_bytes.len()
)));
}
let seed: [u8; 32] = key_bytes[..32]
.try_into()
.map_err(|_| CliError::InvalidArgument("Invalid key data".to_string()))?;
let signing_key = ed25519_dalek::SigningKey::from_bytes(&seed);
let model_data = fs::read(&args.file)
.map_err(|e| CliError::InvalidArgument(format!("Failed to read model: {e}")))?;
let signature = signing_key.sign(&model_data);
let verifying_key = signing_key.verifying_key();
let mut output = model_data;
output.extend_from_slice(&signature.to_bytes());
output.extend_from_slice(verifying_key.as_bytes());
fs::write(&args.output, &output)
.map_err(|e| CliError::InvalidArgument(format!("Failed to write signed model: {e}")))?;
let out_display = args.output.display().to_string();
let pk_hex = hex::encode(verifying_key.as_bytes());
emit_output(
global,
|| {
println!("{{\"status\":\"signed\",\"output\":\"{out_display}\",\"pubkey_hex\":\"{pk_hex}\"}}");
},
|| {
println!("Signed: {out_display}");
println!("Public key: {pk_hex}");
},
);
Ok(CommandResult::success("Model signed"))
}
}
#[cfg(feature = "format-signing")]
fn load_verifying_key_from_file(
pk_path: &std::path::Path,
) -> CliResult<ed25519_dalek::VerifyingKey> {
let pk_bytes = fs::read(pk_path)
.map_err(|e| CliError::InvalidArgument(format!("Failed to read pubkey: {e}")))?;
if pk_bytes.len() < 32 {
return Err(CliError::InvalidArgument(
"Pubkey file too small".to_string(),
));
}
let bytes: [u8; 32] = pk_bytes[..32]
.try_into()
.map_err(|_| CliError::InvalidArgument("Invalid public key length".to_string()))?;
ed25519_dalek::VerifyingKey::from_bytes(&bytes)
.map_err(|e| CliError::InvalidArgument(format!("Invalid public key: {e}")))
}
#[cfg(feature = "format-signing")]
fn load_verifying_key_embedded(
content: &[u8],
pubkey_start: usize,
) -> CliResult<ed25519_dalek::VerifyingKey> {
let bytes: [u8; 32] = content
.get(pubkey_start..)
.ok_or_else(|| CliError::InvalidArgument("Public key offset out of bounds".to_string()))?
.try_into()
.map_err(|_| CliError::InvalidArgument("Invalid embedded public key length".to_string()))?;
ed25519_dalek::VerifyingKey::from_bytes(&bytes)
.map_err(|e| CliError::InvalidArgument(format!("Invalid embedded public key: {e}")))
}
pub(in super::super) fn run_verify_sig(
args: &AprVerifySigArgs,
global: &super::super::super::args::Args,
) -> CliResult<CommandResult> {
#[cfg(not(feature = "format-signing"))]
{
let _ = (args, global);
Err(CliError::InvalidArgument(
"apr verify-sig requires --features format-signing".to_string(),
))
}
#[cfg(feature = "format-signing")]
{
use ed25519_dalek::Verifier;
let content = fs::read(&args.file)
.map_err(|e| CliError::InvalidArgument(format!("Failed to read file: {e}")))?;
if content.len() < 96 {
return Err(CliError::InvalidArgument(
"File too small to contain signature block (need 96+ bytes)".to_string(),
));
}
let sig_start = content.len() - 96;
let pubkey_start = content.len() - 32;
let sig_bytes: [u8; 64] = content[sig_start..pubkey_start]
.try_into()
.map_err(|_| CliError::InvalidArgument("Invalid signature".to_string()))?;
let signature = ed25519_dalek::Signature::from_bytes(&sig_bytes);
let verifying_key = match &args.pubkey {
Some(pk_path) => load_verifying_key_from_file(pk_path)?,
None => load_verifying_key_embedded(&content, pubkey_start)?,
};
let model_data = &content[..sig_start];
let valid = verifying_key.verify(model_data, &signature).is_ok();
emit_output(
global,
|| println!("{{\"valid\":{valid}}}"),
|| println!("Signature {}", if valid { "VALID" } else { "INVALID" }),
);
if valid {
Ok(CommandResult::success("Signature valid"))
} else {
Err(CliError::InvalidArgument(
"Signature verification failed".to_string(),
))
}
}
}