80 lines
		
	
	
		
			1.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			80 lines
		
	
	
		
			1.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| /*global crypto*/
 | |
| 
 | |
| var Hashcash = module.exports;
 | |
| 
 | |
| var textEncoder = new TextEncoder();
 | |
| Hashcash.solve = async function solveHc(hc) {
 | |
| 	var solution = 0;
 | |
| 	var parts = hc.split(':').slice(0, 6);
 | |
| 	if (parts.length < 6) {
 | |
| 		throw new Error('invalid Hashcash-Challenge: ' + hc);
 | |
| 	}
 | |
| 
 | |
| 	var bits = parseInt(parts[1], 10) || -1;
 | |
| 	if (bits > 10 || bits < 0) {
 | |
| 		throw new Error('bad bit values');
 | |
| 	}
 | |
| 	console.log('bits:', bits);
 | |
| 	hc = parts.join(':') + ':';
 | |
| 	async function next() {
 | |
| 		var answer = hc + int52ToBase64(solution);
 | |
| 		var u8 = textEncoder.encode(answer);
 | |
| 		// REALLY SLOW due to async tasks and C++ context switch
 | |
| 		var hash = await crypto.subtle.digest('SHA-256', u8);
 | |
| 		hash = new Uint8Array(hash);
 | |
| 		if (checkHc(hash, bits)) {
 | |
| 			return answer;
 | |
| 		}
 | |
| 		solution += 1;
 | |
| 		return next();
 | |
| 	}
 | |
| 
 | |
| 	return next();
 | |
| };
 | |
| 
 | |
| function int52ToBase64(n) {
 | |
| 	var hex = n.toString(16);
 | |
| 	if (hex.length % 2) {
 | |
| 		hex = '0' + hex;
 | |
| 	}
 | |
| 
 | |
| 	var bin = [];
 | |
| 	var i = 0;
 | |
| 	var d;
 | |
| 	var b;
 | |
| 	while (i < hex.length) {
 | |
| 		d = parseInt(hex.slice(i, i + 2), 16);
 | |
| 		b = String.fromCharCode(d);
 | |
| 		bin.push(b);
 | |
| 		i += 2;
 | |
| 	}
 | |
| 
 | |
| 	return btoa(bin.join('')).replace(/=/g, '');
 | |
| }
 | |
| 
 | |
| function checkHc(hash, bits) {
 | |
| 	var n = Math.floor(bits / 8);
 | |
| 	var m = bits % 8;
 | |
| 	var i;
 | |
| 	if (m > 0) {
 | |
| 		n += 1;
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < n && i < hash.length; i += 1) {
 | |
| 		if (bits > 8) {
 | |
| 			bits -= 8;
 | |
| 			if (0 !== hash[i]) {
 | |
| 				return false;
 | |
| 			}
 | |
| 			continue;
 | |
| 		}
 | |
| 
 | |
| 		if (0 !== hash[i] >> (8 - bits)) {
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		return true;
 | |
| 	}
 | |
| }
 |