1use std::{cmp::Ordering, convert::TryInto, io::Cursor};
3
4use anyhow::Result;
5use byteorder::{LittleEndian, ReadBytesExt};
6use curve25519_dalek::{
7 edwards::{CompressedEdwardsY, EdwardsPoint},
8 scalar::Scalar,
9};
10use ed25519_dalek::{Digest as _, Sha512, Signer as _};
11use rand::{rand_core::UnwrapErr, rngs::SysRng};
12use thiserror::Error;
13use zeroize::Zeroize;
14
15use crate::common::namespace::Namespace;
16
17use super::hash::Hash;
18
19const CHAIN_SIGNATURE_CONTEXT_SEPARATOR: &[u8] = b" for chain ";
21const RUNTIME_SIGNATURE_CONTEXT_SEPARATOR: &[u8] = b" for runtime ";
23
24impl_bytes!(
25 PublicKey,
26 ed25519_dalek::PUBLIC_KEY_LENGTH,
27 "An Ed25519 public key."
28);
29
30#[derive(Error, Debug)]
32enum SignatureError {
33 #[error("point decompression failed")]
34 PointDecompression,
35 #[error("small order A")]
36 SmallOrderA,
37 #[error("small order R")]
38 SmallOrderR,
39 #[error("signature malleability check failed")]
40 Malleability,
41 #[error("invalid signature")]
42 InvalidSignature,
43}
44
45static CURVE_ORDER: &[u64] = &[
46 0x1000000000000000,
47 0,
48 0x14def9dea2f79cd6,
49 0x5812631a5cf5d3ed,
50];
51
52pub struct PrivateKey(pub ed25519_dalek::SigningKey);
54
55impl PrivateKey {
56 pub fn generate() -> Self {
58 let mut rng = UnwrapErr(SysRng);
59 PrivateKey(ed25519_dalek::SigningKey::generate(&mut rng))
60 }
61
62 pub fn to_bytes(&self) -> Vec<u8> {
64 let mut bytes = self.0.to_bytes();
65 let bvec = bytes.to_vec();
66 bytes.zeroize();
67 bvec
68 }
69
70 pub fn from_bytes(bytes: Vec<u8>) -> PrivateKey {
76 let mut sk = bytes.try_into().unwrap();
77 let secret = ed25519_dalek::SigningKey::from_bytes(&sk);
78 sk.zeroize();
79
80 PrivateKey(secret)
81 }
82
83 pub fn from_test_seed(seed: String) -> Self {
85 let mut seed = Hash::digest_bytes(seed.as_bytes());
86 let sk = Self::from_bytes(seed.as_ref().to_vec());
87 seed.zeroize();
88
89 sk
90 }
91
92 pub fn public_key(&self) -> PublicKey {
94 PublicKey(self.0.verifying_key().to_bytes())
95 }
96}
97
98impl Signer for PrivateKey {
99 fn public(&self) -> PublicKey {
100 self.public_key()
101 }
102
103 fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature> {
104 let digest = Hash::digest_bytes_list(&[context, message]);
106
107 Ok(Signature(self.0.sign(digest.as_ref()).to_bytes()))
108 }
109}
110
111impl_bytes!(Signature, 64, "An Ed25519 signature.");
112
113impl Signature {
114 pub fn verify(&self, pk: &PublicKey, context: &[u8], message: &[u8]) -> Result<()> {
116 let digest = Hash::digest_bytes_list(&[context, message]);
120
121 self.verify_raw(pk, digest.as_ref())
122 }
123
124 #[allow(non_snake_case)] pub fn verify_raw(&self, pk: &PublicKey, msg: &[u8]) -> Result<()> {
127 let A = CompressedEdwardsY::from_slice(pk.as_ref())
137 .map_err(|_| SignatureError::PointDecompression)?;
138 let A = A.decompress().ok_or(SignatureError::PointDecompression)?;
139 if A.is_small_order() {
140 return Err(SignatureError::SmallOrderA.into());
141 }
142
143 let sig_slice = self.as_ref();
149 let R_bits = &sig_slice[..32];
150 let S_bits = &sig_slice[32..];
151
152 let R = CompressedEdwardsY::from_slice(R_bits)
153 .map_err(|_| SignatureError::PointDecompression)?;
154 let R = R.decompress().ok_or(SignatureError::PointDecompression)?;
155 if R.is_small_order() {
156 return Err(SignatureError::SmallOrderR.into());
157 }
158
159 if !sc_minimal(S_bits) {
160 return Err(SignatureError::Malleability.into());
161 }
162 let mut S: [u8; 32] = [0u8; 32];
163 S.copy_from_slice(S_bits);
164 #[allow(deprecated)] let S = Scalar::from_bits(S);
166
167 let mut k: Sha512 = Sha512::new();
169 k.update(R_bits);
170 k.update(pk.as_ref());
171 k.update(msg);
172 let k = Scalar::from_hash(k);
173
174 let neg_A = -A;
176 let should_be_small_order =
177 EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &neg_A, &S) - R;
178 match should_be_small_order.is_small_order() {
179 true => Ok(()),
180 false => Err(SignatureError::InvalidSignature.into()),
181 }
182 }
183}
184
185#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
187pub struct Signed {
188 #[cbor(rename = "untrusted_raw_value")]
190 pub blob: Vec<u8>,
191 pub signature: SignatureBundle,
193}
194
195#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
197pub struct MultiSigned {
198 #[cbor(rename = "untrusted_raw_value")]
200 pub blob: Vec<u8>,
201 pub signatures: Vec<SignatureBundle>,
203}
204
205#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
207pub struct SignatureBundle {
208 pub public_key: PublicKey,
210 pub signature: Signature,
212}
213
214impl SignatureBundle {
215 pub fn verify(&self, context: &[u8], message: &[u8]) -> bool {
218 self.signature
219 .verify(&self.public_key, context, message)
220 .is_ok()
221 }
222}
223
224pub trait Signer: Send + Sync {
226 fn public(&self) -> PublicKey;
228
229 fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature>;
231}
232
233fn sc_minimal(raw_s: &[u8]) -> bool {
236 let mut rd = Cursor::new(raw_s);
237 let mut s = [0u64; 4];
238
239 rd.read_u64_into::<LittleEndian>(&mut s[..]).unwrap();
242 s.reverse();
243
244 for i in 0..4 {
246 match s[i].cmp(&CURVE_ORDER[i]) {
247 Ordering::Greater => return false,
248 Ordering::Less => return true,
249 Ordering::Equal => {}
250 }
251 }
252
253 false
255}
256
257pub fn signature_context_with_runtime_separation(
259 mut context: Vec<u8>,
260 runtime_id: &Namespace,
261) -> Vec<u8> {
262 context.extend(RUNTIME_SIGNATURE_CONTEXT_SEPARATOR);
263 context.extend(runtime_id.0);
264 context
265}
266
267pub fn signature_context_with_chain_separation(
269 mut context: Vec<u8>,
270 chain_context: &String,
271) -> Vec<u8> {
272 context.extend(CHAIN_SIGNATURE_CONTEXT_SEPARATOR);
273 context.extend(chain_context.as_bytes());
274 context
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280 use rustc_hex::FromHex;
281
282 #[test]
283 fn test_sc_minimal() {
284 assert!(sc_minimal(&[
286 0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
287 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x10
289 ]));
290
291 assert!(sc_minimal(&[
293 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd5, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
294 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x10
296 ]));
297
298 assert!(sc_minimal(&[
300 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd5, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
301 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
302 0xff, 0xff, 0xff, 0x0f,
303 ]));
304
305 assert!(!sc_minimal(&[
307 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
308 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x10
310 ]));
311
312 assert!(!sc_minimal(&[
314 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
315 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x10
317 ]));
318
319 assert!(!sc_minimal(&[
321 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd7, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
322 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x10
324 ]));
325
326 assert!(!sc_minimal(&[
328 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
329 0xde, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0x10
331 ]));
332
333 assert!(!sc_minimal(&[
335 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
336 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
337 0x00, 0x00, 0x00, 0x10
338 ]));
339
340 assert!(!sc_minimal(&[
342 0x67, 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d, 0xaf, 0xc0,
343 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33, 0x36, 0xa5, 0xc5, 0x1e, 0xb6,
344 0xf9, 0x46, 0xb3, 0x1d,
345 ]))
346 }
347
348 #[test]
349 fn test_private_key_to_bytes() {
350 let secret = PrivateKey::generate();
351 let bytes = secret.to_bytes();
352 let from_bytes = PrivateKey::from_bytes(bytes);
353 assert_eq!(secret.public_key(), from_bytes.public_key());
354 }
355
356 #[test]
357 #[should_panic]
358 fn test_private_key_to_bytes_malformed_a() {
359 PrivateKey::from_bytes(vec![]);
360 }
361
362 #[test]
363 #[should_panic]
364 fn test_private_key_to_bytes_malformed_b() {
365 PrivateKey::from_bytes(vec![1, 2, 3]);
366 }
367
368 #[test]
369 fn verification_small_order_a() {
370 let pbk = "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa";
372 let msg = "9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79";
373 let sig = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43a5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04";
374
375 let pbk: Vec<u8> = pbk.from_hex().unwrap();
376 let msg: Vec<u8> = msg.from_hex().unwrap();
377 let sig: Vec<u8> = sig.from_hex().unwrap();
378
379 let pbk = PublicKey::from(pbk);
380 let sig = Signature::from(sig);
381
382 assert!(
383 sig.verify_raw(&pbk, &msg).is_err(),
384 "small order A not rejected"
385 )
386 }
387
388 #[test]
389 fn verification_small_order_r() {
390 let pbk = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43";
392 let msg = "aebf3f2601a0c8c5d39cc7d8911642f740b78168218da8471772b35f9d35b9ab";
393 let sig = "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa8c4bd45aecaca5b24fb97bc10ac27ac8751a7dfe1baff8b953ec9f5833ca260e";
394
395 let pbk: Vec<u8> = pbk.from_hex().unwrap();
396 let msg: Vec<u8> = msg.from_hex().unwrap();
397 let sig: Vec<u8> = sig.from_hex().unwrap();
398
399 let pbk = PublicKey::from(pbk);
400 let sig = Signature::from(sig);
401
402 assert!(
403 sig.verify_raw(&pbk, &msg).is_err(),
404 "small order R not rejected"
405 )
406 }
407
408 #[test]
409 fn verification_is_cofactored() {
410 let pbk = "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d";
412 let msg = "e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c";
413 let sig = "160a1cb0dc9c0258cd0a7d23e94d8fa878bcb1925f2c64246b2dee1796bed5125ec6bc982a269b723e0668e540911a9a6a58921d6925e434ab10aa7940551a09";
414
415 let pbk: Vec<u8> = pbk.from_hex().unwrap();
416 let msg: Vec<u8> = msg.from_hex().unwrap();
417 let sig: Vec<u8> = sig.from_hex().unwrap();
418
419 let pbk = PublicKey::from(pbk);
420 let sig = Signature::from(sig);
421
422 assert!(
423 sig.verify_raw(&pbk, &msg).is_ok(),
424 "verification is not cofactored(?)"
425 )
426 }
427
428 }