1#![deny(missing_docs,
14 missing_debug_implementations, missing_copy_implementations,
15 trivial_casts, trivial_numeric_casts,
16 unsafe_code,
17 unstable_features,
18 unused_import_braces, unused_qualifications)]
19
20extern crate serde;
21#[macro_use]
22extern crate serde_derive;
23extern crate bincode;
24
25use std::ops::Deref;
26use std::collections::HashSet;
27use std::collections::hash_set::Iter;
28use std::rc::Rc;
29use std::fs::File;
30use std::io::prelude::*;
31
32use bincode::{serialize, deserialize, Infinite};
33
34#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
36pub struct NodeId(pub usize);
37
38impl Deref for NodeId {
39 type Target = usize;
40
41 fn deref(&self) -> &Self::Target {
42 &self.0
43 }
44}
45
46#[derive(Debug, Copy, Clone, PartialEq, Eq)]
49pub enum NewLinkResult {
50 Ok(usize),
52 AlreadyCertified(usize),
54 AllCertificationsUsed(usize),
56 UnknownSource(),
58 UnknownTarget(),
60 SelfLinkingForbidden(),
62}
63
64#[derive(Debug, Copy, Clone, PartialEq, Eq)]
67pub enum RemovedLinkResult {
68 Removed(usize),
70 UnknownCert(usize),
72 UnknownSource(),
74 UnknownTarget(),
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
79struct Node {
80 id: NodeId,
81 pub enabled: bool,
83 certs: HashSet<NodeId>,
84 issued_count: usize,
85}
86
87impl Node {
88 pub fn new(id: usize) -> Node {
90 Node {
91 id: NodeId(id),
92 enabled: true,
93 certs: HashSet::new(),
94 issued_count: 0,
95 }
96 }
97
98 pub fn id(&self) -> NodeId {
100 self.id
101 }
102
103 pub fn link_to(&mut self, to: &mut Node, max_certs: usize) -> NewLinkResult {
107 if self.issued_count >= max_certs {
108 NewLinkResult::AllCertificationsUsed(to.certs.len())
109 } else if to.certs.contains(&self.id()) {
110 NewLinkResult::AlreadyCertified(to.certs.len())
111 } else {
112 to.certs.insert(self.id());
113 self.issued_count += 1;
114 NewLinkResult::Ok(to.certs.len())
115 }
116 }
117
118 pub fn unlink_to(&mut self, to: &mut Node) -> RemovedLinkResult {
120 if to.certs.contains(&self.id()) {
121 to.certs.remove(&self.id());
122 self.issued_count -= 1;
123 RemovedLinkResult::Removed(to.certs.len())
124 } else {
125 RemovedLinkResult::UnknownCert(to.certs.len())
126 }
127 }
128
129 pub fn has_link_from(&self, from: &Node) -> bool {
131 self.certs.contains(&from.id())
132 }
133
134 pub fn has_link_to(&self, to: &Node) -> bool {
136 to.has_link_from(&self)
137 }
138
139 pub fn links_iter(&self) -> Iter<NodeId> {
141 self.certs.iter()
142 }
143
144 pub fn issued_count(&self) -> usize {
146 self.issued_count
147 }
148}
149
150#[derive(Debug, Copy, Clone, PartialEq, Eq)]
152pub struct WotDistance {
153 pub sentries: u32,
155 pub success: u32,
157 pub reached: u32,
159 pub outdistanced: bool,
161}
162
163#[derive(Debug)]
164struct WotStep {
165 pub previous: Option<Rc<Box<WotStep>>>,
166 pub node: NodeId,
167 pub distance: u32,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct WebOfTrust {
178 nodes: Vec<Node>,
179 pub max_cert: usize,
185}
186
187impl WebOfTrust {
188 pub fn new(max_cert: usize) -> WebOfTrust {
190 WebOfTrust {
191 nodes: vec![],
192 max_cert,
193 }
194 }
195
196 pub fn from_file(path: &str) -> Option<WebOfTrust> {
198 let mut file = match File::open(path) {
199 Ok(file) => file,
200 Err(_) => return None,
201 };
202
203 let mut content: Vec<u8> = vec![];
204 if let Err(_) = file.read_to_end(&mut content) {
205 return None;
206 }
207
208 match deserialize::<WebOfTrust>(&content[..]) {
209 Ok(wot) => Some(wot),
210 Err(_) => None,
211 }
212 }
213
214 pub fn to_file(&self, path: &str) -> bool {
216 let encoded: Vec<u8> = serialize(self, Infinite).unwrap();
217
218 match File::create(path) {
219 Ok(mut buffer) => buffer.write_all(&encoded).is_ok(),
220 Err(_) => false,
221 }
222 }
223
224 pub fn add_node(&mut self) -> NodeId {
226 let node_id = self.nodes.len();
227 self.nodes.push(Node::new(node_id));
228
229 NodeId(node_id)
230 }
231
232 pub fn remove_node(&mut self) -> Option<NodeId> {
234 self.nodes.pop();
235
236 if self.nodes.len() > 0 {
237 Some(NodeId(self.nodes.iter().len() - 1))
238 } else {
239 None
240 }
241 }
242
243 fn check_matches(&self, node: NodeId, d: u32, d_max: u32, mut checked: Vec<bool>) -> Vec<bool> {
244 let mut linked_nodes = Vec::new();
245
246 for linked_node in self.nodes[*node].links_iter() {
247 checked[**linked_node] = true;
248 linked_nodes.push(*linked_node);
249 }
250
251 if d < d_max {
252 for linked_node in linked_nodes.iter() {
253 checked = self.check_matches(*linked_node, d + 1, d_max, checked);
254 }
255 }
256
257 checked
258 }
259
260 pub fn compute_distance(
262 &self,
263 member: NodeId,
264 d_min: u32,
265 k_max: u32,
266 x_percent: f64,
267 ) -> WotDistance {
268 let d_min = d_min as usize;
269
270 let mut result = WotDistance {
271 sentries: 0,
272 success: 0,
273 reached: 0,
274 outdistanced: false,
275 };
276
277 let mut sentries: Vec<bool> = self.nodes
278 .iter()
279 .map(|x| {
280 x.enabled && x.issued_count() >= d_min && x.links_iter().count() >= d_min
281 })
282 .collect();
283 sentries[*member] = false;
284
285 let mut checked: Vec<bool> = self.nodes.iter().map(|_| false).collect();
286
287 if k_max >= 1 {
288 checked = self.check_matches(member, 1, k_max, checked);
289 }
290
291 for (&sentry, &check) in sentries.iter().zip(checked.iter()) {
292 if sentry {
293 result.sentries += 1;
294 if check {
295 result.success += 1;
296 result.reached += 1;
297 }
298 } else {
299 if check {
300 result.reached += 1;
301 }
302 }
303 }
304
305 result.outdistanced = (result.success as f64) < x_percent * (result.sentries as f64);
306 result
307 }
308
309 pub fn get_sentries(&self, d_min: usize) -> Vec<NodeId> {
311 self.nodes
312 .iter()
313 .filter(|x| {
314 x.enabled && x.issued_count() >= d_min && x.links_iter().count() >= d_min
315 })
316 .map(|x| x.id())
317 .collect()
318 }
319
320 pub fn get_non_sentries(&self, d_min: usize) -> Vec<NodeId> {
322 self.nodes
323 .iter()
324 .filter(|x| {
325 x.enabled && (x.issued_count < d_min || x.links_iter().count() < d_min)
326 })
327 .map(|x| x.id())
328 .collect()
329 }
330
331 pub fn get_disabled(&self) -> Vec<NodeId> {
333 self.nodes
334 .iter()
335 .filter(|x| !x.enabled)
336 .map(|x| x.id())
337 .collect()
338 }
339
340 fn lookup(
341 &self,
342 source: NodeId,
343 target: NodeId,
344 distance: u32,
345 distance_max: u32,
346 previous: Rc<Box<WotStep>>,
347 paths: &mut Vec<Rc<Box<WotStep>>>,
348 matching_paths: &mut Vec<Rc<Box<WotStep>>>,
349 distances: &mut Vec<u32>,
350 ) {
351 if source != target && distance <= distance_max {
352 let mut local_paths: Vec<Rc<Box<WotStep>>> = vec![];
353
354 for &by in self.nodes[*target].links_iter() {
355 if distance < distances[*by] {
356 distances[*by] = distance;
357 let step = Rc::new(Box::new(WotStep {
358 previous: Some(previous.clone()),
359 node: by,
360 distance,
361 }));
362
363 paths.push(step.clone());
364 local_paths.push(step.clone());
365 if by == source {
366 matching_paths.push(step.clone());
367 }
368 }
369 }
370
371 if distance <= distance_max {
372 for path in local_paths.iter() {
373 self.lookup(
374 source,
375 path.node,
376 distance + 1,
377 distance_max,
378 path.clone(),
379 paths,
380 matching_paths,
381 distances,
382 );
383 }
384 }
385 }
386 }
387
388 pub fn get_paths(&self, from: NodeId, to: NodeId, k_max: u32) -> Vec<Vec<NodeId>> {
390 let mut paths: Vec<Rc<Box<WotStep>>> = vec![];
391 let mut matching_paths: Vec<Rc<Box<WotStep>>> = vec![];
392 let mut distances: Vec<u32> = self.nodes.iter().map(|_| k_max + 1).collect();
393 distances[*to] = 0;
394
395 let root = Rc::new(Box::new(WotStep {
396 previous: None,
397 node: to,
398 distance: 0,
399 }));
400
401 paths.push(root.clone());
402
403 self.lookup(
404 from,
405 to,
406 1,
407 k_max,
408 root,
409 &mut paths,
410 &mut matching_paths,
411 &mut distances,
412 );
413
414 let mut result: Vec<Vec<NodeId>> = Vec::with_capacity(matching_paths.len());
415
416 for step in matching_paths.iter() {
417 let mut vecpath = vec![];
418 let mut step = step.clone();
419
420 loop {
421 vecpath.push(step.node);
422 if step.previous.is_none() {
423 break;
424 }
425 step = step.previous.clone().unwrap();
426 }
427
428 result.push(vecpath);
429 }
430
431 result
432 }
433
434 pub fn size(&self) -> usize {
436 self.nodes.iter().count()
437 }
438
439 pub fn is_enabled(&self, node: NodeId) -> Option<bool> {
441 if *node >= self.size() {
442 None
443 } else {
444 Some(self.nodes[*node].enabled)
445 }
446 }
447
448 pub fn set_enabled(&mut self, node: NodeId, state: bool) -> Option<bool> {
450 if *node >= self.size() {
451 None
452 } else {
453 self.nodes[*node].enabled = state;
454 Some(state)
455 }
456 }
457
458 pub fn add_link(&mut self, from: NodeId, to: NodeId) -> NewLinkResult {
460 if *from == *to {
461 NewLinkResult::SelfLinkingForbidden()
462 } else if *from >= self.size() {
463 NewLinkResult::UnknownSource()
464 } else if *to >= self.size() {
465 NewLinkResult::UnknownTarget()
466 } else {
467 if *from < *to {
468 let (start, end) = self.nodes.split_at_mut(*to);
470 start[*from].link_to(&mut end[0], self.max_cert)
471 } else {
472 let (start, end) = self.nodes.split_at_mut(*from);
474 end[0].link_to(&mut start[*to], self.max_cert)
475 }
476 }
477 }
478
479 pub fn remove_link(&mut self, from: NodeId, to: NodeId) -> RemovedLinkResult {
481 if *from >= self.size() {
482 RemovedLinkResult::UnknownSource()
483 } else if *to >= self.size() {
484 RemovedLinkResult::UnknownTarget()
485 } else {
486 if *from < *to {
487 let (start, end) = self.nodes.split_at_mut(*to);
489 start[*from].unlink_to(&mut end[0])
490 } else {
491 let (start, end) = self.nodes.split_at_mut(*from);
493 end[0].unlink_to(&mut start[*to])
494 }
495 }
496 }
497
498 pub fn exists_link(&self, from: NodeId, to: NodeId) -> bool {
500 if *from >= self.size() || *to >= self.size() {
501 false
502 } else {
503 self.nodes[*from].has_link_to(&self.nodes[*to])
504 }
505 }
506
507 pub fn is_outdistanced(
509 &self,
510 node: NodeId,
511 d_min: u32,
512 d_max: u32,
513 x_percent: f64,
514 ) -> Option<bool> {
515 if *node >= self.size() {
516 None
517 } else {
518 Some(
519 self.compute_distance(node, d_min, d_max, x_percent)
520 .outdistanced,
521 )
522 }
523 }
524}
525
526#[cfg(test)]
527mod tests {
528 use super::*;
529
530 #[test]
531 fn node_tests() {
532 assert_eq!(*Node::new(1).id(), 1);
534
535 let mut node1 = Node::new(1);
537 let mut node2 = Node::new(2);
538
539 assert_eq!(node1.issued_count(), 0);
541 assert_eq!(node2.links_iter().count(), 0);
542 assert!(!node1.has_link_to(&node2));
543 assert!(!node2.has_link_to(&node2));
544 assert!(!node1.has_link_from(&node1));
545 assert!(!node2.has_link_from(&node1));
546
547 match node1.link_to(&mut node2, 10) {
549 NewLinkResult::Ok(1) => (),
550 _ => panic!(),
551 };
552
553 assert_eq!(node1.issued_count(), 1);
554 assert_eq!(node2.links_iter().count(), 1);
555 assert!(node1.has_link_to(&node2));
556 assert!(!node2.has_link_to(&node2));
557 assert!(!node1.has_link_from(&node1));
558 assert!(node2.has_link_from(&node1));
559
560 match node1.link_to(&mut node2, 10) {
562 NewLinkResult::AlreadyCertified(1) => (),
563 _ => panic!(),
564 };
565
566 assert_eq!(node1.issued_count(), 1);
567 assert_eq!(node2.links_iter().count(), 1);
568 assert!(node1.has_link_to(&node2));
569 assert!(!node2.has_link_to(&node2));
570 assert!(!node1.has_link_from(&node1));
571 assert!(node2.has_link_from(&node1));
572
573 let mut node3 = Node::new(3);
575 match node1.link_to(&mut node3, 1) {
576 NewLinkResult::AllCertificationsUsed(0) => (),
577 _ => panic!(),
578 };
579
580 assert_eq!(node1.issued_count(), 1);
581 assert_eq!(node2.links_iter().count(), 1);
582 assert_eq!(node3.links_iter().count(), 0);
583 assert!(node1.has_link_to(&node2));
584 assert!(!node2.has_link_to(&node2));
585 assert!(!node1.has_link_from(&node1));
586 assert!(node2.has_link_from(&node1));
587 }
588
589 #[test]
591 fn wot_tests() {
592 let mut wot = WebOfTrust::new(3);
593
594 assert_eq!(wot.size(), 0);
596
597 assert_eq!(wot.is_enabled(NodeId(0)), None);
599 assert_eq!(wot.is_enabled(NodeId(23)), None);
600
601 assert_eq!(wot.add_node(), NodeId(0));
604 assert_eq!(wot.size(), 1);
605 assert_eq!(wot.get_disabled().len(), 0);
606
607 assert_eq!(wot.add_node(), NodeId(1));
609 assert_eq!(wot.size(), 2);
610 assert_eq!(wot.get_disabled().len(), 0);
611
612 for i in 0..10 {
614 assert_eq!(wot.add_node(), NodeId(i + 2));
615 }
616
617 assert_eq!(wot.size(), 12);
618
619 assert_eq!(
621 wot.add_link(NodeId(0), NodeId(0)),
622 NewLinkResult::SelfLinkingForbidden()
623 );
624
625 assert_eq!(wot.add_link(NodeId(0), NodeId(1)), NewLinkResult::Ok(1));
627 assert_eq!(wot.add_link(NodeId(0), NodeId(2)), NewLinkResult::Ok(1));
628 assert_eq!(wot.add_link(NodeId(0), NodeId(3)), NewLinkResult::Ok(1));
629 assert_eq!(
630 wot.add_link(NodeId(0), NodeId(4)),
631 NewLinkResult::AllCertificationsUsed(0)
632 );
633
634 assert_eq!(wot.max_cert, 3);
635 assert_eq!(wot.exists_link(NodeId(0), NodeId(1)), true);
636 assert_eq!(wot.exists_link(NodeId(0), NodeId(2)), true);
637 assert_eq!(wot.exists_link(NodeId(0), NodeId(3)), true);
638 assert_eq!(wot.exists_link(NodeId(0), NodeId(4)), false);
639
640 wot.max_cert = 4;
641 assert_eq!(wot.max_cert, 4);
642 assert_eq!(wot.exists_link(NodeId(0), NodeId(4)), false);
643 wot.add_link(NodeId(0), NodeId(4));
644 assert_eq!(wot.exists_link(NodeId(0), NodeId(4)), true);
645 wot.remove_link(NodeId(0), NodeId(1));
646 wot.remove_link(NodeId(0), NodeId(2));
647 wot.remove_link(NodeId(0), NodeId(3));
648 wot.remove_link(NodeId(0), NodeId(4));
649
650 assert_eq!(wot.exists_link(NodeId(0), NodeId(6)), false);
652 assert_eq!(wot.exists_link(NodeId(23), NodeId(0)), false);
653 assert_eq!(wot.exists_link(NodeId(2), NodeId(53)), false);
654
655 assert_eq!(wot.is_enabled(NodeId(0)), Some(true));
657 assert_eq!(wot.is_enabled(NodeId(1)), Some(true));
658 assert_eq!(wot.is_enabled(NodeId(2)), Some(true));
659 assert_eq!(wot.is_enabled(NodeId(3)), Some(true));
660 assert_eq!(wot.is_enabled(NodeId(11)), Some(true));
661
662 assert_eq!(wot.set_enabled(NodeId(0), false), Some(false));
664 assert_eq!(wot.set_enabled(NodeId(1), false), Some(false));
665 assert_eq!(wot.set_enabled(NodeId(2), false), Some(false));
666 assert_eq!(wot.get_disabled().len(), 3);
667 assert_eq!(wot.set_enabled(NodeId(1), true), Some(true));
668
669 assert_eq!(wot.is_enabled(NodeId(0)), Some(false));
671 assert_eq!(wot.is_enabled(NodeId(1)), Some(true));
672 assert_eq!(wot.is_enabled(NodeId(2)), Some(false));
673 assert_eq!(wot.is_enabled(NodeId(3)), Some(true));
674 assert_eq!(wot.set_enabled(NodeId(0), true), Some(true));
676 assert_eq!(wot.set_enabled(NodeId(1), true), Some(true));
677 assert_eq!(wot.set_enabled(NodeId(2), true), Some(true));
678 assert_eq!(wot.set_enabled(NodeId(1), true), Some(true));
679 assert_eq!(wot.get_disabled().len(), 0);
680
681 assert_eq!(wot.exists_link(NodeId(2), NodeId(0)), false);
683
684 assert_eq!(wot.add_link(NodeId(2), NodeId(0)), NewLinkResult::Ok(1));
686 assert_eq!(wot.add_link(NodeId(4), NodeId(0)), NewLinkResult::Ok(2));
687 assert_eq!(
688 wot.add_link(NodeId(4), NodeId(0)),
689 NewLinkResult::AlreadyCertified(2)
690 );
691 assert_eq!(
692 wot.add_link(NodeId(4), NodeId(0)),
693 NewLinkResult::AlreadyCertified(2)
694 );
695 assert_eq!(wot.add_link(NodeId(5), NodeId(0)), NewLinkResult::Ok(3));
696
697 assert_eq!(wot.exists_link(NodeId(2), NodeId(0)), true);
706 assert_eq!(wot.exists_link(NodeId(4), NodeId(0)), true);
707 assert_eq!(wot.exists_link(NodeId(5), NodeId(0)), true);
708 assert_eq!(wot.exists_link(NodeId(2), NodeId(1)), false);
709
710 assert_eq!(
712 wot.remove_link(NodeId(4), NodeId(0)),
713 RemovedLinkResult::Removed(2)
714 );
715 assert_eq!(wot.exists_link(NodeId(2), NodeId(0)), true);
724 assert_eq!(wot.exists_link(NodeId(4), NodeId(0)), false);
725 assert_eq!(wot.exists_link(NodeId(5), NodeId(0)), true);
726 assert_eq!(wot.exists_link(NodeId(2), NodeId(1)), false);
727
728 assert_eq!(wot.is_outdistanced(NodeId(0), 1, 1, 1.0), Some(false));
730 assert_eq!(wot.is_outdistanced(NodeId(0), 2, 1, 1.0), Some(false));
732 assert_eq!(wot.is_outdistanced(NodeId(0), 3, 1, 1.0), Some(false));
734 assert_eq!(wot.add_link(NodeId(3), NodeId(1)), NewLinkResult::Ok(1));
738 assert_eq!(wot.add_link(NodeId(3), NodeId(2)), NewLinkResult::Ok(1));
739 assert_eq!(wot.size(), 12);
748 assert_eq!(wot.get_sentries(1).len(), 1);
749 assert_eq!(wot.get_sentries(1)[0], NodeId(2));
750 assert_eq!(wot.get_sentries(2).len(), 0);
751 assert_eq!(wot.get_sentries(3).len(), 0);
752 assert_eq!(wot.get_non_sentries(1).len(), 11); assert_eq!(wot.get_non_sentries(2).len(), 12); assert_eq!(wot.get_non_sentries(3).len(), 12); assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 1).len(), 0); assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 2).len(), 1); assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 2)[0].len(), 3); assert_eq!(wot.is_outdistanced(NodeId(0), 1, 1, 1.0), Some(false)); assert_eq!(wot.is_outdistanced(NodeId(0), 2, 1, 1.0), Some(false)); assert_eq!(wot.is_outdistanced(NodeId(0), 3, 1, 1.0), Some(false)); assert_eq!(wot.is_outdistanced(NodeId(0), 2, 2, 1.0), Some(false)); wot.add_link(NodeId(1), NodeId(3));
764 wot.add_link(NodeId(2), NodeId(3));
765
766 assert_eq!(wot.size(), 12);
767 assert_eq!(wot.get_sentries(1).len(), 3);
768 assert_eq!(wot.get_sentries(1)[0], NodeId(1));
769 assert_eq!(wot.get_sentries(1)[1], NodeId(2));
770 assert_eq!(wot.get_sentries(1)[2], NodeId(3));
771
772 assert_eq!(wot.get_sentries(2).len(), 1);
773 assert_eq!(wot.get_sentries(2)[0], NodeId(3));
774 assert_eq!(wot.get_sentries(3).len(), 0);
775 assert_eq!(wot.get_non_sentries(1).len(), 9); assert_eq!(wot.get_non_sentries(2).len(), 11); assert_eq!(wot.get_non_sentries(3).len(), 12); assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 1).len(), 0); assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 2).len(), 1); assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 2)[0].len(), 3); assert_eq!(wot.is_outdistanced(NodeId(0), 1, 1, 1.0), Some(true)); assert_eq!(wot.is_outdistanced(NodeId(0), 2, 1, 1.0), Some(true)); assert_eq!(wot.is_outdistanced(NodeId(0), 3, 1, 1.0), Some(false)); assert_eq!(wot.is_outdistanced(NodeId(0), 2, 2, 1.0), Some(false)); assert_eq!(wot.size(), 12);
788
789 assert_eq!(wot.remove_node(), Some(NodeId(10)));
791
792 assert_eq!(wot.size(), 11);
794
795 assert_eq!(wot.set_enabled(NodeId(3), false), Some(false));
798 assert_eq!(wot.get_disabled().len(), 1);
799 assert_eq!(wot.is_outdistanced(NodeId(0), 2, 1, 1.0), Some(false)); {
803 let wot2 = wot.clone();
804
805 assert_eq!(wot.size(), wot2.size());
806 assert_eq!(
807 wot.get_non_sentries(1).len(),
808 wot2.get_non_sentries(1).len()
809 );
810 }
811
812 assert_eq!(wot.to_file("test.wot"), true);
814
815 {
817 let wot2 = WebOfTrust::from_file("test.wot").unwrap();
818
819 assert_eq!(wot.size(), wot2.size());
820 assert_eq!(
821 wot.get_non_sentries(1).len(),
822 wot2.get_non_sentries(1).len()
823 );
824 }
825
826 }
827}