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}