1use cesrox::primitives::CesrPrimitive;
2use said::{derivation::HashFunction, SelfAddressingIdentifier};
3use serde::{Deserialize, Serialize};
4
5use super::threshold::SignatureThreshold;
6use crate::{
7 database::redb::rkyv_adapter::said_wrapper::SaidValue,
8 prefix::{attached_signature::Index, BasicPrefix, IndexedSignature},
9};
10
11#[derive(
12 Serialize,
13 Deserialize,
14 Debug,
15 Clone,
16 Default,
17 PartialEq,
18 rkyv::Archive,
19 rkyv::Serialize,
20 rkyv::Deserialize,
21)]
22#[rkyv(derive(Debug))]
23
24pub struct NextKeysData {
25 #[serde(rename = "nt")]
26 pub threshold: SignatureThreshold,
27
28 #[serde(rename = "n")]
29 next_key_hashes: Vec<SaidValue>,
30}
31
32impl NextKeysData {
33 pub fn new(
34 threshold: SignatureThreshold,
35 next_keys_hashes: impl IntoIterator<Item = SelfAddressingIdentifier>,
36 ) -> Self {
37 let next_keys = next_keys_hashes
38 .into_iter()
39 .map(|said| said.into())
40 .collect();
41 Self {
42 threshold,
43 next_key_hashes: next_keys,
44 }
45 }
46
47 pub fn next_keys_hashes(&self) -> Vec<SelfAddressingIdentifier> {
48 self.next_key_hashes
49 .clone()
50 .into_iter()
51 .map(|said| said.into())
52 .collect()
53 }
54
55 pub fn verify_next(&self, next: &KeyConfig) -> Result<bool, SignatureError> {
58 let indexes: Vec<_> = next
59 .public_keys
60 .iter()
61 .filter_map(|key| {
62 self.next_key_hashes
63 .iter()
64 .position(|dig| dig.said.verify_binding(key.to_str().as_bytes()))
65 })
66 .collect();
67
68 self.threshold.enough_signatures(&indexes)?;
70 Ok(true)
71 }
72
73 pub fn check_threshold<'a>(
76 &self,
77 public_keys: &[BasicPrefix],
78 indexes: impl IntoIterator<Item = &'a Index>,
79 ) -> Result<(), SignatureError> {
80 let indexes_in_last_prev = self.matching_previous_indexes(public_keys, indexes);
82
83 self.threshold.enough_signatures(&indexes_in_last_prev)?;
85
86 Ok(())
87 }
88
89 fn matching_previous_indexes<'a>(
92 &self,
93 public_keys: &[BasicPrefix],
94 indexes: impl IntoIterator<Item = &'a Index>,
95 ) -> Vec<usize> {
96 indexes
98 .into_iter()
99 .filter_map(|index| {
100 index.previous_next().and_then(|prev_next| {
101 match (
102 self.next_key_hashes.get(prev_next as usize),
103 public_keys.get(index.current() as usize),
104 ) {
105 (Some(prev_next_digest), Some(current)) => prev_next_digest
106 .said
107 .verify_binding(current.to_str().as_bytes())
108 .then_some(prev_next as usize),
109 _ => None,
110 }
111 })
112 })
113 .collect::<Vec<_>>()
114 }
115}
116
117#[derive(thiserror::Error, Debug, Serialize, Deserialize)]
118pub enum SignatureError {
119 #[error("Not enough signatures while verifying")]
120 NotEnoughSigsError,
121
122 #[error("Signature duplicate while verifying")]
123 DuplicateSignature,
124
125 #[error("Too many signatures while verifying")]
126 TooManySignatures,
127
128 #[error("Key index not present in the set")]
129 MissingIndex,
130
131 #[error("Wrong signature type error")]
132 WrongSignatureTypeError,
133
134 #[error("Wrong key type error")]
135 WrongKeyTypeError,
136}
137#[derive(
138 Serialize,
139 Deserialize,
140 Debug,
141 Clone,
142 Default,
143 PartialEq,
144 rkyv::Archive,
145 rkyv::Serialize,
146 rkyv::Deserialize,
147)]
148#[rkyv(derive(Debug))]
149pub struct KeyConfig {
150 #[serde(rename = "kt")]
151 pub threshold: SignatureThreshold,
152
153 #[serde(rename = "k")]
154 pub public_keys: Vec<BasicPrefix>,
155
156 #[serde(flatten)]
157 pub next_keys_data: NextKeysData,
158}
159
160impl KeyConfig {
161 pub fn new(
162 public_keys: Vec<BasicPrefix>,
163 next_keys_data: NextKeysData,
164 threshold: Option<SignatureThreshold>,
165 ) -> Self {
166 Self {
167 threshold: threshold.map_or_else(
168 || SignatureThreshold::Simple(public_keys.len() as u64 / 2 + 1),
169 |t| t,
170 ),
171 public_keys,
172 next_keys_data,
173 }
174 }
175
176 pub fn verify(
181 &self,
182 message: &[u8],
183 sigs: &[IndexedSignature],
184 ) -> Result<bool, SignatureError> {
185 if !(sigs
187 .iter()
188 .fold(vec![0u64; self.public_keys.len()], |mut acc, sig| {
189 acc[sig.index.current() as usize] += 1;
190 acc
191 })
192 .iter()
193 .all(|n| *n <= 1))
194 {
195 Err(SignatureError::DuplicateSignature.into())
196 } else if
197 sigs.len() > self.public_keys.len() {
199 Err(SignatureError::TooManySignatures.into())
200
201 } else {
203 self.threshold.enough_signatures(
204 &sigs
205 .iter()
206 .map(|sig| sig.index.current() as usize)
207 .collect::<Vec<_>>(),
208 )?;
209
210 sigs.iter()
211 .fold(Ok(true), |acc: Result<bool, SignatureError>, sig| {
212 let verification_result: bool = self
213 .public_keys
214 .get(sig.index.current() as usize)
215 .ok_or_else(|| SignatureError::from(SignatureError::MissingIndex))
216 .and_then(|key: &BasicPrefix| Ok(key.verify(message, &sig.signature)?))?;
217 Ok(acc? && verification_result)
218 })
219 }
220 }
221
222 pub fn verify_next(&self, next: &KeyConfig) -> Result<bool, SignatureError> {
227 self.next_keys_data.verify_next(next)
228 }
229
230 pub fn commit(&self, derivation: &HashFunction) -> NextKeysData {
235 nxt_commitment(self.threshold.clone(), &self.public_keys, derivation)
236 }
237}
238
239pub fn nxt_commitment(
243 threshold: SignatureThreshold,
244 keys: &[BasicPrefix],
245 derivation: &HashFunction,
246) -> NextKeysData {
247 let next_key_hashes = keys
248 .iter()
249 .map(|bp| derivation.derive(bp.to_str().as_bytes()).into())
250 .collect();
251 NextKeysData {
252 threshold,
253 next_key_hashes,
254 }
255}
256
257#[cfg(test)]
258mod test {
259 use cesrox::{parse, primitives::CesrPrimitive};
260 use said::{derivation::HashFunction, derivation::HashFunctionCode};
261
262 use crate::{
263 error::Error,
264 event::sections::{
265 key_config::{nxt_commitment, NextKeysData, SaidValue, SignatureError},
266 threshold::SignatureThreshold,
267 KeyConfig,
268 },
269 prefix::{attached_signature::Index, BasicPrefix, IndexedSignature},
270 };
271
272 #[test]
273 fn test_next_commitment() {
274 let sith = SignatureThreshold::multi_weighted(vec![vec![(1, 2), (1, 2), (1, 2)]]);
278 let next_keys: Vec<BasicPrefix> = [
279 "DHqJ2DNmypwMKelWXLgl3V-9pDRcOenM5Wf03O1xx1Ri",
280 "DEIISiMvtnaPTpMHkoGs4d0JdbwjreW53OUBfMedLUaF",
281 "DDQFJ_uXcZum_DY6NNTtI5UrTEQo6PRWEANpn6hVtfyQ",
282 ]
283 .iter()
284 .map(|x| x.parse().unwrap())
285 .collect();
286 let nxt = nxt_commitment(sith, &next_keys, &HashFunctionCode::Blake3_256.into());
287
288 let threshold = SignatureThreshold::multi_weighted(vec![vec![(1, 2), (1, 2), (1, 2)]]);
289 let next_key_hashes: Vec<SaidValue> = [
290 "EFQZkN8MMEtZzaS-Tq1EEbH886vsf5SzwicSn_ywbzTy",
291 "ENOQnUj8GNr1ICJ1P4qmC3-aHTrpZqKVpZhvHCBVWE1p",
292 "EDFH1MfEJWlI9PpMbgBi_RGP7L4UivrLfozFucuEaWVH",
293 ]
294 .iter()
295 .map(|sai| SaidValue {
296 said: sai.parse().unwrap(),
297 })
298 .collect();
299
300 assert_eq!(
301 nxt,
302 NextKeysData {
303 threshold,
304 next_key_hashes,
305 }
306 );
307 }
308
309 #[test]
310 fn test_threshold() -> Result<(), Error> {
311 use ed25519_dalek::SigningKey;
312 use rand::rngs::OsRng;
313
314 use crate::{
315 keys::{PrivateKey, PublicKey},
316 prefix::SelfSigningPrefix,
317 };
318
319 let (pub_keys, priv_keys): (Vec<BasicPrefix>, Vec<PrivateKey>) = [0, 1, 2]
320 .iter()
321 .map(|_| {
322 let kp = SigningKey::generate(&mut OsRng);
323 (
324 BasicPrefix::Ed25519(PublicKey::new(kp.verifying_key().to_bytes().to_vec())),
325 PrivateKey::new(kp.to_bytes().to_vec()),
326 )
327 })
328 .unzip();
329 let current_threshold = SignatureThreshold::single_weighted(vec![(1, 4), (1, 2), (1, 2)]);
330
331 let next_key_hash = {
332 let next_threshold = SignatureThreshold::single_weighted(vec![(1, 2), (1, 2)]);
333 let next_keys: Vec<BasicPrefix> = [1, 2]
334 .iter()
335 .map(|_| {
336 let kp = SigningKey::generate(&mut OsRng);
337 BasicPrefix::Ed25519(PublicKey::new(kp.verifying_key().to_bytes().to_vec()))
338 })
339 .collect();
340 nxt_commitment(
341 next_threshold,
342 &next_keys,
343 &HashFunctionCode::Blake3_256.into(),
344 )
345 };
346 let key_config = KeyConfig::new(pub_keys, next_key_hash, Some(current_threshold));
347
348 let msg_to_sign = "message to signed".as_bytes();
349
350 let mut signatures = vec![];
351 for i in 0..priv_keys.len() {
352 let sig = priv_keys[i].sign_ed(msg_to_sign)?;
353 signatures.push(IndexedSignature::new_both_same(
354 SelfSigningPrefix::Ed25519Sha512(sig),
355 i as u16,
356 ));
357 }
358
359 let st = key_config.verify(
361 msg_to_sign,
362 &vec![
363 signatures[0].clone(),
364 signatures[1].clone(),
365 signatures[2].clone(),
366 ],
367 );
368 assert!(matches!(st, Ok(true)));
370
371 let st = key_config.verify(
373 msg_to_sign,
374 &vec![signatures[0].clone(), signatures[2].clone()],
375 );
376 assert!(matches!(st, Err(SignatureError::NotEnoughSigsError)));
377
378 let st = key_config.verify(
380 msg_to_sign,
381 &vec![signatures[1].clone(), signatures[2].clone()],
382 );
383 assert!(st.is_ok());
384
385 let st = key_config.verify(
387 msg_to_sign,
388 &vec![
389 signatures[0].clone(),
390 signatures[0].clone(),
391 signatures[0].clone(),
392 ],
393 );
394 assert!(matches!(st, Err(SignatureError::DuplicateSignature)));
395
396 Ok(())
397 }
398
399 #[test]
400 fn test_verify() -> Result<(), Error> {
401 use std::convert::TryFrom;
402
403 use crate::{
404 event::event_data::EventData,
405 event_message::signed_event_message::{Message, Notice},
406 };
407
408 let ev = br#"{"v":"KERI10JSON000207_","t":"icp","d":"EIL2dvwm6lYAsyKKtzxIEFm51gSfwe3IIZSx8kI8ve7_","i":"EIL2dvwm6lYAsyKKtzxIEFm51gSfwe3IIZSx8kI8ve7_","s":"0","kt":["1/2","1/2","1/2"],"k":["DCuDiSPCTq-qBBFDHkhf1_kmysrH8KSsFvoaOSgEbx-X","DNUWS4GJHtBpn2Zvgh_ALFuB6E1OJvtphYLvJG8KfI0F","DAVcM7pvoz37lF1HBxFnaZQeGHKC9wVhlytEzKBfzXhV"],"nt":["1/2","1/2","1/2"],"n":["EFQZkN8MMEtZzaS-Tq1EEbH886vsf5SzwicSn_ywbzTy","ENOQnUj8GNr1ICJ1P4qmC3-aHTrpZqKVpZhvHCBVWE1p","EDFH1MfEJWlI9PpMbgBi_RGP7L4UivrLfozFucuEaWVH"],"bt":"0","b":[],"c":[],"a":[]}-AADAAC3xWTpnv14_khneBqDlrK7JHPUoHNJhWMIXzXbK80RVyEYV7iMsWaAXfepkRsyELBLd25atAtE3iLeDn1I-gUMABDr8iCcrun_otXsarVXpe6jgK2VG20RpgsVvFunUxHsrZRKm6gNjMAoKZkqzDVuY5tKD0XkTmonstex5Wj9dToBACAwNb8Lj-vxJYMi_vIH-ETGG0dVfqIk4ihrQvV1iL1_07eWfu4BwRYCPCZDo0F0Xbkz0DP4xXVfChR-lFd2npUG"#;
411 let parsed = parse(ev).unwrap().1;
412 let signed_msg = Message::try_from(parsed).unwrap();
413 match signed_msg {
414 Message::Notice(Notice::Event(ref e)) => {
415 if let EventData::Icp(icp) = e.to_owned().event_message.data.get_event_data() {
416 let kc = icp.key_config;
417 let msg = e.event_message.encode()?;
418 assert!(kc.verify(&msg, &e.signatures).is_ok());
419 }
420 }
421 _ => (),
422 };
423
424 let ev = br#"{"v":"KERI10JSON0002a6_","t":"rot","d":"EJ4TG5D0URQ0InD_EIDXDoI9v1y3vIk-0LMJMjeZXryh","i":"EIL2dvwm6lYAsyKKtzxIEFm51gSfwe3IIZSx8kI8ve7_","s":"3","p":"ELKSLVpbV9eH3xk2xBqH3fSgOmWTbUoBuE2JsLl0lu2L","kt":["1/2","1/2","1/2"],"k":["DO1ligy1cGMWDCwIw3HiBLOusTzGOAH88fkUMNsdJkMy","DJoOgGofKsiig4kMjV04ju9UCcIs42XxjOtQQPrNAORe","DEt34Sqbzwgy-VpnzePz5JiTDLEgnUU8RtuDkLn_xJh0"],"nt":[["1/2","1/2","1/2"],["1","1"]],"n":["ENzeDznmpi75oO8APbVzyW75xnmgLDJRo0rCHf4gsDPc","ELnNWeDypTMeaIZzbT8GoJJnbmm8ksJ8ic8b2-9KFZQK","ED2lFBwMbkNQy2vxFWLbbEg2V6OLChhLfTxmvuNGWz91","EHy3gn2wZog-q8V3r6RzduTN48nLEHgSYHaoNaWHrxrl","EHuCmMw5ksFOQxvDSXL9h-_94RMKERjqLj_KFSusuHQg"],"bt":"0","br":[],"ba":[],"a":[]}-AADAACxUM40kMP7aGrPIlwO1d6XAvk6jX22u2EwcB_IgsQSaxJlLbXEz4v2j9cUHQKkY7ek47TfFYir-rG5kyLWJa0MABCQ6AlObGVXjIslKCFZkZiBNvQSDLgUU_2sR4RQxghGCExNWG9jwsSAOFBGX5QcEb6Hqu4ZrdbnyV9GxRkR-jkDACC4Ydi6Jlqw9ROIqNvyHoXNoYcIZzI8iD8_YB1-U9J1xb55jG4z-1Ddyx8mLW6_O53boaFobaitvO13z3u5OswF"#;
425 let parsed = parse(ev).unwrap().1;
426 let signed_msg = Message::try_from(parsed).unwrap();
427 match signed_msg {
428 Message::Notice(Notice::Event(ref e)) => {
429 if let EventData::Icp(icp) = e.to_owned().event_message.data.get_event_data() {
430 let kc = icp.key_config;
431 let msg = e.event_message.encode()?;
432 assert!(kc.verify(&msg, &e.signatures).is_ok());
433 }
434 }
435 _ => (),
436 };
437
438 Ok(())
439 }
440
441 #[test]
442 pub fn test_finding_matching_previous_indexes() -> Result<(), Error> {
443 use crate::signer::setup_signers;
444
445 let signers = setup_signers();
446 let hash_function: HashFunction = HashFunctionCode::Blake3_256.into();
447
448 let sample_public_keys: Vec<_> = signers
449 .iter()
450 .map(|bp| BasicPrefix::Ed25519(bp.public_key()))
451 .collect();
452 let sample_digests: Vec<_> = sample_public_keys
453 .clone()
454 .into_iter()
455 .map(|pk| hash_function.derive(pk.to_str().as_bytes()))
456 .collect();
457
458 let threshold = SignatureThreshold::single_weighted(vec![(1, 4), (1, 2), (1, 4), (1, 2)]);
459 let public_keys = sample_public_keys[..5].to_vec();
460 let initial_digests: Vec<_> = sample_digests[..5].to_vec();
461
462 let indexes = vec![Index::BothSame(0), Index::BothSame(1), Index::BothSame(2)];
464
465 let next_keys_data = NextKeysData::new(threshold.clone(), initial_digests.clone());
466 assert_eq!(
467 next_keys_data.matching_previous_indexes(&public_keys, &indexes[..2]),
468 vec![0, 1]
469 );
470 assert_eq!(
471 next_keys_data.matching_previous_indexes(&public_keys, &indexes),
472 vec![0, 1, 2]
473 );
474
475 let indexes = vec![
477 Index::BothDifferent(0, 2),
478 Index::BothDifferent(1, 0),
479 Index::BothDifferent(2, 1),
480 ];
481 let digests = vec![
482 initial_digests[1].clone(),
483 initial_digests[2].clone(),
484 initial_digests[0].clone(),
485 ];
486
487 let next_keys_data = NextKeysData::new(threshold.clone(), digests.to_vec());
488 assert_eq!(
489 next_keys_data.matching_previous_indexes(&public_keys, &indexes[..2]),
490 vec![2, 0]
491 );
492 assert_eq!(
493 next_keys_data.matching_previous_indexes(&public_keys, &indexes),
494 vec![2, 0, 1]
495 );
496
497 let indexes = vec![
499 Index::CurrentOnly(0),
500 Index::BothDifferent(1, 2),
501 Index::BothDifferent(2, 1),
502 ];
503 let digests = vec![
504 initial_digests[0].clone(),
505 initial_digests[2].clone(),
506 initial_digests[1].clone(),
507 ];
508
509 let next_keys_data = NextKeysData::new(threshold.clone(), digests.to_vec());
510 assert_eq!(
511 next_keys_data.matching_previous_indexes(&public_keys, &indexes[..2]),
512 vec![2]
513 );
514 assert_eq!(
515 next_keys_data.matching_previous_indexes(&public_keys, &indexes),
516 vec![2, 1]
517 );
518
519 let indexes = vec![
521 Index::CurrentOnly(0),
522 Index::BothDifferent(1, 2),
523 Index::BothDifferent(2, 1),
524 ];
525 let digests = vec![
526 initial_digests[0].clone(),
527 initial_digests[2].clone(),
528 hash_function.derive("Bad digest".as_bytes()),
529 ];
530
531 let next_keys_data = NextKeysData::new(threshold.clone(), digests.to_vec());
532 assert_eq!(
533 next_keys_data.matching_previous_indexes(&public_keys, &indexes),
534 vec![1]
535 );
536
537 Ok(())
538 }
539}