1use crate::model::clock::{TimeGetter, timestamp};
2use crate::model::crypto::*;
3use libsecp256k1::{Message, PublicKey, SecretKey, SharedSecret, Signature};
4use rand::rngs::OsRng;
5use serde::Serialize;
6use sha2::{Digest, Sha256};
7use std::convert::TryInto;
8
9use super::errors::{LbErrKind, LbResult, SignError, Unexpected};
10
11pub fn generate_key() -> SecretKey {
12 SecretKey::random(&mut OsRng)
13}
14
15pub fn sign<T: Serialize>(
16 sk: &SecretKey, pk: &PublicKey, to_sign: T, time_getter: TimeGetter,
17) -> LbResult<ECSigned<T>> {
18 let timestamped = timestamp(to_sign, time_getter);
19 let serialized = bincode::serialize(×tamped).map_unexpected()?;
20 let digest = Sha256::digest(&serialized);
21 let message = &Message::parse_slice(&digest)
22 .map_err(|err| LbErrKind::Sign(SignError::SignatureParseError(err)))?;
23 let (signature, _) = libsecp256k1::sign(message, sk);
24 Ok(ECSigned {
25 timestamped_value: timestamped,
26 signature: signature.serialize().to_vec(),
27 public_key: *pk,
28 })
29}
30
31pub fn verify<T: Serialize>(
32 pk: &PublicKey, signed: &ECSigned<T>, max_delay_ms: u64, max_skew_ms: u64,
33 time_getter: TimeGetter,
34) -> LbResult<()> {
35 if &signed.public_key != pk {
36 Err(LbErrKind::Sign(SignError::WrongPublicKey))?;
37 }
38
39 let auth_time = signed.timestamped_value.timestamp;
40 let current_time = time_getter().0;
41 let max_skew_ms = max_skew_ms as i64;
42 let max_delay_ms = max_delay_ms as i64;
43
44 if current_time < auth_time - max_skew_ms {
45 Err(LbErrKind::Sign(SignError::SignatureInTheFuture(
46 (current_time - (auth_time - max_delay_ms)) as u64,
47 )))?;
48 }
49
50 if current_time > auth_time + max_delay_ms {
51 Err(LbErrKind::Sign(SignError::SignatureExpired(
52 (auth_time + max_delay_ms - current_time) as u64,
53 )))?;
54 }
55
56 let serialized = bincode::serialize(&signed.timestamped_value)?;
59
60 let digest = Sha256::digest(&serialized).to_vec();
61 let message = &Message::parse_slice(&digest).map_err(|err| {
62 LbErrKind::Unexpected(format!(
63 "unexpected failure to produce a message after hashing: {err:?}"
64 ))
65 })?;
66
67 let signature = Signature::parse_standard_slice(&signed.signature)
68 .map_err(|err| LbErrKind::Sign(SignError::SignatureParseError(err)))?;
69
70 if libsecp256k1::verify(message, &signature, &signed.public_key) {
71 Ok(())
72 } else {
73 Err(LbErrKind::Sign(SignError::SignatureInvalid))?
74 }
75}
76
77pub fn get_aes_key(sk: &SecretKey, pk: &PublicKey) -> LbResult<AESKey> {
78 SharedSecret::<Sha256>::new(pk, sk)
79 .map_unexpected()?
80 .as_ref()
81 .try_into()
82 .map_unexpected()
83}
84
85#[cfg(test)]
86mod unit_tests {
87 use libsecp256k1::PublicKey;
88
89 use crate::model::clock::Timestamp;
90 use crate::model::pubkey::*;
91
92 static EARLY_CLOCK: fn() -> Timestamp = || Timestamp(500);
93 static LATE_CLOCK: fn() -> Timestamp = || Timestamp(520);
94
95 #[test]
96 fn ec_test_sign_verify() {
97 let sk = generate_key();
98 let pk = PublicKey::from_secret_key(&sk);
99 let value = sign(&sk, &pk, "Test", EARLY_CLOCK).unwrap();
100 verify(&pk, &value, 20, 20, LATE_CLOCK).unwrap();
101 }
102
103 #[test]
104 fn ec_test_sign_verify_late() {
105 let sk = generate_key();
106 let pk = PublicKey::from_secret_key(&sk);
107 let value = sign(&sk, &pk, "Test", EARLY_CLOCK).unwrap();
108 verify(&pk, &value, 10, 10, LATE_CLOCK).unwrap_err();
109 }
110
111 #[test]
112 fn ec_test_shared_secret_one_party() {
113 let key = generate_key();
116 let shared_secret1 = get_aes_key(&key, &PublicKey::from_secret_key(&key)).unwrap();
117
118 let shared_secret2 = get_aes_key(&key, &PublicKey::from_secret_key(&key)).unwrap();
119
120 assert_eq!(shared_secret1, shared_secret2);
121 }
122
123 #[test]
124 fn ec_test_shared_secret_two_parties() {
125 let key1 = generate_key();
128 let key2 = generate_key();
129
130 let shared_secret1 = get_aes_key(&key1, &PublicKey::from_secret_key(&key2)).unwrap();
131
132 let shared_secret2 = get_aes_key(&key2, &PublicKey::from_secret_key(&key1)).unwrap();
133
134 assert_eq!(shared_secret1, shared_secret2);
135 }
136
137 #[test]
138 fn same_sk_same_pk_sanity_check() {
139 let key1 = generate_key();
140 let key2 = SecretKey::parse(&key1.serialize()).unwrap();
141
142 assert_eq!(key1, key2);
143
144 assert_eq!(PublicKey::from_secret_key(&key1), PublicKey::from_secret_key(&key2));
145 }
146}