[{"data":1,"prerenderedAt":688},["ShallowReactive",2],{"navigation_docs":3,"-guide-kdf":148,"-guide-kdf-surround":683},[4,40],{"title":5,"path":6,"stem":7,"children":8,"icon":39},"Guide","\u002Fguide","1.guide\u002F01.index",[9,11,15,19,23,27,31,35],{"title":10,"path":6,"stem":7},"Getting Started",{"title":12,"path":13,"stem":14},"Hashing","\u002Fguide\u002Fhashing","1.guide\u002F02.hashing",{"title":16,"path":17,"stem":18},"HMAC and verify","\u002Fguide\u002Fverify","1.guide\u002F03.verify",{"title":20,"path":21,"stem":22},"Salted KDFs","\u002Fguide\u002Fkdf","1.guide\u002F04.kdf",{"title":24,"path":25,"stem":26},"CLI","\u002Fguide\u002Fcli","1.guide\u002F05.cli",{"title":28,"path":29,"stem":30},"Agents","\u002Fguide\u002Fagents","1.guide\u002F06.agents",{"title":32,"path":33,"stem":34},"Custom algorithms","\u002Fguide\u002Fcustom","1.guide\u002F07.custom",{"title":36,"path":37,"stem":38},"Playground","\u002Fguide\u002Fplayground","1.guide\u002F08.playground","i-lucide-book-open",{"title":41,"path":42,"stem":43,"children":44,"icon":147},"Algorithms","\u002Falgorithms","2.algorithms\u002F00.index",[45,47,51,55,59,63,67,71,75,79,83,87,91,95,99,103,107,111,115,119,123,127,131,135,139,143],{"title":46,"path":42,"stem":43},"Every algorithm",{"title":48,"path":49,"stem":50},"SHA-256","\u002Falgorithms\u002Fsha256","2.algorithms\u002F01.sha256",{"title":52,"path":53,"stem":54},"SHA-384","\u002Falgorithms\u002Fsha384","2.algorithms\u002F02.sha384",{"title":56,"path":57,"stem":58},"SHA-512","\u002Falgorithms\u002Fsha512","2.algorithms\u002F03.sha512",{"title":60,"path":61,"stem":62},"SHA-512Half","\u002Falgorithms\u002Fsha512-half","2.algorithms\u002F04.sha512-half",{"title":64,"path":65,"stem":66},"SHA3-256","\u002Falgorithms\u002Fsha3-256","2.algorithms\u002F05.sha3-256",{"title":68,"path":69,"stem":70},"SHA3-512","\u002Falgorithms\u002Fsha3-512","2.algorithms\u002F06.sha3-512",{"title":72,"path":73,"stem":74},"Keccak-256","\u002Falgorithms\u002Fkeccak256","2.algorithms\u002F07.keccak256",{"title":76,"path":77,"stem":78},"BLAKE2b","\u002Falgorithms\u002Fblake2b","2.algorithms\u002F08.blake2b",{"title":80,"path":81,"stem":82},"BLAKE2b-256","\u002Falgorithms\u002Fblake2b-256","2.algorithms\u002F09.blake2b-256",{"title":84,"path":85,"stem":86},"BLAKE2b-224","\u002Falgorithms\u002Fblake2b-224","2.algorithms\u002F10.blake2b-224",{"title":88,"path":89,"stem":90},"BLAKE2s","\u002Falgorithms\u002Fblake2s","2.algorithms\u002F11.blake2s",{"title":92,"path":93,"stem":94},"BLAKE3","\u002Falgorithms\u002Fblake3","2.algorithms\u002F12.blake3",{"title":96,"path":97,"stem":98},"BLAKE-256","\u002Falgorithms\u002Fblake256","2.algorithms\u002F13.blake256",{"title":100,"path":101,"stem":102},"RIPEMD-160","\u002Falgorithms\u002Fripemd160","2.algorithms\u002F14.ripemd160",{"title":104,"path":105,"stem":106},"HASH160","\u002Falgorithms\u002Fhash160","2.algorithms\u002F15.hash160",{"title":108,"path":109,"stem":110},"HASH256","\u002Falgorithms\u002Fhash256","2.algorithms\u002F16.hash256",{"title":112,"path":113,"stem":114},"MD5","\u002Falgorithms\u002Fmd5","2.algorithms\u002F17.md5",{"title":116,"path":117,"stem":118},"SHA-1","\u002Falgorithms\u002Fsha1","2.algorithms\u002F18.sha1",{"title":120,"path":121,"stem":122},"SHA-0","\u002Falgorithms\u002Fsha0","2.algorithms\u002F19.sha0",{"title":124,"path":125,"stem":126},"CRC-32","\u002Falgorithms\u002Fcrc32","2.algorithms\u002F20.crc32",{"title":128,"path":129,"stem":130},"CRC-16\u002FXMODEM","\u002Falgorithms\u002Fcrc16-xmodem","2.algorithms\u002F21.crc16-xmodem",{"title":132,"path":133,"stem":134},"xxHash (XXH64)","\u002Falgorithms\u002Fxxhash","2.algorithms\u002F22.xxhash",{"title":136,"path":137,"stem":138},"FNV-1a (64-bit)","\u002Falgorithms\u002Ffnv1a","2.algorithms\u002F23.fnv1a",{"title":140,"path":141,"stem":142},"scrypt","\u002Falgorithms\u002Fscrypt","2.algorithms\u002F24.scrypt",{"title":144,"path":145,"stem":146},"PBKDF2","\u002Falgorithms\u002Fpbkdf2","2.algorithms\u002F25.pbkdf2","i-lucide-library",{"id":149,"title":20,"body":150,"description":676,"extension":677,"links":678,"meta":679,"navigation":286,"path":21,"seo":681,"stem":22,"__hash__":682},"docs\u002F1.guide\u002F04.kdf.md",{"type":151,"value":152,"toc":670},"minimark",[153,158,163,167,206,213,249,256,381,396,400,545,558,562,587,595,598,602,611,655,666],[154,155,157],"caution",{"title":156},"Not your login system","scrypt and PBKDF2 are here so you can reproduce and check a digest somebody else made: a wallet file, a test vector, a puzzle. Storing your users' passwords is a different job, with rate limits, pepper and migrations. Use a library built for it.",[159,160,162],"h2",{"id":161},"the-salt-comes-back","The salt comes back",[164,165,166],"p",{},"A KDF without a salt draws 32 random bytes. That's the right default and a trap at the same time, because the digest is worthless without those bytes. So the result carries them, and the CLI prints them:",[168,169,174],"pre",{"className":170,"code":171,"language":172,"meta":173,"style":173},"language-bash shiki shiki-themes hashes hashes hashes","hashes scrypt \"correct horse battery staple\"\n# N 16384, r 8, p 1, keyLength 64, salt 31f4aa33e6346bfa6d576a5dce9eec1c0d6c8e959271d03c2f489a71ac52453b\n# bc010c96df4510eef56ce1a1fc1d140ee276b92d30a31e2ca2e065f6dac8977c9c1bd5d20951e54fbd5b4474984c0f45f5adbe8c7b18daeeacbef09dc330a902\n","bash","",[175,176,177,193,200],"code",{"__ignoreMap":173},[178,179,182,186,190],"span",{"class":180,"line":181},"line",1,[178,183,185],{"class":184},"sK71F","hashes",[178,187,189],{"class":188},"shU9J"," scrypt",[178,191,192],{"class":188}," \"correct horse battery staple\"\n",[178,194,196],{"class":180,"line":195},2,[178,197,199],{"class":198},"scIB-","# N 16384, r 8, p 1, keyLength 64, salt 31f4aa33e6346bfa6d576a5dce9eec1c0d6c8e959271d03c2f489a71ac52453b\n",[178,201,203],{"class":180,"line":202},3,[178,204,205],{"class":198},"# bc010c96df4510eef56ce1a1fc1d140ee276b92d30a31e2ca2e065f6dac8977c9c1bd5d20951e54fbd5b4474984c0f45f5adbe8c7b18daeeacbef09dc330a902\n",[164,207,208,209,212],{},"The first line goes to stderr and the digest alone to stdout, so a pipe still gets one clean value. Run it again and you get another salt and another digest. That's what salts are for. ",[175,210,211],{},"--salt"," takes one back:",[168,214,216],{"className":170,"code":215,"language":172,"meta":173,"style":173},"hashes scrypt \"correct horse battery staple\" --salt 73616c74 --N 1024\n# N 1024, r 8, p 1, keyLength 64, salt 73616c74\n# a1687da9760232a5febf395ab288cb93c9ebb6725c005323a68ae49a4c24538951d7e88980797633a82cddf7cc2f37ffcfa42d2a1222eb06efcb687651975e4c\n",[175,217,218,239,244],{"__ignoreMap":173},[178,219,220,222,224,227,230,233,236],{"class":180,"line":181},[178,221,185],{"class":184},[178,223,189],{"class":188},[178,225,226],{"class":188}," \"correct horse battery staple\"",[178,228,229],{"class":188}," --salt",[178,231,232],{"class":188}," 73616c74",[178,234,235],{"class":188}," --N",[178,237,238],{"class":188}," 1024\n",[178,240,241],{"class":180,"line":195},[178,242,243],{"class":198},"# N 1024, r 8, p 1, keyLength 64, salt 73616c74\n",[178,245,246],{"class":180,"line":202},[178,247,248],{"class":198},"# a1687da9760232a5febf395ab288cb93c9ebb6725c005323a68ae49a4c24538951d7e88980797633a82cddf7cc2f37ffcfa42d2a1222eb06efcb687651975e4c\n",[164,250,251,252,255],{},"In the library the same facts sit in ",[175,253,254],{},"result.options",":",[168,257,261],{"className":258,"code":259,"language":260,"meta":173,"style":173},"language-ts shiki shiki-themes hashes hashes hashes","import { create } from \"@agntn\u002Fhashes\";\n\nconst derived = create(\"pbkdf2\").hash(\"password\", {\n  salt: \"73616c74\",\n  iterations: 4096,\n  digest: \"sha256\",\n  keyLength: 32,\n});\nderived.digest; \u002F\u002F \"c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a\"\nderived.options; \u002F\u002F { encoding: \"hex\", iterations: 4096, digest: \"sha256\", keyLength: 32, salt: \"73616c74\" }\n","ts",[175,262,263,282,288,322,334,340,351,357,363,372],{"__ignoreMap":173},[178,264,265,269,273,276,279],{"class":180,"line":181},[178,266,268],{"class":267},"skH_V","import",[178,270,272],{"class":271},"s38Sx"," { create } ",[178,274,275],{"class":267},"from",[178,277,278],{"class":188}," \"@agntn\u002Fhashes\"",[178,280,281],{"class":271},";\n",[178,283,284],{"class":180,"line":195},[178,285,287],{"emptyLinePlaceholder":286},true,"\n",[178,289,290,293,296,299,302,305,308,311,314,316,319],{"class":180,"line":202},[178,291,292],{"class":267},"const",[178,294,295],{"class":271}," derived ",[178,297,298],{"class":267},"=",[178,300,301],{"class":184}," create",[178,303,304],{"class":271},"(",[178,306,307],{"class":188},"\"pbkdf2\"",[178,309,310],{"class":271},").",[178,312,313],{"class":184},"hash",[178,315,304],{"class":271},[178,317,318],{"class":188},"\"password\"",[178,320,321],{"class":271},", {\n",[178,323,325,328,331],{"class":180,"line":324},4,[178,326,327],{"class":271},"  salt: ",[178,329,330],{"class":188},"\"73616c74\"",[178,332,333],{"class":271},",\n",[178,335,337],{"class":180,"line":336},5,[178,338,339],{"class":271},"  iterations: 4096,\n",[178,341,343,346,349],{"class":180,"line":342},6,[178,344,345],{"class":271},"  digest: ",[178,347,348],{"class":188},"\"sha256\"",[178,350,333],{"class":271},[178,352,354],{"class":180,"line":353},7,[178,355,356],{"class":271},"  keyLength: 32,\n",[178,358,360],{"class":180,"line":359},8,[178,361,362],{"class":271},"});\n",[178,364,366,369],{"class":180,"line":365},9,[178,367,368],{"class":271},"derived.digest; ",[178,370,371],{"class":198},"\u002F\u002F \"c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a\"\n",[178,373,375,378],{"class":180,"line":374},10,[178,376,377],{"class":271},"derived.options; ",[178,379,380],{"class":198},"\u002F\u002F { encoding: \"hex\", iterations: 4096, digest: \"sha256\", keyLength: 32, salt: \"73616c74\" }\n",[164,382,383,384,387,388,391,392,395],{},"The salt is hex by default. ",[175,385,386],{},"saltEncoding: \"utf8\""," or ",[175,389,390],{},"\"base64\""," reads it another way, and a ",[175,393,394],{},"Uint8Array"," is taken as it is. A salt that doesn't decode is an error, never silently shorter.",[159,397,399],{"id":398},"the-knobs","The knobs",[401,402,403,422],"table",{},[404,405,406],"thead",{},[407,408,409,413,416,419],"tr",{},[410,411,412],"th",{},"Algorithm",[410,414,415],{},"Option",[410,417,418],{},"Default",[410,420,421],{},"What it does",[423,424,425,441,456,470,485,501,533],"tbody",{},[407,426,427,430,435,438],{},[428,429,140],"td",{},[428,431,432],{},[175,433,434],{},"N",[428,436,437],{},"16384",[428,439,440],{},"CPU and memory cost, a power of 2",[407,442,443,445,450,453],{},[428,444,140],{},[428,446,447],{},[175,448,449],{},"r",[428,451,452],{},"8",[428,454,455],{},"Block size",[407,457,458,460,464,467],{},[428,459,140],{},[428,461,462],{},[175,463,164],{},[428,465,466],{},"1",[428,468,469],{},"Parallelization",[407,471,472,474,479,482],{},[428,473,140],{},[428,475,476],{},[175,477,478],{},"keyLength",[428,480,481],{},"64",[428,483,484],{},"Output bytes",[407,486,487,490,495,498],{},[428,488,489],{},"pbkdf2",[428,491,492],{},[175,493,494],{},"iterations",[428,496,497],{},"600000",[428,499,500],{},"Rounds of HMAC",[407,502,503,505,510,515],{},[428,504,489],{},[428,506,507],{},[175,508,509],{},"digest",[428,511,512],{},[175,513,514],{},"sha512",[428,516,517,518,521,522,521,525,521,527,387,530],{},"The hash under HMAC: ",[175,519,520],{},"sha256",", ",[175,523,524],{},"sha384",[175,526,514],{},[175,528,529],{},"sha3-256",[175,531,532],{},"sha3-512",[407,534,535,537,541,543],{},[428,536,489],{},[428,538,539],{},[175,540,478],{},[428,542,481],{},[428,544,484],{},[164,546,547,548,550,551,554,555,557],{},"scrypt checks RFC 7914's bounds the way OpenSSL does, so ",[175,549,434],{}," has to stay below 2 to the power 16·r when r is small. The defaults are honest about what they are. PBKDF2's 600000 rounds is OWASP's number for HMAC-SHA256, and with SHA-512 OWASP asks for 220000, so the default errs slow. scrypt's N=16384 with p=1 sits below what OWASP asks for passwords today, and the security note says so out loud instead of hiding it. The ",[552,553,140],"a",{"href":141}," and ",[552,556,144],{"href":145}," pages have the full notes.",[159,559,561],{"id":560},"when-an-agent-picks-the-cost","When an agent picks the cost",[164,563,564,565,554,568,571,572,574,575,577,578,580,581,583,584,586],{},"The library lets you ask for any cost. A tool call doesn't, because one argument from a model shouldn't pin the CPU for a minute or allocate gigabytes. ",[175,566,567],{},"hash_compute",[175,569,570],{},"hash_verify"," cap ",[175,573,434],{}," at 1048576, ",[175,576,449],{}," at 32, ",[175,579,164],{}," at 16, ",[175,582,494],{}," at 10 million and ",[175,585,478],{}," at 1024 bytes, and scrypt's working memory, 128·r·(N + p + 2) bytes, at 256 MiB:",[168,588,593],{"className":589,"code":591,"language":592,"meta":173},[590],"language-text","Invalid option N=1048576: with r and p needs 1073744896 bytes, over 268435456 in a tool call\n","text",[175,594,591],{"__ignoreMap":173},[164,596,597],{},"The tool answer names the salt it drew, like the CLI does. An MCP client sees only the text, so a salt that lived only in structured details would be a salt the model never saw.",[159,599,601],{"id":600},"verifying","Verifying",[164,603,604,605,554,608,610],{},"Verify needs the salt the expected digest was made with. Without it the answer could only be no, so ",[175,606,607],{},"hashes verify",[175,609,570],{}," refuse to run:",[168,612,614],{"className":170,"code":613,"language":172,"meta":173,"style":173},"hashes verify pbkdf2 password c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a --iterations 4096 --digest sha256 --keyLength 32\n# Missing required option: salt (the one the expected digest was made with)\n",[175,615,616,650],{"__ignoreMap":173},[178,617,618,620,623,626,629,632,635,638,641,644,647],{"class":180,"line":181},[178,619,185],{"class":184},[178,621,622],{"class":188}," verify",[178,624,625],{"class":188}," pbkdf2",[178,627,628],{"class":188}," password",[178,630,631],{"class":188}," c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a",[178,633,634],{"class":188}," --iterations",[178,636,637],{"class":188}," 4096",[178,639,640],{"class":188}," --digest",[178,642,643],{"class":188}," sha256",[178,645,646],{"class":188}," --keyLength",[178,648,649],{"class":188}," 32\n",[178,651,652],{"class":180,"line":195},[178,653,654],{"class":198},"# Missing required option: salt (the one the expected digest was made with)\n",[164,656,657,658,661,662,665],{},"Add ",[175,659,660],{},"--salt 73616c74"," and it says ",[175,663,664],{},"MATCH",".",[667,668,669],"style",{},"html pre.shiki code .sK71F, html code.shiki .sK71F{--shiki-light:var(--shiki-token-function);--shiki-default:var(--shiki-token-function);--shiki-dark:var(--shiki-token-function)}html pre.shiki code .shU9J, html code.shiki .shU9J{--shiki-light:var(--shiki-token-string);--shiki-default:var(--shiki-token-string);--shiki-dark:var(--shiki-token-string)}html pre.shiki code .scIB-, html code.shiki .scIB-{--shiki-light:var(--shiki-token-comment);--shiki-default:var(--shiki-token-comment);--shiki-dark:var(--shiki-token-comment)}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .skH_V, html code.shiki .skH_V{--shiki-light:var(--shiki-token-keyword);--shiki-default:var(--shiki-token-keyword);--shiki-dark:var(--shiki-token-keyword)}html pre.shiki code .s38Sx, html code.shiki .s38Sx{--shiki-light:var(--ui-text-highlighted);--shiki-default:var(--ui-text-highlighted);--shiki-dark:var(--ui-text-highlighted)}",{"title":173,"searchDepth":195,"depth":195,"links":671},[672,673,674,675],{"id":161,"depth":195,"text":162},{"id":398,"depth":195,"text":399},{"id":560,"depth":195,"text":561},{"id":600,"depth":195,"text":601},"scrypt and PBKDF2 draw a salt when you give none and print it next to the digest. Keep it or the digest is useless","md",null,{"icon":680},"i-lucide-hourglass",{"title":20,"description":676},"ViZkK2dsgEdZjACG9xsyxyN-51SaM9rd0F0yznbQeok",[684,686],{"title":16,"path":17,"stem":18,"description":685,"children":-1},"Key a digest with HMAC and compare an expected digest byte for byte. Hex ignores case and base64 never does",{"title":24,"path":25,"stem":26,"description":687,"children":-1},"The hashes command. Hash and HMAC and verify from a shell or stdin with the digest alone on stdout",1790688234252]