Skip to main content

oasis_runtime_sdk/crypto/signature/
mod.rs

1//! Cryptographic signatures.
2use std::convert::TryFrom;
3
4use digest::{typenum::Unsigned as _, Digest as _};
5use rand::TryCryptoRng;
6use thiserror::Error;
7
8use crate::core::common::crypto::signature::{
9    PublicKey as CorePublicKey, Signature as CoreSignature, Signer as CoreSigner,
10};
11
12pub mod context;
13mod digests;
14pub mod ed25519;
15pub mod secp256k1;
16pub mod secp256r1;
17pub mod secp384r1;
18pub mod sr25519;
19
20/// A specific combination of signature and hash.
21#[allow(non_camel_case_types)]
22#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, cbor::Encode, cbor::Decode)]
23pub enum SignatureType {
24    #[cbor(rename = "ed25519_oasis")]
25    Ed25519_Oasis,
26    #[cbor(rename = "ed25519_pure")]
27    Ed25519_Pure,
28    #[cbor(rename = "ed25519_prehashed_sha512")]
29    Ed25519_PrehashedSha512,
30    #[cbor(rename = "secp256k1_oasis")]
31    Secp256k1_Oasis,
32    #[cbor(rename = "secp256k1_prehashed_keccak256")]
33    Secp256k1_PrehashedKeccak256,
34    #[cbor(rename = "secp256k1_prehashed_sha256")]
35    Secp256k1_PrehashedSha256,
36    #[cbor(rename = "sr25519_pure")]
37    Sr25519_Pure,
38    #[cbor(rename = "secp256r1_prehashed_sha256")]
39    Secp256r1_PrehashedSha256,
40    #[cbor(rename = "secp384r1_prehashed_sha384")]
41    Secp384r1_PrehashedSha384,
42}
43
44impl SignatureType {
45    pub fn as_int(&self) -> u8 {
46        match self {
47            Self::Ed25519_Oasis => 0,
48            Self::Ed25519_Pure => 1,
49            Self::Ed25519_PrehashedSha512 => 2,
50            Self::Secp256k1_Oasis => 3,
51            Self::Secp256k1_PrehashedKeccak256 => 4,
52            Self::Secp256k1_PrehashedSha256 => 5,
53            Self::Sr25519_Pure => 6,
54            Self::Secp256r1_PrehashedSha256 => 7,
55            Self::Secp384r1_PrehashedSha384 => 8,
56        }
57    }
58
59    pub fn is_prehashed(&self) -> bool {
60        matches!(
61            self,
62            Self::Ed25519_PrehashedSha512
63                | Self::Secp256k1_PrehashedKeccak256
64                | Self::Secp256k1_PrehashedSha256
65                | Self::Secp256r1_PrehashedSha256
66                | Self::Secp384r1_PrehashedSha384
67        )
68    }
69
70    pub fn is_ed25519_variant(&self) -> bool {
71        matches!(
72            self,
73            Self::Ed25519_Oasis | Self::Ed25519_Pure | Self::Ed25519_PrehashedSha512
74        )
75    }
76
77    pub fn is_secp256k1_variant(&self) -> bool {
78        matches!(
79            self,
80            Self::Secp256k1_Oasis
81                | Self::Secp256k1_PrehashedKeccak256
82                | Self::Secp256k1_PrehashedSha256
83        )
84    }
85
86    pub fn is_secp256r1_variant(&self) -> bool {
87        matches!(self, Self::Secp256r1_PrehashedSha256)
88    }
89
90    pub fn is_secp384r1_variant(&self) -> bool {
91        matches!(self, Self::Secp384r1_PrehashedSha384)
92    }
93
94    pub fn is_sr25519_variant(&self) -> bool {
95        matches!(self, Self::Sr25519_Pure)
96    }
97}
98
99impl TryFrom<u8> for SignatureType {
100    type Error = Error;
101
102    fn try_from(value: u8) -> Result<Self, Self::Error> {
103        match value {
104            0 => Ok(Self::Ed25519_Oasis),
105            1 => Ok(Self::Ed25519_Pure),
106            2 => Ok(Self::Ed25519_PrehashedSha512),
107            3 => Ok(Self::Secp256k1_Oasis),
108            4 => Ok(Self::Secp256k1_PrehashedKeccak256),
109            5 => Ok(Self::Secp256k1_PrehashedSha256),
110            6 => Ok(Self::Sr25519_Pure),
111            7 => Ok(Self::Secp256r1_PrehashedSha256),
112            8 => Ok(Self::Secp384r1_PrehashedSha384),
113            _ => Err(Error::InvalidArgument),
114        }
115    }
116}
117
118/// A public key used for signing.
119#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, cbor::Encode, cbor::Decode)]
120pub enum PublicKey {
121    #[cbor(rename = "ed25519")]
122    Ed25519(ed25519::PublicKey),
123
124    #[cbor(rename = "secp256k1")]
125    Secp256k1(secp256k1::PublicKey),
126
127    #[cbor(rename = "secp256r1")]
128    Secp256r1(secp256r1::PublicKey),
129
130    #[cbor(rename = "secp384r1")]
131    Secp384r1(secp384r1::PublicKey),
132
133    #[cbor(rename = "sr25519")]
134    Sr25519(sr25519::PublicKey),
135}
136
137/// Error.
138#[derive(Error, Debug)]
139pub enum Error {
140    #[error("malformed public key")]
141    MalformedPublicKey,
142    #[error("malformed private key")]
143    MalformedPrivateKey,
144    #[error("malformed signature")]
145    MalformedSignature,
146    #[error("signature verification failed")]
147    VerificationFailed,
148    #[error("invalid argument")]
149    InvalidArgument,
150    #[error("invalid digest length")]
151    InvalidDigestLength,
152    #[error("rng error")]
153    RngError,
154    #[error("other signing error")]
155    SigningError,
156}
157
158impl PublicKey {
159    /// Return the key type as string.
160    pub fn key_type(&self) -> &str {
161        match self {
162            Self::Ed25519(_) => "ed25519",
163            Self::Secp256k1(_) => "secp256k1",
164            Self::Secp256r1(_) => "secp256r1",
165            Self::Secp384r1(_) => "secp384r1",
166            Self::Sr25519(_) => "sr25519",
167        }
168    }
169
170    /// Return a byte representation of this public key.
171    pub fn as_bytes(&self) -> &[u8] {
172        match self {
173            PublicKey::Ed25519(pk) => pk.as_bytes(),
174            PublicKey::Secp256k1(pk) => pk.as_bytes(),
175            PublicKey::Secp256r1(pk) => pk.as_bytes(),
176            PublicKey::Secp384r1(pk) => pk.as_bytes(),
177            PublicKey::Sr25519(pk) => pk.as_bytes(),
178        }
179    }
180
181    /// Construct a public key from a slice of bytes.
182    pub fn from_bytes(sig_type: SignatureType, bytes: &[u8]) -> Result<Self, Error> {
183        match sig_type {
184            SignatureType::Ed25519_Oasis
185            | SignatureType::Ed25519_Pure
186            | SignatureType::Ed25519_PrehashedSha512 => {
187                Ok(Self::Ed25519(ed25519::PublicKey::from_bytes(bytes)?))
188            }
189            SignatureType::Secp256k1_Oasis
190            | SignatureType::Secp256k1_PrehashedKeccak256
191            | SignatureType::Secp256k1_PrehashedSha256 => {
192                Ok(Self::Secp256k1(secp256k1::PublicKey::from_bytes(bytes)?))
193            }
194            SignatureType::Secp256r1_PrehashedSha256 => {
195                Ok(Self::Secp256r1(secp256r1::PublicKey::from_bytes(bytes)?))
196            }
197            SignatureType::Secp384r1_PrehashedSha384 => {
198                Ok(Self::Secp384r1(secp384r1::PublicKey::from_bytes(bytes)?))
199            }
200            SignatureType::Sr25519_Pure => {
201                Ok(Self::Sr25519(sr25519::PublicKey::from_bytes(bytes)?))
202            }
203        }
204    }
205
206    /// Verify a signature.
207    pub fn verify(
208        &self,
209        context: &[u8],
210        message: &[u8],
211        signature: &Signature,
212    ) -> Result<(), Error> {
213        match self {
214            PublicKey::Ed25519(pk) => pk.verify(context, message, signature),
215            PublicKey::Secp256k1(pk) => pk.verify(context, message, signature),
216            PublicKey::Secp256r1(pk) => pk.verify(context, message, signature),
217            PublicKey::Secp384r1(pk) => pk.verify(context, message, signature),
218            PublicKey::Sr25519(pk) => pk.verify(context, message, signature),
219        }
220    }
221
222    /// Verify signature raw using the underlying method, without the domain
223    /// separation schema.
224    pub fn verify_raw(&self, message: &[u8], signature: &Signature) -> Result<(), Error> {
225        match self {
226            PublicKey::Ed25519(pk) => pk.verify_raw(message, signature),
227            PublicKey::Secp256k1(pk) => pk.verify_raw(message, signature),
228            PublicKey::Secp256r1(pk) => pk.verify_raw(message, signature),
229            PublicKey::Secp384r1(pk) => pk.verify_raw(message, signature),
230            PublicKey::Sr25519(_) => Err(Error::InvalidArgument),
231        }
232    }
233
234    /// Verify the signature of a message.
235    pub fn verify_by_type(
236        &self,
237        signature_type: SignatureType,
238        context_or_hash: &[u8],
239        message: &[u8],
240        signature: &Signature,
241    ) -> Result<(), Error> {
242        match self {
243            Self::Ed25519(pk) => match signature_type {
244                SignatureType::Ed25519_Oasis => pk.verify(context_or_hash, message, signature),
245                SignatureType::Ed25519_Pure => pk.verify_raw(message, signature),
246                SignatureType::Ed25519_PrehashedSha512 => {
247                    if context_or_hash.len()
248                        != <sha2::Sha512 as sha2::digest::OutputSizeUser>::OutputSize::USIZE
249                    {
250                        return Err(Error::InvalidArgument);
251                    }
252                    let digest =
253                        digests::DummyDigest::<sha2::Sha512>::new_precomputed(context_or_hash);
254                    pk.verify_digest(digest, signature)
255                }
256                _ => Err(Error::InvalidArgument),
257            },
258            Self::Secp256k1(pk) => match signature_type {
259                SignatureType::Secp256k1_Oasis => pk.verify(context_or_hash, message, signature),
260                SignatureType::Secp256k1_PrehashedKeccak256 => {
261                    if context_or_hash.len()
262                        != <sha3::Keccak256 as sha3::digest::OutputSizeUser>::OutputSize::USIZE
263                    {
264                        return Err(Error::InvalidArgument);
265                    }
266                    // Use SHA-256 for RFC6979 even if Keccak256 was used for the message.
267                    let digest = digests::DummyDigest::<k256::sha2::Sha256>::new_precomputed(
268                        context_or_hash,
269                    );
270                    pk.verify_digest(digest, signature)
271                }
272                SignatureType::Secp256k1_PrehashedSha256 => {
273                    if context_or_hash.len()
274                        != <sha2::Sha256 as sha2::digest::OutputSizeUser>::OutputSize::USIZE
275                    {
276                        return Err(Error::InvalidArgument);
277                    }
278                    let digest = digests::DummyDigest::<k256::sha2::Sha256>::new_precomputed(
279                        context_or_hash,
280                    );
281                    pk.verify_digest(digest, signature)
282                }
283                _ => Err(Error::InvalidArgument),
284            },
285            Self::Secp256r1(pk) => match signature_type {
286                SignatureType::Secp256r1_PrehashedSha256 => {
287                    if context_or_hash.len()
288                        != <sha2::Sha256 as sha2::digest::OutputSizeUser>::OutputSize::USIZE
289                    {
290                        return Err(Error::InvalidArgument);
291                    }
292                    let digest =
293                        digests::DummyDigest::<sha2::Sha256>::new_precomputed(context_or_hash);
294                    pk.verify_digest(digest, signature)
295                }
296                _ => Err(Error::InvalidArgument),
297            },
298            Self::Secp384r1(pk) => match signature_type {
299                SignatureType::Secp384r1_PrehashedSha384 => {
300                    if context_or_hash.len()
301                        != <sha2::Sha384 as sha2::digest::OutputSizeUser>::OutputSize::USIZE
302                    {
303                        return Err(Error::InvalidArgument);
304                    }
305                    let digest =
306                        digests::DummyDigest::<sha2::Sha384>::new_precomputed(context_or_hash);
307                    pk.verify_digest(digest, signature)
308                }
309                _ => Err(Error::InvalidArgument),
310            },
311            Self::Sr25519(pk) => match signature_type {
312                SignatureType::Sr25519_Pure => pk.verify_raw(context_or_hash, message, signature),
313                _ => Err(Error::InvalidArgument),
314            },
315        }
316    }
317
318    /// Verify a batch of signatures of the same message.
319    pub fn verify_batch_multisig(
320        context: &[u8],
321        message: &[u8],
322        public_keys: &[PublicKey],
323        signatures: &[Signature],
324    ) -> Result<(), Error> {
325        if public_keys.len() != signatures.len() {
326            return Err(Error::InvalidArgument);
327        }
328
329        // TODO: Use actual batch verification.
330        for (pk, sig) in public_keys.iter().zip(signatures.iter()) {
331            pk.verify(context, message, sig)?;
332        }
333        Ok(())
334    }
335}
336
337impl AsRef<[u8]> for PublicKey {
338    fn as_ref(&self) -> &[u8] {
339        self.as_bytes()
340    }
341}
342
343impl PartialEq<CorePublicKey> for PublicKey {
344    fn eq(&self, other: &CorePublicKey) -> bool {
345        match self {
346            PublicKey::Ed25519(pk) => pk.as_bytes() == other.as_ref(),
347            _ => false,
348        }
349    }
350}
351
352impl TryFrom<PublicKey> for CorePublicKey {
353    type Error = &'static str;
354
355    fn try_from(pk: PublicKey) -> Result<Self, Self::Error> {
356        match pk {
357            PublicKey::Ed25519(pk) => Ok(pk.into()),
358            _ => Err("not an Ed25519 public key"),
359        }
360    }
361}
362
363impl From<CorePublicKey> for PublicKey {
364    fn from(pk: CorePublicKey) -> Self {
365        Self::Ed25519(pk.into())
366    }
367}
368
369/// Variable-length opaque signature.
370#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Encode, cbor::Decode)]
371#[cbor(transparent)]
372pub struct Signature(Vec<u8>);
373
374impl AsRef<[u8]> for Signature {
375    fn as_ref(&self) -> &[u8] {
376        &self.0
377    }
378}
379
380impl From<Vec<u8>> for Signature {
381    fn from(v: Vec<u8>) -> Signature {
382        Signature(v)
383    }
384}
385
386impl From<Signature> for Vec<u8> {
387    fn from(s: Signature) -> Vec<u8> {
388        s.0
389    }
390}
391
392impl From<Signature> for CoreSignature {
393    fn from(s: Signature) -> Self {
394        s.as_ref().into()
395    }
396}
397
398/// Common trait for memory signers.
399pub trait Signer: Send + Sync {
400    /// Create a new random signer.
401    fn random(rng: &mut impl TryCryptoRng) -> Result<Self, Error>
402    where
403        Self: Sized;
404
405    /// Create a new signer from the given seed.
406    fn new_from_seed(seed: &[u8]) -> Result<Self, Error>
407    where
408        Self: Sized;
409
410    /// Recreate signer from a byte serialization.
411    fn from_bytes(bytes: &[u8]) -> Result<Self, Error>
412    where
413        Self: Sized;
414
415    /// Serialize the signer into bytes.
416    fn to_bytes(&self) -> Vec<u8>;
417
418    /// Return the public key counterpart to the signer's secret key.
419    fn public_key(&self) -> PublicKey;
420
421    /// Generate a signature over the context and message.
422    fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature, Error>;
423
424    /// Generate a signature over the message.
425    fn sign_raw(&self, message: &[u8]) -> Result<Signature, Error>;
426}
427
428impl<T: Signer + ?Sized> Signer for std::sync::Arc<T> {
429    fn random(_rng: &mut impl TryCryptoRng) -> Result<Self, Error>
430    where
431        Self: Sized,
432    {
433        Err(Error::InvalidArgument)
434    }
435
436    fn new_from_seed(_seed: &[u8]) -> Result<Self, Error>
437    where
438        Self: Sized,
439    {
440        Err(Error::InvalidArgument)
441    }
442
443    fn from_bytes(_bytes: &[u8]) -> Result<Self, Error>
444    where
445        Self: Sized,
446    {
447        Err(Error::InvalidArgument)
448    }
449
450    fn to_bytes(&self) -> Vec<u8> {
451        T::to_bytes(self)
452    }
453
454    fn public_key(&self) -> PublicKey {
455        T::public_key(self)
456    }
457
458    fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature, Error> {
459        T::sign(self, context, message)
460    }
461
462    fn sign_raw(&self, message: &[u8]) -> Result<Signature, Error> {
463        T::sign_raw(self, message)
464    }
465}
466
467impl<T: CoreSigner> Signer for &T {
468    fn random(_rng: &mut impl TryCryptoRng) -> Result<Self, Error>
469    where
470        Self: Sized,
471    {
472        Err(Error::InvalidArgument)
473    }
474
475    fn new_from_seed(_seed: &[u8]) -> Result<Self, Error>
476    where
477        Self: Sized,
478    {
479        Err(Error::InvalidArgument)
480    }
481
482    fn from_bytes(_bytes: &[u8]) -> Result<Self, Error>
483    where
484        Self: Sized,
485    {
486        Err(Error::InvalidArgument)
487    }
488
489    fn to_bytes(&self) -> Vec<u8> {
490        vec![]
491    }
492
493    fn public_key(&self) -> PublicKey {
494        PublicKey::Ed25519(self.public().into())
495    }
496
497    fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature, Error> {
498        let raw_sig = CoreSigner::sign(*self, context, message).map_err(|_| Error::SigningError)?;
499        Ok(Signature(raw_sig.as_ref().into()))
500    }
501
502    fn sign_raw(&self, _message: &[u8]) -> Result<Signature, Error> {
503        Err(Error::InvalidArgument)
504    }
505}
506
507impl Signer for crate::core::identity::Identity {
508    fn random(_rng: &mut impl TryCryptoRng) -> Result<Self, Error>
509    where
510        Self: Sized,
511    {
512        Err(Error::InvalidArgument)
513    }
514
515    fn new_from_seed(_seed: &[u8]) -> Result<Self, Error>
516    where
517        Self: Sized,
518    {
519        Err(Error::InvalidArgument)
520    }
521
522    fn from_bytes(_bytes: &[u8]) -> Result<Self, Error>
523    where
524        Self: Sized,
525    {
526        Err(Error::InvalidArgument)
527    }
528
529    fn to_bytes(&self) -> Vec<u8> {
530        vec![]
531    }
532
533    fn public_key(&self) -> PublicKey {
534        PublicKey::Ed25519(self.public().into())
535    }
536
537    fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature, Error> {
538        let raw_sig = CoreSigner::sign(self, context, message).map_err(|_| Error::SigningError)?;
539        Ok(Signature(raw_sig.as_ref().into()))
540    }
541
542    fn sign_raw(&self, _message: &[u8]) -> Result<Signature, Error> {
543        Err(Error::InvalidArgument)
544    }
545}
546
547/// A memory-backed signer.
548pub enum MemorySigner {
549    Ed25519(ed25519::MemorySigner),
550    Secp256k1(secp256k1::MemorySigner),
551    Secp256r1(secp256r1::MemorySigner),
552    Secp384r1(secp384r1::MemorySigner),
553    Sr25519(sr25519::MemorySigner),
554}
555
556impl MemorySigner {
557    /// Create a new memory signer from a seed.
558    pub fn new_from_seed(sig_type: SignatureType, seed: &[u8]) -> Result<Self, Error> {
559        if sig_type.is_ed25519_variant() {
560            Ok(Self::Ed25519(ed25519::MemorySigner::new_from_seed(seed)?))
561        } else if sig_type.is_secp256k1_variant() {
562            Ok(Self::Secp256k1(secp256k1::MemorySigner::new_from_seed(
563                seed,
564            )?))
565        } else if sig_type.is_secp256r1_variant() {
566            Ok(Self::Secp256r1(secp256r1::MemorySigner::new_from_seed(
567                seed,
568            )?))
569        } else if sig_type.is_secp384r1_variant() {
570            Ok(Self::Secp384r1(secp384r1::MemorySigner::new_from_seed(
571                seed,
572            )?))
573        } else if sig_type.is_sr25519_variant() {
574            Ok(Self::Sr25519(sr25519::MemorySigner::new_from_seed(seed)?))
575        } else {
576            Err(Error::InvalidArgument)
577        }
578    }
579
580    /// Create a new signer for testing purposes.
581    pub fn new_test(sig_type: SignatureType, name: &str) -> Self {
582        if sig_type.is_secp384r1_variant() {
583            Self::new_from_seed(sig_type, &sha2::Sha384::digest(name)).unwrap()
584        } else {
585            Self::new_from_seed(sig_type, &sha2::Sha512_256::digest(name)).unwrap()
586        }
587    }
588
589    /// Reconstruct the signer from its byte representation.
590    pub fn from_bytes(sig_type: SignatureType, bytes: &[u8]) -> Result<Self, Error> {
591        if sig_type.is_ed25519_variant() {
592            Ok(Self::Ed25519(ed25519::MemorySigner::from_bytes(bytes)?))
593        } else if sig_type.is_secp256k1_variant() {
594            Ok(Self::Secp256k1(secp256k1::MemorySigner::from_bytes(bytes)?))
595        } else if sig_type.is_secp256r1_variant() {
596            Ok(Self::Secp256r1(secp256r1::MemorySigner::from_bytes(bytes)?))
597        } else if sig_type.is_secp384r1_variant() {
598            Ok(Self::Secp384r1(secp384r1::MemorySigner::from_bytes(bytes)?))
599        } else if sig_type.is_sr25519_variant() {
600            Ok(Self::Sr25519(sr25519::MemorySigner::from_bytes(bytes)?))
601        } else {
602            Err(Error::InvalidArgument)
603        }
604    }
605
606    /// Return a byte representation of the signer.
607    pub fn to_bytes(&self) -> Vec<u8> {
608        match self {
609            Self::Ed25519(signer) => signer.to_bytes(),
610            Self::Secp256k1(signer) => signer.to_bytes(),
611            Self::Secp256r1(signer) => signer.to_bytes(),
612            Self::Secp384r1(signer) => signer.to_bytes(),
613            Self::Sr25519(signer) => signer.to_bytes(),
614        }
615    }
616
617    /// Public key corresponding to the signer.
618    pub fn public_key(&self) -> PublicKey {
619        match self {
620            Self::Ed25519(signer) => signer.public_key(),
621            Self::Secp256k1(signer) => signer.public_key(),
622            Self::Secp256r1(signer) => signer.public_key(),
623            Self::Secp384r1(signer) => signer.public_key(),
624            Self::Sr25519(signer) => signer.public_key(),
625        }
626    }
627
628    /// Generate a signature with the private key over the context and message.
629    pub fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature, Error> {
630        match self {
631            Self::Ed25519(signer) => signer.sign(context, message),
632            Self::Secp256k1(signer) => signer.sign(context, message),
633            Self::Secp256r1(signer) => signer.sign(context, message),
634            Self::Secp384r1(signer) => signer.sign(context, message),
635            Self::Sr25519(signer) => signer.sign(context, message),
636        }
637    }
638
639    /// Generate a signature with the private key over the message.
640    pub fn sign_raw(&self, message: &[u8]) -> Result<Signature, Error> {
641        match self {
642            Self::Ed25519(signer) => signer.sign_raw(message),
643            Self::Secp256k1(signer) => signer.sign_raw(message),
644            Self::Secp256r1(signer) => signer.sign_raw(message),
645            Self::Secp384r1(signer) => signer.sign_raw(message),
646            Self::Sr25519(signer) => signer.sign_raw(message),
647        }
648    }
649
650    /// Generate a signature for the specified message and optional context.
651    pub fn sign_by_type(
652        &self,
653        signature_type: SignatureType,
654        context_or_hash: &[u8],
655        message: &[u8],
656    ) -> Result<Signature, Error> {
657        match self {
658            Self::Ed25519(signer) => match signature_type {
659                SignatureType::Ed25519_Oasis => signer.sign(context_or_hash, message),
660                SignatureType::Ed25519_Pure => signer.sign_raw(message),
661                SignatureType::Ed25519_PrehashedSha512 => {
662                    if context_or_hash.len()
663                        != <sha2::Sha512 as sha2::digest::OutputSizeUser>::OutputSize::USIZE
664                    {
665                        return Err(Error::InvalidArgument);
666                    }
667                    let digest =
668                        digests::DummyDigest::<sha2::Sha512>::new_precomputed(context_or_hash);
669                    signer.sign_digest(digest)
670                }
671                _ => Err(Error::InvalidArgument),
672            },
673            Self::Secp256k1(signer) => match signature_type {
674                SignatureType::Secp256k1_Oasis => signer.sign(context_or_hash, message),
675                SignatureType::Secp256k1_PrehashedKeccak256 => {
676                    if context_or_hash.len()
677                        != <sha3::Keccak256 as sha3::digest::OutputSizeUser>::OutputSize::USIZE
678                    {
679                        return Err(Error::InvalidArgument);
680                    }
681                    // Use SHA-256 for RFC6979 even if Keccak256 was used for the message.
682                    let digest = digests::DummyDigest::<k256::sha2::Sha256>::new_precomputed(
683                        context_or_hash,
684                    );
685                    signer.sign_digest(digest)
686                }
687                SignatureType::Secp256k1_PrehashedSha256 => {
688                    if context_or_hash.len()
689                        != <sha2::Sha256 as sha2::digest::OutputSizeUser>::OutputSize::USIZE
690                    {
691                        return Err(Error::InvalidArgument);
692                    }
693                    let digest = digests::DummyDigest::<k256::sha2::Sha256>::new_precomputed(
694                        context_or_hash,
695                    );
696                    signer.sign_digest(digest)
697                }
698                _ => Err(Error::InvalidArgument),
699            },
700            Self::Secp256r1(signer) => match signature_type {
701                SignatureType::Secp256r1_PrehashedSha256 => {
702                    if context_or_hash.len()
703                        != <sha2::Sha256 as sha2::digest::OutputSizeUser>::OutputSize::USIZE
704                    {
705                        return Err(Error::InvalidArgument);
706                    }
707                    let digest =
708                        digests::DummyDigest::<sha2::Sha256>::new_precomputed(context_or_hash);
709                    signer.sign_digest(digest)
710                }
711                _ => Err(Error::InvalidArgument),
712            },
713            Self::Secp384r1(signer) => match signature_type {
714                SignatureType::Secp384r1_PrehashedSha384 => {
715                    if context_or_hash.len()
716                        != <sha2::Sha384 as sha2::digest::OutputSizeUser>::OutputSize::USIZE
717                    {
718                        return Err(Error::InvalidArgument);
719                    }
720                    let digest =
721                        digests::DummyDigest::<sha2::Sha384>::new_precomputed(context_or_hash);
722                    signer.sign_digest(digest)
723                }
724                _ => Err(Error::InvalidArgument),
725            },
726            Self::Sr25519(signer) => match signature_type {
727                SignatureType::Sr25519_Pure => signer.sign(context_or_hash, message),
728                _ => Err(Error::InvalidArgument),
729            },
730        }
731    }
732}
733
734#[cfg(test)]
735mod test {
736    use super::*;
737
738    #[test]
739    fn test_signature_conversion() {
740        let raw = vec![0x00, 0x01, 0x02, 0x03];
741        let sig = Signature::from(raw.clone());
742        let v: Vec<u8> = sig.clone().into();
743        assert_eq!(v, raw);
744
745        let vref: &[u8] = v.as_ref();
746        assert_eq!(vref, sig.as_ref());
747    }
748
749    #[test]
750    fn test_memory_signer() {
751        let ctx = b"oasis-core/test: context";
752        let corrupt_ctx = b"oasis-core/test: wrong context";
753        let message = b"this is a message";
754        let corrupt_message = b"this isn't a message";
755
756        for sig_type in [
757            SignatureType::Ed25519_Oasis,
758            SignatureType::Ed25519_Pure,
759            SignatureType::Secp256k1_Oasis,
760            SignatureType::Sr25519_Pure,
761        ] {
762            let signer = MemorySigner::new_test(sig_type, "memory signer test");
763            let pk = signer.public_key();
764
765            let signature = signer
766                .sign_by_type(sig_type, ctx, message)
767                .expect("signing should succeed");
768
769            pk.verify_by_type(sig_type, ctx, message, &signature)
770                .expect("signature should verify");
771            pk.verify_by_type(sig_type, ctx, corrupt_message, &signature)
772                .expect_err("signature should fail verification");
773            if matches!(sig_type, SignatureType::Ed25519_Oasis)
774                || matches!(sig_type, SignatureType::Secp256k1_Oasis)
775            {
776                pk.verify_by_type(sig_type, corrupt_ctx, message, &signature)
777                    .expect_err("signature should fail verification");
778                pk.verify_by_type(sig_type, corrupt_ctx, corrupt_message, &signature)
779                    .expect_err("signature should fail verification");
780            }
781        }
782    }
783
784    #[test]
785    fn test_memory_signer_prehashed() {
786        let message = b"this is a message";
787        let corrupt_message = b"this isn't a message";
788
789        let sig_types: &[(SignatureType, Box<dyn Fn(&[u8]) -> Vec<u8>>)] = &[
790            (
791                SignatureType::Ed25519_PrehashedSha512,
792                Box::new(|message| sha2::Sha512::digest(message).to_vec()),
793            ),
794            (
795                SignatureType::Secp256k1_PrehashedKeccak256,
796                Box::new(|message| sha3::Keccak256::digest(message).to_vec()),
797            ),
798            (
799                SignatureType::Secp256k1_PrehashedSha256,
800                Box::new(|message| sha2::Sha256::digest(message).to_vec()),
801            ),
802            (
803                SignatureType::Secp256r1_PrehashedSha256,
804                Box::new(|message| sha2::Sha256::digest(message).to_vec()),
805            ),
806            (
807                SignatureType::Secp384r1_PrehashedSha384,
808                Box::new(|message| sha2::Sha384::digest(message).to_vec()),
809            ),
810        ];
811
812        for (sig_type, hasher) in sig_types {
813            let hash = hasher(message);
814            let corrupt_hash = hasher(corrupt_message);
815
816            let signer = MemorySigner::new_test(*sig_type, "memory signer test");
817            let pk = signer.public_key();
818
819            let signature = signer
820                .sign_by_type(*sig_type, &hash, b"")
821                .expect("signing should succeed");
822            pk.verify_by_type(*sig_type, &hash, b"", &signature)
823                .expect("signature should verify");
824            pk.verify_by_type(*sig_type, &corrupt_hash, b"", &signature)
825                .expect_err("corrupt hash shouldn't verify");
826        }
827    }
828}