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;
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);
}
}