oasis_runtime_sdk/crypto/signature/
sr25519.rs1use base64::prelude::*;
3use rand_core::{CryptoRng, RngCore};
4use schnorrkel::{self, context::SigningTranscript};
5use sha2::{Digest, Sha512_256};
6
7use crate::crypto::signature::{Error, Signature, Signer};
8
9#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, cbor::Encode, cbor::Decode)]
11#[cbor(transparent, no_default)]
12pub struct PublicKey(Vec<u8>);
13
14impl PublicKey {
15 pub fn as_bytes(&self) -> &[u8] {
17 &self.0
26 }
27
28 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
30 PublicKey::decompress_public_key(bytes)?;
32 Ok(PublicKey(bytes.to_vec()))
33 }
34
35 pub fn verify(
37 &self,
38 context: &[u8],
39 message: &[u8],
40 signature: &Signature,
41 ) -> Result<(), Error> {
42 let context = schnorrkel::context::SigningContext::new(context);
44
45 let mut digest = Sha512_256::new();
51 digest.update(message);
52 let transcript = context.hash256(digest);
53
54 self.verify_transcript(transcript, signature)
55 }
56
57 pub fn verify_raw(
59 &self,
60 context: &[u8],
61 message: &[u8],
62 signature: &Signature,
63 ) -> Result<(), Error> {
64 let context = schnorrkel::signing_context(context);
66 let transcript = context.bytes(message);
67 self.verify_transcript(transcript, signature)
68 }
69
70 pub fn verify_transcript<T: SigningTranscript>(
72 &self,
73 transcript: T,
74 signature: &Signature,
75 ) -> Result<(), Error> {
76 let public_key = PublicKey::decompress_public_key(&self.0)?;
77
78 let signature = schnorrkel::Signature::from_bytes(signature.as_ref())
79 .map_err(|_| Error::MalformedSignature)?;
80
81 public_key
82 .verify(transcript, &signature)
83 .map_err(|_| Error::VerificationFailed)
84 }
85
86 fn decompress_public_key(bytes: &[u8]) -> Result<schnorrkel::PublicKey, Error> {
87 schnorrkel::PublicKey::from_bytes(bytes).map_err(|_| Error::MalformedPublicKey)
88 }
89}
90
91impl From<&'static str> for PublicKey {
92 fn from(s: &'static str) -> PublicKey {
93 PublicKey::from_bytes(&BASE64_STANDARD.decode(s).unwrap()).unwrap()
94 }
95}
96
97pub struct MemorySigner {
99 keypair: schnorrkel::Keypair,
100}
101
102impl Signer for MemorySigner {
103 fn random(rng: &mut (impl RngCore + CryptoRng)) -> Result<Self, Error> {
104 Ok(Self {
105 keypair: schnorrkel::Keypair::generate_with(rng),
106 })
107 }
108
109 fn new_from_seed(seed: &[u8]) -> Result<Self, Error> {
110 let msk =
111 schnorrkel::MiniSecretKey::from_bytes(seed).map_err(|_| Error::MalformedPrivateKey)?;
112 let keypair = msk.expand_to_keypair(schnorrkel::ExpansionMode::Ed25519);
113 Ok(Self { keypair })
114 }
115
116 fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
117 Ok(Self {
118 keypair: schnorrkel::Keypair::from_half_ed25519_bytes(bytes)
119 .map_err(|_| Error::MalformedPrivateKey)?,
120 })
121 }
122
123 fn to_bytes(&self) -> Vec<u8> {
124 self.keypair.to_half_ed25519_bytes().to_vec()
125 }
126
127 fn public_key(&self) -> super::PublicKey {
128 super::PublicKey::Sr25519(PublicKey(self.keypair.public.to_bytes().to_vec()))
129 }
130
131 fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature, Error> {
132 let sig = self.keypair.sign_simple(context, message);
133 Ok(Signature(sig.to_bytes().to_vec()))
134 }
135
136 fn sign_raw(&self, _message: &[u8]) -> Result<Signature, Error> {
137 Err(Error::InvalidArgument)
139 }
140}
141
142#[cfg(test)]
143mod test {
144 use super::*;
145
146 #[test]
147 fn test_polkadot_vectors() {
148 let seed = hex::decode("fac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e")
150 .unwrap();
151 let signer = MemorySigner::new_from_seed(&seed).unwrap();
152 assert_eq!(
153 hex::encode(signer.public_key().as_bytes()),
154 "46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a",
155 );
156
157 let raw = hex::decode("28b0ae221c6bb06856b287f60d7ea0d98552ea5a16db16956849aa371db3eb51fd190cce74df356432b410bd64682309d6dedb27c76845daf388557cbac3ca3446ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a").unwrap();
158 let signer = MemorySigner::from_bytes(&raw).unwrap();
159 assert_eq!(
160 hex::encode(signer.public_key().as_bytes()),
161 "46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a",
162 );
163
164 let msg =
166 b"I hereby verify that I control 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
167 let signature = hex::decode("1037eb7e51613d0dcf5930ae518819c87d655056605764840d9280984e1b7063c4566b55bf292fcab07b369d01095879b50517beca4d26e6a65866e25fec0d83").unwrap();
168 let pk = hex::decode("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d")
169 .unwrap();
170 let pk = PublicKey::from_bytes(&pk).unwrap();
171 pk.verify_raw(b"substrate", msg, &signature.into()).unwrap();
172
173 let msg = b"<Bytes>message to sign</Bytes>";
175 let signature = hex::decode("48ce2c90e08651adfc8ecef84e916f6d1bb51ebebd16150ee12df247841a5437951ea0f9d632ca165e6ab391532e75e701be6a1caa88c8a6bcca3511f55b4183").unwrap();
176 let pk = hex::decode("f84d048da2ddae2d9d8fd6763f469566e8817a26114f39408de15547f6d47805")
177 .unwrap();
178 let pk = PublicKey::from_bytes(&pk).unwrap();
179 pk.verify_raw(b"substrate", msg, &signature.clone().into())
180 .unwrap();
181
182 let msg = b"message to sign";
184 pk.verify_raw(b"substrate", msg, &signature.into())
185 .unwrap_err();
186 }
187}