From ef3ea08b79124dac8d34c6c0d7874543f2cd75ef Mon Sep 17 00:00:00 2001 From: Julien Voisin Date: Wed, 3 Jun 2026 17:35:28 +0200 Subject: [PATCH] perf(challenge/proofofwork): stream sha256 into stack buffer in Validate (#1653) Signed-off-by: jvoisin Co-authored-by: Jason Cameron --- docs/docs/CHANGELOG.md | 1 + lib/challenge/proofofwork/proofofwork.go | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/docs/CHANGELOG.md b/docs/docs/CHANGELOG.md index fa7912b5..e9227961 100644 --- a/docs/docs/CHANGELOG.md +++ b/docs/docs/CHANGELOG.md @@ -41,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Marginally improve the performances of PoW validation - Marginally improve the performances of challenges generation/display - Significantly improve the performances of the gzip middleware +- Significantly improve the performances of the PoW validation ## v1.25.0: Necron diff --git a/lib/challenge/proofofwork/proofofwork.go b/lib/challenge/proofofwork/proofofwork.go index 385237be..d8bb6f8a 100644 --- a/lib/challenge/proofofwork/proofofwork.go +++ b/lib/challenge/proofofwork/proofofwork.go @@ -1,14 +1,15 @@ package proofofwork import ( + "crypto/sha256" "crypto/subtle" + "encoding/hex" "fmt" "log/slog" "net/http" "strconv" "strings" - "github.com/TecharoHQ/anubis/internal" chall "github.com/TecharoHQ/anubis/lib/challenge" "github.com/TecharoHQ/anubis/lib/localization" "github.com/a-h/templ" @@ -66,11 +67,20 @@ func (i *Impl) Validate(r *http.Request, lg *slog.Logger, in *chall.ValidateInpu return chall.NewError("validate", "invalid response", fmt.Errorf("%w response", chall.ErrMissingField)) } - calcString := challenge + nonceStr - calculated := internal.SHA256sum(calcString) + // Stream the challenge and nonce into a single sha256 hasher to avoid + // the intermediate "challenge + nonceStr" concatenation. Hex-encode + // the digest into a stack buffer so the comparison runs without + // allocating a heap string. + h := sha256.New() + h.Write([]byte(challenge)) + h.Write([]byte(nonceStr)) + var sumBuf [sha256.Size]byte + sum := h.Sum(sumBuf[:0]) + var hexBuf [sha256.Size * 2]byte + hex.Encode(hexBuf[:], sum) - if subtle.ConstantTimeCompare([]byte(response), []byte(calculated)) != 1 { - return chall.NewError("validate", "invalid response", fmt.Errorf("%w: wanted response %s but got %s", chall.ErrFailed, calculated, response)) + if subtle.ConstantTimeCompare([]byte(response), hexBuf[:]) != 1 { + return chall.NewError("validate", "invalid response", fmt.Errorf("%w: wanted response %s but got %s", chall.ErrFailed, string(hexBuf[:]), response)) } // compare the leading zeroes