CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-polkadot--wasm-crypto

WebAssembly interface layer providing high-performance cryptographic functions for blockchain applications in the Polkadot ecosystem.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

key-derivation.mddocs/

Key Derivation Functions

Password-based key derivation functions for generating cryptographic keys from passwords and salts, including PBKDF2 and Scrypt algorithms.

Capabilities

PBKDF2 Key Derivation

Password-Based Key Derivation Function 2 (PBKDF2) for deriving cryptographic keys from passwords.

/**
 * Derives key using PBKDF2
 * @param data - Password data as Uint8Array
 * @param salt - Salt as Uint8Array (recommended: at least 16 bytes)
 * @param rounds - Number of iterations (recommended: at least 10,000)
 * @returns 64-byte derived key as Uint8Array
 */
function pbkdf2(data: Uint8Array, salt: Uint8Array, rounds: number): Uint8Array;

Usage Example:

import { waitReady, pbkdf2 } from "@polkadot/wasm-crypto";

await waitReady();

const password = new TextEncoder().encode("my-secure-password");
const salt = new Uint8Array(16);
crypto.getRandomValues(salt); // Generate random salt

// Derive key with different iteration counts
const key10k = pbkdf2(password, salt, 10000);
const key100k = pbkdf2(password, salt, 100000);

console.log("PBKDF2 key length:", key10k.length); // 64
console.log("Keys are different:", 
  Array.from(key10k).join(',') !== Array.from(key100k).join(',')
); // true

Scrypt Key Derivation

Scrypt key derivation function designed to be memory-hard and resist hardware attacks.

/**
 * Derives key using Scrypt
 * @param password - Password as Uint8Array
 * @param salt - Salt as Uint8Array (recommended: at least 16 bytes)
 * @param log2n - CPU/memory cost parameter (power of 2, e.g., 14 = 2^14 = 16384)
 * @param r - Block size parameter (typically 8)
 * @param p - Parallelization parameter (typically 1)
 * @returns 64-byte derived key as Uint8Array
 */
function scrypt(password: Uint8Array, salt: Uint8Array, log2n: number, r: number, p: number): Uint8Array;

Usage Example:

import { waitReady, scrypt } from "@polkadot/wasm-crypto";

await waitReady();

const password = new TextEncoder().encode("my-secure-password");
const salt = new Uint8Array(16);
crypto.getRandomValues(salt); // Generate random salt

// Common Scrypt parameters
const log2n = 14; // N = 2^14 = 16384 (memory cost)
const r = 8;      // Block size
const p = 1;      // Parallelization

const derivedKey = scrypt(password, salt, log2n, r, p);

console.log("Scrypt key length:", derivedKey.length); // 64

Parameter Guidelines

PBKDF2 Parameters

  • Rounds: Minimum 10,000, recommended 100,000+ for high security
  • Salt: At least 16 bytes, preferably 32 bytes of random data
  • Output: Always 64 bytes

Scrypt Parameters

  • log2n: Common values are 12-16 (N = 4096-65536)
    • 12: Low security, fast (N = 4096)
    • 14: Medium security (N = 16384) - good default
    • 16: High security, slower (N = 65536)
  • r: Usually 8 (block size parameter)
  • p: Usually 1 (parallelization parameter)
  • Salt: At least 16 bytes, preferably 32 bytes of random data
  • Output: Always 64 bytes

Security Considerations

import { waitReady, pbkdf2, scrypt } from "@polkadot/wasm-crypto";

async function demonstrateSecureKeyDerivation() {
  await waitReady();
  
  const password = new TextEncoder().encode("user-password");
  
  // Generate cryptographically secure salt
  const salt = new Uint8Array(32);
  crypto.getRandomValues(salt);
  
  // PBKDF2 with high iteration count
  const pbkdf2Key = pbkdf2(password, salt, 100000);
  
  // Scrypt with recommended parameters
  const scryptKey = scrypt(password, salt, 14, 8, 1);
  
  // Store salt alongside derived key for later verification
  const storedData = {
    salt: Array.from(salt),
    pbkdf2Key: Array.from(pbkdf2Key),
    scryptKey: Array.from(scryptKey)
  };
  
  console.log("Salt length:", salt.length); // 32
  console.log("Both keys derived successfully");
  
  return storedData;
}

demonstrateSecureKeyDerivation();

Performance Comparison

import { waitReady, pbkdf2, scrypt } from "@polkadot/wasm-crypto";

async function compareKeyDerivationPerformance() {
  await waitReady();
  
  const password = new TextEncoder().encode("test-password");
  const salt = new Uint8Array(32).fill(1); // Fixed salt for consistent timing
  
  // Time PBKDF2
  console.time("PBKDF2 (100k iterations)");
  const pbkdf2Key = pbkdf2(password, salt, 100000);
  console.timeEnd("PBKDF2 (100k iterations)");
  
  // Time Scrypt
  console.time("Scrypt (N=16384, r=8, p=1)");
  const scryptKey = scrypt(password, salt, 14, 8, 1);
  console.timeEnd("Scrypt (N=16384, r=8, p=1)");
  
  console.log("PBKDF2 result length:", pbkdf2Key.length); // 64
  console.log("Scrypt result length:", scryptKey.length); // 64
  
  return { pbkdf2Key, scryptKey };
}

compareKeyDerivationPerformance();

Complete Key Derivation Workflow

import { waitReady, pbkdf2, scrypt, hmacSha256 } from "@polkadot/wasm-crypto";

async function demonstrateKeyDerivationWorkflow() {
  await waitReady();
  
  // Simulate user registration
  const userPassword = "user-secure-password-123";
  const passwordBytes = new TextEncoder().encode(userPassword);
  
  // Generate unique salt for this user
  const userSalt = new Uint8Array(32);
  crypto.getRandomValues(userSalt);
  
  // Derive master key using Scrypt (more secure for password storage)
  const masterKey = scrypt(passwordBytes, userSalt, 14, 8, 1);
  
  // Derive application-specific keys using HMAC
  const encryptionKey = hmacSha256(masterKey, new TextEncoder().encode("encryption"));
  const authKey = hmacSha256(masterKey, new TextEncoder().encode("authentication"));
  
  // For comparison, also show PBKDF2 derivation
  const pbkdf2MasterKey = pbkdf2(passwordBytes, userSalt, 100000);
  
  console.log("User salt:", Array.from(userSalt.slice(0, 8)).map(b => b.toString(16).padStart(2, '0')).join(''));
  console.log("Scrypt master key:", Array.from(masterKey.slice(0, 8)).map(b => b.toString(16).padStart(2, '0')).join(''));
  console.log("PBKDF2 master key:", Array.from(pbkdf2MasterKey.slice(0, 8)).map(b => b.toString(16).padStart(2, '0')).join(''));
  console.log("Encryption key:", Array.from(encryptionKey.slice(0, 8)).map(b => b.toString(16).padStart(2, '0')).join(''));
  console.log("Auth key:", Array.from(authKey.slice(0, 8)).map(b => b.toString(16).padStart(2, '0')).join(''));
  
  return {
    userSalt,
    masterKey,
    pbkdf2MasterKey,
    encryptionKey,
    authKey
  };
}

demonstrateKeyDerivationWorkflow();

Install with Tessl CLI

npx tessl i tessl/npm-polkadot--wasm-crypto

docs

bip39.md

ed25519.md

hashing.md

index.md

key-derivation.md

secp256k1.md

sr25519.md

vrf.md

tile.json