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