How DS2API Implements DeepSeek Proof of Work (PoW): A Complete Technical Guide
DS2API implements DeepSeek Proof of Work through a native Go package that brute-forces SHA-3-256 hashes using a custom 23-round Keccak permutation to generate valid x-ds-pow-response headers for protected API endpoints.
The CJackHwang/ds2api repository provides a production-ready Go implementation of DeepSeek's Proof of Work protocol. This self-contained solution eliminates external cryptographic dependencies while delivering deterministic cross-platform behavior for solving server-issued challenges.
Understanding the Challenge Structure
DeepSeek's API issues PoW challenges as JSON objects containing cryptographic parameters. The pow/deepseek_pow.go file defines the Challenge struct that captures these server requirements:
type Challenge struct {
Algorithm string `json:"algorithm"` // Only "DeepSeekHashV1" is supported
Challenge string `json:"challenge"` // 64-char hex target hash
Salt string `json:"salt"` // Random per-request salt
ExpireAt int64 `json:"expire_at"` // Unix timestamp when challenge expires
Difficulty int64 `json:"difficulty"` // Max nonce to try (default 144000)
Signature string `json:"signature"` // Server-signed data
TargetPath string `json:"target_path"` // Protected endpoint path
}
The prefix construction determines the input data hashed during solving. The BuildPrefix function concatenates the salt, expiration timestamp, and delimiters into a fixed string absorbed before the nonce:
func BuildPrefix(salt string, expireAt int64) string {
return salt + "_" + strconv.FormatInt(expireAt, 10) + "_"
}
The DeepSeekHashV1 Algorithm
DS2API implements DeepSeekHashV1 in pow/deepseek_hash.go as a modified SHA-3-256 hash that skips the initial Keccak round. This pure-Go implementation mirrors DeepSeek's WebAssembly reference (wasm_deepseek_hash_v1) exactly.
The algorithm operates through four distinct phases:
- State initialization: Creates a 25-word uint64 array (
[25]uint64) representing the Keccak-f[1600] state - Data absorption: Processes input in 136-byte blocks (the SHA-3-256 rate) using the custom permutation
- Custom permutation: Executes the
keccakF23function performing 23 rounds (rounds 1-23, omitting round 0) of the standard Keccak-f transformation - Digest extraction: Applies standard SHA-3 padding (
0x06suffix and0x80final byte) before extracting the first four 64-bit words as the 32-byte digest
func DeepSeekHashV1(data []byte) [32]byte {
// Implementation handles 23-round Keccak-f[1600] without external dependencies
// Returns deterministic 32-byte hash matching DeepSeek's WebAssembly output
}
Solving the PoW Challenge
The SolvePow function in pow/deepseek_pow.go performs a deterministic brute-force search across the nonce space [0, difficulty) to find a value satisfying:
DeepSeekHashV1(BuildPrefix(salt, expireAt) || decimal(nonce)) == challenge_target
The solver implements several performance optimizations:
- Pre-absorption: Computes the Keccak state for the prefix once, storing it in
baseStateto avoid reprocessing fixed data for every nonce attempt - Incremental hashing: Appends each candidate nonce's decimal ASCII representation to the absorbed prefix state
- Cancellation support: Checks the provided
context.Contextevery 1024 iterations to enable responsive timeout handling - Little-endian comparison: Decodes the 64-character hex target into four uint64 words (
t0throught3) for direct state comparison
If the search exhausts the difficulty bound without finding a match, the function returns an error indicating no solution exists within the constraints.
Constructing the Response Header
Once a valid nonce is discovered, BuildPowHeader serializes the solution into the Base64-encoded JSON format expected by DeepSeek's API:
func BuildPowHeader(c *Challenge, answer int64) (string, error) {
payload, err := json.Marshal(map[string]any{
"algorithm": c.Algorithm,
"challenge": c.Challenge,
"salt": c.Salt,
"answer": answer,
"signature": c.Signature,
"target_path": c.TargetPath,
})
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(payload), nil
}
The convenience wrapper SolveAndBuildHeader orchestrates the entire workflow:
func SolveAndBuildHeader(ctx context.Context, c *Challenge) (string, error) {
if c.Algorithm != "DeepSeekHashV1" {
return "", errors.New("pow: unsupported algorithm: " + c.Algorithm)
}
difficulty := c.Difficulty
if difficulty == 0 {
difficulty = 144000 // Fallback default difficulty
}
answer, err := SolvePow(ctx, c.Challenge, c.Salt, c.ExpireAt, difficulty)
if err != nil {
return "", err
}
return BuildPowHeader(c, answer)
}
The resulting Base64 string must be attached to subsequent requests as the x-ds-pow-response HTTP header.
Practical Implementation Examples
Solving a Real-Time Challenge from DeepSeek API
This example demonstrates fetching a challenge, solving it with context cancellation support, and attaching the header to a protected request:
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/CJackHwang/ds2api/pow"
)
func main() {
// Fetch PoW challenge from DeepSeek endpoint
resp, err := http.Get("https://api.deepseek.com/v0/chat/create_pow_challenge")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var challenge pow.Challenge
if err := json.Unmarshal(body, &challenge); err != nil {
panic(err)
}
// Solve with 10-second timeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
headerValue, err := pow.SolveAndBuildHeader(ctx, &challenge)
if err != nil {
panic(err) // Handles timeout or no-solution cases
}
// Attach header to protected request
req, _ := http.NewRequest("POST", "https://api.deepseek.com/v0/chat/completions", nil)
req.Header.Set("x-ds-pow-response", headerValue)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
protectedResp, _ := client.Do(req)
fmt.Println("Protected endpoint status:", protectedResp.Status)
}
Custom Difficulty and Manual Nonce Verification
For servers requiring higher work factors or custom verification:
// Increase difficulty beyond default 144000
challenge.Difficulty = 500_000
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
header, err := pow.SolveAndBuildHeader(ctx, &challenge)
if err != nil {
fmt.Printf("PoW solving failed: %v\n", err)
return
}
// The header contains base64-encoded JSON with the answer field
fmt.Printf("Generated PoW header: %s\n", header)
Summary
- DS2API provides a zero-dependency Go implementation of DeepSeek's Proof of Work in the
powpackage - DeepSeekHashV1 uses a modified SHA-3-256 with 23 Keccak rounds (skipping round 0), implemented in
pow/deepseek_hash.go - The Challenge struct in
pow/deepseek_pow.gocaptures server requirements including difficulty, salt, and expiration timestamps - SolvePow optimizes performance through prefix pre-absorption and context-aware cancellation checks every 1024 iterations
- SolveAndBuildHeader generates the
x-ds-pow-responseheader by Base64-encoding a JSON payload containing the discovered nonce
Frequently Asked Questions
What makes DeepSeekHashV1 different from standard SHA-3-256?
DeepSeekHashV1 omits the first round of the standard Keccak-f[1600] permutation. While SHA-3-256 uses 24 rounds (rounds 0-23), DeepSeek's implementation executes only 23 rounds (rounds 1-23). This subtle modification requires custom cryptographic code, as standard libraries cannot configure the starting round index. DS2API's pow/deepseek_hash.go implements this precisely to match DeepSeek's WebAssembly reference.
How does DS2API handle high-difficulty PoW challenges efficiently?
The solver optimizes through state pre-absorption. Rather than re-hashing the entire prefix (salt + timestamp + delimiter) for every nonce attempt, SolvePow computes the Keccak state after absorbing the prefix once, then clones this base state for each candidate nonce. This reduces the per-iteration workload significantly when searching large nonce spaces up to the default difficulty of 144,000 or higher.
Can the PoW solver be cancelled mid-computation?
Yes. The SolvePow function accepts a context.Context parameter and checks for cancellation every 1024 iterations. This allows applications to enforce strict timeouts or respond to shutdown signals without leaking goroutines. If the context is cancelled before a solution is found, the function immediately returns the context error.
Where does DS2API validate the PoW challenge signature?
While the Challenge struct includes a Signature field for server-signed data, the core pow package focuses on solving valid challenges rather than cryptographic verification of the signature itself. According to the source structure, signature validation likely occurs in upstream handlers such as api/index.go before the challenge reaches the solver, ensuring only authentic challenges consume computational resources.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →