Last active
July 4, 2021 02:50
-
-
Save atoponce/a740edff0fef641454bdd471e39ef8f6 to your computer and use it in GitHub Desktop.
Gathering entropy via timing between keypresses
This file contains hidden or 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
#!/usr/bin/env node | |
'use strict' | |
const crypto = require('crypto') | |
const readline = require('readline') | |
const fs = require('fs'); | |
const zlib = require('zlib'); | |
// https://spellingbee.com/sites/default/files/inline-files/Words_of_the_Champions_Printable_FINAL.pdf | |
// Only ASCII from "THREE BEE", and alphabetized | |
const SCIPPS = [ | |
"Achernar", "Adelaide", "Aesopian", "Airedale", "Aitutakian", "Apollo", "Aramaic", "Basenji", "Bauhaus", "Beethovenian", "Bolognese", "Bunyanesque", "Castilian", "Chalcolithic", "Chantilly", "Columbia", "Conestoga", "Connemara", "Daliesque", "Diplodocus", "Erewhonian", "Feldenkrais", "Ficus", "Foley", "Freudian", "Fribourg", "Geiger", "Giza", "Glaswegian", "Groenendael", "Haitian", "Himalayan", "Huguenot", "Hyperion", "Icarian", "Jacobean", "Jungian", "Keplerian", "Keynesian", "Kjeldahl", "Lascaux", "Lisztian", "Luddite", "Machiavellian", "Madagascar", "Magellan", "McIntosh", "Mediterranean", "Merrimack", "Naugahyde", "Nereid", | |
"Nicoise", "Orwellian", "Ouagadougou", "Panagia", "Parmentier", "Pepysian", "Plantagenet", "Ponzi", "Pythagorean", "Rastafarian", "Rorschach", "Rubicon", "Sahel", "Sbrinz", "Sinai", "Stradivarius", "Teflon", "Teutonic", "Ushuaia", "Valkyrian", "Wensleydale", "Yeatsian", "Zanni", "a posteriori", "abattoir", "abeyance", "absorptive", "abundance", "accelerates", "accordance", "accoutrement", "acequia", "ad hominem", "ad nauseam", "adiabatic", "adrenergic", "adscititious", "adumbrate", "aerophilatelic", "affenpinscher", "affogato", "aficionado", "agalma", "agelicism", "ageusia", "agitprop", "agnolotti", "agnomen", "ague", "ahimsa", "ailette", | |
"aioli", "ajimez", "akaryote", "allelopathy", "allochroous", "allonym", "almoner", "alpargata", "altazimuth", "amaryllis", "ammonite", "amphistylar", "amygdala", "anaglyphy", "anagrams", "analgesia", "anaphylaxis", "anathema", "andouille", "anechoic", "anemone", "angiitis", "anhinga", "aniseikonia", "ankh", "anodyne", "antenatus", "apocryphal", "apodyterium", "apoplexy", "aporia", "aposematic", "appositive", "apprentice", "appurtenances", "aquiclude", "arachnophagous", "ardoise", "arenaceous", "argot", "argyria", "aristoi", "arthralgia", "ascetic", "ascites", "asparagus", "aspersions", "asphyxiate", "asterion", "atlatl", "atmospheric", | |
"au courant", "auteur", "autophagy", "avgolemono", "avifauna", "avuncular", "azedarach", "azulejo", "badinage", "badminton", "bahuvrihi", "bailiwick", "ballabile", "ballotage", "bantam", "bas-relief", "basilica", "bathos", "bauxite", "bavardage", "bayonet", "bdelloid", "beaumontage", "beccafico", "beelzebub", "benison", "bestial", "betony", "beurre", "bhangra", "bialy", "bibelot", "bibimbap", "bibliopegist", "bienvenue", "bijouterie", "bindi", "binturong", "bireme", "blancmange", "blatherskite", "blottesque", "bloviate", "bobolink", "bodhran", "bolide", "bonspiel", "boudin", "bouffant", "bouillon", "boulevardier", | |
"bourgeois", "boutade", "boutonniere", "bozzetto", "brevet", "breviloquence", "brioche", "brouillon", "brucellosis", "bruja", "brume", "bucatini", "buccal", "bucolic", "budgerigar", "buffa", "bulgur", "cabal", "cabaletta", "cabochon", "cachexia", "caisson", "calamitous", "caldera", "calefacient", "calumny", "camarilla", "camembert", "canaille", "canard", "cantatrice", "capoeira", "capotasto", "capsaicin", "carapace", "carborane", "carmagnole", "carte blanche", "cartouches", "caryatid", "cassock", "castellated", "catachresis", "catarrh", "caveola", "cenote", "cephalopod", "cetology", "champignon", "chanoyu", "chastushka", | |
"cheongsam", "chevalier", "chicanery", "chicle", "chiffonade", "chimera", "choucroute", "chrysolite", "cicatrize", "cicerone", "cinerarium", "clavichord", "clematis", "clerihew", "cnidarian", "coadjutor", "coalescence", "coaxation", "coccygeal", "codicil", "codswallop", "coiffure", "coincidence", "colcannon", "colloque", "colossal", "colporteur", "coltan", "comanchero", "commodore", "commorients", "concinnate", "connoisseur", "consanguine", "consigliere", "contaminated", "contrapposto", "contretemps", "contumelious", "cordillera", "cormorant", "cornichon", "corrigenda", "corsair", "coterie", "coulibiac", "coulomb", "couverture", "cozen", "crepuscular", "crescive", | |
"croquembouche", "croustade", "culminate", "currycomb", "cygnet", "cyrillic", "dactylic", "daguerreotype", "damson", "danseur", "dauerlauf", "de rigueur", "decastich", "degauss", "deleterious", "demitasse", "demulcent", "demurrage", "dengue", "denouement", "denouncement", "depilatory", "derecho", "derogatory", "desiccate", "desman", "deuterium", "devastavit", "dhole", "dhurrie", "diaphoresis", "diastole", "digerati", "diktat", "diluent", "diphtheria", "dirigible", "dirndl", "disciform", "disembogue", "divan", "dorsiflexor", "draegerman", "dreikanter", "dropsonde", "dubitante", "dudgeon", "duello", "dulcinea", "duxelles", "dysphasia", | |
"dysrhythmia", "ecchymosis", "ecclesiology", "effleurage", "effrontery", "eleemosynary", "elegiac", "elision", "emanant", "embolus", "embouchure", "emollient", "emolument", "empennage", "emphatic", "encephalitis", "encina", "ennui", "enoptromancy", "ensilage", "entomophagy", "epenthesis", "epideictic", "erubescent", "erythroblast", "escabeche", "escritoire", "esplanade", "estival", "estovers", "ethylene", "euphonious", "euripus", "examen", "exaugural", "execrable", "exiguous", "exogenous", "expatiate", "exposure", "expugnable", "exsect", "extravasate", "facile", "facsimile", "fait accompli", "fanfaronade", "farfalle", "farina", "farouche", "farrago", | |
"ferruginous", "fetticus", "filar", "fixity", "fjeld", "flagellum", "flaneur", "flavedo", "floruit", "focaccia", "force majeure", "fortissimo", "fossiliferous", "foudroyant", "framboise", "frangipane", "frazil", "frigate", "frison", "fulgent", "funori", "gagaku", "gaillardia", "galapago", "gallium", "galoot", "gambol", "ganache", "gannet", "garrulous", "gasthaus", "gazoz", "gendarme", "genoise", "gentian", "gentilitial", "genuflect", "gerundial", "gesellschaft", "gimbaled", "ginglymus", "girandole", "glacis", "glaucomatous", "glazier", "glossopetrae", "glyceraldehyde", "gnomon", "goanna", "golem", "googol", | |
"goosander", "gorgon", "graticule", "griffonage", "grimthorpe", "grison", "grissino", "guanine", "guayabera", "gudgeon", "guerrilla", "guilloche", "gules", "gyascutus", "gyttja", "habiliments", "hackamore", "hagiographer", "halcyon", "hallux", "halogens", "hamadryad", "hangul", "haori", "harangue", "haricot", "hariolation", "harmattan", "hauberk", "haughty", "haupia", "hauteur", "heinousness", "heliacal", "helium", "hellebore", "hemorrhage", "hepatectomy", "heritage", "hermeneutics", "hesitate", "hesped", "heuristic", "hierurgical", "hilum", "hinoki", "hircine", "hirsute", "histolysis", "hoi polloi", "hokum", | |
"holobenthic", "horologist", "hortatory", "hsaing-waing", "huapango", "huipil", "hummock", "hydrargyrum", "hymnal", "hypallage", "hypertrophy", "hyssop", "iatrogenic", "ibidem", "ichthyology", "icosahedron", "ignoble", "ikat", "ikebana", "illative", "imaret", "imbroglio", "immiscible", "immure", "impugn", "incarnadine", "inchoate", "incomprehensible", "incunabula", "inesculent", "insouciance", "interferon", "internecine", "interpellate", "intonaco", "intriguing", "inveighed", "isagoge", "jabot", "jacana", "jacaranda", "jacquard", "jai alai", "jalousie", "jibboom", "jicama", "jodhpurs", "joropo", "judoka", "julienne", "kaffeeklatsch", | |
"kakapo", "kalanchoe", "kalimba", "kanban", "kanji", "katakana", "kathakali", "katsura", "kente", "kepi", "kibitzer", "kichel", "kinesiology", "kipuka", "kobold", "krewe", "kugel", "kurta", "kwashiorkor", "lachsschinken", "lacrosse", "lacustrine", "lanolated", "lapidary", "largesses", "laryngitis", "lassitude", "laterigrade", "latitudinarian", "latke", "laulau", "lebensraum", "leberwurst", "lecithin", "lefse", "lemniscus", "leonine", "levees", "lidocaine", "lilliputian", "limicolous", "linnet", "lipophilic", "litigious", "littoral", "llanero", "loess", "lokelani", "longevous", "loup-garou", "loupe", | |
"luculent", "luthier", "lysozyme", "macaque", "mackinaw", "macropterous", "maillot", "malachite", "malleolus", "mamushi", "mangonel", "manteau", "maquette", "maquillage", "marinate", "maringouin", "martinet", "mascarpone", "maxillae", "mediobrome", "megacephalic", "megrims", "meiosis", "melee", "mendicity", "meringue", "mesial", "mignonette", "milieu", "millegrain", "misdemeanor", "mizuna", "modiste", "moiety", "moraine", "morel", "mortadella", "mostaccioli", "moulage", "mountebank", "moussaka", "mufti", "mustelid", "myeloma", "nacelle", "nainsook", "naranjilla", "naumachia", "nefarious", "neophyte", "nescience", | |
"nictitate", "nidicolous", "nihilism", "nilpotent", "nimiety", "nisse", "nitid", "nival", "niveau", "nockerl", "nonage", "nonpareil", "notturno", "noumenon", "nubilous", "nudibranch", "nugatory", "nunchaku", "nyctinasty", "obdurate", "obeisant", "obliviscence", "obloquy", "obnebulate", "ochlocracy", "ocotillo", "octonocular", "oeuvre", "ogival", "olecranon", "oleiculture", "onychitis", "onychorrhexis", "oolite", "oppidan", "opportunity", "oppugn", "ormolu", "orogeny", "ossicle", "otacoustic", "otiose", "oubliette", "oviparous", "oxalis", "oxyacetylene", "oyez", "pahoehoe", "paillard", "paladin", "palaver", | |
"palindrome", "palladium", "palsy", "pamphlet", "panegyric", "panettone", "panjandrum", "papeterie", "pappardelle", "parachuted", "paraffin", "parallax", "paramahamsa", "paraquat", "paronomasia", "paroxysm", "parquet", "parterre", "pasilla", "pasquinade", "pastiche", "pastitsio", "patois", "pejerrey", "pejorate", "pekoe", "pelagial", "pelisse", "pendeloque", "penicillin", "penurious", "peregrination", "periodically", "perorate", "persiflage", "pertinacity", "phloem", "phulkari", "phytophilous", "piccata", "pikas", "pillor", "piloncillo", "pinetum", "pinioned", "pinniped", "pirouetted", "piscivorous", "pistou", "plagiarism", "planetesimal", | |
"plangency", "playwright", "plenipotentiary", "plumassier", "pneumatocyst", "pochoir", "podagra", "pointelle", "polemic", "politeia", "poltroon", "polydactyly", "pompadour", "pompeii", "portmanteau", "potager", "potwalloper", "prana", "precariously", "predilection", "prescient", "presentient", "prestidigitation", "prestigious", "proclamation", "profiterole", "profligacy", "prognosticate", "proportionate", "proprioceptive", "proselytizer", "proximo", "pruritus", "pseudonymous", "psoriasis", "ptosis", "puchero", "puerilely", "pulchritude", "pusillanimous", "putsch", "pylorus", "quatrefoil", "quattrocento", "querida", "querulous", "queue", "quidnunc", "quokka", "radicchio", "rafflesia", | |
"rajpramukh", "ranine", "ranunculus", "rapprochement", "rathskeller", "ravigote", "realgar", "realia", "realpolitik", "reboation", "reconnoiter", "redingote", "regnal", "reluctant", "rembrandt", "renminbi", "renvoi", "repartee", "repoussage", "rescissible", "reseau", "retinoscopy", "revanche", "reveille", "rhabdoid", "rheostat", "rheumatic", "rhinorrhagia", "rhizome", "rhyton", "rinceau", "riparian", "risibility", "risorgimento", "rissole", "ritenuto", "rocaille", "rococo", "rondeau", "rongeur", "rouille", "roux", "rubato", "rubefacient", "ruelle", "rugose", "rupicolous", "saccadic", "saccharide", "sacerdotal", "sakura", | |
"samarium", "sambal", "sangfroid", "saponaceous", "satiety", "satsuma", "saturnine", "sauger", "scaberulous", "schefflera", "scintillation", "scrivener", "scurrilous", "sebaceous", "secant", "sedulous", "seiche", "seine", "semaphore", "seneschal", "senile", "senryu", "sepulchral", "sequoia", "serricorn", "sesquipedalian", "sforzando", "shubunkin", "simulacrum", "sinciput", "sinophile", "sirenian", "skeuomorph", "smelters", "sojourner", "solace", "solecism", "solenoid", "solipsist", "sommelier", "somnolent", "sopapilla", "sorghum", "sororal", "sotto voce", "souchong", "speleothem", "sphygmometer", "spiedini", "spirulina", "spodumene", | |
"spondylitis", "sporran", "squadron", "stanchion", "stannum", "steeplechasing", "stevedore", "stirrups", "stretto", "strychnine", "sturnine", "styptic", "subrident", "succade", "succussion", "suffused", "sulcus", "sumpsimus", "supercilious", "surcease", "surfeit", "susurrus", "sylph", "syncope", "synecdoche", "synesthesia", "synod", "syzygy", "tachyon", "tamarack", "tamari", "tanager", "tannined", "taoiseach", "tapetum", "tarpaulin", "tartaric", "tatterdemalion", "taurine", "tazza", "telegnosis", "temblor", "tenon", "teppanyaki", "teratism", "terpsichore", "tetrachoric", "thalamus", "thalassic", "thaumaturge", "theca", | |
"theodicy", "therapeutic", "thermohaline", "threnody", "thylacine", "tiffin", "tikkun", "tinnient", "titian", "tmesis", "toccata", "tokonoma", "tomalley", "tomography", "topazolite", "toponymic", "toque", "toreador", "toreutics", "toroidal", "totipotency", "tourelle", "tournedos", "towhee", "toxicosis", "tralatitious", "transhumance", "transience", "transmontane", "trichinosis", "trichotillomania", "trigeminal", "triquetra", "tristeza", "trompe l'oeil", "trouvaille", "tryptophan", "tsukupin", "tuatara", "tulsi", "tumultuous", "tumulus", "tussock", "ullage", "ululate", "umami", "unguiculate", "unwonted", "upsilon", "urticaria", "urushiol", | |
"ushabti", "ustion", "vaccary", "valetudinary", "variscite", "velamen", "venenate", "verandas", "verdure", "veridical", "verisimilitude", "vermeil", "vermicelli", "vervain", "vestigial", "vicenary", "vicissitudes", "vigneron", "vilipend", "vinaigrette", "violaceous", "vireo", "visite", "vitiate", "vizierial", "voltammetry", "wahine", "wakame", "warison", "wassail", "wasteweir", "weltschmerz", "whippoorwill", "wickiup", "woad", "xerogel", "xiphias", "xyloglyphy", "xylyl", "yakitori", "yosenabe", "yttriferous", "yuloh", "zabaglione", "zaibatsu", "zazen", "zeitgeist", "zocalo", "zortzico", "zydeco", "zymurgy", | |
] | |
function uniformRandom(count) { | |
let rand | |
const min = 2 ** 16 % count | |
do { | |
rand = parseInt(crypto.randomBytes(2).toString('hex'), 16) | |
} while (rand < min) | |
return rand % count | |
} | |
function shuffle(array) { | |
let counter = array.length | |
while (counter > 0) { | |
let index = uniformRandom(counter) | |
counter-- | |
let temp = array[counter] | |
array[counter] = array[index] | |
array[index] = temp | |
} | |
return array | |
} | |
function debias (bits) { | |
let bitstr = '' | |
for (let i = 0; i < 8; i++) { | |
let pair = (bits >> BigInt(14 - 2 * i) & 0x3n) | |
if (pair === 1n || pair === 2n) bitstr += (pair >> 1n) | |
} | |
return bitstr | |
} | |
function processEntropy (arr) { | |
let unbiasedBitstr = '' | |
for (let i = 0; i < arr.length; i++ ) unbiasedBitstr += debias(arr[i]) | |
return unbiasedBitstr | |
} | |
function collectInput () { | |
let input = '' | |
let words = '' | |
const ns = [] | |
const challenge = shuffle(SCIPPS) | |
for (let i = 0; i < 100; i++) { | |
words += challenge[i] | |
words += ' ' | |
} | |
console.log('Type, not paste these 100 words. Be as accurate as possible, but don\'t stress it. Entropy is calculated on keypress timings, not the content itself. Type <ctrl>-<c> when finished:') | |
console.log() | |
console.log(words) | |
console.log() | |
readline.emitKeypressEvents(process.stdin) | |
process.stdin.setRawMode(true) | |
process.stdin.on('keypress', (str, key) => { | |
process.stdout.write(str) | |
ns.push(process.hrtime.bigint() & 0xffffn) // least significant 16-bits (65536 nanoseconds) | |
if (key.name === 'return') process.stdout.write('\n') | |
if (key.ctrl && key.name === 'c') { | |
let bitstr = processEntropy(ns) | |
const entropy = [] | |
const div = Math.floor(bitstr.length / 16) | |
for (let i = 0; i < div; i++) entropy.push(parseInt(bitstr.substr(16 * i, 16), 2)) | |
console.log() // blank line | |
console.log() // blank line | |
console.log(JSON.stringify(entropy)) | |
process.exit(0) | |
} | |
}) | |
} | |
collectInput() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment