Last active
May 26, 2022 00:00
-
-
Save kelvysmoura/9c4c340da856bcbcb99de78573e444c4 to your computer and use it in GitHub Desktop.
Hashcash / Proof of Work (POW)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Esse é um estudo sobre Hashcash que acabou se tornando Proof of Work (POW) | |
* | |
* As semelhança que eu identifiquei: | |
* - Ambos usam da capacidade computacional para resolver um desafio, que é encontrar um quantidade de zeros "0" | |
* em uma hash SHA-256. | |
* | |
* As diferenças que eu identifiquei: | |
* - Hashcash foi inicial feito para enviar spam de email. É um desafio enviado para pelo servidor, parecido com | |
* versão:timestamp_de_validade:nonce:SHA-256:SOLUÇÃO. A solução é o que o cliente (navegador) precisa descobrir. | |
* | |
* - PWO como é normalmente usada para transações de criptomoedas vai gerar um hash baseado nas informações da blockchain. | |
* | |
* | |
* COMO TESTAR? | |
* 1. Baixar esse codigo para um arquivo JS | |
* 2. importar esse JS para um HTML | |
* 3. Abir o HTML no navegador | |
* 4. Abrir o devtools do navegador e executar pow(). | |
* 5. A função aceita um inteiro que por padrão é 2 e essa é a dificuldade da hash. Agora é so brincar um pouco com a | |
* dificuldade, ir aumentando pra ver o tanto de recurso usado a cada 0 exigido. | |
* | |
* Para validar a hash gerada por esse JS, dentro do PHP, basta pegar o serverData exibido no console | |
* e executar na função hash(), ficando assim | |
* | |
* $hash = hash('sha256', serverData); | |
* | |
* O valor da variavel PHP deve ser identica a hash mostrar no console do navegador | |
* | |
* :) | |
*/ | |
/** | |
* Uma hash válida | |
*/ | |
let hash = ''; | |
/** | |
* Esse nonce é no contexto de POW. | |
* É usado como parte da string do hash e enquanto a hash não for o esperado pela dificuldade, é incrementado +1 no nonce | |
*/ | |
let nonce = -1; | |
/** | |
* A dificuldade é o número de zeros que deve ser encontrado no início do hash | |
*/ | |
async function pow(difficulty = 2) { | |
console.log(new Date()); | |
/** | |
* A expressão Array(difficulty + 1).join(0) vai gerar uma string com a quatidade de zeros de difficulty+1 | |
* Se a dificuldade for 2, então a string obitida será "00" | |
* | |
* A expressão hash.substr(0, difficulty) pega apenas um pedaço do inicio da hash e esse pedaço é do tamnho da dificuldade | |
* Se a hash gerada for 0078271db0176e77e3bcda9deaa8ee2e5bc4223b66ad1a35a15260aa32e7a1dd, substr vai pegar apenas "00" se a dificuldade for 2. | |
* | |
* Dessa forma enquando a while não for "00" === "00", vai continuar interando e gerando uma nova hash até | |
* encontrar uma hash que comece com essa quantidade de zeros | |
*/ | |
while(hash.substr(0, difficulty) !== Array(difficulty + 1).join(0)){ | |
nonce++; | |
hash = await hash256(serverData()); | |
} | |
console.table({nonce, hash, serverData: serverData()}); | |
console.log(new Date()); | |
hash = ''; | |
} | |
/** | |
* Aqui a o inicio da string está mais próximo do padrão Hashcash e nesse contexto o nonce é um código recebido do | |
* servidor e no final deve ser colocado a solução. | |
* Mas do jeito que ta abaixo a parte do nonce ja ta no padrão PWO, com algumas informações no começo e no final o nonce | |
* | |
* No final não importa muito que coloca aqui, qualquer informação da certo. Acho importante ter uma informação que possa | |
* verificado pelo servidor ou uma informação que tenha disponivel no servidor na hora de bater e conferir a hash | |
*/ | |
function serverData() { | |
return `VERSAO:DATA:TIMERSTAMP:....:NONCE:${nonce}`; | |
} | |
/** | |
* Aqui é so um código que peguei pronto para gerar hash SHA-256 | |
*/ | |
function hash256(data) { | |
data = new TextEncoder().encode(data); | |
return crypto.subtle.digest('SHA-256', data).then(response => { | |
let hashArray = Array.from(new Uint8Array(response)); | |
let hashHex = hashArray.map(hash => hash.toString(16).padStart(2, 0)).join(''); | |
return hashHex | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment