spark_cryptography/
error.rs

1use thiserror::Error;
2
3#[derive(Error, Debug, PartialEq, Eq)]
4pub enum SparkCryptographyError {
5    #[error("Invalid leaf: {0}")]
6    InvalidLeaf(InvalidLeafError),
7
8    #[error("Invalid seed")]
9    InvalidSeed,
10
11    #[error("Invalid key: {0}")]
12    InvalidKey(InvalidKeyError),
13
14    #[error("Invalid identifier: {0}")]
15    InvalidIdentifier(InvalidIdentifierError),
16
17    #[error("Invalid commitment: {0}")]
18    InvalidCommitment(InvalidCommitmentError),
19
20    #[error("Invalid nonce: {0}")]
21    InvalidNonce(InvalidNonceError),
22
23    #[error("Invalid key package: {0}")]
24    InvalidKeyPackage(InvalidKeyPackageError),
25
26    #[error("Invalid signature share: {0}")]
27    InvalidSignatureShare(InvalidSignatureShareError),
28
29    #[error("Invalid derivation path: {0}")]
30    InvalidDerivationPath(String),
31
32    #[error("Invalid role: {0}")]
33    InvalidRole(InvalidRoleError),
34
35    #[error("Secp256k1 error: {0}")]
36    SecpError(SecpError),
37
38    #[error("FROST operation error: {0}")]
39    FrostOperation(FrostOperationError),
40}
41
42impl From<bitcoin::secp256k1::Error> for SparkCryptographyError {
43    fn from(err: bitcoin::secp256k1::Error) -> Self {
44        Self::SecpError(SecpError::BitcoinSecp256k1Error(err))
45    }
46}
47
48impl From<String> for SparkCryptographyError {
49    fn from(_: String) -> Self {
50        Self::FrostOperation(FrostOperationError::GenericError)
51    }
52}
53
54#[derive(Error, Debug, PartialEq, Eq)]
55pub enum InvalidLeafError {
56    #[error("Invalid leaf ID: {0}")]
57    InvalidLeafId(String),
58
59    #[error("Index not in leaf index range: {0}")]
60    IndexNotInLeafIndexRange(u32),
61
62    #[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.")]
63    CannotDeriveChildNumberFromIndex(u32),
64}
65
66#[derive(Error, Debug, PartialEq, Eq)]
67pub enum SecpError {
68    #[error("Cannot operator on equal public keys")]
69    PubkeysAreEqual,
70
71    #[from(bitcoin::secp256k1::Error)]
72    #[error("Bitcoin secp256k1 error: {0}")]
73    BitcoinSecp256k1Error(bitcoin::secp256k1::Error),
74}
75
76#[derive(Error, Debug, PartialEq, Eq)]
77pub enum InvalidKeyError {
78    #[error("Invalid verifying key format")]
79    InvalidFormat,
80    #[error("Invalid key length")]
81    InvalidLength,
82    #[error("Invalid verifying key")]
83    InvalidVerifyingKey,
84    #[error("Invalid public key")]
85    InvalidPublicKey,
86}
87
88#[derive(Error, Debug, PartialEq, Eq)]
89pub enum InvalidCommitmentError {
90    #[error("Invalid commitment format")]
91    InvalidFormat,
92    #[error("Invalid commitment map structure")]
93    InvalidCommitmentMap,
94    #[error("Invalid commitment value")]
95    InvalidCommitmentValue,
96    #[error("Failed to parse commitment")]
97    ParseError,
98}
99
100#[derive(Error, Debug, PartialEq, Eq)]
101pub enum InvalidNonceError {
102    #[error("Invalid nonce format")]
103    InvalidFormat,
104    #[error("Invalid nonce length")]
105    InvalidLength,
106    #[error("Failed to parse nonce")]
107    ParseError,
108}
109
110#[derive(Error, Debug, PartialEq, Eq)]
111pub enum InvalidIdentifierError {
112    #[error("Invalid identifier format")]
113    InvalidFormat,
114    #[error("Invalid identifier length")]
115    InvalidLength,
116    #[error("Failed to parse identifier")]
117    ParseError,
118}
119
120#[derive(Error, Debug, PartialEq, Eq)]
121pub enum InvalidSignatureShareError {
122    #[error("Invalid signature share format")]
123    InvalidFormat,
124    #[error("Signature verification failed")]
125    VerificationFailed,
126    #[error("Invalid participant")]
127    InvalidParticipant,
128    #[error("Failed to parse signature share")]
129    ParseError,
130    #[error("Failed to aggregate signatures")]
131    AggregationError,
132}
133
134#[derive(Error, Debug, PartialEq, Eq)]
135pub enum InvalidKeyPackageError {
136    #[error("Missing key package")]
137    MissingKeyPackage,
138    #[error("Invalid key package format")]
139    InvalidFormat,
140    #[error("Invalid key package content")]
141    InvalidContent,
142    #[error("Failed to parse key package")]
143    ParseError,
144}
145
146#[derive(Error, Debug, PartialEq, Eq)]
147pub enum InvalidRoleError {
148    #[error("Invalid role")]
149    InvalidRole,
150    #[error("Unsupported role")]
151    UnsupportedRole,
152}
153
154#[derive(Error, Debug, PartialEq, Eq)]
155pub enum FrostOperationError {
156    #[error("Failed to parse FROST operation")]
157    ParseError,
158    #[error("Failed to aggregate FROST operation")]
159    AggregationError,
160    #[error("Failed to serialize FROST operation")]
161    SerializationError,
162    #[error("Generic FROST operation error")]
163    GenericError,
164}
165
166#[cfg(test)]
167mod tests {
168    use super::*;
169
170    #[test]
171    fn test_invalid_leaf_error_messages() {
172        let err = InvalidLeafError::InvalidLeafId("test_id".to_string());
173        assert_eq!(err.to_string(), "Invalid leaf ID: test_id");
174
175        let err = InvalidLeafError::IndexNotInLeafIndexRange(100);
176        assert_eq!(err.to_string(), "Index not in leaf index range: 100");
177
178        let err = InvalidLeafError::CannotDeriveChildNumberFromIndex(0x80000000);
179        assert_eq!(
180            err.to_string(),
181            "Cannot derive child number from index: 2147483648. Index must be less than 0x7FFFFFFF or 2,147,483,647 both for hardened and normal indices."
182        );
183    }
184
185    #[test]
186    fn test_secp_error_conversion() {
187        use bitcoin::secp256k1::Error as Secp256k1Error;
188
189        // Test conversion from bitcoin::secp256k1::Error
190        let secp_err = Secp256k1Error::InvalidPublicKey;
191        let spark_err: SparkCryptographyError = secp_err.into();
192
193        assert!(matches!(
194            spark_err,
195            SparkCryptographyError::SecpError(SecpError::BitcoinSecp256k1Error(
196                Secp256k1Error::InvalidPublicKey
197            ))
198        ));
199    }
200
201    #[test]
202    fn test_spark_cryptography_error_messages() {
203        let err = SparkCryptographyError::InvalidSeed;
204        assert_eq!(err.to_string(), "Invalid seed");
205
206        let err = SparkCryptographyError::InvalidDerivationPath("m/44'/0'".to_string());
207        assert_eq!(err.to_string(), "Invalid derivation path: m/44'/0'");
208
209        let err = SparkCryptographyError::InvalidLeaf(InvalidLeafError::InvalidLeafId(
210            "test".to_string(),
211        ));
212        assert_eq!(err.to_string(), "Invalid leaf: Invalid leaf ID: test");
213    }
214
215    #[test]
216    fn test_error_equality() {
217        let err1 = SparkCryptographyError::InvalidSeed;
218        let err2 = SparkCryptographyError::InvalidSeed;
219        assert_eq!(err1, err2);
220
221        let err1 = SecpError::PubkeysAreEqual;
222        let err2 = SecpError::PubkeysAreEqual;
223        assert_eq!(err1, err2);
224    }
225}