pub trait KeyCustody: Send + Sync {
// Required methods
fn generate_keypair(
&self,
key_type: KeyType,
) -> impl Future<Output = Result<KeyHandle, PlatformError>> + Send;
fn sign(
&self,
key: &KeyHandle,
data: &[u8],
) -> impl Future<Output = Result<Signature, PlatformError>> + Send;
fn public_key(
&self,
key: &KeyHandle,
) -> impl Future<Output = Result<PublicKey, PlatformError>> + Send;
fn destroy_key(
&self,
key: &KeyHandle,
) -> impl Future<Output = Result<(), PlatformError>> + Send;
fn dh_agree(
&self,
key: &KeyHandle,
peer_public: &[u8; 32],
) -> impl Future<Output = Result<SharedSecret, PlatformError>> + Send;
fn derive_pseudonym(
&self,
key: &KeyHandle,
context_id: &[u8],
) -> impl Future<Output = Result<PseudonymKeypair, PlatformError>> + Send;
fn derive_rotatable_pseudonym(
&self,
key: &KeyHandle,
context_id: &[u8],
pseudonym_epoch: u64,
) -> impl Future<Output = Result<PseudonymKeypair, PlatformError>> + Send;
fn custody_type(&self, key: &KeyHandle) -> CustodyType;
}Expand description
Cryptographic key management trait.
Abstracts key generation, signing, key agreement, and pseudonym derivation
behind a uniform interface. Production implementations delegate to hardware
security modules (Secure Enclave on iOS, Android Keystore on Android). The
testing implementation (InMemoryKeyCustody) stores keys in a
HashMap.
All methods that perform I/O or hardware interaction are async. The
custody_type method is synchronous because it
only inspects local state.
See ADR-006 for the full design rationale.
Required Methods§
Sourcefn generate_keypair(
&self,
key_type: KeyType,
) -> impl Future<Output = Result<KeyHandle, PlatformError>> + Send
fn generate_keypair( &self, key_type: KeyType, ) -> impl Future<Output = Result<KeyHandle, PlatformError>> + Send
Generate a new keypair of the specified type.
Ed25519 keys may be hardware-backed (Secure Enclave, Keystore).
X25519 wrapping keys are always software-managed but routed through
KeyCustody for API consistency.
Returns an opaque KeyHandle that references the generated key.
Sourcefn sign(
&self,
key: &KeyHandle,
data: &[u8],
) -> impl Future<Output = Result<Signature, PlatformError>> + Send
fn sign( &self, key: &KeyHandle, data: &[u8], ) -> impl Future<Output = Result<Signature, PlatformError>> + Send
Sign data with an Ed25519 key.
§Errors
Returns PlatformError::KeyNotFound if the handle is invalid.
Returns PlatformError::WrongKeyType if the handle refers to an
X25519 key.
Sourcefn public_key(
&self,
key: &KeyHandle,
) -> impl Future<Output = Result<PublicKey, PlatformError>> + Send
fn public_key( &self, key: &KeyHandle, ) -> impl Future<Output = Result<PublicKey, PlatformError>> + Send
Return the public key for a handle.
Works for both Ed25519 and X25519 key handles.
§Errors
Returns PlatformError::KeyNotFound if the handle is invalid.
Sourcefn destroy_key(
&self,
key: &KeyHandle,
) -> impl Future<Output = Result<(), PlatformError>> + Send
fn destroy_key( &self, key: &KeyHandle, ) -> impl Future<Output = Result<(), PlatformError>> + Send
Destroy key material associated with a handle.
After this call, all subsequent operations with the same handle will
return PlatformError::KeyNotFound.
§Errors
Returns PlatformError::KeyNotFound if the handle is already invalid.
Sourcefn dh_agree(
&self,
key: &KeyHandle,
peer_public: &[u8; 32],
) -> impl Future<Output = Result<SharedSecret, PlatformError>> + Send
fn dh_agree( &self, key: &KeyHandle, peer_public: &[u8; 32], ) -> impl Future<Output = Result<SharedSecret, PlatformError>> + Send
Perform X25519 Diffie-Hellman key agreement.
Returns the 32-byte shared secret. The private key never leaves the custody boundary — the scalar multiplication happens inside the adapter.
§Errors
Returns PlatformError::KeyNotFound if the handle is invalid.
Returns PlatformError::WrongKeyType if the handle refers to an
Ed25519 key.
Sourcefn derive_pseudonym(
&self,
key: &KeyHandle,
context_id: &[u8],
) -> impl Future<Output = Result<PseudonymKeypair, PlatformError>> + Send
fn derive_pseudonym( &self, key: &KeyHandle, context_id: &[u8], ) -> impl Future<Output = Result<PseudonymKeypair, PlatformError>> + Send
Derive a deterministic, context-scoped pseudonym keypair (v1, non-rotatable).
Algorithm (all implementations MUST produce identical output):
seed = HMAC-SHA256(identity_key_material, context_id || "scp-pseudonym")pseudonym_keypair = Ed25519_keygen(seed[0..32])
For hardware-backed keys: the HMAC is computed inside the HSM using an
associated symmetric key derived during generate_keypair.
For software keys: the HMAC uses the raw Ed25519 public key bytes (ADR-027 amendment).
The returned PseudonymKeypair is always software-managed (derived
output).
For contexts that support pseudonym rotation (BLACK-001 mitigation),
use derive_rotatable_pseudonym instead.
§Errors
Returns PlatformError::KeyNotFound if the handle is invalid.
Returns PlatformError::WrongKeyType if the handle refers to an
X25519 key.
Sourcefn derive_rotatable_pseudonym(
&self,
key: &KeyHandle,
context_id: &[u8],
pseudonym_epoch: u64,
) -> impl Future<Output = Result<PseudonymKeypair, PlatformError>> + Send
fn derive_rotatable_pseudonym( &self, key: &KeyHandle, context_id: &[u8], pseudonym_epoch: u64, ) -> impl Future<Output = Result<PseudonymKeypair, PlatformError>> + Send
Derive a rotatable, epoch-scoped pseudonym keypair (v2).
Mitigates relay-side pseudonym correlation (BLACK-001) by including a rotation epoch in the HMAC derivation, producing a different pseudonym for each epoch within the same context.
Algorithm (all implementations MUST produce identical output):
seed = HMAC-SHA256(identity_key_material, context_id || epoch_BE || "scp-pseudonym-v2")pseudonym_keypair = Ed25519_keygen(seed[0..32])
where epoch_BE is the pseudonym_epoch as an 8-byte big-endian u64.
The domain separator "scp-pseudonym-v2" is intentionally different from
the v1 separator "scp-pseudonym" so that epoch 0 in v2 produces a
different pseudonym than the v1 derivation. This prevents accidental
domain confusion.
§Errors
Returns PlatformError::KeyNotFound if the handle is invalid.
Returns PlatformError::WrongKeyType if the handle refers to an
X25519 key.
Sourcefn custody_type(&self, key: &KeyHandle) -> CustodyType
fn custody_type(&self, key: &KeyHandle) -> CustodyType
Returns the custody type for a given key handle.
This is a synchronous query against local state — no I/O is required.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.