@blockutil/kheavyhash
v0.1.0
Published
TypeScript/JavaScript implementation of the KHeavyHash algorithm compatible with the Go reference implementation
Maintainers
Readme
@blockutil/kheavyhash
TypeScript/JavaScript implementation of the KHeavyHash algorithm compatible with the Go reference implementation at github.com/bcutil/kheavyhash.
⚠️ Important Notice: This implementation is not optimized for mining purposes and is not intended for mining. It is designed for reference, testing, and educational purposes. For production mining operations, please use optimized implementations.
Features
- ✅ Full TypeScript support with type definitions
- ✅ JavaScript/ES modules compatible
- ✅ Deterministic output matching Go reference implementation
- ✅ Comprehensive test suite following FIRST principles
- ✅ Docker development environment (VS Code/Cursor dev container support)
- ✅ CI/CD ready
- ✅ Zero dependencies (pure TypeScript implementation)
Compatibility
- Node.js: >= 18.0.0
- TypeScript: >= 4.5.0
- JavaScript: ES2022+ (modern browsers and Node.js)
- Module System: ESM (ES Modules) with CommonJS fallback support
Installation
pnpm add @blockutil/kheavyhashor
npm install @blockutil/kheavyhashor
yarn add @blockutil/kheavyhashQuick Start
import { kheavyhash, bytesToHex, hexToBytes } from '@blockutil/kheavyhash';
// Construct 80-byte input
const prePowHash = hexToBytes('0ad86e9bef09726cdc75913e44ec96521391c7ceb2aae3c633f46a94bf4d2546');
// Set timestamp as little-endian 64-bit integer
const timestamp = new Uint8Array(8);
const view = new DataView(timestamp.buffer);
view.setBigUint64(0, BigInt(0x19568d36b3e), true); // true = little-endian
// Padding must be all zeros (32 bytes)
const padding = new Uint8Array(32);
// Set nonce as little-endian 64-bit integer
const nonce = new Uint8Array(8);
view.setBigUint64(0, BigInt(0x571506849306fd39), true); // true = little-endian
// Combine into 80-byte input
const input = new Uint8Array(80);
input.set(prePowHash, 0); // Bytes 0-31
input.set(timestamp, 32); // Bytes 32-39
input.set(padding, 40); // Bytes 40-71 (zeros)
input.set(nonce, 72); // Bytes 72-79
// Hash
const hash = kheavyhash(input);
console.log(bytesToHex(hash)); // 32-byte hash as hex stringUsage Examples
Example 1: Using Hex String Input
import { kheavyhash, bytesToHex } from '@blockutil/kheavyhash';
// All 80 bytes as hex string (160 hex characters)
const hexInput =
'0ad86e9bef09726cdc75913e44ec96521391c7ceb2aae3c633f46a94bf4d2546' + // prePowHash (32 bytes)
'3ed68b9501950000' + // timestamp (8 bytes, little-endian)
'0'.repeat(64) + // padding (32 bytes, must be zeros)
'39fd0630849571'; // nonce (8 bytes, little-endian)
const hash = kheavyhash(hexInput);
console.log(bytesToHex(hash));Example 2: Iterative Hashing (Mining Simulation)
import { kheavyhash, bytesToHex, hexToBytes } from '@blockutil/kheavyhash';
// Initial prePowHash
let prePowHash = hexToBytes('0ad86e9bef09726cdc75913e44ec96521391c7ceb2aae3c633f46a94bf4d2546');
const timestamp = 0x19568d36b3e; // Fixed timestamp
let nonce = 0;
// Mine for multiple iterations
for (let i = 0; i < 1000; i++) {
// Construct input
const input = new Uint8Array(80);
input.set(prePowHash, 0);
// Set timestamp (little-endian)
const timestampBytes = new Uint8Array(8);
const view = new DataView(timestampBytes.buffer);
view.setBigUint64(0, BigInt(timestamp), true);
input.set(timestampBytes, 32);
// Padding (already zeros, no need to set)
// Set nonce (little-endian)
const nonceBytes = new Uint8Array(8);
view.setBigUint64(0, BigInt(nonce), true);
input.set(nonceBytes, 72);
// Hash
const hash = kheavyhash(input);
// Use output as next prePowHash
prePowHash = hash;
// Increment nonce for next iteration
nonce++;
if (i % 100 === 0) {
console.log(`Iteration ${i}: ${bytesToHex(hash)}`);
}
}Example 3: Input Validation
import { validateInput, kheavyhash } from '@blockutil/kheavyhash';
function safeHash(input: unknown): Uint8Array | null {
if (!validateInput(input)) {
console.error('Invalid input: must be 80-byte Uint8Array or 160-char hex string');
return null;
}
try {
return kheavyhash(input);
} catch (error) {
console.error('Hash failed:', error);
return null;
}
}
// Usage
const hash1 = safeHash(new Uint8Array(80)); // ✅ Valid
const hash2 = safeHash('0'.repeat(160)); // ✅ Valid
const hash3 = safeHash(new Uint8Array(79)); // ❌ Invalid (wrong length)Input Format
KHeavyHash requires exactly 80 bytes with the following structure:
| Bytes | Field | Size | Description | Endianness |
| ----- | ------------ | -------- | --------------------------- | ----------------- |
| 0-31 | prePowHash | 32 bytes | Previous proof-of-work hash | N/A |
| 32-39 | timestamp | 8 bytes | Block timestamp | Little-endian |
| 40-71 | padding | 32 bytes | Must be all zeros | N/A |
| 72-79 | nonce | 8 bytes | Mining nonce | Little-endian |
Important Notes:
- The
timestampandnoncemust be encoded as little-endian 64-bit integers - The
paddingfield (bytes 40-71) must be all zeros - Total input must be exactly 80 bytes (160 hex characters if using hex string)
API Reference
For complete API documentation, see API.md.
Main exports:
kheavyhash(input: Uint8Array | string): Uint8Array- Main hash functionvalidateInput(input: unknown): boolean- Input validation type guardhexToBytes(hex: string): Uint8Array- Convert hex string to bytesbytesToHex(bytes: Uint8Array, prefix?: boolean): string- Convert bytes to hex string
All functions are fully documented with JSDoc comments. Use your IDE's IntelliSense for inline documentation.
Development
Prerequisites
- Node.js >= 18.0.0
- pnpm >= 8.0.0 (or npm/yarn)
Setup
# Install dependencies
pnpm install
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Build
pnpm build
# Lint
pnpm lint
# Format code
pnpm format
# Type check
pnpm type-checkDocker Development
This project includes a Docker development environment for consistent builds:
# Build and start container
docker-compose up -d
# Run commands in container
docker-compose exec kheavyhash pnpm test
docker-compose exec kheavyhash pnpm build
# Stop container
docker-compose downVS Code / Cursor Dev Container
The project includes a .devcontainer configuration for VS Code and Cursor:
- Open the project in VS Code/Cursor
- When prompted, click "Reopen in Container"
- The development environment will be set up automatically
Testing
This project follows FIRST principles for unit testing:
- Fast: Tests run quickly with no external dependencies
- Independent: Each test is isolated and independent
- Repeatable: Tests produce deterministic results
- Self-Validating: Clear pass/fail outcomes
- Timely: Tests written alongside implementation
Test Suites
# Run all tests
pnpm test
# Run tests with coverage
pnpm test:coverage
# Run tests in watch mode
pnpm test:watchTest Vectors
Test vectors from the Go reference implementation are available in test/kheavyhash-vectors.test.ts. These validate the implementation against known outputs from github.com/bcutil/kheavyhash.
Iteration Testing
Test 1000 iterations by feeding output back as input:
# TypeScript-only test
pnpm test:iterations
# Compare with Go implementation (requires Go)
pnpm test:iterations:goExtended Comparison Script
Compare the TypeScript implementation with the Go reference implementation side-by-side:
# Test if Go module is accessible
bash scripts/test-go-module.sh
# Using bash script (requires Go and built TypeScript)
bash scripts/compare-with-go.sh
# Using TypeScript script (requires Go, tsx, and built TypeScript)
pnpm test:comparePrerequisites for comparison script:
- Go must be installed
- Go module
github.com/bcutil/kheavyhashmust be available - TypeScript implementation must be built (
pnpm build)
Versioning
This project follows Semantic Versioning (SemVer 2.0.0).
Version Format
MAJOR.MINOR.PATCHVersion Bump Rules
- MAJOR version: Incompatible API changes
- MINOR version: Backward-compatible new features
- PATCH version: Backward-compatible bug fixes
Current Version
- Current:
0.1.0(pre-release) - Stability: Pre-1.0.0 versions may have breaking changes
Version History
See CHANGELOG.md (if available) or git history for version history.
Contributing
This project uses Conventional Commits for commit messages.
Commit Format
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]Allowed types:
feat: New feature (→ MINOR bump)fix: Bug fix (→ PATCH bump)docs: Documentation changesstyle: Formatting, no code logic changesrefactor: Code changes that neither fix bugs nor add featurestest: Add/modify tests onlychore: Maintenance tasksperf: Performance improvementsbuild: Build system changesci: CI configuration changesrevert: Reverts a previous commit
Breaking changes:
- Must include
!after the type/scope, OR - Must include a
BREAKING CHANGE:footer - Breaking changes require a MAJOR version bump
License
MIT - See LICENSE file for details.
Third-Party Licenses
This package includes code adapted from external sources. See THIRD_PARTY_LICENSES.md for details.
