saa-auth 0.27.3

Custom credentials built on top of curves and their verification logic for smart account auth
Documentation

#[cfg(feature = "cosmwasm")]
use saa_common::wasm::{Addr, Deps, Api};
use saa_common::{
    ensure, AuthError, Binary, CredentialError, CredentialId, CredentialInfo, CredentialName, 
    String, ToString, Verifiable, Identifiable
};

use CredentialName::CosmosArbitrary as CosmosName;


#[saa_schema::saa_type]
pub struct CosmosArbitrary {
    pub pubkey:    Binary,
    pub signature: Binary,
    pub message:   Binary,
    #[cfg(not(feature = "cosmos_arb_addr"))]
    pub hrp:       Option<String>,
    #[cfg(feature = "cosmos_arb_addr")]
    pub address:   String
}


#[cfg(any(feature = "cosmwasm", feature = "native"))]
impl CosmosArbitrary {

    #[allow(unused_variables)]
    #[cfg(feature = "cosmwasm")]
    fn get_address(&self, api: &dyn Api) -> Result<Addr, AuthError> {
        #[cfg(feature = "cosmos_arb_addr")]
        return Ok(api.addr_validate(&self.address)?);
        #[cfg(not(feature = "cosmos_arb_addr"))]
        if let Some(ref hrp) = self.hrp {
            Ok(Addr::unchecked(saa_crypto::pubkey_to_address(&self.pubkey, hrp)?))
        } else {
            Err(AuthError::Generic("Must provide prefix for the public key".to_string()))
        }
    }

    #[cfg(not(feature = "cosmwasm"))]
    fn get_address(&self) -> Result<String, AuthError> {
        #[cfg(feature = "cosmos_arb_addr")]
        return self.address.clone();
        #[cfg(not(feature = "cosmos_arb_addr"))]
        if let Some(ref hrp) = self.hrp {
            saa_crypto::pubkey_to_address(&self.pubkey, hrp)?;
        } else {
            Err(AuthError::Generic("Must provide prefix for the public key".to_string()))
        }
    }

    fn message_digest(&self, addr: &str) -> [u8; 32] {
        saa_crypto::sha256(super::utils::wrap_msg_arb_036(
                addr, 
                &self.message.to_string()
            ).as_bytes()
        )
    }
}


impl Identifiable for CosmosArbitrary {
    fn cred_id(&self) -> CredentialId {
        self.pubkey.to_string().to_lowercase()
    }
    
    fn name(&self) -> CredentialName {
        CosmosName
    }
}


impl Verifiable for CosmosArbitrary {
    
    fn message(&self) -> std::borrow::Cow<'_, [u8]> {
        std::borrow::Cow::Borrowed(self.message.as_slice())
    }

    fn validate(&self) -> Result<(), AuthError> {
        ensure!(self.signature.len() > 0 &&
            self.message.to_string().len() > 0 && 
            self.pubkey.len() > 0,  CredentialError::MissingData(CosmosName)
        );
        Ok(())
    }
    
    #[cfg(any(feature = "native", feature = "cosmwasm"))]
    fn verify(&self,
        #[cfg(feature = "cosmwasm")]
        deps: Deps
    ) -> Result<CredentialInfo, AuthError> {
        use saa_common::CredentialAddress;

        let address = self.get_address(
            #[cfg(feature = "cosmwasm")]
            deps.api
        )?;
        #[cfg(all(feature = "native", not(feature = "cosmwasm")))]
        let res = saa_crypto::secp256k1_verify(
            &self.message_digest(address.as_str()),
            &self.signature, 
            &self.pubkey
        )?;
        #[cfg(feature = "cosmwasm")]
        let res = deps.api.secp256k1_verify(
            &self.message_digest(address.as_str()),
            &self.signature, 
            &self.pubkey
        )?;
        saa_common::ensure!(res, AuthError::Signature(CosmosName, self.cred_id()));
        let hrp = address.as_str().split('1').next().map(|s| s.to_string());
        Ok(CredentialInfo {
            hrp,
            extension: None,
            name: CosmosName,
            address: Some(CredentialAddress::Bech32(address)),
        })
    }

}

#[cfg(feature = "replay")]
impl saa_crypto::ReplayProtection for CosmosArbitrary {}