{"id":98,"date":"2026-06-17T20:53:03","date_gmt":"2026-06-17T20:53:03","guid":{"rendered":"https:\/\/shattered.io\/fi\/2026\/06\/17\/blake3-hash-nodejs\/"},"modified":"2026-06-17T20:54:28","modified_gmt":"2026-06-17T20:54:28","slug":"blake3-hash-nodejs","status":"publish","type":"post","link":"https:\/\/shattered.io\/fi\/blake3-hash-nodejs\/","title":{"rendered":"BLAKE3-hajautus Node.js:ss\u00e4: 10 vaihetta, 30 min [2026]"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">BLAKE3 on vuonna 2020 julkaistu hajautusalgoritmi, joka tuottaa jopa 3,5 kertaa suuremman suorituskyvyn kuin SHA-256 x86_64-arkkitehtuurilla. Algoritmilla on puumainen rinnakkaisrakenne, 128 bitin t\u00f6rm\u00e4yskest\u00e4vyys ja laajennettava tulospiituus, joten se sopii erinomaisesti tiedostojen tarkistussummiin, viestiautentikointikoodeihin ja avainten johdannaisiin. T\u00e4ss\u00e4 oppaassa asennat blake3-paketin version 3.0.0, kirjoitat 10 toimivaa koodiesimerkki\u00e4 ja opit tyypillisimm\u00e4t sudenkuopat tuotantok\u00e4yt\u00f6ss\u00e4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mika-on-blake3-ja-miksi-se-korvaa-sha-256n-monissa-kayttotapauksissa\">Mik\u00e4 on BLAKE3 ja miksi se korvaa SHA-256:n monissa k\u00e4ytt\u00f6tapauksissa<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">BLAKE3 syntyi BLAKE2:n jatkoksi. Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O&#8217;Hearn ja Jack O&#8217;Connor julkaisivat algoritmin tammikuussa 2020. Suunnittelun l\u00e4ht\u00f6kohta oli yhdist\u00e4\u00e4 BLAKE2:n nopeus Merkle-puurakenteeseen, joka mahdollistaa rinnakkaistamisen useilla prosessoriytimill\u00e4 ja SIMD-vektoriyksik\u00f6ill\u00e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">K\u00e4yt\u00e4nn\u00f6n vaikutus on merkitt\u00e4v\u00e4. Viralliset vertailumittaukset x86_64 EPYC-prosessorilla osoittavat BLAKE3:n saavuttavan 6 121 MB\/s 10 megatavun sy\u00f6tteell\u00e4, kun SHA-256 ylt\u00e4\u00e4 1 772 MB\/s ja SHA-512 2 560 MB\/s. Pienemm\u00e4ll\u00e4 64 tavun sy\u00f6tteell\u00e4 ero on pienempi: BLAKE3 tuottaa 1 069 MB\/s vastaan SHA-256:n 860 MB\/s. Arm64-arkkitehtuurilla SHA-256 on paikoin nopeampi, koska prosessoreissa on usein laitteistokiihdytys SHA-laskennalle, mutta x86_64-palvelimilla BLAKE3 voittaa ylivoimaisesti suurilla sy\u00f6tteill\u00e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Turvallisuusominaisuudet vastaavat SHA-256:ta: t\u00f6rm\u00e4yskest\u00e4vyys on 128 bitti\u00e4, esikuvakest\u00e4vyys 256 bitti\u00e4 ja toisen esikuvan kest\u00e4vyys 256 bitti\u00e4. BLAKE3 tukee my\u00f6s kolmea erikoistilaa, joita SHA-256 ei tarjoa suoraan: avaimellinen hajautus (keyed hash), avainten johdannainen (KDF) ja laajennettu tuloste (XOF). Solana-lohkoketju k\u00e4ytt\u00e4\u00e4 BLAKE3:a tilihajautuksiin, mik\u00e4 osoittaa algoritmin kelpoisuuden tuotantoj\u00e4rjestelmiss\u00e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Node.js:n sis\u00e4\u00e4nrakennettu <code>crypto<\/code>-moduuli ei tue BLAKE3:a edes versiossa 22. Siksi tarvitset kolmannen osapuolen paketin. Kaksi suosituinta vaihtoehtoa ovat <strong>blake3<\/strong> (npm, versio 3.0.0, k\u00e4ytt\u00e4\u00e4 WebAssembly\u00e4 ja natiivia sidontaa) ja <strong>@noble\/hashes<\/strong> (versio 2.2.0, puhdas TypeScript-toteutus, nolla riippuvuutta, tietoturva-auditoitu). T\u00e4ss\u00e4 oppaassa k\u00e4ytet\u00e4\u00e4n molempia, mutta p\u00e4\u00e4paino on blake3-paketissa.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"blake3-vs-sha-256-vs-sha-512-suorituskyky-ja-turvallisuus\">BLAKE3 vs SHA-256 vs SHA-512: suorituskyky ja turvallisuus<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ennen koodiin sukeltamista on hy\u00f6dyllist\u00e4 katsoa algoritmien ominaisuuksia rinnakkain. Alla oleva taulukko kokoaa viralliset spesifikaatiot ja vertailumittaukset.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Algoritmi<\/th><th>Tulospiituus<\/th><th>T\u00f6rm\u00e4yskest\u00e4vyys<\/th><th>Rinnakkaistettavissa<\/th><th>Nopeus x86_64, 10 Mt (MB\/s)<\/th><th>Nopeus x86_64, 64 B (MB\/s)<\/th><\/tr><\/thead><tbody><tr><td><strong>BLAKE3<\/strong><\/td><td>Muuttuva (oletus 256 bit)<\/td><td>128 bit<\/td><td>Kyll\u00e4 (Merkle-puu)<\/td><td>6 121<\/td><td>1 069<\/td><\/tr><tr><td>SHA-256<\/td><td>256 bit<\/td><td>128 bit<\/td><td>Ei<\/td><td>1 772<\/td><td>860<\/td><\/tr><tr><td>SHA-512<\/td><td>512 bit<\/td><td>256 bit<\/td><td>Ei<\/td><td>2 560<\/td><td>1 000<\/td><\/tr><tr><td>SHA3-512<\/td><td>512 bit<\/td><td>256 bit<\/td><td>Ei<\/td><td>Hitaampi kuin SHA-512<\/td><td>Hitaampi kuin SHA-512<\/td><\/tr><tr><td>BLAKE2b<\/td><td>Muuttuva (maks. 512 bit)<\/td><td>256 bit<\/td><td>Rajoitetusti<\/td><td>~3 000<\/td><td>~900<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">SHA-256 ja SHA-512 ovat tarpeellisia protokollissa, joissa standardi on pakollinen, kuten TLS-sertifikaateissa tai digitaalisissa allekirjoituksissa, koska ne noudattavat FIPS-standardeja. BLAKE3 sopii paremmin suorituskykykriittiseen sis\u00e4iseen k\u00e4ytt\u00f6\u00f6n: tiedostojen eheyden tarkistamiseen, sis\u00e4ll\u00f6n osoitteistamiseen (content-addressable storage) ja nopeaan MAC-laskentaan.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"esitietovaatimukset\">Esitietovaatimukset<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ennen aloittamista varmista, ett\u00e4 kehitysymp\u00e4rist\u00f6ss\u00e4si on seuraavat komponentit:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Node.js 20.x LTS<\/strong> tai uudempi (blake3-paketti vaatii v\u00e4hint\u00e4\u00e4n Node.js 16, mutta 20.x on suositeltava pitk\u00e4aikaistuki)<\/li><li><strong>npm 10.x<\/strong> tai yarn 4.x pakettienhallintaan<\/li><li><strong>Python 3.x<\/strong> node-gyp-k\u00e4\u00e4nt\u00e4j\u00e4\u00e4 varten (tarvitaan, jos blake3:n natiivi sidos ladataan)<\/li><li>C++-k\u00e4\u00e4nt\u00e4j\u00e4: GCC 12+ Linuxilla, Clang 14+ macOS:lla, Visual C++ 2019+ Windowsilla<\/li><li>Perustiedot Node.js:st\u00e4 ja async\/await-syntaksista<\/li><li>Ymm\u00e4rrys hajautusfunktioiden k\u00e4yt\u00f6st\u00e4 (suositeltava: lue ensin <a href=\"\/fi\/sha-256\/\">SHA-256-artikkeli<\/a>)<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Tarkista Node.js-versio ennen aloittamista:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>node --version\n# v20.14.0 tai uudempi\nnpm --version\n# 10.7.0 tai uudempi<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-1-projektin-rakenne-ja-alustus\">Vaihe 1: Projektin rakenne ja alustus<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Luo uusi hakemisto ja alusta npm-projekti. ESM-moduulij\u00e4rjestelm\u00e4 (ES Modules) on suositeltava, koska blake3 3.0.0 tukee sit\u00e4 t\u00e4ysim\u00e4\u00e4r\u00e4isesti ja CommonJS-yhteensopivuus on rajatumpaa.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir blake3-demo && cd blake3-demo\nnpm init -y\n\n# Lis\u00e4\u00e4 \"type\": \"module\" package.json-tiedostoon\nnode -e \"\nconst fs = require('fs');\nconst pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));\npkg.type = 'module';\nfs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));\nconsole.log('package.json p\u00e4ivitetty: type=module');\n\"\n\nmkdir src test<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Projektin lopullinen hakemistorakenne tulee n\u00e4ytt\u00e4m\u00e4\u00e4n t\u00e4lt\u00e4:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>blake3-demo\/\n\u251c\u2500\u2500 package.json\n\u251c\u2500\u2500 src\/\n\u2502   \u251c\u2500\u2500 basic-hash.mjs\n\u2502   \u251c\u2500\u2500 file-hash.mjs\n\u2502   \u251c\u2500\u2500 keyed-hash.mjs\n\u2502   \u251c\u2500\u2500 kdf.mjs\n\u2502   \u251c\u2500\u2500 xof.mjs\n\u2502   \u251c\u2500\u2500 cas.mjs\n\u2502   \u2514\u2500\u2500 benchmark.mjs\n\u2514\u2500\u2500 test\/\n    \u2514\u2500\u2500 hash.test.mjs<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-2-blake3-paketin-asennus-ja-vahvistus\">Vaihe 2: blake3-paketin asennus ja vahvistus<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Asenna blake3-paketti tarkalla versionumerolla. Paketti lataa ensin natiivisen sidonnan node-gyp:n avulla. Jos k\u00e4\u00e4nt\u00e4minen ep\u00e4onnistuu, se palaa automaattisesti WebAssembly-toteutukseen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install blake3@3.0.0\n\n# Tarkista asennus ja API\nnode --input-type=module << 'EOF'\nimport blake3 from 'blake3';\nconsole.log('blake3 versio 3.0.0 ladattu');\nconsole.log('Saatavilla olevat funktiot:', Object.keys(blake3).join(', '));\nEOF<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Onnistuneen asennuksen j\u00e4lkeen terminaalissa n\u00e4kyy:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>blake3 versio 3.0.0 ladattu\nSaatavilla olevat funktiot: hash, createHash, keyedHash, createKeyedHash, derive, createDeriveKey<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Jos natiivinen sidonta k\u00e4\u00e4nnet\u00e4\u00e4n onnistuneesti, BLAKE3 k\u00e4ytt\u00e4\u00e4 C++-toteutusta AVX2- tai AVX512-vektoriohjeilla ja saavuttaa t\u00e4yden suorituskyvyn. WebAssembly-varaj\u00e4rjestelm\u00e4 on noin 30 prosenttia hitaampi kuin natiivitoteutus, joten tuotantopalvelimella kannattaa varmistaa, ett\u00e4 k\u00e4\u00e4nt\u00e4j\u00e4riippuvuudet ovat kunnossa ennen k\u00e4ytt\u00f6\u00f6nottoa.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-3-perustiivisteen-laskeminen\">Vaihe 3: Perustiivisteen laskeminen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">BLAKE3:n yksinkertaisin k\u00e4ytt\u00f6tapaus on tiivisteen laskeminen merkkijonosta tai Buffer-objektista. Luo tiedosto <code>src\/basic-hash.mjs<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { hash } from 'blake3';\n\n\/\/ Merkkijonon tiiviste, eksplisiittinen UTF-8-enkoodaus\nconst viesti = 'Hei, maailma!';\nconst tiiviste = hash(Buffer.from(viesti, 'utf8'));\nconsole.log('Tiiviste (hex):', tiiviste.toString('hex'));\n\/\/ 256-bittinen (32 tavua) heksadesimaalimerkkijono\n\n\/\/ Uint8Array toimii my\u00f6s suoraan\nconst data = new TextEncoder().encode('Hei, maailma!');\nconst tiiviste2 = hash(data);\nconsole.log('Sama tulos:', tiiviste.toString('hex') === tiiviste2.toString('hex'));\n\/\/ true - molemmat tuottavat saman tiivisteen\n\n\/\/ Pidempi tuloste: 512 bitti\u00e4 (64 tavua)\nconst pitkaTiiviste = hash(Buffer.from(viesti, 'utf8'), { length: 64 });\nconsole.log('512-bittinen:', pitkaTiiviste.toString('hex'));\nconsole.log('Pituus:', pitkaTiiviste.length, 'tavua');<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Aja skripti komennolla <code>node src\/basic-hash.mjs<\/code>. Odotettu tuloste:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Tiiviste (hex): a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3\nSama tulos: true\n512-bittinen: a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3...\nPituus: 64 tavua<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>hash()<\/code>-funktio on synkroninen. Se ottaa sy\u00f6tteekseen <code>Buffer<\/code>:n, <code>Uint8Array<\/code>:n tai <code>string<\/code>:n. Oletustulospiituus on 32 tavua (256 bitti\u00e4), mutta <code>length<\/code>-optiolla sen voi asettaa haluamaansa kokoon. T\u00e4rke\u00e4\u00e4: eksplisiittinen UTF-8-enkoodaus est\u00e4\u00e4 yll\u00e4tykset eri alustoilla.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-4-suurten-tiedostojen-hajautus-stream-rajapinnalla\">Vaihe 4: Suurten tiedostojen hajautus stream-rajapinnalla<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Suurten tiedostojen tiivisteen laskeminen kerralla muistiin ladattuna on tehotonta ja voi kaataa sovelluksen muistin loppuessa. BLAKE3:n <code>createHash()<\/code> tuottaa Node.js-yhteensopivan Writable stream -objektin, jolla tiedoston voi k\u00e4sitell\u00e4 paloina.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Luo <code>src\/file-hash.mjs<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { createHash } from 'blake3';\nimport { createReadStream } from 'fs';\nimport { pipeline } from 'stream\/promises';\n\nasync function laskeTiedostoTiiviste(polku, puskuriKoko = 64 * 1024) {\n  const hasher = createHash();\n  const lukija = createReadStream(polku, { highWaterMark: puskuriKoko });\n  await pipeline(lukija, hasher);\n  return hasher.digest('hex');\n}\n\n\/\/ Laske t\u00e4m\u00e4n skriptin oma tiiviste\nconst tiiviste = await laskeTiedostoTiiviste('.\/src\/file-hash.mjs');\nconsole.log('Tiedoston BLAKE3-tiiviste:', tiiviste);\n\n\/\/ Vertaa suoritusaikaa eri puskurikoilla\nfor (const koko of [4096, 65536, 1024 * 1024]) {\n  const alku = performance.now();\n  await laskeTiedostoTiiviste('\/dev\/zero', koko);\n  const aika = performance.now() - alku;\n  console.log(`Puskuri ${koko} B: ${aika.toFixed(1)} ms`);\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Stream-rajapinta on v\u00e4ltt\u00e4m\u00e4t\u00f6n gigatasoisissa tiedostoissa. 64 kilotavun puskurikoko (<code>highWaterMark: 64 * 1024<\/code>) on yleinen optimum, joka tasapainottaa I\/O-pyynt\u00f6jen m\u00e4\u00e4r\u00e4n ja muistin k\u00e4yt\u00f6n. Isompi puskuri ei v\u00e4ltt\u00e4m\u00e4tt\u00e4 nopeuta laskentaa, koska pullonkaula on usein levyn I\/O, ei itse hajautusfunktio.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-5-avaimellinen-hajautus-viestien-autentikoinnissa\">Vaihe 5: Avaimellinen hajautus viestien autentikoinnissa<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">BLAKE3:n avaimellinen hajautustila toimii MAC-koodina (Message Authentication Code) ilman HMAC-rakennetta. SHA-256-pohjaisessa HMAC:ssa algoritmi ajetaan kahdesti (katso <a href=\"\/fi\/hmac-node-js\/\">HMAC Node.js:ss\u00e4 -opas<\/a>), mutta BLAKE3:n keyed hash tuottaa saman turvallisuustason yhdell\u00e4 l\u00e4p\u00e4isyll\u00e4. Tulos: noin puolet laskenta-ajasta.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Luo <code>src\/keyed-hash.mjs<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { keyedHash } from 'blake3';\nimport { randomBytes, timingSafeEqual } from 'crypto';\n\n\/\/ Avain t\u00e4ytyy olla tarkalleen 32 tavua (256 bitti\u00e4)\nconst avain = randomBytes(32);\nconst viesti = Buffer.from('Maksutieto: 100 EUR asiakkaalle #4421', 'utf8');\n\n\/\/ Laske MAC\nconst mac = keyedHash(avain, viesti);\nconsole.log('MAC (hex):', mac.toString('hex'));\n\n\/\/ Todenna viesti oikealla avaimella\nconst tarkistus = keyedHash(avain, viesti);\nconst onValidi = timingSafeEqual(mac, tarkistus);\nconsole.log('Todentaminen onnistui:', onValidi); \/\/ true\n\n\/\/ V\u00e4\u00e4r\u00e4 avain tuottaa eri MAC:n\nconst vaaraAvain = randomBytes(32);\nconst vaaraTarkistus = keyedHash(vaaraAvain, viesti);\nconst onVaara = timingSafeEqual(mac, vaaraTarkistus);\nconsole.log('V\u00e4\u00e4r\u00e4 avain hyl\u00e4tty:', !onVaara); \/\/ true\n\n\/\/ K\u00e4yt\u00e4nn\u00f6n API-esimerkki: webhook-allekirjoitusten todentaminen\nfunction todennaWebhook(avain, runko, allekirjoitus) {\n  const laskettu = keyedHash(avain, Buffer.from(runko, 'utf8'));\n  const odotettu = Buffer.from(allekirjoitus, 'hex');\n  if (laskettu.length !== odotettu.length) return false;\n  return timingSafeEqual(laskettu, odotettu);\n}\n\nconst webhookRunko = JSON.stringify({ tapahtuma: 'maksu', summa: 100 });\nconst webhookAllekirjoitus = keyedHash(avain, Buffer.from(webhookRunko)).toString('hex');\nconsole.log('Webhook validi:', todennaWebhook(avain, webhookRunko, webhookAllekirjoitus));<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Avaimellinen hajautus on parempi vaihtoehto kuin yksinkertainen tiiviste salaisuuden lis\u00e4\u00e4miseen (ns. \"secret prefix\" tai \"secret suffix\" -menetelm\u00e4t). Rakenteessa <code>hash(salaisuus + viesti)<\/code> pituuslaajennushy\u00f6kk\u00e4ys on mahdollinen SHA-256:n kanssa. BLAKE3:n keyed hash on suunniteltu v\u00e4ltt\u00e4m\u00e4\u00e4n t\u00e4m\u00e4 ongelma alusta asti.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-6-avainten-johdannainen-key-derivation-function\">Vaihe 6: Avainten johdannainen (Key Derivation Function)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">BLAKE3:n KDF-tila mahdollistaa useiden avainten johtamisen yhdest\u00e4 p\u00e4\u00e4avaimesta. T\u00e4m\u00e4 on v\u00e4ltt\u00e4m\u00e4t\u00f6nt\u00e4, kun samasta salaisuudesta tarvitaan erillisi\u00e4 avaimia eri k\u00e4ytt\u00f6tarkoituksiin, kuten salaukseen ja autentikointiin. Luo <code>src\/kdf.mjs<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { derive } from 'blake3';\nimport { randomBytes } from 'crypto';\n\n\/\/ P\u00e4\u00e4avain (esim. DH-avaintenvaihdon tulos tai session secret)\nconst paaSalaisuus = randomBytes(32);\n\n\/\/ Kontekstimerkint\u00e4 identifioi k\u00e4ytt\u00f6tarkoituksen yksil\u00f6llisesti.\n\/\/ Sen t\u00e4ytyy pysy\u00e4 muuttumattomana koko sovelluksen elinkaaren ajan.\nconst SALAUS_KTX = 'blake3-demo 2026-06-17 aes256-gcm salausavain v1';\nconst HMAC_KTX   = 'blake3-demo 2026-06-17 hmac-sha256 autentikointi v1';\n\n\/\/ Johda kaksi erillist\u00e4 avainta samasta p\u00e4\u00e4salaisuudesta\nconst salausAvain = derive(SALAUS_KTX, paaSalaisuus);\nconst authAvain   = derive(HMAC_KTX,   paaSalaisuus);\n\nconsole.log('Salausavain:', salausAvain.toString('hex'));\nconsole.log('Authavain:  ', authAvain.toString('hex'));\nconsole.log('Avaimet eroavat:', salausAvain.toString('hex') !== authAvain.toString('hex'));\n\/\/ true - sama p\u00e4\u00e4salaisuus, eri kontekstit, eri avaimet\n\n\/\/ Johda 64-tavuinen avain AES-256:lle ja IV:lle kerralla\nconst laajaAvain = derive(SALAUS_KTX, paaSalaisuus, { length: 64 });\nconst aesAvain = laajaAvain.slice(0, 32);  \/\/ 256-bittinen AES-avain\nconst iv       = laajaAvain.slice(32, 48); \/\/ 128-bittinen IV\n\nconsole.log('AES-avain:', aesAvain.toString('hex'));\nconsole.log('IV:', iv.toString('hex'));\nconsole.log('Pituudet:', aesAvain.length, 'ja', iv.length, 'tavua');<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Kontekstimerkint\u00e4 on kriittinen turvallisuuden kannalta. Hyv\u00e4ksi k\u00e4yt\u00e4nn\u00f6ksi on vakiintunut sis\u00e4llytt\u00e4\u00e4 sovelluksen nimi, p\u00e4iv\u00e4m\u00e4\u00e4r\u00e4, k\u00e4ytt\u00f6tarkoitus ja versionumero. Muuta kontekstia vain, jos haluat tarkoituksellisesti tehd\u00e4 vanhoista johdetuista avaimista k\u00e4ytt\u00f6kelvottomia.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-7-laajennettu-tuloste-xof\">Vaihe 7: Laajennettu tuloste (XOF)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">BLAKE3 toimii my\u00f6s XOF-funktiona (eXtendable Output Function), jolloin se tuottaa mielivaltaisen pitk\u00e4n deterministisen tulosteen. T\u00e4m\u00e4 sopii pseudosatunnaistiedon generointiin tai lookup-taulukoiden rakentamiseen. Luo <code>src\/xof.mjs<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { hash } from 'blake3';\n\nconst siemen = Buffer.from('deterministinen siemen 2026', 'utf8');\n\n\/\/ Tuota 128 tavua (1024 bitti\u00e4) laajennettua tulostetta\nconst xof128 = hash(siemen, { length: 128 });\nconsole.log('XOF 128 tavua:', xof128.toString('hex'));\nconsole.log('Pituus:', xof128.length, 'tavua');\n\n\/\/ Ensimm\u00e4iset 32 tavua vastaavat oletustiivistett\u00e4\nconst perus = hash(siemen);\nconsole.log('Alkaa oletustiivisteell\u00e4:',\n  Buffer.compare(perus, xof128.slice(0, 32)) === 0); \/\/ true\n\n\/\/ K\u00e4ytt\u00f6tapaus: generoi deterministinen S-laatikko kryptografiaan\nfunction generoiSLaatikko(avain, koko = 256) {\n  const data = hash(Buffer.from(avain, 'utf8'), { length: koko });\n  return Array.from(data);\n}\n\nconst slaatikko = generoiSLaatikko('sovellus-v1-slaatikko', 256);\nconsole.log('S-laatikko (ensimm\u00e4iset 8 arvoa):', slaatikko.slice(0, 8));\nconsole.log('S-laatikko koko:', slaatikko.length);<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-8-suorituskykymittaus-ja-vertailu\">Vaihe 8: Suorituskykymittaus ja vertailu<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mitataan BLAKE3:n todellinen suorituskyky kehitysymp\u00e4rist\u00f6ss\u00e4si ja verrataan sit\u00e4 Node.js:n sis\u00e4\u00e4nrakennettuun SHA-256:een. Luo <code>src\/benchmark.mjs<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { hash } from 'blake3';\nimport { createHash } from 'crypto';\n\nfunction mittaa(nimi, fn, iteraatiot, dataKoko) {\n  \/\/ L\u00e4mmittelyvaihe est\u00e4\u00e4 JIT-k\u00e4\u00e4nt\u00e4j\u00e4n vinouttamisen\n  for (let i = 0; i < 200; i++) fn();\n  const alku = performance.now();\n  for (let i = 0; i < iteraatiot; i++) fn();\n  const ms = performance.now() - alku;\n  const mbps = (dataKoko * iteraatiot) \/ (ms \/ 1000) \/ (1024 * 1024);\n  return { nimi, mbps: mbps.toFixed(0) };\n}\n\nconst KOOT = [\n  { koko: 64,            iter: 50000, label: '64 B' },\n  { koko: 1024,          iter: 20000, label: '1 kt' },\n  { koko: 65536,         iter: 2000,  label: '64 kt' },\n  { koko: 1024 * 1024,   iter: 200,   label: '1 Mt' },\n];\n\nconsole.log('Algoritmi     | 64 B    | 1 kt    | 64 kt   | 1 Mt');\nconsole.log('--------------|---------|---------|---------|--------');\n\nconst blake3Tulokset = [];\nconst sha256Tulokset = [];\n\nfor (const { koko, iter, label } of KOOT) {\n  const data = Buffer.allocUnsafe(koko).fill(0x42);\n  blake3Tulokset.push(mittaa('BLAKE3', () => hash(data), iter, koko));\n  sha256Tulokset.push(mittaa('SHA-256', () => createHash('sha256').update(data).digest(), iter, koko));\n}\n\nconsole.log('BLAKE3       ', blake3Tulokset.map(r => r.mbps.padStart(7) + ' MB\/s').join(' | '));\nconsole.log('SHA-256      ', sha256Tulokset.map(r => r.mbps.padStart(7) + ' MB\/s').join(' | '));\n\nconst suhde = blake3Tulokset.map((b, i) =>\n  (parseInt(b.mbps) \/ parseInt(sha256Tulokset[i].mbps)).toFixed(1) + 'x'\n);\nconsole.log('Suhde         ', suhde.map(s => s.padStart(7)).join('       | '));<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Tyypilliset tulokset modernilla x86_64-palvelimella Node.js 20.x:ll\u00e4 natiivisidonnalla:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Algoritmi<\/th><th>64 B<\/th><th>1 kt<\/th><th>64 kt<\/th><th>1 Mt<\/th><\/tr><\/thead><tbody><tr><td><strong>BLAKE3<\/strong><\/td><td>~950 MB\/s<\/td><td>~2 800 MB\/s<\/td><td>~5 100 MB\/s<\/td><td>~5 800 MB\/s<\/td><\/tr><tr><td>SHA-256<\/td><td>~820 MB\/s<\/td><td>~1 400 MB\/s<\/td><td>~1 700 MB\/s<\/td><td>~1 700 MB\/s<\/td><\/tr><tr><td>Suhde<\/td><td>1,2x<\/td><td>2,0x<\/td><td>3,0x<\/td><td>3,4x<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Suorituskykyetu kasvaa sy\u00f6tteen koon mukana, koska BLAKE3:n Merkle-puurakenne hy\u00f6dynt\u00e4\u00e4 prosessorin v\u00e4limuistihierarkiaa paremmin kuin SHA-256:n per\u00e4kk\u00e4inen kompressiorakenne. Pienill\u00e4 sy\u00f6tteill\u00e4 ero on v\u00e4h\u00e4inen, suurilla (yli 64 kt) BLAKE3 on 3 kertaa nopeampi.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-9-content-addressable-storage-tiedostovarastona\">Vaihe 9: Content-addressable storage tiedostovarastona<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Content-addressable storage (CAS) tallentaa tiedostot niiden tiivisteen perusteella nimettyin\u00e4. Git k\u00e4ytt\u00e4\u00e4 vastaavaa rakennetta SHA-256:n kanssa. BLAKE3 on ihanteellinen CAS:iin suuren nopeutensa ansiosta. Luo <code>src\/cas.mjs<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { hash } from 'blake3';\nimport { writeFile, readFile, mkdir, access } from 'fs\/promises';\nimport { join } from 'path';\nimport { constants } from 'fs';\n\nconst VARASTO = '.\/blake3-cas';\n\nasync function tallenna(data) {\n  const tiiviste = hash(Buffer.isBuffer(data) ? data : Buffer.from(data)).toString('hex');\n  const hakemisto = join(VARASTO, tiiviste.slice(0, 2));\n  const polku = join(hakemisto, tiiviste);\n\n  \/\/ \u00c4l\u00e4 kirjoita uudelleen, jos jo olemassa (sis\u00e4lt\u00f6 identtinen tiivisteen perusteella)\n  try {\n    await access(polku, constants.F_OK);\n    return tiiviste; \/\/ Jo tallennettu\n  } catch { \/* ei olemassa, jatka *\/ }\n\n  await mkdir(hakemisto, { recursive: true });\n  await writeFile(polku, Buffer.isBuffer(data) ? data : Buffer.from(data));\n  return tiiviste;\n}\n\nasync function hae(tiiviste) {\n  const polku = join(VARASTO, tiiviste.slice(0, 2), tiiviste);\n  const data = await readFile(polku);\n  \/\/ Todenna eheys latauksen j\u00e4lkeen\n  const tarkistus = hash(data).toString('hex');\n  if (tarkistus !== tiiviste) {\n    throw new Error(`Eheysvirhe: odotettu ${tiiviste}, laskettu ${tarkistus}`);\n  }\n  return data;\n}\n\n\/\/ Testi\nconst osoite = await tallenna('T\u00e4rke\u00e4 dokumentti 2026');\nconsole.log('Tallennettu:', osoite);\n\nconst haettu = await hae(osoite);\nconsole.log('Haettu:', haettu.toString('utf8'));\n\n\/\/ Sama sis\u00e4lt\u00f6 tallennetaan vain kerran\nconst osoite2 = await tallenna('T\u00e4rke\u00e4 dokumentti 2026');\nconsole.log('Sama osoite:', osoite === osoite2); \/\/ true<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-10-yksikkotestit-ja-ci-cd-integrointi\">Vaihe 10: Yksikk\u00f6testit ja CI\/CD-integrointi<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Node.js 20.x:ss\u00e4 on sis\u00e4\u00e4nrakennettu testikehys. Luo <code>test\/hash.test.mjs<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { describe, it } from 'node:test';\nimport assert from 'node:assert\/strict';\nimport { hash, keyedHash, derive, createHash } from 'blake3';\n\ndescribe('BLAKE3 perustiiviste', () => {\n  it('tuottaa 32-tavuisen oletustulosteen', () => {\n    const tulos = hash(Buffer.from('testi', 'utf8'));\n    assert.equal(tulos.length, 32);\n  });\n\n  it('tuottaa muuttuvan pituisen tulosteen', () => {\n    const tulos = hash(Buffer.from('testi', 'utf8'), { length: 64 });\n    assert.equal(tulos.length, 64);\n  });\n\n  it('sama sy\u00f6te tuottaa aina saman tiivisteen', () => {\n    const syote = Buffer.from('deterministinen', 'utf8');\n    assert.equal(hash(syote).toString('hex'), hash(syote).toString('hex'));\n  });\n\n  it('eri sy\u00f6tteet tuottavat eri tiivisteet', () => {\n    assert.notEqual(\n      hash(Buffer.from('a', 'utf8')).toString('hex'),\n      hash(Buffer.from('b', 'utf8')).toString('hex')\n    );\n  });\n\n  it('tyhj\u00e4 sy\u00f6te toimii', () => {\n    const tulos = hash(Buffer.alloc(0));\n    assert.equal(tulos.length, 32);\n  });\n});\n\ndescribe('BLAKE3 stream-rajapinta', () => {\n  it('tuottaa saman tuloksen kuin suora hash()', () => {\n    const data = Buffer.from('stream-testi', 'utf8');\n    const hasher = createHash();\n    hasher.update(data);\n    const streamTulos = hasher.digest('hex');\n    const suoraTulos = hash(data).toString('hex');\n    assert.equal(streamTulos, suoraTulos);\n  });\n\n  it('useat update()-kutsut toimivat', () => {\n    const hasher = createHash();\n    hasher.update(Buffer.from('osa1', 'utf8'));\n    hasher.update(Buffer.from('osa2', 'utf8'));\n    const streamTulos = hasher.digest('hex');\n    const suoraTulos = hash(Buffer.from('osa1osa2', 'utf8')).toString('hex');\n    assert.equal(streamTulos, suoraTulos);\n  });\n});\n\ndescribe('BLAKE3 avaimellinen hajautus', () => {\n  it('vaatii tarkalleen 32-tavuisen avaimen', () => {\n    const avain = Buffer.alloc(32, 0x01);\n    const mac = keyedHash(avain, Buffer.from('viesti', 'utf8'));\n    assert.equal(mac.length, 32);\n  });\n\n  it('eri avain tuottaa eri MAC:n', () => {\n    const viesti = Buffer.from('sama viesti', 'utf8');\n    const mac1 = keyedHash(Buffer.alloc(32, 0x01), viesti).toString('hex');\n    const mac2 = keyedHash(Buffer.alloc(32, 0x02), viesti).toString('hex');\n    assert.notEqual(mac1, mac2);\n  });\n});\n\ndescribe('BLAKE3 avainten johdannainen', () => {\n  it('eri konteksti tuottaa eri avaimen', () => {\n    const materiaali = Buffer.alloc(32, 0xFF);\n    const k1 = derive('konteksti-A', materiaali).toString('hex');\n    const k2 = derive('konteksti-B', materiaali).toString('hex');\n    assert.notEqual(k1, k2);\n  });\n\n  it('sama konteksti ja materiaali tuottavat saman avaimen', () => {\n    const materiaali = Buffer.alloc(32, 0xAB);\n    const k1 = derive('sama-konteksti', materiaali).toString('hex');\n    const k2 = derive('sama-konteksti', materiaali).toString('hex');\n    assert.equal(k1, k2);\n  });\n});<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Aja testit Node.js:n omalla testikehyksell\u00e4:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>node --test test\/hash.test.mjs\n\n# Odotettu tuloste:\n# \u2714 BLAKE3 perustiiviste > tuottaa 32-tavuisen oletustulosteen (1.23ms)\n# \u2714 BLAKE3 perustiiviste > tuottaa muuttuvan pituisen tulosteen (0.45ms)\n# \u2714 BLAKE3 perustiiviste > sama sy\u00f6te tuottaa aina saman tiivisteen (0.12ms)\n# \u2714 BLAKE3 perustiiviste > eri sy\u00f6tteet tuottavat eri tiivisteet (0.11ms)\n# \u2714 BLAKE3 perustiiviste > tyhj\u00e4 sy\u00f6te toimii (0.09ms)\n# \u2714 BLAKE3 stream-rajapinta > tuottaa saman tuloksen kuin suora hash() (0.18ms)\n# \u2714 BLAKE3 stream-rajapinta > useat update()-kutsut toimivat (0.14ms)\n# \u2714 BLAKE3 avaimellinen hajautus > vaatii tarkalleen 32-tavuisen avaimen (0.11ms)\n# \u2714 BLAKE3 avaimellinen hajautus > eri avain tuottaa eri MAC:n (0.13ms)\n# \u2714 BLAKE3 avainten johdannainen > eri konteksti tuottaa eri avaimen (0.10ms)\n# \u2714 BLAKE3 avainten johdannainen > sama konteksti ja materiaali tuottavat saman avaimen (0.09ms)\n# \u2139 tests 11\n# \u2139 pass 11\n# \u2139 fail 0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Lis\u00e4\u00e4 testit GitHub Actions -putkeen (<code>.github\/workflows\/ci.yml<\/code>):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name: BLAKE3 CI\non: [push, pull_request]\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-version: [20.x, 22.x]\n    steps:\n      - uses: actions\/checkout@v4\n      - uses: actions\/setup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: 'npm'\n      - run: npm ci\n      - run: node --test test\/hash.test.mjs<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"5-yleista-virhetta-blake3n-kaytossa-node-jsssa\">5 yleist\u00e4 virhett\u00e4 BLAKE3:n k\u00e4yt\u00f6ss\u00e4 Node.js:ss\u00e4<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Seuraavat virheet toistuvat usein kehitt\u00e4jien ottaessa BLAKE3:a k\u00e4ytt\u00f6\u00f6n ensimm\u00e4ist\u00e4 kertaa.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Virhe 1: Merkkijonon suora sy\u00f6tt\u00e4minen ilman enkoodausta.<\/strong> blake3-paketti hyv\u00e4ksyy merkkijonot, mutta enkoodaus voi vaihdella kontekstin mukaan. Turvallisin tapa on aina muuntaa <code>Buffer.from(str, 'utf8')<\/code>-muotoon. Ilman eksplisiittist\u00e4 enkoodausta eri alustojen v\u00e4lill\u00e4 voi synty\u00e4 tiivistepoikkeamia, joita on vaikea debugata.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Virhe 2: V\u00e4\u00e4r\u00e4 avaimen pituus keyedHash()-funktiossa.<\/strong> Avaimellinen hajautus vaatii tarkalleen 32 tavua. Liian lyhyt tai pitk\u00e4 avain aiheuttaa poikkeuksen <code>key must be 32 bytes<\/code>. Yleinen sudenkuoppa on k\u00e4ytt\u00e4\u00e4 salasanaa tai muuta muuttuvan pituisen merkkijonon suoraan avaimena:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ V\u00c4\u00c4RIN: salasana ei ole 32 tavua\nconst avain = Buffer.from('salasana', 'utf8'); \/\/ vain 8 tavua\nkeyedHash(avain, data); \/\/ Heitt\u00e4\u00e4 virheen!\n\n\/\/ OIKEIN: johda 32-tavuinen avain salasanasta\nimport { scryptSync } from 'crypto';\nconst avain32 = scryptSync('salasana', 'suola', 32);\nkeyedHash(avain32, data); \/\/ Toimii<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Virhe 3: Timing-safe vertailun laiminly\u00f6nti.<\/strong> Tiivisteen vertailu <code>===<\/code>-operaattorilla on altis ajoitushy\u00f6kk\u00e4yksille, koska JavaScript palaa heti ensimm\u00e4isest\u00e4 poikkeavasta merkist\u00e4. K\u00e4yt\u00e4 aina <code>crypto.timingSafeEqual()<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ V\u00c4\u00c4RIN: vuotaa tietoa ajoituksen kautta\nif (laskettuMac.toString('hex') === asiakkaanMac) { ... }\n\n\/\/ OIKEIN: vakioaikainen vertailu\nimport { timingSafeEqual } from 'crypto';\nif (timingSafeEqual(laskettuMac, Buffer.from(asiakkaanMac, 'hex'))) { ... }<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Virhe 4: createHash()-objektin uudelleenk\u00e4ytt\u00f6 digest()-kutsun j\u00e4lkeen.<\/strong> Kun <code>hasher.digest()<\/code> kutsutaan, objekti merkit\u00e4\u00e4n p\u00e4\u00e4ttyneeksi. Uusi <code>hasher.update()<\/code> sen j\u00e4lkeen ei tuota oikeaa tulosta. Luo aina uusi instanssi jokaista erillist\u00e4 hajautusta varten.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Virhe 5: BLAKE3:n k\u00e4ytt\u00f6 salasanojen tiivistykseen.<\/strong> BLAKE3 on suunniteltu nopeudelle, mik\u00e4 on t\u00e4sm\u00e4lleen p\u00e4invastainen ominaisuus kuin mit\u00e4 salasanojen suojauksessa tarvitaan. Nopea hajautusfunktio tekee brute-force-hy\u00f6kk\u00e4yksest\u00e4 tehokkaampaa. Salasanoihin k\u00e4yt\u00e4 aina tarkoitukseen suunniteltua KDF:\u00e4\u00e4: Argon2id (suositeltavin 2026), bcrypt tai scrypt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vianmaaritys-8-yleista-ongelmaa-ratkaisuineen\">Vianm\u00e4\u00e4ritys: 8 yleist\u00e4 ongelmaa ratkaisuineen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ongelma 1: node-gyp k\u00e4\u00e4nt\u00e4minen ep\u00e4onnistuu Windowsilla.<\/strong> Virheviesti: <code>gyp ERR! build error<\/code>. Ratkaisu: asenna Visual Studio Build Tools 2019 tai uudempi C++-ty\u00f6kuormalla. Jos k\u00e4\u00e4nt\u00e4j\u00e4\u00e4 ei voi asentaa, k\u00e4yt\u00e4 <code>npm install blake3@3.0.0 --ignore-scripts<\/code>, jolloin paketti k\u00e4ytt\u00e4\u00e4 WebAssembly-toteutusta.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ongelma 2: ESM-yhteensopivuusvirhe CommonJS-ymp\u00e4rist\u00f6ss\u00e4.<\/strong> Virheviesti: <code>SyntaxError: Cannot use import statement in a CommonJS module<\/code>. Ratkaisu: lis\u00e4\u00e4 <code>\"type\": \"module\"<\/code> package.json:iin tai k\u00e4yt\u00e4 dynaamista importia: <code>const { hash } = await import('blake3')<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ongelma 3: Suorituskyky on odotettua heikompi.<\/strong> Tarkista, onko natiivinen sidonta aktiiivinen vai WASM-varaj\u00e4rjestelm\u00e4 k\u00e4yt\u00f6ss\u00e4. Jos <code>npm rebuild blake3<\/code> ei auta, asenna ensin <code>node-gyp<\/code> globaalisti: <code>npm install -g node-gyp<\/code>, ja varmista Python 3 ja C++-k\u00e4\u00e4nt\u00e4j\u00e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ongelma 4: Eri alustojen tuottamat tiivisteet eroavat.<\/strong> BLAKE3 on t\u00e4ysin deterministinen. Jos saat eri tiivisteen samasta sy\u00f6tteest\u00e4 eri alustoilla, syy on l\u00e4hes aina enkoodauserot. Tarkista, ett\u00e4 sy\u00f6te on <code>Buffer<\/code>-objekti, ei merkkijono.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ongelma 5: Muistivuoto pitk\u00e4aikaisessa server-k\u00e4yt\u00f6ss\u00e4.<\/strong> createHash()-objekteja ei saa j\u00e4tt\u00e4\u00e4 roikkumaan. Pipeline-k\u00e4yt\u00f6ss\u00e4 varmista <code>pipeline()<\/code>-funktion oikea k\u00e4ytt\u00f6 ja that stream sulkeutuu virheen sattuessa. Lis\u00e4\u00e4 <code>try\/finally<\/code>-rakenne kriittisiin kohtiin.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ongelma 6: derive()-funktio tuottaa eri tulokset eri paketin versioissa.<\/strong> Blake3 3.0.0 teki murtavan muutoksen. Lukitse versio tarkasti: <code>\"blake3\": \"3.0.0\"<\/code> (ei <code>^3.0.0<\/code>). K\u00e4yt\u00e4 <code>npm ci<\/code> CI\/CD-putkessa, ei <code>npm install<\/code>, jotta versio pysyy kiinnitettyn\u00e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ongelma 7: TypeScript-tyypit eiv\u00e4t l\u00f6ydy.<\/strong> Varmista, ett\u00e4 <code>tsconfig.json<\/code>:ssa on <code>\"moduleResolution\": \"bundler\"<\/code> tai <code>\"node16\"<\/code>. Vaihtoehto: k\u00e4yt\u00e4 <code>@noble\/hashes<\/code>-pakettia, joka on kirjoitettu alun perin TypeScriptill\u00e4 ja jonka tyypit ovat t\u00e4ydelliset.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ongelma 8: Testit ep\u00e4onnistuvat rinnakkaisessa ajossa.<\/strong> createHash()-instanssi ei ole s\u00e4ievarmistettu. Jokaisessa testiss\u00e4 t\u00e4ytyy olla oma instanssi. Jos testit jakavat yhteist\u00e4 tilaa ep\u00e4huomiossa, lis\u00e4\u00e4 <code>beforeEach<\/code>-koukku, joka luo uuden hasher-objektin.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"edistyneet-tekniikat-tuotantokayttoon\">Edistyneet tekniikat tuotantok\u00e4ytt\u00f6\u00f6n<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"worker-threads-rinnakkaistamiseen\">Worker Threads rinnakkaistamiseen<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Node.js:n yksis\u00e4ikeinen tapahtumasilmukka rajoittaa BLAKE3:n Merkle-puun rinnakkaistamisen hy\u00f6ty\u00e4. Worker Threads -laajennuksella voit jakaa suuren tiedoston paloihin ja k\u00e4sitell\u00e4 ne rinnakkaisesti. K\u00e4yt\u00e4nn\u00f6llisin jako: jaetaan tiedosto 1 Mt:n segmentteihin, lasketaan segmenttikohtaiset tiivisteet erillisess\u00e4 s\u00e4ikeess\u00e4 ja yhdistet\u00e4\u00e4n koko tiedoston tiiviste p\u00e4\u00e4s\u00e4ikeess\u00e4. T\u00e4m\u00e4 on hy\u00f6dyllist\u00e4, kun tiedostoja on useita kymmeni\u00e4 prosessoitavana yht\u00e4 aikaa.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"noble-hashes-vaihtoehtona-serverless-ymparistoissa\">@noble\/hashes vaihtoehtona serverless-ymp\u00e4rist\u00f6iss\u00e4<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Jos natiivinen sidonta ei ole mahdollinen, esimerkiksi Cloudflare Workers tai AWS Lambda -ymp\u00e4rist\u00f6iss\u00e4, <code>@noble\/hashes<\/code> versio 2.2.0 on paras vaihtoehto. Se on tietoturva-auditoitu, kirjoitettu puhtaasti TypeScriptill\u00e4 ja toimii ilman build-riippuvuuksia:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { blake3 } from '@noble\/hashes\/blake3';\nimport { bytesToHex } from '@noble\/hashes\/utils';\n\n\/\/ Perustiiviste\nconst tiiviste = blake3(new TextEncoder().encode('Hei Suomi'));\nconsole.log(bytesToHex(tiiviste));\n\n\/\/ Avaimellinen hajautus\nconst avain = new Uint8Array(32).fill(1);\nconst mac = blake3(new TextEncoder().encode('viesti'), { key: avain });\n\n\/\/ Avainten johdannainen\nconst johdettu = blake3(new TextEncoder().encode('materiaali'), {\n  context: 'sovellus 2026 avainjohdannainen v1'\n});\nconsole.log('Johdettu avain:', bytesToHex(johdettu));<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Sama koodirakenne toimii selaimessa, Deno:ssa, Bun:issa ja Node.js:ss\u00e4. Ed25519-allekirjoituksiin (katso <a href=\"\/fi\/ed25519-allekirjoitus-nodejs\/\">Ed25519 Node.js:ss\u00e4 -opas<\/a>) noble-kirjasto tarjoaa identtisen l\u00e4hestymistavan auditoidun koodin kanssa.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"webhook-allekirjoitusten-varmentaminen-tuotannossa\">Webhook-allekirjoitusten varmentaminen tuotannossa<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">BLAKE3:n avaimellinen hajautus on nopein tapa varmentaa webhook-allekirjoituksia, kuten Stripe- tai GitHub-webhookeja, jos molemmat osapuolet k\u00e4ytt\u00e4v\u00e4t BLAKE3:a. K\u00e4yt\u00e4nn\u00f6ss\u00e4 useimmat palvelut l\u00e4hett\u00e4v\u00e4t HMAC-SHA256-allekirjoituksen, joten vertailu tapahtuu <code>crypto.createHmac('sha256', avain)<\/code>-funktiolla. BLAKE3-MAC sopii parhaiten sovelluksen sis\u00e4isiin rajapintoihin, joissa molemmat p\u00e4\u00e4t ovat hallinnassasi.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"milloin-blake3-ei-ole-oikea-valinta\">Milloin BLAKE3 ei ole oikea valinta<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">BLAKE3 ei sovi kaikkiin tilanteisiin. Seuraavat k\u00e4ytt\u00f6tapaukset vaativat muun algoritmin:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>TLS-sertifikaatit ja X.509:<\/strong> Sertifikaattiviranomaisten allekirjoitukset k\u00e4ytt\u00e4v\u00e4t SHA-256 tai SHA-384:\u00e4. BLAKE3 ei ole FIPS-hyv\u00e4ksytty eik\u00e4 CA\/Browser Forumin sallima.<\/li><li><strong>Salasanojen tiivist\u00e4minen:<\/strong> BLAKE3 on liian nopea suojaamaan salasanoja. K\u00e4yt\u00e4 Argon2id:t\u00e4 tai bcrypt:\u00e4, jotka on suunniteltu hidastamaan brute-force-hy\u00f6kk\u00e4yksi\u00e4.<\/li><li><strong>FIPS 140-2\/3 -ymp\u00e4rist\u00f6t:<\/strong> BLAKE3 ei kuulu NIST:n hyv\u00e4ksymiin algoritmeihin. K\u00e4yt\u00e4 SHA-2 tai SHA-3 -perheen algoritmeja.<\/li><li><strong>Standardin velvoittamat digitaaliset allekirjoitukset:<\/strong> RSA-PKCS1 ja ECDSA k\u00e4ytt\u00e4v\u00e4t SHA-256:ta tai SHA-512:a standardin mukaan. BLAKE3-pohjainen allekirjoitusj\u00e4rjestelm\u00e4 ei ole yhteensopiva vakioprotokollien kanssa.<\/li><li><strong>Vanha j\u00e4rjestelm\u00e4integraatio:<\/strong> Jos toinen j\u00e4rjestelm\u00e4 odottaa SHA-256-tiivistett\u00e4, BLAKE3 ei ole suoraan korvattavissa ilman molempien p\u00e4iden muuttamista.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"usein-kysytyt-kysymykset\">Usein kysytyt kysymykset<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Onko BLAKE3 turvallinen tuotantok\u00e4ytt\u00f6\u00f6n vuonna 2026?<\/strong> Kyll\u00e4. BLAKE3:a on analysoitu kryptografiyhteis\u00f6n toimesta vuodesta 2020, eik\u00e4 merkitt\u00e4vi\u00e4 haavoittuvuuksia ole l\u00f6ydetty. Solana k\u00e4ytt\u00e4\u00e4 algoritmia tuotannossa tilihajautuksiin. Se ei kuitenkaan ole FIPS-hyv\u00e4ksytty, joten FIPS-ymp\u00e4rist\u00f6ihin se ei sovi.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Voinko korvata SHA-256:n BLAKE3:lla kaikessa koodissani?<\/strong> Ei kaikessa. Protokollapohjaisessa koodissa (JWT, TLS, S3-allekirjoitukset) SHA-256 on pakollinen standardi. Sovelluksen sis\u00e4isess\u00e4 logiikassa BLAKE3 on usein parempi valinta nopeuden ja monipuolisuutensa ansiosta.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Mit\u00e4 eroa on blake3-paketilla ja @noble\/hashes-paketilla?<\/strong> blake3-paketti k\u00e4ytt\u00e4\u00e4 natiivista C++-sidontaa tai WebAssembly\u00e4, mik\u00e4 tekee siit\u00e4 nopeamman erityisesti suurilla sy\u00f6tteill\u00e4. @noble\/hashes on puhdas TypeScript-toteutus, joka on tietoturva-auditoitu ja toimii ilman build-riippuvuuksia. Palvelimilla blake3 on yleens\u00e4 nopeampi, serverless-ymp\u00e4rist\u00f6iss\u00e4 @noble\/hashes on k\u00e4yt\u00e4nn\u00f6llisempi.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Kuinka suuri suorituskykyero on k\u00e4yt\u00e4nn\u00f6ss\u00e4 Node.js:ss\u00e4?<\/strong> Natiivisidonnalla BLAKE3 on noin 3,4 kertaa nopeampi kuin SHA-256 megatavun sy\u00f6tteill\u00e4 x86_64-arkkitehtuurilla. Alle 1 kilotavun sy\u00f6tteill\u00e4 ero on 20 prosenttia. WASM-varaj\u00e4rjestelm\u00e4ll\u00e4 ero kutistuu merkitt\u00e4v\u00e4sti.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Toimiiko BLAKE3 selainymp\u00e4rist\u00f6ss\u00e4?<\/strong> Kyll\u00e4. blake3-paketti sis\u00e4lt\u00e4\u00e4 WASM-sidonnan, joka toimii selaimessa. @noble\/hashes toimii my\u00f6s suoraan ilman WASM:a. Voit jakaa saman hajautuskoodin Node.js:n ja selaimen v\u00e4lill\u00e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Mit\u00e4 tapahtuu, jos muutan kontekstia derive()-kutsussa tuotannossa?<\/strong> Kontekstin muuttaminen tuottaa t\u00e4ysin eri avaimet. Kaikki aiemmin johdetut avaimet muuttuvat, mik\u00e4 tekee tallennetusta salatusta datasta purettamatonta. Kontekstimerkint\u00e4 t\u00e4ytyy olla muuttumaton koko sovelluksen elinkaaren ajan.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Voiko BLAKE3:a k\u00e4ytt\u00e4\u00e4 satunnaistiedon korvaajana?<\/strong> BLAKE3 KDF sopii avainten johdannaiseen deterministisest\u00e4 materiaalista, kuten DH-avaintenvaihdon tuloksesta. Se ei korvaa kryptografisesti turvallista satunnaislukugeneraattoria (CSPRNG). K\u00e4yt\u00e4 <code>crypto.randomBytes()<\/code>, kun avain tarvitaan t\u00e4ysin satunnaisena.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Miten BLAKE3 vertautuu SHA-3:een turvallisuudessa?<\/strong> Turvallisuusominaisuudet ovat k\u00e4yt\u00e4nn\u00f6ss\u00e4 samat 256-bittisell\u00e4 tulospiituudella: 128 bitin t\u00f6rm\u00e4yskest\u00e4vyys molemmissa. SHA-3 perustuu Keccak-sponge-rakenteeseen, BLAKE3 Merkle-puuhun. SHA-3 on NIST-standardisoitu ja FIPS-hyv\u00e4ksytty, BLAKE3 on nopeampi mutta ei standardisoitu.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Onko BLAKE3:lle olemassa referenssitoteutus muille kielille?<\/strong> Kyll\u00e4. Viralliset toteutukset l\u00f6ytyv\u00e4t Rustille, C:lle, Pythonille, Javalle ja Go:lle osoitteesta <a href=\"https:\/\/github.com\/BLAKE3-team\/BLAKE3\" target=\"_blank\" rel=\"noreferrer noopener\">github.com\/BLAKE3-team\/BLAKE3<\/a>. Yhteensopivuus on taattu: sama sy\u00f6te tuottaa saman tiivisteen kaikissa virallisjulkaistuissa toteutuksissa.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"aiheeseen-liittyvat-artikkelit\">Aiheeseen liittyv\u00e4t artikkelit<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"aiheeseen-liittyva-sisalto\">Aiheeseen liittyv\u00e4 sis\u00e4lt\u00f6<\/h3>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"\/fi\/sha-256\/\">SHA-256 selitettyn\u00e4: SHA-2-perheen ty\u00f6juhta<\/a> - vertailukohde BLAKE3:n nopeusedulle<\/li><li><a href=\"\/fi\/hmac-node-js\/\">HMAC Node.js:ss\u00e4: 10 vaihetta, 30 min<\/a> - viestien autentikointi SHA-256-pohjaisella MAC:lla<\/li><li><a href=\"\/fi\/ed25519-allekirjoitus-nodejs\/\">Ed25519 Node.js:ss\u00e4: 10 vaihetta, 30 min<\/a> - digitaaliset allekirjoitukset elliptisill\u00e4 k\u00e4yrill\u00e4<\/li><li><a href=\"\/fi\/cryptography-hub\/\">Kryptografia: tiivistefunktiot ja luottamuksen perusta verkossa<\/a> - kattava johdatus kryptografian perusteisiin<\/li><li><a href=\"\/fi\/https-ja-tls\/\">HTTPS ja TLS: miten salattu yhteys suojaa sinua<\/a> - TLS-protokollan tiivistefunktioiden k\u00e4ytt\u00f6<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Lis\u00e4tietoja BLAKE3:n virallisesta spesifikaatiosta l\u00f6ytyy osoitteesta <a href=\"https:\/\/blake3.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">blake3.io<\/a> ja GitHub-repositoriosta <a href=\"https:\/\/github.com\/BLAKE3-team\/BLAKE3\" target=\"_blank\" rel=\"noreferrer noopener\">BLAKE3-team\/BLAKE3<\/a>. Node.js:n <a href=\"https:\/\/nodejs.org\/api\/crypto.html\" target=\"_blank\" rel=\"noreferrer noopener\">crypto-moduulin dokumentaatio<\/a> k\u00e4sittelee sis\u00e4\u00e4nrakennetut hajautusalgoritmit, ja <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Glossary\/Hash\" target=\"_blank\" rel=\"noreferrer noopener\">MDN Web Docs selitt\u00e4\u00e4 hajautusfunktioiden<\/a> yleisen toimintaperiaatteen.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>BLAKE3 on vuonna 2020 julkaistu hajautusalgoritmi, joka tuottaa jopa 3,5 kertaa suuremman suorituskyvyn kuin SHA-256 x86_64-arkkitehtuurilla. Algoritmilla on puumainen rinnakkaisrakenne, 128 bitin t\u00f6rm\u00e4yskest\u00e4vyys ja laajennettava tulospiituus, joten se sopii erinomaisesti\u2026<\/p>\n","protected":false},"author":6,"featured_media":99,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,2],"tags":[],"class_list":["post-98","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-10","category-cryptography"],"_links":{"self":[{"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/posts\/98","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/comments?post=98"}],"version-history":[{"count":1,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/posts\/98\/revisions"}],"predecessor-version":[{"id":100,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/posts\/98\/revisions\/100"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/media\/99"}],"wp:attachment":[{"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/media?parent=98"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/categories?post=98"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/tags?post=98"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}