use alloc::{format, string::ToString, vec, vec::Vec};
use mls_rs::client_builder::MlsConfig;
use mls_rs::identity::basic::{BasicCredential, BasicIdentityProvider};
use mls_rs::identity::SigningIdentity;
use mls_rs::{CipherSuite, CipherSuiteProvider, Client, CryptoProvider};
use mls_rs_core::crypto::{SignaturePublicKey, SignatureSecretKey};
use mls_rs_crypto_rustcrypto::RustCryptoProvider;
use offline_protocol_core::Address;
use offline_protocol_sealed::{derive_address, LEAF_KEY_PACKAGE_LIFETIME};
use crate::adapters::{GroupStateAdapter, KeyPackageAdapter};
use crate::error::{LeafError, Result};
use crate::shared::Arc;
use crate::store::{LeafStore, KEY_TYPE_IDENTITY};
pub const CIPHERSUITE: CipherSuite = CipherSuite::CURVE25519_AES128;
const KEY_ID_SECRET: &str = "signature_secret";
const KEY_ID_PUBLIC: &str = "signature_public";
#[derive(Clone)]
pub(crate) struct Identity {
pub(crate) secret: SignatureSecretKey,
pub(crate) public: SignaturePublicKey,
pub(crate) address: Address,
}
impl Identity {
pub(crate) fn provision(store: &Arc<dyn LeafStore>) -> Result<Self> {
if store
.load(KEY_TYPE_IDENTITY, KEY_ID_SECRET)
.map_err(|e| LeafError::Storage(e.to_string()))?
.is_some()
{
return Err(LeafError::AlreadyProvisioned);
}
let suite = suite_provider()?;
let (secret, public) = suite
.signature_key_generate()
.map_err(|e| LeafError::Crypto(format!("cannot generate a signature key: {e:?}")))?;
store
.store(KEY_TYPE_IDENTITY, KEY_ID_PUBLIC, public.as_bytes())
.map_err(|e| LeafError::Storage(e.to_string()))?;
store
.store(KEY_TYPE_IDENTITY, KEY_ID_SECRET, secret.as_bytes())
.map_err(|e| LeafError::Storage(e.to_string()))?;
let address = derive_address(public.as_bytes())?;
Ok(Self {
secret,
public,
address,
})
}
pub(crate) fn resume(store: &Arc<dyn LeafStore>) -> Result<Self> {
let secret = store
.load(KEY_TYPE_IDENTITY, KEY_ID_SECRET)
.map_err(|e| LeafError::Storage(e.to_string()))?
.ok_or(LeafError::NotProvisioned)?;
let public = store
.load(KEY_TYPE_IDENTITY, KEY_ID_PUBLIC)
.map_err(|e| LeafError::Storage(e.to_string()))?
.ok_or(LeafError::NotProvisioned)?;
let secret = SignatureSecretKey::from(secret);
let public = SignaturePublicKey::from(public);
let derived = suite_provider()?
.signature_key_derive_public(&secret)
.map_err(|e| {
LeafError::Crypto(format!("cannot derive a public key from the secret: {e:?}"))
})?;
if derived.as_bytes() != public.as_bytes() {
return Err(LeafError::Storage(alloc::string::String::from(
"the stored public key is not the one this device's secret derives to",
)));
}
let address = derive_address(public.as_bytes())?;
Ok(Self {
secret,
public,
address,
})
}
pub(crate) fn signing_identity(&self) -> SigningIdentity {
let credential = BasicCredential::new(self.address.to_string().into_bytes());
SigningIdentity::new(credential.into_credential(), self.public.clone())
}
}
pub(crate) fn crypto_provider() -> RustCryptoProvider {
RustCryptoProvider::with_enabled_cipher_suites(vec![CIPHERSUITE])
}
pub(crate) fn suite_provider() -> Result<<RustCryptoProvider as CryptoProvider>::CipherSuiteProvider>
{
crypto_provider()
.cipher_suite_provider(CIPHERSUITE)
.ok_or_else(|| {
LeafError::Crypto(alloc::string::String::from(
"the crypto provider does not support the protocol's ciphersuite",
))
})
}
pub(crate) fn build_client(
identity: &Identity,
store: &Arc<dyn LeafStore>,
) -> Result<Client<impl MlsConfig>> {
Ok(Client::builder()
.identity_provider(BasicIdentityProvider)
.crypto_provider(crypto_provider())
.group_state_storage(GroupStateAdapter::new(Arc::clone(store)))
.key_package_repo(KeyPackageAdapter::new(Arc::clone(store)))
.signing_identity(
identity.signing_identity(),
identity.secret.clone(),
CIPHERSUITE,
)
.key_package_lifetime(LEAF_KEY_PACKAGE_LIFETIME)
.build())
}
pub(crate) fn sign(identity: &Identity, payload: &[u8]) -> Result<Vec<u8>> {
suite_provider()?
.sign(&identity.secret, payload)
.map_err(|e| LeafError::Crypto(format!("cannot sign: {e:?}")))
}
pub(crate) fn verify(public_key: &[u8], signature: &[u8], payload: &[u8]) -> Result<()> {
let key = SignaturePublicKey::from(public_key.to_vec());
suite_provider()?
.verify(&key, signature, payload)
.map_err(|e| LeafError::ControlFrameRefused(format!("signature does not verify: {e:?}")))
}