commit bc395adfaf073db748a281f2dd686733d34deaa8
parent f0d716b591bb6bc3d0a7c7d58730c4210dcd7ff0
Author: Yuval Langer <yuvallangerontheroad@gmail.com>
Date: Sun, 18 Sep 2022 18:25:09 +0300
Move everything from `/src/bin/diceware.rs` and `/src/lib.rs` into `/src/main.rs`.
Diffstat:
M | build.rs | | | 8 | ++++---- |
D | src/bin/diceware.rs | | | 247 | ------------------------------------------------------------------------------- |
D | src/lib.rs | | | 51 | --------------------------------------------------- |
A | src/main.rs | | | 285 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 289 insertions(+), 302 deletions(-)
diff --git a/build.rs b/build.rs
@@ -8,7 +8,7 @@ use std::string::String;
fn make_diceware_wordlist(array_name: String) -> impl Fn(&str) -> String {
move |contents: &str| {
// 7776 words = 6*6*6*6*6; five 6 faced dice throws.
- format!("pub static {}: [&str; 7776] = [\n", array_name)
+ format!("pub(crate) static {}: [&str; 7776] = [\n", array_name)
+ &contents
.split('\n')
.skip(2)
@@ -33,7 +33,7 @@ fn make_diceware_wordlist(array_name: String) -> impl Fn(&str) -> String {
fn make_minilock_wordlist(contents: &str) -> std::string::String {
// 58110 words in the MiniLock wordlist.
- "pub static MINILOCK_WORDLIST: [&str; 58110] = [\n".to_owned()
+ "pub(crate) static MINILOCK_WORDLIST: [&str; 58110] = [\n".to_owned()
+ &contents[1023..543718]
.split(',')
.map(|x| format!(" \"{}\",\n", x))
@@ -43,7 +43,7 @@ fn make_minilock_wordlist(contents: &str) -> std::string::String {
fn make_eff_long_wordlist(contents: &str) -> String {
// 7776 words = 6*6*6*6*6; five 6 faced dice throws.
- "pub static EFF_LONG_WORDLIST: [&str; 7776] = [\n".to_owned()
+ "pub(crate) static EFF_LONG_WORDLIST: [&str; 7776] = [\n".to_owned()
+ &contents
.split('\n')
.take(6 * 6 * 6 * 6 * 6)
@@ -56,7 +56,7 @@ fn make_eff_long_wordlist(contents: &str) -> String {
fn make_eff_short_wordlist(array_name: String) -> impl Fn(&str) -> String {
move |contents: &str| {
// 1296 words = 6*6*6*6; five 6 faced dice throws.
- format!("pub static {}: [&str; 1296] = [\n", array_name)
+ format!("pub(crate) static {}: [&str; 1296] = [\n", array_name)
+ &contents
.split('\n')
.take(6 * 6 * 6 * 6)
diff --git a/src/bin/diceware.rs b/src/bin/diceware.rs
@@ -1,247 +0,0 @@
-extern crate getopts;
-extern crate rand;
-
-use std::io::BufRead;
-use std::process::exit;
-
-use getopts::Options;
-use rand::thread_rng;
-
-use diceware::entropyn;
-use diceware::load_wordlist_file;
-use diceware::print_words_rng;
-use diceware::wordlists::BEALE_WORDLIST;
-use diceware::wordlists::EFF_LONG_WORDLIST;
-use diceware::wordlists::EFF_SHORT_WORDLIST_1;
-use diceware::wordlists::EFF_SHORT_WORDLIST_2_0;
-use diceware::wordlists::MINILOCK_WORDLIST;
-use diceware::wordlists::REINHOLD_WORDLIST;
-
-fn make_options() -> Options {
- let mut opts = Options::new();
- opts.optflag("h", "help", "This help message.");
- opts.optflag("e", "entropy", "Display number of entropy bits.");
- opts.optflag("r", "dicerolls", "Provide results of physical dice rolls. Word per line, same digit order as in the files, digits between and including 1 and 6.");
- opts.optopt("n", "nword", "Number of words in a passphrase.", "NWORD");
- opts.optopt(
- "d",
- "delimiter",
- "The delimiter character used to separate the words.",
- "DELIM",
- );
- opts.optopt("f", "wordlist-file", "Path to a wordlist file.", "FILE");
- opts.optopt(
- "l",
- "wordlist",
- "Wordlist to use. (efflong (default), effshort1, effshort2, minilock, reinhold, or beale)",
- "WORDLIST",
- );
- opts
-}
-
-fn print_usage(program: &str, opts: Options) {
- let brief = format!("Usage: {} [options]", program);
- print!("{}", opts.usage(&brief));
-}
-
-fn unknown_wordlist(wordlist_name: &str) -> ! {
- eprintln!(
- "Unknown wordlist: {}. Available wordlists: efflong (default), effshort1, effshort2, beale, reinhold, or minilock.",
- wordlist_name,
- );
- exit(-1)
-}
-
-fn find_number_of_rolls_needed(wordlist_length: u32) -> u32 {
- let mut x = wordlist_length as u64;
- let mut nrolls: u32 = 0;
- while x != 0 {
- x /= 6;
- nrolls += 1;
- }
- nrolls
-}
-
-fn rolls_to_word_index(number_of_rolls_needed: u32, rolls: &[u8]) -> usize {
- if number_of_rolls_needed == rolls.len() as u32 {
- let mut word_number = 0;
- for (i, roll) in rolls.iter().rev().enumerate() {
- word_number += (roll
- .checked_sub(1)
- .expect("Must be a die roll result between and including 1 and 6.")
- as usize)
- * 6_usize.pow(i as u32);
- }
- word_number
- } else {
- panic!(
- "Wrong number of die casts: {}. Needs to be {} die casts.",
- rolls.len(),
- number_of_rolls_needed
- )
- }
-}
-
-fn print_words_rolls(
- wordlist: &[&str],
- delimiter: &char,
- is_entropy_printed: &bool,
- rolls: &[&[u8]],
-) {
- let number_of_rolls_needed = find_number_of_rolls_needed(wordlist.len() as u32);
- for roll_index in 0..(rolls.len() - 1) {
- let roll_sum = rolls_to_word_index(
- number_of_rolls_needed,
- rolls
- .get(roll_index)
- .unwrap_or_else(|| panic!("Bad roll index: {}", roll_index)),
- );
- let word = wordlist
- .get(roll_sum)
- .unwrap_or_else(|| panic!("Wrong word index: {}", roll_sum));
- print!("{}{}", &word, delimiter);
- }
- let roll_sum = rolls_to_word_index(number_of_rolls_needed, rolls.last().unwrap());
- let word = wordlist.get(roll_sum).unwrap();
- print!("{}", &word);
-
- println!();
- if *is_entropy_printed {
- println!("{}", entropyn(wordlist, rolls.len() as u64))
- }
-}
-
-fn read_rolls() -> Vec<Vec<u8>> {
- let stdin = std::io::stdin();
- let mut rolls: Vec<Vec<u8>> = Vec::new();
- let mut last_number_of_dice = None;
- for line in stdin.lock().lines() {
- let line_value = line.unwrap();
- let line_value_trimmed = line_value.trim();
- if line_value_trimmed.is_empty() {
- continue;
- }
- let current_number_of_dice = line_value_trimmed.len();
- if let Some(last_number_of_dice_value) = last_number_of_dice {
- if last_number_of_dice_value != current_number_of_dice {
- panic!("Not all dice rolls were of the same number of die.");
- } else {
- last_number_of_dice = Some(current_number_of_dice);
- }
- }
-
- rolls.push(
- line_value_trimmed
- .chars()
- .map(|c| {
- c.to_string()
- .parse()
- .unwrap_or_else(|e| panic!("Not a digit: \"{}\". Error: {}", c, e))
- })
- .collect(),
- );
- }
- rolls
-}
-
-fn main() {
- let args: Vec<String> = std::env::args().collect();
- let program = &args[0];
-
- let opts = make_options();
-
- let matches = match opts.parse(&args[1..]) {
- Ok(m) => m,
- Err(f) => {
- println!("{}\n", f);
- print_usage(program, opts);
- exit(-1);
- }
- };
-
- if matches.opt_present("h") {
- print_usage(program, opts);
- return;
- };
-
- let is_physical_rolls = matches.opt_present("r");
-
- let word_num: u64 = matches
- .opt_str("n")
- .map_or(8, |n_str| n_str.parse::<u64>().ok().unwrap());
-
- let delimiter: char = matches
- .opt_str("d")
- .map_or(' ', |n_str| n_str.parse::<char>().ok().unwrap());
-
- let is_entropy_printed = matches.opt_present("entropy");
-
- let wordlist_name = if let Some(wordlist_option) = matches.opt_str("l") {
- match wordlist_option.to_lowercase().as_ref() {
- z @ ("beale" | "reinhold" | "minilock" | "efflong" | "effshort1" | "effshort2") => z,
- _ => unknown_wordlist(&wordlist_option),
- }
- .to_string()
- } else {
- "efflong".to_string()
- };
-
- let mut rng = thread_rng();
-
- if let Some(wordlist_filepath) = matches.opt_str("f") {
- let wordlist_string = load_wordlist_file(&wordlist_filepath);
- let wordlist = wordlist_string
- .split('\n')
- .map(|x| x.trim())
- .filter(|x| x != &"")
- .collect::<Vec<&str>>();
-
- if is_physical_rolls {
- let rolls = read_rolls();
-
- print_words_rolls(
- &wordlist,
- &delimiter,
- &is_entropy_printed,
- &rolls.iter().map(|x| x.as_ref()).collect::<Vec<&[u8]>>(),
- );
- } else if word_num != 0 {
- print_words_rng(
- &wordlist,
- &word_num,
- &delimiter,
- &is_entropy_printed,
- &mut rng,
- );
- };
- } else {
- let wordlist = match wordlist_name.as_ref() {
- "efflong" => EFF_LONG_WORDLIST.as_ref(),
- "reinhold" => REINHOLD_WORDLIST.as_ref(),
- "beale" => BEALE_WORDLIST.as_ref(),
- "minilock" => MINILOCK_WORDLIST.as_ref(),
- "effshort1" => EFF_SHORT_WORDLIST_1.as_ref(),
- "effshort2" => EFF_SHORT_WORDLIST_2_0.as_ref(),
- _ => unknown_wordlist(&wordlist_name),
- };
-
- if is_physical_rolls {
- let rolls = read_rolls();
-
- print_words_rolls(
- wordlist,
- &delimiter,
- &is_entropy_printed,
- &rolls.iter().map(|x| x.as_ref()).collect::<Vec<&[u8]>>(),
- );
- } else if word_num != 0 {
- print_words_rng(
- wordlist,
- &word_num,
- &delimiter,
- &is_entropy_printed,
- &mut rng,
- );
- };
- };
-}
diff --git a/src/lib.rs b/src/lib.rs
@@ -1,51 +0,0 @@
-extern crate rand;
-
-use std::fs::File;
-use std::io::Read;
-
-use rand::rngs::ThreadRng;
-use rand::seq::SliceRandom;
-
-pub mod wordlists {
- include!(concat!(env!("OUT_DIR"), "/diceware.rs"));
-}
-
-pub fn entropy(wordlist: &[&str]) -> f64 {
- (wordlist.len() as f64).log2()
-}
-
-pub fn entropyn(wordlist: &[&str], n: u64) -> f64 {
- entropy(wordlist) * (n as f64)
-}
-
-pub fn print_words_rng(
- wordlist: &[&str],
- word_num: &u64,
- delimiter: &char,
- is_entropy_printed: &bool,
- rng: &mut ThreadRng,
-) {
- for _ in 0..(word_num - 1) {
- let word = wordlist.choose(rng).unwrap();
- print!("{}{}", &word, delimiter);
- }
- let word = wordlist.choose(rng).unwrap();
- print!("{}", word);
-
- println!();
- if *is_entropy_printed {
- println!("{}", entropyn(wordlist, *word_num))
- }
-}
-
-pub fn load_wordlist_file(filepath: &str) -> String {
- let mut wordlist_file = match File::open(&filepath) {
- Ok(ok) => ok,
- Err(err) => panic!("Unable to open file: {}; due to error: {}", filepath, err),
- };
- let mut wordlist_string = String::new();
- if let Err(err) = wordlist_file.read_to_string(&mut wordlist_string) {
- panic!("Unable to read file: {}; due to error: {}", filepath, err)
- }
- wordlist_string
-}
diff --git a/src/main.rs b/src/main.rs
@@ -0,0 +1,285 @@
+extern crate getopts;
+extern crate rand;
+
+use std::fs::File;
+use std::io::BufRead;
+use std::io::Read;
+use std::process::exit;
+
+use getopts::Options;
+use rand::prelude::SliceRandom;
+use rand::rngs::ThreadRng;
+use rand::thread_rng;
+
+fn make_options() -> Options {
+ let mut opts = Options::new();
+ opts.optflag("h", "help", "This help message.");
+ opts.optflag("e", "entropy", "Display number of entropy bits.");
+ opts.optflag("r", "dicerolls", "Provide results of physical dice rolls. Word per line, same digit order as in the files, digits between and including 1 and 6.");
+ opts.optopt("n", "nword", "Number of words in a passphrase.", "NWORD");
+ opts.optopt(
+ "d",
+ "delimiter",
+ "The delimiter character used to separate the words.",
+ "DELIM",
+ );
+ opts.optopt("f", "wordlist-file", "Path to a wordlist file.", "FILE");
+ opts.optopt(
+ "l",
+ "wordlist",
+ "Wordlist to use. (efflong (default), effshort1, effshort2, minilock, reinhold, or beale)",
+ "WORDLIST",
+ );
+ opts
+}
+
+fn print_usage(program: &str, opts: Options) {
+ let brief = format!("Usage: {} [options]", program);
+ print!("{}", opts.usage(&brief));
+}
+
+fn unknown_wordlist(wordlist_name: &str) -> ! {
+ eprintln!(
+ "Unknown wordlist: {}. Available wordlists: efflong (default), effshort1, effshort2, beale, reinhold, or minilock.",
+ wordlist_name,
+ );
+ exit(-1)
+}
+
+fn find_number_of_rolls_needed(wordlist_length: u32) -> u32 {
+ let mut x = wordlist_length as u64;
+ let mut nrolls: u32 = 0;
+ while x != 0 {
+ x /= 6;
+ nrolls += 1;
+ }
+ nrolls
+}
+
+fn rolls_to_word_index(number_of_rolls_needed: u32, rolls: &[u8]) -> usize {
+ if number_of_rolls_needed == rolls.len() as u32 {
+ let mut word_number = 0;
+ for (i, roll) in rolls.iter().rev().enumerate() {
+ word_number += (roll
+ .checked_sub(1)
+ .expect("Must be a die roll result between and including 1 and 6.")
+ as usize)
+ * 6_usize.pow(i as u32);
+ }
+ word_number
+ } else {
+ panic!(
+ "Wrong number of die casts: {}. Needs to be {} die casts.",
+ rolls.len(),
+ number_of_rolls_needed
+ )
+ }
+}
+
+fn print_words_rolls(
+ wordlist: &[&str],
+ delimiter: &char,
+ is_entropy_printed: &bool,
+ rolls: &[&[u8]],
+) {
+ let number_of_rolls_needed = find_number_of_rolls_needed(wordlist.len() as u32);
+ for roll_index in 0..(rolls.len() - 1) {
+ let roll_sum = rolls_to_word_index(
+ number_of_rolls_needed,
+ rolls
+ .get(roll_index)
+ .unwrap_or_else(|| panic!("Bad roll index: {}", roll_index)),
+ );
+ let word = wordlist
+ .get(roll_sum)
+ .unwrap_or_else(|| panic!("Wrong word index: {}", roll_sum));
+ print!("{}{}", &word, delimiter);
+ }
+ let roll_sum = rolls_to_word_index(number_of_rolls_needed, rolls.last().unwrap());
+ let word = wordlist.get(roll_sum).unwrap();
+ print!("{}", &word);
+
+ println!();
+ if *is_entropy_printed {
+ println!("{}", entropyn(wordlist, rolls.len() as u64))
+ }
+}
+
+fn read_rolls() -> Vec<Vec<u8>> {
+ let stdin = std::io::stdin();
+ let mut rolls: Vec<Vec<u8>> = Vec::new();
+ let mut last_number_of_dice = None;
+ for line in stdin.lock().lines() {
+ let line_value = line.unwrap();
+ let line_value_trimmed = line_value.trim();
+ if line_value_trimmed.is_empty() {
+ continue;
+ }
+ let current_number_of_dice = line_value_trimmed.len();
+ if let Some(last_number_of_dice_value) = last_number_of_dice {
+ if last_number_of_dice_value != current_number_of_dice {
+ panic!("Not all dice rolls were of the same number of die.");
+ } else {
+ last_number_of_dice = Some(current_number_of_dice);
+ }
+ }
+
+ rolls.push(
+ line_value_trimmed
+ .chars()
+ .map(|c| {
+ c.to_string()
+ .parse()
+ .unwrap_or_else(|e| panic!("Not a digit: \"{}\". Error: {}", c, e))
+ })
+ .collect(),
+ );
+ }
+ rolls
+}
+
+mod wordlists {
+ include!(concat!(env!("OUT_DIR"), "/diceware.rs"));
+}
+
+fn entropy(wordlist: &[&str]) -> f64 {
+ (wordlist.len() as f64).log2()
+}
+
+fn entropyn(wordlist: &[&str], n: u64) -> f64 {
+ entropy(wordlist) * (n as f64)
+}
+
+fn print_words_rng(
+ wordlist: &[&str],
+ word_num: &u64,
+ delimiter: &char,
+ is_entropy_printed: &bool,
+ rng: &mut ThreadRng,
+) {
+ for _ in 0..(word_num - 1) {
+ let word = wordlist.choose(rng).unwrap();
+ print!("{}{}", &word, delimiter);
+ }
+ let word = wordlist.choose(rng).unwrap();
+ print!("{}", word);
+
+ println!();
+ if *is_entropy_printed {
+ println!("{}", entropyn(wordlist, *word_num))
+ }
+}
+
+fn load_wordlist_file(filepath: &str) -> String {
+ let mut wordlist_file = match File::open(&filepath) {
+ Ok(ok) => ok,
+ Err(err) => panic!("Unable to open file: {}; due to error: {}", filepath, err),
+ };
+ let mut wordlist_string = String::new();
+ if let Err(err) = wordlist_file.read_to_string(&mut wordlist_string) {
+ panic!("Unable to read file: {}; due to error: {}", filepath, err)
+ }
+ wordlist_string
+}
+
+fn main() {
+ let args: Vec<String> = std::env::args().collect();
+ let program = &args[0];
+
+ let opts = make_options();
+
+ let matches = match opts.parse(&args[1..]) {
+ Ok(m) => m,
+ Err(f) => {
+ println!("{}\n", f);
+ print_usage(program, opts);
+ exit(-1);
+ }
+ };
+
+ if matches.opt_present("h") {
+ print_usage(program, opts);
+ return;
+ };
+
+ let is_physical_rolls = matches.opt_present("r");
+
+ let word_num: u64 = matches
+ .opt_str("n")
+ .map_or(8, |n_str| n_str.parse::<u64>().ok().unwrap());
+
+ let delimiter: char = matches
+ .opt_str("d")
+ .map_or(' ', |n_str| n_str.parse::<char>().ok().unwrap());
+
+ let is_entropy_printed = matches.opt_present("entropy");
+
+ let wordlist_name = if let Some(wordlist_option) = matches.opt_str("l") {
+ match wordlist_option.to_lowercase().as_ref() {
+ z @ ("beale" | "reinhold" | "minilock" | "efflong" | "effshort1" | "effshort2") => z,
+ _ => unknown_wordlist(&wordlist_option),
+ }
+ .to_string()
+ } else {
+ "efflong".to_string()
+ };
+
+ let mut rng = thread_rng();
+
+ if let Some(wordlist_filepath) = matches.opt_str("f") {
+ let wordlist_string = load_wordlist_file(&wordlist_filepath);
+ let wordlist = wordlist_string
+ .split('\n')
+ .map(|x| x.trim())
+ .filter(|x| x != &"")
+ .collect::<Vec<&str>>();
+
+ if is_physical_rolls {
+ let rolls = read_rolls();
+
+ print_words_rolls(
+ &wordlist,
+ &delimiter,
+ &is_entropy_printed,
+ &rolls.iter().map(|x| x.as_ref()).collect::<Vec<&[u8]>>(),
+ );
+ } else if word_num != 0 {
+ print_words_rng(
+ &wordlist,
+ &word_num,
+ &delimiter,
+ &is_entropy_printed,
+ &mut rng,
+ );
+ };
+ } else {
+ let wordlist = match wordlist_name.as_ref() {
+ "efflong" => wordlists::EFF_LONG_WORDLIST.as_ref(),
+ "reinhold" => wordlists::REINHOLD_WORDLIST.as_ref(),
+ "beale" => wordlists::BEALE_WORDLIST.as_ref(),
+ "minilock" => wordlists::MINILOCK_WORDLIST.as_ref(),
+ "effshort1" => wordlists::EFF_SHORT_WORDLIST_1.as_ref(),
+ "effshort2" => wordlists::EFF_SHORT_WORDLIST_2_0.as_ref(),
+ _ => unknown_wordlist(&wordlist_name),
+ };
+
+ if is_physical_rolls {
+ let rolls = read_rolls();
+
+ print_words_rolls(
+ wordlist,
+ &delimiter,
+ &is_entropy_printed,
+ &rolls.iter().map(|x| x.as_ref()).collect::<Vec<&[u8]>>(),
+ );
+ } else if word_num != 0 {
+ print_words_rng(
+ wordlist,
+ &word_num,
+ &delimiter,
+ &is_entropy_printed,
+ &mut rng,
+ );
+ };
+ };
+}