Add ed25519 signing and public key derivation to native library

ober

b5a37982c91459980e157bbb36447bd0423e0e1d

diff --git a/jerboa-native-rs/Cargo.lock b/jerboa-native-rs/Cargo.lock
index c306761..075476a 100644
--- a/jerboa-native-rs/Cargo.lock
+++ b/jerboa-native-rs/Cargo.lock
@@ -112,6 +112,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
+[[package]]
 name = "cpufeatures"
 version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -148,6 +154,7 @@ dependencies = [
  "cfg-if",
  "cpufeatures",
  "curve25519-dalek-derive",
+ "digest",
  "fiat-crypto",
  "rustc_version",
  "subtle",
@@ -166,6 +173,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "der"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
+dependencies = [
+ "const-oid",
+ "zeroize",
+]
+
+[[package]]
 name = "deranged"
 version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -186,6 +203,30 @@ dependencies = [
 ]
 
 [[package]]
+name = "ed25519"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
+dependencies = [
+ "pkcs8",
+ "signature",
+]
+
+[[package]]
+name = "ed25519-dalek"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
+dependencies = [
+ "curve25519-dalek",
+ "ed25519",
+ "serde",
+ "sha2",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
 name = "fallible-iterator"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -367,6 +408,7 @@ dependencies = [
 name = "jerboa-native"
 version = "0.1.0"
 dependencies = [
+ "ed25519-dalek",
  "flate2",
  "hkdf",
  "inotify",
@@ -590,6 +632,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
 
 [[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der",
+ "spki",
+]
+
+[[package]]
 name = "pkg-config"
 version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -934,6 +986,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "rand_core 0.6.4",
+]
+
+[[package]]
 name = "simd-adler32"
 version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -962,6 +1023,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
+[[package]]
 name = "stringprep"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/jerboa-native-rs/Cargo.toml b/jerboa-native-rs/Cargo.toml
index 11ae2b5..9b429bc 100644
--- a/jerboa-native-rs/Cargo.toml
+++ b/jerboa-native-rs/Cargo.toml
@@ -15,6 +15,7 @@ libc = "0.2"
 rusqlite = { version = "0.32", features = ["bundled"] }
 postgres = "0.19"
 x25519-dalek = { version = "2", features = ["static_secrets"] }
+ed25519-dalek = { version = "2", features = ["hazmat"] }
 hkdf = "0.12"
 sha2 = "0.10"
 rcgen = { version = "0.13", features = ["ring", "pem"] }
diff --git a/jerboa-native-rs/src/ed25519.rs b/jerboa-native-rs/src/ed25519.rs
new file mode 100644
index 0000000..ca609cd
--- /dev/null
+++ b/jerboa-native-rs/src/ed25519.rs
@@ -0,0 +1,62 @@
+use ed25519_dalek::{SigningKey, Signer};
+
+/// Ed25519 sign — called from chez_ssh_shim.c when CHEZ_SSH_NO_OPENSSL is defined.
+/// seed: 32-byte private key seed
+/// data/datalen: message to sign
+/// sig_out: 64-byte buffer for the signature
+/// Returns 0 on success, -1 on error.
+#[no_mangle]
+pub extern "C" fn ed25519_sign_standalone(
+    seed: *const u8,
+    data: *const u8,
+    datalen: usize,
+    sig_out: *mut u8,
+) -> i32 {
+    if seed.is_null() || sig_out.is_null() {
+        return -1;
+    }
+    if data.is_null() && datalen > 0 {
+        return -1;
+    }
+    let seed_bytes: [u8; 32] = unsafe {
+        let mut arr = [0u8; 32];
+        std::ptr::copy_nonoverlapping(seed, arr.as_mut_ptr(), 32);
+        arr
+    };
+    let signing_key = SigningKey::from_bytes(&seed_bytes);
+    let msg = if datalen == 0 {
+        &[]
+    } else {
+        unsafe { std::slice::from_raw_parts(data, datalen) }
+    };
+    let signature = signing_key.sign(msg);
+    unsafe {
+        std::ptr::copy_nonoverlapping(signature.to_bytes().as_ptr(), sig_out, 64);
+    }
+    0
+}
+
+/// Ed25519 derive public key from seed.
+/// seed: 32-byte private key seed
+/// pubkey_out: 32-byte buffer for the public key
+/// Returns 0 on success, -1 on error.
+#[no_mangle]
+pub extern "C" fn ed25519_derive_pubkey_standalone(
+    seed: *const u8,
+    pubkey_out: *mut u8,
+) -> i32 {
+    if seed.is_null() || pubkey_out.is_null() {
+        return -1;
+    }
+    let seed_bytes: [u8; 32] = unsafe {
+        let mut arr = [0u8; 32];
+        std::ptr::copy_nonoverlapping(seed, arr.as_mut_ptr(), 32);
+        arr
+    };
+    let signing_key = SigningKey::from_bytes(&seed_bytes);
+    let public_key = signing_key.verifying_key();
+    unsafe {
+        std::ptr::copy_nonoverlapping(public_key.as_bytes().as_ptr(), pubkey_out, 32);
+    }
+    0
+}
diff --git a/jerboa-native-rs/src/lib.rs b/jerboa-native-rs/src/lib.rs
index b044761..8ed19bd 100644
--- a/jerboa-native-rs/src/lib.rs
+++ b/jerboa-native-rs/src/lib.rs
@@ -10,6 +10,7 @@ mod x509;
 mod antidebug;
 mod integrity;
 mod x25519;
+mod ed25519;
 mod process_ctl;
 
 #[cfg(target_os = "linux")]