Calcul multi-cœurs des SHA-1

Pour effectuer les calculs de SHA-1 en parallèle, nous allons utiliser le crate rayon. Celui-ci fournit notamment des extensions sur les types classiques permettant d'obtenir des itérateurs parallèles qui exploitent automatiquement tous les cœurs de la machine courante.

  1. Ajoutez rayon comme dépendance à votre Cargo.toml.
  2. Dans votre module hibp, importez le prélude de rayon qui fournira toutes les fonctions et extensions utiles, rayon::prelude::*.
  3. Écrivez une fonction hibp::all_sha1() qui calcule en parallèle tous les préfixes et suffixes des SHA-1 des comptes passés en paramètre en utilisant la fonction hibp::sha1() définie précedemment :
fn all_sha1(accounts: &[Account]) -> Vec<(String, String, &Account)> {
  todo!()
}

Dans cette fonction, vous serez probablement amenés à utiliser la méthode d'extension par_iter() fournie par rayon en lieu et place de iter().

Test des performances

Pour pouvoir comparer les performances avec et sans rayon, nous allons mettre en place le début de l'infrastructure permettant d'ajouter notre nouvelle commande à notre programme principal.

  1. Écrivez une fonction publique hibp::all_sha1_timed() avec la même signature que hibp::all_sha1() qui affiche le nombre de micro-secondes écoulées dans cette fonction avant d'en retourner le résultat. Vous pourrez utiliser les types std::time::{Instant, Duration} qui représentent respectivement un point dans le temps (opaque) et une durée, obtenue par exemple en soustrayant deux points dans le temps. Grâce à Instant::now() vous pouvez capturer la date courante, et avec la méthode as_micros() sur une valeur de type Duration vous obtiendrez sa durée en microsecondes.

  2. Dans votre programme principal, ajoutez une sous-commande hibp. Celle-ci devra prendre en paramètre obligatoire un fichier. Les comptes seront chargés depuis ce fichier, puis hibp::all_sha1_timed() sera invoquée. On verra donc le temps de calcul des SHA-1.

  3. Essayez de remplacer par_iter() par iter() et comparez les temps de traitement.

Regroupement des SHA-1 de même préfixe

  1. Implémentez la fonction hibp::sha1_by_prefix() qui à partir des comptes et en utilisant les méthodes précédentes regroupe au sein d'une table de hashage les comptes dont le SHA-1 a le même préfixe et accompagne chaque compte de son suffixe :
fn sha1_by_prefix(accounts: &[Account]) -> HashMap<String, Vec<(String, &Account)>> {
  todo!()
}

Par exemple, on prendra l'exemple fictif supposant que :

  • Le compte "elba" a comme mot de passe "BWE!y4xj:i" et son SHA-1 est 8E7336BBDBE0B7F31DE9A06B053ECDF5E356A946.
  • Le compte "dyanna" a comme mot de passe "NvLK25b+" et son SHA-1 est EF867658E9572AC965BBDC5212FAE656570DB09B.
  • Le compte "tahira" a comme mot de passe "xQS?" et son SHA-1 est 8E7334AB061EAB6673D2C591D6C77CEEE12DE961.

Dans ce cas, la fonction hibp::sha1_by_prefix() renverra, en pseudo-notation :

{
  "8E733": [
    ("6BBDBE0B7F31DE9A06B053ECDF5E356A946",
     Account { login: "elba", password: "BWE!y4xj:i" }),
    ("4AB061EAB6673D2C591D6C77CEEE12DE961",
     Account { login: "tahira", password: "xQS?" })
  ],
  "EF867": [
    ("658E9572AC965BBDC5212FAE656570DB09B",
     Account { login: "dyanna", password: "NvLK25b+" }),
  ],
}