Skip to main content

actr_platform_native/
crypto.rs

1//! Native cryptography provider (ed25519-dalek + sha2)
2
3use async_trait::async_trait;
4use ed25519_dalek::{PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH, Signature, VerifyingKey};
5use sha2::{Digest, Sha256};
6
7use actr_platform_traits::{CryptoProvider, PlatformError};
8
9/// Native cryptography provider backed by ed25519-dalek and sha2.
10pub struct NativeCryptoProvider;
11
12#[async_trait]
13impl CryptoProvider for NativeCryptoProvider {
14    async fn ed25519_verify(
15        &self,
16        public_key: &[u8],
17        message: &[u8],
18        signature: &[u8],
19    ) -> Result<(), PlatformError> {
20        let pubkey_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.try_into().map_err(|_| {
21            PlatformError::Crypto(format!(
22                "Ed25519 public key must be {PUBLIC_KEY_LENGTH} bytes"
23            ))
24        })?;
25
26        let verifying_key = VerifyingKey::from_bytes(&pubkey_bytes)
27            .map_err(|e| PlatformError::Crypto(format!("invalid Ed25519 public key: {e}")))?;
28
29        let sig_bytes: [u8; SIGNATURE_LENGTH] = signature.try_into().map_err(|_| {
30            PlatformError::Crypto(format!(
31                "Ed25519 signature must be {SIGNATURE_LENGTH} bytes"
32            ))
33        })?;
34        let sig = Signature::from_bytes(&sig_bytes);
35
36        verifying_key
37            .verify_strict(message, &sig)
38            .map_err(|e| PlatformError::Crypto(format!("Ed25519 verification failed: {e}")))
39    }
40
41    async fn sha256(&self, data: &[u8]) -> Result<[u8; 32], PlatformError> {
42        let mut hasher = Sha256::new();
43        hasher.update(data);
44        Ok(hasher.finalize().into())
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    use ed25519_dalek::{Signer, SigningKey};
52    use rand::rngs::OsRng;
53
54    #[tokio::test]
55    async fn sha256_produces_correct_hash() {
56        let provider = NativeCryptoProvider;
57        let hash = provider.sha256(b"hello").await.unwrap();
58        // Known SHA-256 of "hello"
59        let expected = [
60            0x2c, 0xf2, 0x4d, 0xba, 0x5f, 0xb0, 0xa3, 0x0e, 0x26, 0xe8, 0x3b, 0x2a, 0xc5, 0xb9,
61            0xe2, 0x9e, 0x1b, 0x16, 0x1e, 0x5c, 0x1f, 0xa7, 0x42, 0x5e, 0x73, 0x04, 0x33, 0x62,
62            0x93, 0x8b, 0x98, 0x24,
63        ];
64        assert_eq!(hash, expected);
65    }
66
67    #[tokio::test]
68    async fn ed25519_verify_valid_signature() {
69        let provider = NativeCryptoProvider;
70        let signing_key = SigningKey::generate(&mut OsRng);
71        let verifying_key = signing_key.verifying_key();
72
73        let message = b"test message";
74        let signature = signing_key.sign(message);
75
76        let result = provider
77            .ed25519_verify(verifying_key.as_bytes(), message, &signature.to_bytes())
78            .await;
79        assert!(result.is_ok());
80    }
81
82    #[tokio::test]
83    async fn ed25519_verify_rejects_bad_signature() {
84        let provider = NativeCryptoProvider;
85        let signing_key = SigningKey::generate(&mut OsRng);
86        let verifying_key = signing_key.verifying_key();
87
88        let message = b"test message";
89        let bad_sig = [0u8; 64];
90
91        let result = provider
92            .ed25519_verify(verifying_key.as_bytes(), message, &bad_sig)
93            .await;
94        assert!(result.is_err());
95    }
96}