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; | ||
|  | 	} | ||
|  | } |