spark-cryptography 0.1.11

Cryptography module for Spark Rust SDK
Documentation
use thiserror::Error;

#[derive(Error, Debug, PartialEq, Eq)]
pub enum SparkCryptographyError {
    #[error("Invalid leaf: {0}")]
    InvalidLeaf(InvalidLeafError),

    #[error("Invalid seed")]
    InvalidSeed,

    #[error("Invalid key: {0}")]
    InvalidKey(InvalidKeyError),

    #[error("Invalid identifier: {0}")]
    InvalidIdentifier(InvalidIdentifierError),

    #[error("Invalid commitment: {0}")]
    InvalidCommitment(InvalidCommitmentError),

    #[error("Invalid nonce: {0}")]
    InvalidNonce(InvalidNonceError),

    #[error("Invalid key package: {0}")]
    InvalidKeyPackage(InvalidKeyPackageError),

    #[error("Invalid signature share: {0}")]
    InvalidSignatureShare(InvalidSignatureShareError),

    #[error("Invalid derivation path: {0}")]
    InvalidDerivationPath(String),

    #[error("Invalid role: {0}")]
    InvalidRole(InvalidRoleError),

    #[error("Secp256k1 error: {0}")]
    SecpError(SecpError),

    #[error("FROST operation error: {0}")]
    FrostOperation(FrostOperationError),
}

impl From<bitcoin::secp256k1::Error> for SparkCryptographyError {
    fn from(err: bitcoin::secp256k1::Error) -> Self {
        Self::SecpError(SecpError::BitcoinSecp256k1Error(err))
    }
}

impl From<String> for SparkCryptographyError {
    fn from(_: String) -> Self {
        Self::FrostOperation(FrostOperationError::GenericError)
    }
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum InvalidLeafError {
    #[error("Invalid leaf ID: {0}")]
    InvalidLeafId(String),

    #[error("Index not in leaf index range: {0}")]
    IndexNotInLeafIndexRange(u32),

    #[error("Cannot derive child number from index: {0}. Index must be less than 0x7FFFFFFF or 2,147,483,647 both for hardened and normal indices.")]
    CannotDeriveChildNumberFromIndex(u32),
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum SecpError {
    #[error("Cannot operator on equal public keys")]
    PubkeysAreEqual,

    #[from(bitcoin::secp256k1::Error)]
    #[error("Bitcoin secp256k1 error: {0}")]
    BitcoinSecp256k1Error(bitcoin::secp256k1::Error),
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum InvalidKeyError {
    #[error("Invalid verifying key format")]
    InvalidFormat,
    #[error("Invalid key length")]
    InvalidLength,
    #[error("Invalid verifying key")]
    InvalidVerifyingKey,
    #[error("Invalid public key")]
    InvalidPublicKey,
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum InvalidCommitmentError {
    #[error("Invalid commitment format")]
    InvalidFormat,
    #[error("Invalid commitment map structure")]
    InvalidCommitmentMap,
    #[error("Invalid commitment value")]
    InvalidCommitmentValue,
    #[error("Failed to parse commitment")]
    ParseError,
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum InvalidNonceError {
    #[error("Invalid nonce format")]
    InvalidFormat,
    #[error("Invalid nonce length")]
    InvalidLength,
    #[error("Failed to parse nonce")]
    ParseError,
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum InvalidIdentifierError {
    #[error("Invalid identifier format")]
    InvalidFormat,
    #[error("Invalid identifier length")]
    InvalidLength,
    #[error("Failed to parse identifier")]
    ParseError,
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum InvalidSignatureShareError {
    #[error("Invalid signature share format")]
    InvalidFormat,
    #[error("Signature verification failed")]
    VerificationFailed,
    #[error("Invalid participant")]
    InvalidParticipant,
    #[error("Failed to parse signature share")]
    ParseError,
    #[error("Failed to aggregate signatures")]
    AggregationError,
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum InvalidKeyPackageError {
    #[error("Missing key package")]
    MissingKeyPackage,
    #[error("Invalid key package format")]
    InvalidFormat,
    #[error("Invalid key package content")]
    InvalidContent,
    #[error("Failed to parse key package")]
    ParseError,
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum InvalidRoleError {
    #[error("Invalid role")]
    InvalidRole,
    #[error("Unsupported role")]
    UnsupportedRole,
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum FrostOperationError {
    #[error("Failed to parse FROST operation")]
    ParseError,
    #[error("Failed to aggregate FROST operation")]
    AggregationError,
    #[error("Failed to serialize FROST operation")]
    SerializationError,
    #[error("Generic FROST operation error")]
    GenericError,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_invalid_leaf_error_messages() {
        let err = InvalidLeafError::InvalidLeafId("test_id".to_string());
        assert_eq!(err.to_string(), "Invalid leaf ID: test_id");

        let err = InvalidLeafError::IndexNotInLeafIndexRange(100);
        assert_eq!(err.to_string(), "Index not in leaf index range: 100");

        let err = InvalidLeafError::CannotDeriveChildNumberFromIndex(0x80000000);
        assert_eq!(
            err.to_string(),
            "Cannot derive child number from index: 2147483648. Index must be less than 0x7FFFFFFF or 2,147,483,647 both for hardened and normal indices."
        );
    }

    #[test]
    fn test_secp_error_conversion() {
        use bitcoin::secp256k1::Error as Secp256k1Error;

        // Test conversion from bitcoin::secp256k1::Error
        let secp_err = Secp256k1Error::InvalidPublicKey;
        let spark_err: SparkCryptographyError = secp_err.into();

        assert!(matches!(
            spark_err,
            SparkCryptographyError::SecpError(SecpError::BitcoinSecp256k1Error(
                Secp256k1Error::InvalidPublicKey
            ))
        ));
    }

    #[test]
    fn test_spark_cryptography_error_messages() {
        let err = SparkCryptographyError::InvalidSeed;
        assert_eq!(err.to_string(), "Invalid seed");

        let err = SparkCryptographyError::InvalidDerivationPath("m/44'/0'".to_string());
        assert_eq!(err.to_string(), "Invalid derivation path: m/44'/0'");

        let err = SparkCryptographyError::InvalidLeaf(InvalidLeafError::InvalidLeafId(
            "test".to_string(),
        ));
        assert_eq!(err.to_string(), "Invalid leaf: Invalid leaf ID: test");
    }

    #[test]
    fn test_error_equality() {
        let err1 = SparkCryptographyError::InvalidSeed;
        let err2 = SparkCryptographyError::InvalidSeed;
        assert_eq!(err1, err2);

        let err1 = SecpError::PubkeysAreEqual;
        let err2 = SecpError::PubkeysAreEqual;
        assert_eq!(err1, err2);
    }
}