Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 20 additions & 30 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ use std::io::Write;
use std::path::PathBuf;

use clap::{Parser, Subcommand};
use leansig::serialization::Serializable;
use leansig::signature::{
generalized_xmss::instantiations_poseidon_top_level::lifetime_2_to_the_32::hashing_optimized::SIGTopLevelTargetSumLifetime32Dim64Base8,
SignatureScheme,
};
use serde_json::Value;

// Type alias for the public key type
type PublicKeyType = <SIGTopLevelTargetSumLifetime32Dim64Base8 as SignatureScheme>::PublicKey;

/// A CLI tool to generate cryptographic keys for hash-based signatures.
#[derive(Parser, Debug)]
Expand Down Expand Up @@ -111,40 +114,27 @@ fn generate_keys(
}

/// Convert pubkey JSON file to hex string
/// Reads the JSON file, extracts root and parameter arrays,
/// converts each u32 to 4 bytes (little-endian), concatenates,
/// and returns hex string with "0x" prefix
/// Reads the JSON file, deserializes into PublicKey type using serde,
/// then uses SSZ serialization (to_bytes) to get canonical form bytes.
/// Returns hex string with "0x" prefix.
///
/// Note: The JSON file contains field elements in Montgomery form (internal representation).
/// We must use to_bytes() which performs SSZ serialization to get the canonical form
/// that is expected by from_bytes() during signature verification.
fn pubkey_json_to_hex(pk_file_path: &PathBuf) -> Result<String, Box<dyn std::error::Error>> {
// Read JSON file
let json_content = fs::read_to_string(pk_file_path)?;
let json: Value = serde_json::from_str(&json_content)?;

// Extract root array (8 u32 integers)
let root_array = json["root"]
.as_array()
.ok_or("Missing or invalid 'root' array")?;

// Extract parameter array (5 u32 integers)
let param_array = json["parameter"]
.as_array()
.ok_or("Missing or invalid 'parameter' array")?;

// Convert root array to bytes (little-endian)
let mut pubkey_bytes = Vec::new();
for val in root_array {
let num = val.as_u64().ok_or("Invalid number in root array")? as u32;
pubkey_bytes.extend_from_slice(&num.to_le_bytes());
}

// Convert parameter array to bytes (little-endian)
for val in param_array {
let num = val.as_u64().ok_or("Invalid number in parameter array")? as u32;
pubkey_bytes.extend_from_slice(&num.to_le_bytes());
}


// Deserialize into PublicKeyType using serde (this handles Montgomery form)
let public_key: PublicKeyType = serde_json::from_str(&json_content)?;

// Use to_bytes() which uses SSZ serialization (canonical form)
// This is the correct format expected by from_bytes() during verification
let pubkey_bytes = public_key.to_bytes();

// Convert bytes to hex string with "0x" prefix
let hex_string = format!("0x{}", hex::encode(&pubkey_bytes));

Ok(hex_string)
}

Expand Down