Add PoW module

This commit is contained in:
2024-04-02 16:45:09 -06:00
parent 27954f6a8c
commit 8b25ba39b8
5 changed files with 131 additions and 1 deletions

88
src/pow/pow.service.ts Normal file
View File

@@ -0,0 +1,88 @@
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { Cache } from 'cache-manager';
import { randomBytes, createHash } from 'crypto';
@Injectable()
export class PowService {
private readonly logger = new Logger(PowService.name);
private difficulty = 5;
constructor(
@Inject(CACHE_MANAGER) private cacheManager: Cache,
) { }
/**
* Generate a proof of work challenge, stored to redis for verification within
* the next 10 seconds.
*/
async generateChallenge() {
const challenge = this.generateRandom256BitString();
console.log(challenge)
await this.cacheManager.set(challenge, true, 60 * 1000);
return challenge;
}
generateRandom256BitString() {
const randomString = randomBytes(32).toString('hex');
return randomString;
}
hashAndCheck(string: string) {
return this.hashPassesDifficulty(this.hashString(string), this.difficulty);
}
hashPassesDifficulty(hash: string, difficulty: number) {
return hash.startsWith('0'.repeat(difficulty));
}
/**
* Verify that the proof of work submitted has a leading number of
* zeroes equal to the challenge length and the challenge exists.
*/
async verifyChallenge(challenge: string, proof: string): Promise<boolean> {
const expected = await this.cacheManager.get<boolean>(challenge);
return expected ? this.hashAndCheck(proof + challenge) : false;
}
async markChallengeAsComplete(challenge: string) {
await this.cacheManager.del(challenge);
}
/**
* Perform a proof of work challenge to find a proof that hashes to a value
*/
async performChallenge(challenge: string) {
let proof = this.generateRandom256BitString();
let hash = this.hashString(proof + challenge);
while (!this.hashPassesDifficulty(hash, this.difficulty)) {
proof = this.generateRandom256BitString();
hash = this.hashString(proof + challenge);
}
return { proof, hash };
}
/**
* sha512 the provided string and return the result.
*/
hashString(input: string) {
return createHash('sha512').update(input).digest('hex');
}
/**
* Set the difficulty of the proof of work challenge.
*/
setDifficulty(difficulty: number) {
this.difficulty = difficulty;
}
/**
* Get the current difficulty of the proof of work challenge.
*/
getDifficulty() {
return this.difficulty;
}
}