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