oasis_runtime_sdk/crypto/signature/
sr25519.rs1use base64::prelude::*;
3use rand::TryCryptoRng;
4use schnorrkel::{self, context::SigningTranscript};
5use sha2_old::{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 TryCryptoRng) -> Result<Self, Error> {
104 Ok(Self {
105 keypair: schnorrkel::Keypair::generate_with(WrappedCryptoRng(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
142pub struct WrappedCryptoRng<R>(pub R);
143
144impl<R> rand_core::RngCore for WrappedCryptoRng<R>
145where
146 R: TryCryptoRng,
147{
148 fn next_u32(&mut self) -> u32 {
149 self.0.try_next_u32().unwrap()
150 }
151
152 fn next_u64(&mut self) -> u64 {
153 self.0.try_next_u64().unwrap()
154 }
155
156 fn fill_bytes(&mut self, dst: &mut [u8]) {
157 self.0.try_fill_bytes(dst).unwrap()
158 }
159
160 fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), rand_core::Error> {
161 self.fill_bytes(dst);
162 Ok(())
163 }
164}
165
166impl<R> rand_core::CryptoRng for WrappedCryptoRng<R> where R: TryCryptoRng {}
167
168#[cfg(test)]
169mod test {
170 use super::*;
171
172 #[test]
173 fn test_polkadot_vectors() {
174 let seed = hex::decode("fac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e")
176 .unwrap();
177 let signer = MemorySigner::new_from_seed(&seed).unwrap();
178 assert_eq!(
179 hex::encode(signer.public_key().as_bytes()),
180 "46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a",
181 );
182
183 let raw = hex::decode("28b0ae221c6bb06856b287f60d7ea0d98552ea5a16db16956849aa371db3eb51fd190cce74df356432b410bd64682309d6dedb27c76845daf388557cbac3ca3446ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a").unwrap();
184 let signer = MemorySigner::from_bytes(&raw).unwrap();
185 assert_eq!(
186 hex::encode(signer.public_key().as_bytes()),
187 "46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a",
188 );
189
190 let msg =
192 b"I hereby verify that I control 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
193 let signature = hex::decode("1037eb7e51613d0dcf5930ae518819c87d655056605764840d9280984e1b7063c4566b55bf292fcab07b369d01095879b50517beca4d26e6a65866e25fec0d83").unwrap();
194 let pk = hex::decode("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d")
195 .unwrap();
196 let pk = PublicKey::from_bytes(&pk).unwrap();
197 pk.verify_raw(b"substrate", msg, &signature.into()).unwrap();
198
199 let msg = b"<Bytes>message to sign</Bytes>";
201 let signature = hex::decode("48ce2c90e08651adfc8ecef84e916f6d1bb51ebebd16150ee12df247841a5437951ea0f9d632ca165e6ab391532e75e701be6a1caa88c8a6bcca3511f55b4183").unwrap();
202 let pk = hex::decode("f84d048da2ddae2d9d8fd6763f469566e8817a26114f39408de15547f6d47805")
203 .unwrap();
204 let pk = PublicKey::from_bytes(&pk).unwrap();
205 pk.verify_raw(b"substrate", msg, &signature.clone().into())
206 .unwrap();
207
208 let msg = b"message to sign";
210 pk.verify_raw(b"substrate", msg, &signature.into())
211 .unwrap_err();
212 }
213}