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
21/// `Result` specialized to this crate for convenience.
22pub type SignatureResult<T> = Result<T, SignatureError>;
23
24/// Three-round trip multi-signature stage identifies used in error reporting
25#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
26pub enum MultiSignatureStage {
27 /// Initial commitment phase of a multi-signature
28 Commitment,
29 /// Reveal phase of a multi-signature
30 Reveal,
31 /// Actual cosigning phase of a multi-signature
32 Cosignature,
33}
34
35impl Display for MultiSignatureStage {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 use self::MultiSignatureStage::*;
38 match *self {
39 Commitment => write!(f, "commitment"),
40 Reveal => write!(f, "reveal"),
41 Cosignature => write!(f, "cosignature"),
42 }
43 }
44}
45
46/// Errors which may occur while processing signatures and keypairs.
47///
48/// All these errors represent a failed signature when they occur in
49/// the context of verifying a signature, including in deserializaing
50/// for verification. We expose the distinction among them primarily
51/// for debugging purposes.
52///
53/// This error may arise due to:
54///
55/// * Being given bytes with a length different to what was expected.
56///
57/// * A problem decompressing `r`, a curve point, in the `Signature`, or the
58/// curve point for a `PublicKey`.
59///
60/// * A problem with the format of `s`, a scalar, in the `Signature`. This
61/// is only raised if the high-bit of the scalar was set. (Scalars must
62/// only be constructed from 255-bit integers.)
63///
64/// * Multi-signature protocol errors
65//
66// * Failure of a signature to satisfy the verification equation.
67#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
68pub enum SignatureError {
69 /// A signature verification equation failed.
70 ///
71 /// We emphasise that all variants represent a failed signature,
72 /// not only this one.
73 EquationFalse,
74 /// Invalid point provided, usually to `verify` methods.
75 PointDecompressionError,
76 /// Invalid scalar provided, usually to `Signature::from_bytes`.
77 ScalarFormatError,
78 /// The provided key is not valid.
79 InvalidKey,
80 /// An error in the length of bytes handed to a constructor.
81 ///
82 /// To use this, pass a string specifying the `name` of the type
83 /// which is returning the error, and the `length` in bytes which
84 /// its constructor expects.
85 BytesLengthError {
86 /// Identifies the type returning the error
87 name: &'static str,
88 /// Describes the type returning the error
89 description: &'static str,
90 /// Length expected by the constructor in bytes
91 length: usize
92 },
93 /// Signature not marked as schnorrkel, maybe try ed25519 instead.
94 NotMarkedSchnorrkel,
95 /// There is no record of the preceding multi-signautre protocol
96 /// stage for the specified public key.
97 MuSigAbsent {
98 /// Identifies the multi-signature protocol stage during which
99 /// the error occurred.
100 musig_stage: MultiSignatureStage,
101 },
102 /// For this public key, there are either conflicting records for
103 /// the preceding multi-signautre protocol stage or else duplicate
104 /// duplicate records for the current stage.
105 MuSigInconsistent {
106 /// Identifies the multi-signature protocol stage during which
107 /// the error occurred.
108 musig_stage: MultiSignatureStage,
109 /// Set true if the stage was reached correctly once but this
110 /// duplicate disagrees.
111 duplicate: bool,
112 },
113}
114
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 E: serde_crate::de::Error
153{
154 E::custom(err)
155}