gunnar-core 3.0.0

gunnar's repository model, identity table, ACL and path sandbox. gunnar-ssh, gunnar-grpc and gunnar-cli all sit on it.
Documentation
//! Test keys for the known-answer tests, MINTED HERE from published test vectors
//! rather than committed: this repository is public and `xtask key-census` admits
//! no private key beyond the documented test PKI (2026-10-03, finish-bump).
//!
//! * Ed25519: RFC 8032 section 7.1, TEST 1 secret key.
//! * ECDSA P-256: RFC 6979 appendix A.2.5 private key `x` and its public point.
//!
//! Both are printed in their RFCs; they protect nothing.
#![allow(dead_code)]

use gunnar_core::ssh_key::{private::Ed25519Keypair, LineEnding, PrivateKey};

pub const ED25519_TEST1_SEED_HEX: &str =
    "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60";

const P256_X_HEX: &str = "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721";
const P256_UX_HEX: &str = "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6";
const P256_UY_HEX: &str = "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299";

fn bytes32(hex_str: &str) -> [u8; 32] {
    let v = hex::decode(hex_str).expect("hex");
    v.try_into().expect("32 bytes")
}

/// The OpenSSH private-key encoding of the RFC 8032 TEST 1 key, comment
/// `gunnar-kat`, exactly as `ssh-key` writes it (checkint derived from the key,
/// as for any key that was not minted with an RNG at hand).
pub fn ed25519_openssh() -> Vec<u8> {
    let pair = Ed25519Keypair::from_seed(&bytes32(ED25519_TEST1_SEED_HEX));
    let key = PrivateKey::new(pair.into(), "gunnar-kat").expect("build the key");
    key.to_openssh(LineEnding::LF)
        .expect("encode")
        .as_bytes()
        .to_vec()
}

/// PKCS#8 DER (RFC 5915 ECPrivateKey inside, public key included) of the RFC 6979
/// A.2.5 P-256 key, assembled byte by byte so no key file has to exist.
pub fn p256_pkcs8_der() -> Vec<u8> {
    let mut der =
        hex::decode("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420")
            .expect("prefix");
    der.extend_from_slice(&bytes32(P256_X_HEX));
    der.extend_from_slice(&[0xa1, 0x44, 0x03, 0x42, 0x00, 0x04]);
    der.extend_from_slice(&bytes32(P256_UX_HEX));
    der.extend_from_slice(&bytes32(P256_UY_HEX));
    der
}