Created
April 27, 2018 16:41
-
-
Save copyninja/0559f208b27fec8836616d4c5e4369b6 to your computer and use it in GitHub Desktop.
Assert causes panic with HashSet<String>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use serde_json::{self, from_str, Value}; | |
use std::collections::{HashMap, HashSet}; | |
use util::{bytes_to_hexstr, random_bytes}; | |
const RAW_WORDS: &'static str = r#"{ | |
\"00\": [\"aardvark\", \"adroitness\"], \"01\": [\"absurd\", \"adviser\"], | |
\"02\": [\"accrue\", \"aftermath\"], \"03\": [\"acme\", \"aggregate\"], | |
\"04\": [\"adrift\", \"alkali\"], \"05\": [\"adult\", \"almighty\"], | |
\"06\": [\"afflict\", \"amulet\"], \"07\": [\"ahead\", \"amusement\"], | |
\"08\": [\"aimless\", \"antenna\"], \"09\": [\"Algol\", \"applicant\"], | |
\"0A\": [\"allow\", \"Apollo\"], \"0B\": [\"alone\", \"armistice\"], | |
\"0C\": [\"ammo\", \"article\"], \"0D\": [\"ancient\", \"asteroid\"], | |
\"0E\": [\"apple\", \"Atlantic\"], \"0F\": [\"artist\", \"atmosphere\"], | |
\"10\": [\"assume\", \"autopsy\"], \"11\": [\"Athens\", \"Babylon\"], | |
\"12\": [\"atlas\", \"backwater\"], \"13\": [\"Aztec\", \"barbecue\"], | |
\"14\": [\"baboon\", \"belowground\"], \"15\": [\"backfield\", \"bifocals\"], | |
\"16\": [\"backward\", \"bodyguard\"], \"17\": [\"banjo\", \"bookseller\"], | |
\"18\": [\"beaming\", \"borderline\"], \"19\": [\"bedlamp\", \"bottomless\"], | |
\"1A\": [\"beehive\", \"Bradbury\"], \"1B\": [\"beeswax\", \"bravado\"], | |
\"1C\": [\"befriend\", \"Brazilian\"], \"1D\": [\"Belfast\", \"breakaway\"], | |
\"1E\": [\"berserk\", \"Burlington\"], \"1F\": [\"billiard\", \"businessman\"], | |
\"20\": [\"bison\", \"butterfat\"], \"21\": [\"blackjack\", \"Camelot\"], | |
\"22\": [\"blockade\", \"candidate\"], \"23\": [\"blowtorch\", \"cannonball\"], | |
\"24\": [\"bluebird\", \"Capricorn\"], \"25\": [\"bombast\", \"caravan\"], | |
\"26\": [\"bookshelf\", \"caretaker\"], \"27\": [\"brackish\", \"celebrate\"], | |
\"28\": [\"breadline\", \"cellulose\"], \"29\": [\"breakup\", \"certify\"], | |
\"2A\": [\"brickyard\", \"chambermaid\"], \"2B\": [\"briefcase\", \"Cherokee\"], | |
\"2C\": [\"Burbank\", \"Chicago\"], \"2D\": [\"button\", \"clergyman\"], | |
\"2E\": [\"buzzard\", \"coherence\"], \"2F\": [\"cement\", \"combustion\"], | |
\"30\": [\"chairlift\", \"commando\"], \"31\": [\"chatter\", \"company\"], | |
\"32\": [\"checkup\", \"component\"], \"33\": [\"chisel\", \"concurrent\"], | |
\"34\": [\"choking\", \"confidence\"], \"35\": [\"chopper\", \"conformist\"], | |
\"36\": [\"Christmas\", \"congregate\"], \"37\": [\"clamshell\", \"consensus\"], | |
\"38\": [\"classic\", \"consulting\"], \"39\": [\"classroom\", \"corporate\"], | |
\"3A\": [\"cleanup\", \"corrosion\"], \"3B\": [\"clockwork\", \"councilman\"], | |
\"3C\": [\"cobra\", \"crossover\"], \"3D\": [\"commence\", \"crucifix\"], | |
\"3E\": [\"concert\", \"cumbersome\"], \"3F\": [\"cowbell\", \"customer\"], | |
\"40\": [\"crackdown\", \"Dakota\"], \"41\": [\"cranky\", \"decadence\"], | |
\"42\": [\"crowfoot\", \"December\"], \"43\": [\"crucial\", \"decimal\"], | |
\"44\": [\"crumpled\", \"designing\"], \"45\": [\"crusade\", \"detector\"], | |
\"46\": [\"cubic\", \"detergent\"], \"47\": [\"dashboard\", \"determine\"], | |
\"48\": [\"deadbolt\", \"dictator\"], \"49\": [\"deckhand\", \"dinosaur\"], | |
\"4A\": [\"dogsled\", \"direction\"], \"4B\": [\"dragnet\", \"disable\"], | |
\"4C\": [\"drainage\", \"disbelief\"], \"4D\": [\"dreadful\", \"disruptive\"], | |
\"4E\": [\"drifter\", \"distortion\"], \"4F\": [\"dropper\", \"document\"], | |
\"50\": [\"drumbeat\", \"embezzle\"], \"51\": [\"drunken\", \"enchanting\"], | |
\"52\": [\"Dupont\", \"enrollment\"], \"53\": [\"dwelling\", \"enterprise\"], | |
\"54\": [\"eating\", \"equation\"], \"55\": [\"edict\", \"equipment\"], | |
\"56\": [\"egghead\", \"escapade\"], \"57\": [\"eightball\", \"Eskimo\"], | |
\"58\": [\"endorse\", \"everyday\"], \"59\": [\"endow\", \"examine\"], | |
\"5A\": [\"enlist\", \"existence\"], \"5B\": [\"erase\", \"exodus\"], | |
\"5C\": [\"escape\", \"fascinate\"], \"5D\": [\"exceed\", \"filament\"], | |
\"5E\": [\"eyeglass\", \"finicky\"], \"5F\": [\"eyetooth\", \"forever\"], | |
\"60\": [\"facial\", \"fortitude\"], \"61\": [\"fallout\", \"frequency\"], | |
\"62\": [\"flagpole\", \"gadgetry\"], \"63\": [\"flatfoot\", \"Galveston\"], | |
\"64\": [\"flytrap\", \"getaway\"], \"65\": [\"fracture\", \"glossary\"], | |
\"66\": [\"framework\", \"gossamer\"], \"67\": [\"freedom\", \"graduate\"], | |
\"68\": [\"frighten\", \"gravity\"], \"69\": [\"gazelle\", \"guitarist\"], | |
\"6A\": [\"Geiger\", \"hamburger\"], \"6B\": [\"glitter\", \"Hamilton\"], | |
\"6C\": [\"glucose\", \"handiwork\"], \"6D\": [\"goggles\", \"hazardous\"], | |
\"6E\": [\"goldfish\", \"headwaters\"], \"6F\": [\"gremlin\", \"hemisphere\"], | |
\"70\": [\"guidance\", \"hesitate\"], \"71\": [\"hamlet\", \"hideaway\"], | |
\"72\": [\"highchair\", \"holiness\"], \"73\": [\"hockey\", \"hurricane\"], | |
\"74\": [\"indoors\", \"hydraulic\"], \"75\": [\"indulge\", \"impartial\"], | |
\"76\": [\"inverse\", \"impetus\"], \"77\": [\"involve\", \"inception\"], | |
\"78\": [\"island\", \"indigo\"], \"79\": [\"jawbone\", \"inertia\"], | |
\"7A\": [\"keyboard\", \"infancy\"], \"7B\": [\"kickoff\", \"inferno\"], | |
\"7C\": [\"kiwi\", \"informant\"], \"7D\": [\"klaxon\", \"insincere\"], | |
\"7E\": [\"locale\", \"insurgent\"], \"7F\": [\"lockup\", \"integrate\"], | |
\"80\": [\"merit\", \"intention\"], \"81\": [\"minnow\", \"inventive\"], | |
\"82\": [\"miser\", \"Istanbul\"], \"83\": [\"Mohawk\", \"Jamaica\"], | |
\"84\": [\"mural\", \"Jupiter\"], \"85\": [\"music\", \"leprosy\"], | |
\"86\": [\"necklace\", \"letterhead\"], \"87\": [\"Neptune\", \"liberty\"], | |
\"88\": [\"newborn\", \"maritime\"], \"89\": [\"nightbird\", \"matchmaker\"], | |
\"8A\": [\"Oakland\", \"maverick\"], \"8B\": [\"obtuse\", \"Medusa\"], | |
\"8C\": [\"offload\", \"megaton\"], \"8D\": [\"optic\", \"microscope\"], | |
\"8E\": [\"orca\", \"microwave\"], \"8F\": [\"payday\", \"midsummer\"], | |
\"90\": [\"peachy\", \"millionaire\"], \"91\": [\"pheasant\", \"miracle\"], | |
\"92\": [\"physique\", \"misnomer\"], \"93\": [\"playhouse\", \"molasses\"], | |
\"94\": [\"Pluto\", \"molecule\"], \"95\": [\"preclude\", \"Montana\"], | |
\"96\": [\"prefer\", \"monument\"], \"97\": [\"preshrunk\", \"mosquito\"], | |
\"98\": [\"printer\", \"narrative\"], \"99\": [\"prowler\", \"nebula\"], | |
\"9A\": [\"pupil\", \"newsletter\"], \"9B\": [\"puppy\", \"Norwegian\"], | |
\"9C\": [\"python\", \"October\"], \"9D\": [\"quadrant\", \"Ohio\"], | |
\"9E\": [\"quiver\", \"onlooker\"], \"9F\": [\"quota\", \"opulent\"], | |
\"A0\": [\"ragtime\", \"Orlando\"], \"A1\": [\"ratchet\", \"outfielder\"], | |
\"A2\": [\"rebirth\", \"Pacific\"], \"A3\": [\"reform\", \"pandemic\"], | |
\"A4\": [\"regain\", \"Pandora\"], \"A5\": [\"reindeer\", \"paperweight\"], | |
\"A6\": [\"rematch\", \"paragon\"], \"A7\": [\"repay\", \"paragraph\"], | |
\"A8\": [\"retouch\", \"paramount\"], \"A9\": [\"revenge\", \"passenger\"], | |
\"AA\": [\"reward\", \"pedigree\"], \"AB\": [\"rhythm\", \"Pegasus\"], | |
\"AC\": [\"ribcage\", \"penetrate\"], \"AD\": [\"ringbolt\", \"perceptive\"], | |
\"AE\": [\"robust\", \"performance\"], \"AF\": [\"rocker\", \"pharmacy\"], | |
\"B0\": [\"ruffled\", \"phonetic\"], \"B1\": [\"sailboat\", \"photograph\"], | |
\"B2\": [\"sawdust\", \"pioneer\"], \"B3\": [\"scallion\", \"pocketful\"], | |
\"B4\": [\"scenic\", \"politeness\"], \"B5\": [\"scorecard\", \"positive\"], | |
\"B6\": [\"Scotland\", \"potato\"], \"B7\": [\"seabird\", \"processor\"], | |
\"B8\": [\"select\", \"provincial\"], \"B9\": [\"sentence\", \"proximate\"], | |
\"BA\": [\"shadow\", \"puberty\"], \"BB\": [\"shamrock\", \"publisher\"], | |
\"BC\": [\"showgirl\", \"pyramid\"], \"BD\": [\"skullcap\", \"quantity\"], | |
\"BE\": [\"skydive\", \"racketeer\"], \"BF\": [\"slingshot\", \"rebellion\"], | |
\"C0\": [\"slowdown\", \"recipe\"], \"C1\": [\"snapline\", \"recover\"], | |
\"C2\": [\"snapshot\", \"repellent\"], \"C3\": [\"snowcap\", \"replica\"], | |
\"C4\": [\"snowslide\", \"reproduce\"], \"C5\": [\"solo\", \"resistor\"], | |
\"C6\": [\"southward\", \"responsive\"], \"C7\": [\"soybean\", \"retraction\"], | |
\"C8\": [\"spaniel\", \"retrieval\"], \"C9\": [\"spearhead\", \"retrospect\"], | |
\"CA\": [\"spellbind\", \"revenue\"], \"CB\": [\"spheroid\", \"revival\"], | |
\"CC\": [\"spigot\", \"revolver\"], \"CD\": [\"spindle\", \"sandalwood\"], | |
\"CE\": [\"spyglass\", \"sardonic\"], \"CF\": [\"stagehand\", \"Saturday\"], | |
\"D0\": [\"stagnate\", \"savagery\"], \"D1\": [\"stairway\", \"scavenger\"], | |
\"D2\": [\"standard\", \"sensation\"], \"D3\": [\"stapler\", \"sociable\"], | |
\"D4\": [\"steamship\", \"souvenir\"], \"D5\": [\"sterling\", \"specialist\"], | |
\"D6\": [\"stockman\", \"speculate\"], \"D7\": [\"stopwatch\", \"stethoscope\"], | |
\"D8\": [\"stormy\", \"stupendous\"], \"D9\": [\"sugar\", \"supportive\"], | |
\"DA\": [\"surmount\", \"surrender\"], \"DB\": [\"suspense\", \"suspicious\"], | |
\"DC\": [\"sweatband\", \"sympathy\"], \"DD\": [\"swelter\", \"tambourine\"], | |
\"DE\": [\"tactics\", \"telephone\"], \"DF\": [\"talon\", \"therapist\"], | |
\"E0\": [\"tapeworm\", \"tobacco\"], \"E1\": [\"tempest\", \"tolerance\"], | |
\"E2\": [\"tiger\", \"tomorrow\"], \"E3\": [\"tissue\", \"torpedo\"], | |
\"E4\": [\"tonic\", \"tradition\"], \"E5\": [\"topmost\", \"travesty\"], | |
\"E6\": [\"tracker\", \"trombonist\"], \"E7\": [\"transit\", \"truncated\"], | |
\"E8\": [\"trauma\", \"typewriter\"], \"E9\": [\"treadmill\", \"ultimate\"], | |
\"EA\": [\"Trojan\", \"undaunted\"], \"EB\": [\"trouble\", \"underfoot\"], | |
\"EC\": [\"tumor\", \"unicorn\"], \"ED\": [\"tunnel\", \"unify\"], | |
\"EE\": [\"tycoon\", \"universe\"], \"EF\": [\"uncut\", \"unravel\"], | |
\"F0\": [\"unearth\", \"upcoming\"], \"F1\": [\"unwind\", \"vacancy\"], | |
\"F2\": [\"uproot\", \"vagabond\"], \"F3\": [\"upset\", \"vertigo\"], | |
\"F4\": [\"upshot\", \"Virginia\"], \"F5\": [\"vapor\", \"visitor\"], | |
\"F6\": [\"village\", \"vocalist\"], \"F7\": [\"virus\", \"voyager\"], | |
\"F8\": [\"Vulcan\", \"warranty\"], \"F9\": [\"waffle\", \"Waterloo\"], | |
\"FA\": [\"wallet\", \"whimsical\"], \"FB\": [\"watchword\", \"Wichita\"], | |
\"FC\": [\"wayside\", \"Wilmington\"], \"FD\": [\"willow\", \"Wyoming\"], | |
\"FE\": [\"woodlark\", \"yesteryear\"], \"FF\": [\"Zulu\", \"Yucatan\"] | |
}"#; | |
#[derive(Debug, PartialEq, Clone)] | |
pub struct PGPWordlist { | |
_byte_even_words: HashMap<String, String>, | |
_byte_odd_words: HashMap<String, String>, | |
} | |
impl PGPWordlist { | |
pub fn new() -> Self { | |
let raw_words: Value = serde_json::from_str(RAW_WORDS).unwrap(); | |
let map_obj = raw_words.as_object().unwrap(); | |
let even_words = map_obj | |
.iter() | |
.map(|item| { | |
let (k, v): (&String, &Value) = item; | |
let both_words: Vec<String> = v.as_array() | |
.unwrap() | |
.iter() | |
.map(|v| v.as_str().unwrap().to_string()) | |
.collect(); | |
(k.to_string(), both_words[1].as_str().to_string()) | |
}) | |
.collect::<HashMap<String, String>>(); | |
let odd_words = map_obj | |
.iter() | |
.map(|item| { | |
let (k, v): (&String, &Value) = item; | |
let both_words: Vec<String> = v.as_array() | |
.unwrap() | |
.iter() | |
.map(|v| v.as_str().unwrap().to_string()) | |
.collect(); | |
(k.to_string(), both_words[0].as_str().to_string()) | |
}) | |
.collect::<HashMap<String, String>>(); | |
PGPWordlist { | |
_byte_even_words: even_words, | |
_byte_odd_words: odd_words, | |
} | |
} | |
pub fn get_completions( | |
&self, | |
prefix: &str, | |
num_words: usize, | |
) -> HashSet<String> { | |
let count_dashes = prefix.matches('-').count(); | |
let words; | |
let mut completions = HashSet::new(); | |
if count_dashes % 2 == 0 { | |
words = self._byte_odd_words | |
.values() | |
.map(String::to_string) | |
.collect::<Vec<String>>(); | |
} else { | |
words = self._byte_even_words | |
.values() | |
.map(String::to_string) | |
.collect::<Vec<String>>(); | |
} | |
let last_partial_word = prefix.split('-').last(); | |
let lp = if let Some(w) = last_partial_word { | |
w.len() | |
} else { | |
0 | |
}; | |
for word in words { | |
let mut suffix = prefix.to_string(); | |
if word.starts_with(last_partial_word.unwrap()) { | |
if lp == 0 { | |
suffix.push_str(&word); | |
} else { | |
let p = prefix.len() - lp; | |
suffix.insert_str(p as usize, &word); | |
} | |
if count_dashes + 1 < num_words { | |
suffix.push_str("-"); | |
} | |
completions.insert(suffix); | |
} | |
} | |
completions | |
} | |
pub fn choose_words(&self, length: u8) -> String { | |
let mut rnd: [u8; 1] = [0; 1]; | |
let mut words: Vec<String> = Vec::new(); | |
for i in 0..length { | |
random_bytes(&mut rnd); | |
let key = bytes_to_hexstr(&rnd).to_uppercase(); | |
if i % 2 == 0 { | |
let word = self._byte_odd_words[&key].as_str(); | |
words.push(word.to_string()); | |
} else { | |
let word = self._byte_even_words[&key].as_str(); | |
words.push(word.to_string()); | |
} | |
} | |
words.join("-") | |
} | |
} | |
#[cfg(test)] | |
mod test { | |
use super::PGPWordlist; | |
use std::collections::HashSet; | |
#[test] | |
fn test_completions() { | |
let w = PGPWordlist::new(); | |
let c: HashSet<String> = w.get_completions("ar", 2); | |
assert!(c.contains(&String::from("article-"))); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment