huskies: merge 728_story_cryptographic_peer_handshake_with_trusted_keys_gating

This commit is contained in:
dave
2026-04-27 19:17:05 +00:00
parent ded8c6fd66
commit aa7b26a24a
6 changed files with 640 additions and 139 deletions
+28 -17
View File
@@ -40,10 +40,7 @@
//! verifier needs a set of allowed public keys; this module provides the
//! `verify_challenge` primitive but leaves the allow-list to story 480.
use bft_json_crdt::keypair::{
ED25519_PUBLIC_KEY_LENGTH, ED25519_SIGNATURE_LENGTH, Ed25519KeyPair, Ed25519PublicKey,
Ed25519Signature, sign, verify,
};
use bft_json_crdt::keypair::{Ed25519KeyPair, Ed25519Signature, sign};
use ed25519_dalek::SigningKey;
use fastcrypto::traits::{KeyPair, ToFromBytes};
use rand::RngCore;
@@ -95,34 +92,48 @@ pub fn sign_challenge(keypair: &Ed25519KeyPair, challenge: &str) -> SignatureHex
/// Verify that `signature_hex` is a valid Ed25519 signature over `challenge`
/// produced by the private key corresponding to `pubkey_hex`.
///
/// Uses [`verify_message_strict`] internally — the strict (non-malleable)
/// variant from `ed25519-dalek`. Cofactor-manipulated or otherwise
/// non-canonical signatures are rejected.
pub fn verify_challenge(pubkey_hex: &str, challenge: &str, signature_hex: &str) -> bool {
verify_message_strict(pubkey_hex, challenge.as_bytes(), signature_hex)
}
/// Verify an Ed25519 signature over an arbitrary `message` using
/// `ed25519_dalek::VerifyingKey::verify_strict`.
///
/// Returns `true` only if:
/// - `pubkey_hex` decodes to a valid 32-byte Ed25519 public key.
/// - `signature_hex` decodes to a valid 64-byte Ed25519 signature.
/// - The signature is cryptographically valid for `challenge`.
/// - The signature is a strict (non-malleable) Ed25519 signature over `message`.
///
/// Returns `false` on any decode error or crypto failure — callers should
/// treat `false` as an auth rejection and close the connection.
pub fn verify_challenge(pubkey_hex: &str, challenge: &str, signature_hex: &str) -> bool {
/// Returns `false` on any decode error or crypto failure.
pub fn verify_message_strict(pubkey_hex: &str, message: &[u8], signature_hex: &str) -> bool {
let pubkey_bytes = match hex_decode(pubkey_hex) {
Some(b) if b.len() == ED25519_PUBLIC_KEY_LENGTH => b,
Some(b) if b.len() == 32 => b,
_ => return false,
};
let sig_bytes = match hex_decode(signature_hex) {
Some(b) if b.len() == ED25519_SIGNATURE_LENGTH => b,
Some(b) if b.len() == 64 => b,
_ => return false,
};
let pubkey = match Ed25519PublicKey::from_bytes(&pubkey_bytes) {
let pubkey_arr: [u8; 32] = match pubkey_bytes.try_into() {
Ok(a) => a,
Err(_) => return false,
};
let sig_arr: [u8; 64] = match sig_bytes.try_into() {
Ok(a) => a,
Err(_) => return false,
};
let verifying_key = match ed25519_dalek::VerifyingKey::from_bytes(&pubkey_arr) {
Ok(k) => k,
Err(_) => return false,
};
let sig = ed25519_dalek::Signature::from_bytes(&sig_arr);
let sig = match Ed25519Signature::from_bytes(&sig_bytes) {
Ok(s) => s,
Err(_) => return false,
};
verify(pubkey, challenge.as_bytes(), sig)
verifying_key.verify_strict(message, &sig).is_ok()
}
// ── Public key helpers ────────────────────────────────────────────────