silent_payments_psbt/
error.rs1use silent_payments_core::CryptoError;
11use thiserror::Error;
12
13#[derive(Debug, Error)]
15pub enum PsbtError {
16 #[error("PSBT output missing scan public key in SP_V0_INFO field")]
18 MissingScanKey,
19
20 #[error("missing ECDH share for scan key {scan_key}")]
22 MissingEcdhShare { scan_key: String },
23
24 #[error("missing DLEQ proof for scan key {scan_key}")]
26 MissingDleqProof { scan_key: String },
27
28 #[error("invalid {field} length: expected {expected}, got {actual}")]
30 InvalidFieldLength {
31 field: String,
32 expected: usize,
33 actual: usize,
34 },
35
36 #[error("invalid public key in PSBT field: {reason}")]
38 InvalidPublicKey { reason: String },
39
40 #[error(transparent)]
42 InvalidProof(#[from] DleqError),
43
44 #[error("scan key {scan_key} has both global and per-input ECDH shares")]
46 DuplicateShareType { scan_key: String },
47
48 #[error("output index {index} out of bounds (PSBT has {count} outputs)")]
50 OutputIndexOutOfBounds { index: usize, count: usize },
51
52 #[error("PSBT has no Silent Payment output fields")]
54 NoSpOutputs,
55
56 #[error("not all required ECDH shares and DLEQ proofs are present")]
58 IncompleteSigning,
59
60 #[error("cryptographic error: {0}")]
62 Crypto(CryptoError),
63}
64
65impl From<CryptoError> for PsbtError {
66 fn from(err: CryptoError) -> Self {
67 PsbtError::Crypto(err)
68 }
69}
70
71#[derive(Debug, Error)]
73pub enum DleqError {
74 #[error("DLEQ proof is invalid")]
76 InvalidProof,
77
78 #[error("DLEQ proof verification returned false")]
80 VerificationFailed,
81
82 #[error("key mismatch in DLEQ proof: {reason}")]
84 MismatchedKeys { reason: String },
85
86 #[error("proof must be {expected} bytes, got {actual}")]
88 MalformedProofBytes { expected: usize, actual: usize },
89
90 #[error("DLEQ proof generation failed: {reason}")]
92 GenerationFailed { reason: String },
93
94 #[error("secp256k1 error: {0}")]
96 Crypto(String),
97}
98
99impl From<dleq::DleqError> for DleqError {
100 fn from(err: dleq::DleqError) -> Self {
101 match err {
102 dleq::DleqError::RangeError(e) => DleqError::Crypto(e.to_string()),
103 dleq::DleqError::Secp256k1Error(e) => DleqError::Crypto(e.to_string()),
104 dleq::DleqError::VerificationFailed => DleqError::VerificationFailed,
105 }
106 }
107}
108
109impl From<bitcoin::secp256k1::Error> for DleqError {
110 fn from(err: bitcoin::secp256k1::Error) -> Self {
111 DleqError::Crypto(err.to_string())
112 }
113}