schnorrkel/errors.rs
1// -*- mode: rust; -*-
2//
3// This file is part of schnorrkel.
4// Copyright (c) 2019 Isis Lovecruft and Web 3 Foundation
5// See LICENSE for licensing information.
6//
7// Authors:
8// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
9// - Jeff Burdges <jeff@web3.foundation>
10
11//! ### Errors which may occur when parsing keys and/or signatures to or from wire formats.
12
13// rustc seems to think the typenames in match statements (e.g. in
14// Display) should be snake cased, for some reason.
15#![allow(non_snake_case)]
16
17use core::fmt;
18use core::fmt::Display;
19
20/// `Result` specialized to this crate for convenience.
21pub type SignatureResult<T> = Result<T, SignatureError>;
22
23/// Three-round trip multi-signature stage identifies used in error reporting
24#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
25pub enum MultiSignatureStage {
26 /// Initial commitment phase of a multi-signature
27 Commitment,
28 /// Reveal phase of a multi-signature
29 Reveal,
30 /// Actual cosigning phase of a multi-signature
31 Cosignature,
32}
33
34impl Display for MultiSignatureStage {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 use self::MultiSignatureStage::*;
37 match *self {
38 Commitment => write!(f, "commitment"),
39 Reveal => write!(f, "reveal"),
40 Cosignature => write!(f, "cosignature"),
41 }
42 }
43}
44
45/// Errors which may occur while processing signatures and keypairs.
46///
47/// All these errors represent a failed signature when they occur in
48/// the context of verifying a signature, including in deserializaing
49/// for verification. We expose the distinction among them primarily
50/// for debugging purposes.
51///
52/// This error may arise due to:
53///
54/// * Being given bytes with a length different to what was expected.
55///
56/// * A problem decompressing `r`, a curve point, in the `Signature`, or the
57/// curve point for a `PublicKey`.
58///
59/// * A problem with the format of `s`, a scalar, in the `Signature`. This
60/// is only raised if the high-bit of the scalar was set. (Scalars must
61/// only be constructed from 255-bit integers.)
62///
63/// * Multi-signature protocol errors
64//
65// * Failure of a signature to satisfy the verification equation.
66#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
67pub enum SignatureError {
68 /// A signature verification equation failed.
69 ///
70 /// We emphasise that all variants represent a failed signature,
71 /// not only this one.
72 EquationFalse,
73 /// Invalid point provided, usually to `verify` methods.
74 PointDecompressionError,
75 /// Invalid scalar provided, usually to `Signature::from_bytes`.
76 ScalarFormatError,
77 /// The provided key is not valid.
78 InvalidKey,
79 /// An error in the length of bytes handed to a constructor.
80 ///
81 /// To use this, pass a string specifying the `name` of the type
82 /// which is returning the error, and the `length` in bytes which
83 /// its constructor expects.
84 BytesLengthError {
85 /// Identifies the type returning the error
86 name: &'static str,
87 /// Describes the type returning the error
88 description: &'static str,
89 /// Length expected by the constructor in bytes
90 length: usize,
91 },
92 /// Signature not marked as schnorrkel, maybe try ed25519 instead.
93 NotMarkedSchnorrkel,
94 /// There is no record of the preceding multi-signautre protocol
95 /// stage for the specified public key.
96 MuSigAbsent {
97 /// Identifies the multi-signature protocol stage during which
98 /// the error occurred.
99 musig_stage: MultiSignatureStage,
100 },
101 /// For this public key, there are either conflicting records for
102 /// the preceding multi-signautre protocol stage or else duplicate
103 /// duplicate records for the current stage.
104 MuSigInconsistent {
105 /// Identifies the multi-signature protocol stage during which
106 /// the error occurred.
107 musig_stage: MultiSignatureStage,
108 /// Set true if the stage was reached correctly once but this
109 /// duplicate disagrees.
110 duplicate: bool,
111 },
112}
113
114#[rustfmt::skip]
115impl Display for SignatureError {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 use self::SignatureError::*;
118 match *self {
119 EquationFalse =>
120 write!(f, "Verification equation failed"),
121 PointDecompressionError =>
122 write!(f, "Cannot decompress Ristretto point"),
123 ScalarFormatError =>
124 write!(f, "Cannot use scalar with high-bit set"),
125 InvalidKey =>
126 write!(f, "The provided key is not valid"),
127 BytesLengthError { name, length, .. } =>
128 write!(f, "{name} must be {length} bytes in length"),
129 NotMarkedSchnorrkel =>
130 write!(f, "Signature bytes not marked as a schnorrkel signature"),
131 MuSigAbsent { musig_stage, } =>
132 write!(f, "Absent {musig_stage} violated multi-signature protocol"),
133 MuSigInconsistent { musig_stage, duplicate, } =>
134 if duplicate {
135 write!(f, "Inconsistent duplicate {musig_stage} in multi-signature")
136 } else {
137 write!(f, "Inconsistent {musig_stage} violated multi-signature protocol")
138 },
139 }
140 }
141}
142
143#[cfg(feature = "failure")]
144impl failure::Fail for SignatureError {}
145
146/// Convert `SignatureError` into `::serde::de::Error` aka `SerdeError`
147///
148/// We should do this with `From` but right now the orphan rules prohibit
149/// `impl From<SignatureError> for E where E: serde::de::Error`.
150#[cfg(feature = "serde")]
151pub fn serde_error_from_signature_error<E>(err: SignatureError) -> E
152where
153 E: serde_crate::de::Error,
154{
155 E::custom(err)
156}