Implement algorithm switching

This commit implements every algorithm I have played with so far. It also allows for you to switch which algorithm you want to use at runtime.
This commit is contained in:
Zoe
2025-11-25 18:09:17 +00:00
parent 570531fe32
commit e16383e9b9
20 changed files with 1262 additions and 476 deletions

View File

@@ -1,7 +1,7 @@
import { LitElement, html, css, isServer, type PropertyValues } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { type ChallengeSolveRequest, type SolutionMessage, WorkerMessageType, type WorkerRequest, WorkerResponseType } from './types/worker';
import { type Challenge, ChallengeStrategy } from '@impost/lib';
import { type Challenge, ChallengeStrategy, ChallengeAlgorithm } from '@impost/lib';
import { get_wasm_module } from '@impost/lib/solver';
import ChallengeWorker from './solver-worker?worker&inline';
@@ -172,7 +172,7 @@ export class PowCaptcha extends LitElement {
async initWorkers() {
this.solverWorkers = [];
const num_workers = 1;
const num_workers = navigator.hardwareConcurrency || 4;
for (let i = 0; i < num_workers; i++) {
this.solverWorkers.push(new ChallengeWorker());
}
@@ -275,11 +275,52 @@ export class PowCaptcha extends LitElement {
// } as WorkerRequest);
// break;
// }
switch (request.strategy) {
case ChallengeStrategy.kCTF:
switch (request.algorithm) {
case ChallengeAlgorithm.SHA256:
switch (request.strategy) {
case ChallengeStrategy.LeadingZeroes:
worker.postMessage({
algorithm: ChallengeAlgorithm.SHA256,
strategy: ChallengeStrategy.LeadingZeroes,
salt: request.salt,
difficulty: request.difficulty,
} as WorkerRequest);
break;
case ChallengeStrategy.TargetNumber:
worker.postMessage({
algorithm: ChallengeAlgorithm.SHA256,
strategy: ChallengeStrategy.TargetNumber,
target: request.target,
salt: request.salt,
} as WorkerRequest);
break;
}
break;
case ChallengeAlgorithm.Argon2id:
switch (request.strategy) {
case ChallengeStrategy.LeadingZeroes:
worker.postMessage({
algorithm: ChallengeAlgorithm.Argon2id,
strategy: ChallengeStrategy.LeadingZeroes,
salt: request.salt,
difficulty: request.difficulty,
} as WorkerRequest);
break;
case ChallengeStrategy.TargetNumber:
worker.postMessage({
algorithm: ChallengeAlgorithm.Argon2id,
strategy: ChallengeStrategy.TargetNumber,
target: request.target,
salt: request.salt,
} as WorkerRequest);
break;
}
break;
case ChallengeAlgorithm.kCTF:
worker.postMessage({
strategy: ChallengeStrategy.kCTF,
challenge: request.challenge,
algorithm: ChallengeAlgorithm.kCTF,
salt: request.salt,
difficulty: request.difficulty,
} as WorkerRequest);
break;
}
@@ -329,11 +370,52 @@ export class PowCaptcha extends LitElement {
// };
// break;
// }
switch (this.challengeData.strategy) {
case ChallengeStrategy.kCTF:
switch (this.challengeData.algorithm) {
case ChallengeAlgorithm.SHA256:
switch (this.challengeData.strategy) {
case ChallengeStrategy.LeadingZeroes:
request = {
algorithm: ChallengeAlgorithm.SHA256,
strategy: ChallengeStrategy.LeadingZeroes,
salt: this.challengeData.salt,
difficulty: this.challengeData.difficulty,
};
break;
case ChallengeStrategy.TargetNumber:
request = {
algorithm: ChallengeAlgorithm.SHA256,
strategy: ChallengeStrategy.TargetNumber,
target: this.challengeData.target,
salt: this.challengeData.salt,
};
break;
}
break;
case ChallengeAlgorithm.Argon2id:
switch (this.challengeData.strategy) {
case ChallengeStrategy.LeadingZeroes:
request = {
algorithm: ChallengeAlgorithm.Argon2id,
strategy: ChallengeStrategy.LeadingZeroes,
salt: this.challengeData.salt,
difficulty: this.challengeData.difficulty,
};
break;
case ChallengeStrategy.TargetNumber:
request = {
algorithm: ChallengeAlgorithm.Argon2id,
strategy: ChallengeStrategy.TargetNumber,
target: this.challengeData.target,
salt: this.challengeData.salt,
};
break;
}
break;
case ChallengeAlgorithm.kCTF:
request = {
strategy: ChallengeStrategy.kCTF,
challenge: this.challengeData.challenge,
algorithm: ChallengeAlgorithm.kCTF,
salt: this.challengeData.salt,
difficulty: this.challengeData.difficulty,
};
break;
}
@@ -346,9 +428,13 @@ export class PowCaptcha extends LitElement {
// TODO: We need to do a better job of tracking solvers, so if one worker
// errors out, we only error out if all workers have errored out.
let worker_promises: Promise<SolutionMessage>[] = [];
for (let worker of this.solverWorkers) {
// dispatch to all workers, func is async so it will not block
worker_promises.push(this.issueChallengeToWorker(worker, request));
if (request.algorithm === ChallengeAlgorithm.kCTF) {
worker_promises.push(this.issueChallengeToWorker(this.solverWorkers[0], request));
} else {
for (let worker of this.solverWorkers) {
// dispatch to all workers, func is async so it will not block
worker_promises.push(this.issueChallengeToWorker(worker, request));
}
}
let solution = await Promise.race(worker_promises);
@@ -370,7 +456,7 @@ export class PowCaptcha extends LitElement {
await fetch(`${this.challengeUrl}/challenge`, {
method: 'POST',
body: JSON.stringify({
challenge: this.challengeData.challenge,
salt: this.challengeData.salt,
solution: solution.solution,
}),
headers: {
@@ -382,7 +468,7 @@ export class PowCaptcha extends LitElement {
this.dispatchEvent(new CustomEvent('impost:solved', {
detail: {
challenge: this.challengeData.challenge,
salt: this.challengeData.salt,
solution: solution.solution,
},
bubbles: true,

View File

@@ -8,7 +8,8 @@ import {
WorkerResponseType,
} from "./types/worker";
import { type SolverModule, init_solver, solve } from '@impost/lib/solver';
import { type SolverModule, init_solver, solve, type SolveParams } from '@impost/lib/solver';
import { ChallengeStrategy, ChallengeAlgorithm } from '@impost/lib';
let solver: SolverModule | null = null;
@@ -59,9 +60,59 @@ onmessage = async (event: MessageEvent<WorkerRequest>) => {
return;
}
let solution: string;
let solution: string | number;
try {
solution = solve(solver, event.data.challenge);
let params = {
name: event.data.algorithm,
salt: event.data.salt,
};
switch (event.data.algorithm) {
case ChallengeAlgorithm.SHA256:
switch (event.data.strategy) {
case ChallengeStrategy.LeadingZeroes:
// @ts-ignore
params.strategy = ChallengeStrategy.LeadingZeroes;
// @ts-ignore
params.difficulty = event.data.difficulty;
break;
case ChallengeStrategy.TargetNumber:
// @ts-ignore
params.strategy = ChallengeStrategy.TargetNumber;
// @ts-ignore
params.target = event.data.target;
break;
}
break;
case ChallengeAlgorithm.Argon2id:
switch (event.data.strategy) {
case ChallengeStrategy.LeadingZeroes:
// @ts-ignore
params.strategy = ChallengeStrategy.LeadingZeroes;
// @ts-ignore
params.difficulty = event.data.difficulty;
break;
case ChallengeStrategy.TargetNumber:
// @ts-ignore
params.strategy = ChallengeStrategy.TargetNumber;
// @ts-ignore
params.target = event.data.target;
break;
}
break;
case ChallengeAlgorithm.kCTF:
// @ts-ignore
params.strategy = ChallengeStrategy.Null;
// @ts-ignore
params.difficulty = event.data.difficulty;
break;
}
solution = solve(solver, params as SolveParams);
if (event.data.algorithm !== ChallengeAlgorithm.kCTF) {
solution = Atomics.load(atomic_solution!, 0);
}
} catch (error: any) {
postMessage({
type: WorkerResponseType.Error,
@@ -70,6 +121,7 @@ onmessage = async (event: MessageEvent<WorkerRequest>) => {
return;
}
postMessage({
type: WorkerResponseType.Solution,
solution,

View File

@@ -1,4 +1,4 @@
import { ChallengeStrategy } from "@impost/lib";
import { ChallengeAlgorithm, ChallengeStrategy } from "@impost/lib";
export enum WorkerMessageType {
Init = "init",
@@ -12,37 +12,40 @@ interface WorkerInitRequest {
sab: SharedArrayBuffer;
}
// interface ChallengeLeadingZeroesSolveRequest {
// strategy: ChallengeStrategy.LeadingZeroes;
// salt: string;
// difficulty: number;
// }
interface ChallengeLeadingZeroesSolveRequest {
algorithm: ChallengeAlgorithm.SHA256 | ChallengeAlgorithm.Argon2id;
strategy: ChallengeStrategy.LeadingZeroes;
salt: string;
difficulty: number;
}
// interface WorkerChallengeLeadingZeroesSolveRequest extends ChallengeLeadingZeroesSolveRequest {
// type: WorkerMessageType.Challenge;
// }
interface WorkerChallengeLeadingZeroesSolveRequest extends ChallengeLeadingZeroesSolveRequest {
type: WorkerMessageType.Challenge;
}
// interface ChallengeTargetNumberSolveRequest {
// strategy: ChallengeStrategy.TargetNumber;
// target: string;
// salt: string;
// }
interface ChallengeTargetNumberSolveRequest {
algorithm: ChallengeAlgorithm.SHA256 | ChallengeAlgorithm.Argon2id;
strategy: ChallengeStrategy.TargetNumber;
target: string;
salt: string;
}
// interface WorkerChallengeTargetNumberSolveRequest extends ChallengeTargetNumberSolveRequest {
// type: WorkerMessageType.Challenge;
// }
interface WorkerChallengeTargetNumberSolveRequest extends ChallengeTargetNumberSolveRequest {
type: WorkerMessageType.Challenge;
}
interface ChallengekCTFSolveRequest {
strategy: ChallengeStrategy.kCTF;
challenge: string;
algorithm: ChallengeAlgorithm.kCTF;
salt: string;
difficulty: number;
}
interface WorkerChallengekCTFSolveRequest extends ChallengekCTFSolveRequest {
type: WorkerMessageType.Challenge;
}
export type ChallengeSolveRequest = ChallengekCTFSolveRequest;
type WorkerChallengeSolveRequest = WorkerChallengekCTFSolveRequest;
export type ChallengeSolveRequest = ChallengekCTFSolveRequest | ChallengeLeadingZeroesSolveRequest | ChallengeTargetNumberSolveRequest;
type WorkerChallengeSolveRequest = WorkerChallengekCTFSolveRequest | WorkerChallengeLeadingZeroesSolveRequest | WorkerChallengeTargetNumberSolveRequest;
export type WorkerRequest = WorkerInitRequest | WorkerChallengeSolveRequest;
@@ -59,7 +62,7 @@ interface ErrorMessageResponse {
interface SolutionMessageResponse {
type: WorkerResponseType.Solution;
solution: string;
solution: string | number;
}
interface InitOkMessageResponse {