oasis_runtime_sdk/crypto/signature/
mod.rs

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