From b7b983eb94e70902a6b1a8246e06186f7e60a3ce Mon Sep 17 00:00:00 2001 From: forest Date: Sun, 8 Dec 2024 23:46:12 -0600 Subject: [PATCH 1/3] ditch base32768 thing, stick to all-js-on-same-host to comply with CSP --- example/index.html | 30 +- example/main.go | 3 +- proofOfWorkerStub.js | 7 +- static/captcha.js | 21 +- static/proofOfWorker.js | 486 +++++++++++++---------------- static/scrypt.wasm | Bin 0 -> 37575 bytes static/scrypt_wasm_bg.wasm | Bin 0 -> 37575 bytes wasm_build/build_wasm.sh | 30 +- wasm_build/build_wasm_webworker.js | 64 ---- wasm_build/package-lock.json | 13 - wasm_build/package.json | 14 - 11 files changed, 281 insertions(+), 387 deletions(-) create mode 100644 static/scrypt.wasm create mode 100644 static/scrypt_wasm_bg.wasm delete mode 100644 wasm_build/build_wasm_webworker.js delete mode 100644 wasm_build/package-lock.json delete mode 100644 wasm_build/package.json diff --git a/example/index.html b/example/index.html index 00c675c..41070e8 100644 --- a/example/index.html +++ b/example/index.html @@ -2,7 +2,6 @@ - 📋 Todo List ``` -I think that concludes the walkthrough! In the Todo App, as soon as `captcha.js` calls `myCaptchaCallback`, the form will be completely filled out and the submit button will be enabled. When the form is posted, the browser will make a `POST` request to the server, and the server logic we already discussed will take over, closing the loop. +I think that concludes the walkthrough! In the Todo App, as soon as `pow-bot-deterrent.js` calls `myPowCallback`, the form will be completely filled out and the submit button will be enabled. When the form is posted, the browser will make a `POST` request to the server, and the server logic we already discussed will take over, closing the loop. # Implementation Details for Developers -💥PoW! Captcha uses [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)s and [WebAssembly (WASM)](https://developer.mozilla.org/en-US/docs/WebAssembly) to calculate Proof of Work in the browser as efficiently as possible. WebWorkers allow the application to run code on multiple threads and take advantage of multi-core CPUs. WebAssembly gives us access to *actual integers* (😲) and more low-level memory operations that have been historically missing from JavaScript. +💥PoW! Bot Deterrent uses [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)s and [WebAssembly (WASM)](https://developer.mozilla.org/en-US/docs/WebAssembly) to calculate Proof of Work in the browser as efficiently as possible. WebWorkers allow the application to run code on multiple threads and take advantage of multi-core CPUs. WebAssembly gives us access to *actual integers* (😲) and more low-level memory operations that have been historically missing from JavaScript. I measured the performance of the application with and without WebWorker / WebAssembly on a variety of devices. @@ -527,7 +528,7 @@ I tried two different implementations of the scrypt hash function, one from the | Macbook Air 2018 | not tested | not tested | ~ 32h/s | | Google Pixel 3a | not tested | not tested | ~ 24h/s | -I had some trouble getting the WASM module loaded properly inside the WebWorkers. In my production environment, the web application server and the captcha server are running on separate subdomains, so I was getting cross-origin security violation issues. +I had some trouble getting the WASM module loaded properly inside the WebWorkers. In my production environment, the web application server and the Bot Deterrent server are running on separate subdomains, so I was getting cross-origin security violation issues. I ended up embedding the WASM binary inside the WebWorker javascript `proofOfWorker.js` using a boutique binary encoding called [base32768](https://github.com/qntm/base32768). I set up a custom build process for this in the `wasm_build` folder. It even includes the scripts necessary to clone the github.com/MyEtherWallet/scrypt-wasm repo and install the Rust compiler! You are welcome! However, this script does assume that you are running on a Linux computer. I have not tested it outside of Linux. @@ -538,20 +539,20 @@ I ended up embedding the WASM binary inside the WebWorker javascript `proofOfWor When you calculate the hash of a file or a piece of data, you get this random string of characters: ``` -forest@thingpad:~/Desktop/git/sequentialread-pow-captcha$ sha256sum LICENSE.md +forest@thingpad:~/Desktop/git/pow-bot-deterrent$ sha256sum LICENSE.md 119ba12858fcf041fc43bb3331eaeaf313e1d01e278d5cc911fd2c60dc1c503f LICENSE.md ``` Here, I have called the SHA256 hash function on the GPLv3 `LICENSE.md` file in this repo. The result is displayed as a hexidecimal string, that is, each character can have one of 16 possible values, 0-9 and a-f. You can think of it like rolling a whole bunch of 16-sided dice, however, it's not random like dice are, its *pseudorandom*, meaning that given the same input file, if we execute the same hash function multiple times, it will return the same output. All the dice will land the same way every time: ``` -forest@thingpad:~/Desktop/git/sequentialread-pow-captcha$ sha256sum LICENSE.md +forest@thingpad:~/Desktop/git/pow-bot-deterrent$ sha256sum LICENSE.md 119ba12858fcf041fc43bb3331eaeaf313e1d01e278d5cc911fd2c60dc1c503f LICENSE.md -forest@thingpad:~/Desktop/git/sequentialread-pow-captcha$ sha256sum LICENSE.md +forest@thingpad:~/Desktop/git/pow-bot-deterrent$ sha256sum LICENSE.md 119ba12858fcf041fc43bb3331eaeaf313e1d01e278d5cc911fd2c60dc1c503f LICENSE.md -forest@thingpad:~/Desktop/git/sequentialread-pow-captcha$ sha256sum LICENSE.md +forest@thingpad:~/Desktop/git/pow-bot-deterrent$ sha256sum LICENSE.md 119ba12858fcf041fc43bb3331eaeaf313e1d01e278d5cc911fd2c60dc1c503f LICENSE.md ``` @@ -559,10 +560,10 @@ However, If I change the input, even if I only change it a tiny bit, say, append ``` # append the letter a to the end of the file -forest@thingpad:~/Desktop/git/sequentialread-pow-captcha$ echo 'a' >> LICENSE.md +forest@thingpad:~/Desktop/git/pow-bot-deterrent$ echo 'a' >> LICENSE.md # calculate the SHA256 hash again -forest@thingpad:~/Desktop/git/sequentialread-pow-captcha$ sha256sum LICENSE.md +forest@thingpad:~/Desktop/git/pow-bot-deterrent$ sha256sum LICENSE.md 67e0e2cc3429b799036bfa95e2bd7854a0e468939d6cb9d4a3e9d32c3b6615dc LICENSE.md ``` @@ -575,11 +576,11 @@ The number or string of "`a`"s, whatever it is you use to change the file before This is exactly how Bitcoin mining works, Bitcoin requires miners to search for SHA256 hashes that end in a rediculously unlikely number of zeros, like flipping 100 coins and getting 100 heads in a row. -💥PoW! Captcha uses a different hash function called [Scrypt](https://en.wikipedia.org/wiki/Scrypt). Scrypt was designed to take an arbitrarily long amount of time to execute on a computer, and to be hard to optimize. +💥PoW! Bot Deterrent uses a different hash function called [Scrypt](https://en.wikipedia.org/wiki/Scrypt). Scrypt was designed to take an arbitrarily long amount of time to execute on a computer, and to be hard to optimize. A modified version of Scrypt is used by the crypto currency [Litecoin](https://en.wikipedia.org/wiki/Litecoin). -Like I mentioned in the condensed "What is Proof of Work" section, because of this pseudorandom behaviour, we can't predict how long a given captcha will take to complete. The UI does have a "progress bar" but the behaviour of the bar is more related to probability than to progress. In fact, it displays the "probability that we should have found the answer already", which is related to the amount of work done so far, but it's not exactly a linear relationship. +Like I mentioned in the condensed "What is Proof of Work" section, because of this pseudorandom behaviour, we can't predict how long a given challenge will take to complete. The UI does have a "progress bar" but the behaviour of the bar is more related to probability than to progress. In fact, it displays the "probability that we should have found the answer already", which is related to the amount of work done so far, but it's not exactly a linear relationship. Here is a screenshot of a plot I generated using WolframAlpha while I was developing this progress bar, given the formula for the progress bar's width: diff --git a/build-docker.sh b/build-docker.sh index e855a73..7e13c18 100755 --- a/build-docker.sh +++ b/build-docker.sh @@ -17,25 +17,25 @@ sed -E 's/GOARCH=/GOARCH=amd64/' -i dockerbuild/Dockerfile-amd64 sed -E 's/GOARCH=/GOARCH=arm/' -i dockerbuild/Dockerfile-arm sed -E 's/GOARCH=/GOARCH=arm64/' -i dockerbuild/Dockerfile-arm64 -docker build -f dockerbuild/Dockerfile-amd64 -t sequentialread/pow-captcha:$VERSION-amd64 . -docker build -f dockerbuild/Dockerfile-arm -t sequentialread/pow-captcha:$VERSION-arm . -docker build -f dockerbuild/Dockerfile-arm64 -t sequentialread/pow-captcha:$VERSION-arm64 . +docker build -f dockerbuild/Dockerfile-amd64 -t sequentialread/pow-bot-deterrent:$VERSION-amd64 . +docker build -f dockerbuild/Dockerfile-arm -t sequentialread/pow-bot-deterrent:$VERSION-arm . +docker build -f dockerbuild/Dockerfile-arm64 -t sequentialread/pow-bot-deterrent:$VERSION-arm64 . -docker push sequentialread/pow-captcha:$VERSION-amd64 -docker push sequentialread/pow-captcha:$VERSION-arm -docker push sequentialread/pow-captcha:$VERSION-arm64 +docker push sequentialread/pow-bot-deterrent:$VERSION-amd64 +docker push sequentialread/pow-bot-deterrent:$VERSION-arm +docker push sequentialread/pow-bot-deterrent:$VERSION-arm64 export DOCKER_CLI_EXPERIMENTAL=enabled -docker manifest create sequentialread/pow-captcha:$VERSION \ - sequentialread/pow-captcha:$VERSION-amd64 \ - sequentialread/pow-captcha:$VERSION-arm \ - sequentialread/pow-captcha:$VERSION-arm64 +docker manifest create sequentialread/pow-bot-deterrent:$VERSION \ + sequentialread/pow-bot-deterrent:$VERSION-amd64 \ + sequentialread/pow-bot-deterrent:$VERSION-arm \ + sequentialread/pow-bot-deterrent:$VERSION-arm64 -docker manifest annotate --arch amd64 sequentialread/pow-captcha:$VERSION sequentialread/pow-captcha:$VERSION-amd64 -docker manifest annotate --arch arm sequentialread/pow-captcha:$VERSION sequentialread/pow-captcha:$VERSION-arm -docker manifest annotate --arch arm64 sequentialread/pow-captcha:$VERSION sequentialread/pow-captcha:$VERSION-arm64 +docker manifest annotate --arch amd64 sequentialread/pow-bot-deterrent:$VERSION sequentialread/pow-bot-deterrent:$VERSION-amd64 +docker manifest annotate --arch arm sequentialread/pow-bot-deterrent:$VERSION sequentialread/pow-bot-deterrent:$VERSION-arm +docker manifest annotate --arch arm64 sequentialread/pow-bot-deterrent:$VERSION sequentialread/pow-bot-deterrent:$VERSION-arm64 -docker manifest push sequentialread/pow-captcha:$VERSION +docker manifest push sequentialread/pow-bot-deterrent:$VERSION rm -rf dockerbuild || true \ No newline at end of file diff --git a/example/index.html b/example/index.html index 41070e8..5ee7d6c 100644 --- a/example/index.html +++ b/example/index.html @@ -5,7 +5,7 @@ 📋 Todo List