Proof of Work
Stateless HMAC-SHA256 proof-of-work protocol, client Web Worker solver, and O(1) server verification.
Waiting for callApi() challenge generation...
Visual Design Language & Components
UI components and visual states for client-side proof-of-work verification.
Technical Specification & Architecture
Cryptographic HMAC tokens, context fingerprinting, replay resistance, and multi-tenant sharding.
1. The Stateless HMAC Challenge Token
HMAC-SHA256Servers do not store active challenges in Redis or databases. Puzzles are distributed as cryptographically signed stateless tokens verified in O(1) time:
سرورها چالشهای فعال را در دیتابیس یا ردیس ذخیره نمیکنند. معماها به عنوان توکنهای بدون حالت و امضاشده صادر میشوند که در زمان O(1) تأیید میگردند:
1Token = Base64Url(Payload) + "." + HMAC_SHA256(SecretKey, Base64Url(Payload))
2. Context Binding & Swapping Prevention
Every challenge binds cryptographically to the exact form context: ctx = SHA256(form_fields). A bot cannot pre-compute a proof for account A and reuse it for account B or an invoice.
هر چالش به صورت رمزنگاریشده به زمینه فرم متصل است. باتها نمیتوانند اثبات حلشده را از یک حساب به حساب یا عملیات دیگر منتقل کنند.
3. Dynamic Difficulty & Subnet Escalation
Clean residential traffic receives effortless baseline difficulty (14–16 bits, ~0.8s). Datacenter/Tor subnets generating rapid requests face scaled difficulty (18–22 bits), exhausting automated bot servers.
کاربران عادی سختی پایه (۰.۸ ثانیه) دریافت میکنند؛ در حالی که دیتاسنترها و باتهای مشکوک با سختیهای تصاعدی مواجه شده و توان سرورشان مسدود میشود.
4. Compliant Server Trust Model & Anti-Spoofing Architecture
Server SecretUnlike third-party CAPTCHAs where trust is delegated to Google or Cloudflare, in Mehr PoW your backend server is the Root of Trust. The client never chooses difficulty or validates its own tokens:
- Cryptographic Tamper-Proofing: The target difficulty (e.g. 18 or 21 bits), timestamp, and context are signed into the HMAC token with
SERVER_SECRET_KEY. If a client tampers with difficulty in DevTools, the HMAC fails upon form submission. - Rogue Server Immunity: If an attacker redirects the PoW library to a fake server issuing trivial 4-bit challenges, the final application server rejects the submission in O(1) time because the signature was not signed with the real
SERVER_SECRET_KEY. - Dynamic Server Policy: The backend challenge endpoint (
POST /pow/challenge) inspects the client's IP, TLS/JA4 fingerprint, request velocity, and risk tier to dynamically assign difficulty before signing.
برخلاف کپچاهای شخصثالث که به گوگل یا کلودفلر وابسته هستند، در اثبات کار مهر سرور اصلی برنامه شما مرجع نهایی امنیت است. کلاینت هرگز درجه سختی را مشخص نمیکند:
- غیرقابل دستکاری: درجه سختی (مثلاً ۱۸ یا ۲۱ بیت)، زمان صدور و زمینه فرم درون توکن با کلید محرمانه سرور امضا میشوند. هرگونه تغییر در مرورگر باعث خطای فوری HMAC میگردد.
- مصونیت از جعل سرور: اگر مهاجم کلاینت را به یک سرور جعلی هدایت کند تا سختی ناچیز بگیرد، سرور مقصد فرم نهایی را بلافاصله رد میکند زیرا امضای آن با کلید سرور اصلی همخوانی ندارد.
- سیاستگذاری پویا: سرور بر اساس آدرس IP، فینگرپرینت TLS و نرخ درخواست، سختی متغیر تعیین کرده و سپس آن را امضا میکند.
5. Standard HTTP API & Cross-Origin (domain) Contract
REST / JSONFor decoupled frontends (e.g. static website on example.com and API on api.example.com), the client accepts an optional domain option. The backend enables standard CORS headers (Access-Control-Allow-Origin):
برای سامانههایی که فرانتاند (مثلاً روی example.com) و سرور بکاند (روی api.example.com) دامنههای مجزا دارند، کلاینت فیلد اختیاری domain را میپذیرد:
1// Request Payload
2{ "action": "account.register", "context": "usr_4f81" }
3
4// Response (HTTP 200 OK)
5{
6 "token": "eyJ2IjoxLCJz...8f9b2c",
7 "salt": "a1f9d287c4b03e1a",
8 "difficulty": 18,
9 "context": "usr_4f81",
10 "exp": 1729000180
11}
1// Form Submission / JSON Payload
2{
3 "pow_token": "eyJ2IjoxLCJz...8f9b2c",
4 "pow_nonce": 268412,
5 ...formData
6}
7
8// Result (O(1) Verification)
9{ "valid": true, "action": "account.register" }
Implementation Guide & Architecture Flow
Cryptographic sequence flow, browser drop-in client, and backend verification middleware.
End-to-End Protocol Flowchart
This interactive architecture sequence illustrates the trust lifecycle between the client browser (untrusted environment), the challenge gateway (stateless HMAC issuer), and your protected backend API. Solving runs non-blockingly inside background Web Workers, while the server verifies solutions in < 0.05ms without database state.
این فلوچارت تعاملی معماری، چرخه اعتماد میان مرورگر کلاینت (محیط غیرقابلاعتماد)، گیتوی صادرکننده چالش (امضای بدون دیتابیس) و سرور مقصد برنامه شما را نشان میدهد. محاسبات در پسزمینه کلاینت اجرا شده و اعتبارسنجی سرور در کمتر از ۰.۰۵ میلیثانیه بدون بار دیتابیس انجام میگیرد.
Client requests a proof-of-work challenge on initial form load (background mode) or when primary submission is initiated. Sends action name and request context fingerprint.
مرورگر کاربر در پسزمینه بارگذاری صفحه یا هنگام آغاز ثبت فرم، درخواست دریافت چالش را ارسال میکند. نام عملیات و فینگرپرینت زمینه ارسال میگردد.
Gateway evaluates IP reputation, rate velocity, and endpoint tier, then returns salt, expiration, and assigned difficulty (14–24 bits) sealed with SERVER_SECRET_KEY.
سرور چالش بر اساس رتبه آدرس IP و حساسیت عملیات، سالت، زمان انقضا و درجه سختی را مشخص کرده و با کلید محرمانه سرور بدون ذخیره در دیتابیس امضا میکند.
An off-thread Web Worker computes nonces without blocking the browser UI thread.
یک وبورکر مستقل خارج از ترد اصلی رابط کاربری، نانسهای متوالی را بررسی میکند تا تعداد بیتهای صفر معین تولید شود؛ رابط کاربری با ۶۰ فریم بر ثانیه کاملاً روان میماند.
The user submits the form or API request. MehrPoW transparently attaches X-Mehr-PoW-Token and X-Mehr-PoW-Nonce headers alongside the form payload.
کاربر فرم یا درخواست نهایی را ارسال میکند. کتابخانه مهر به صورت خودکار هدرهای توکن امضاشده و نانس محاسبهشده را همراه با اطلاعات فرم ارسال مینماید.
Destination backend verifies HMAC signature with its private secret, checks expiration, and re-computes a single SHA-256 hash to confirm proof in under 0.05ms.
سرور مقصد امضای HMAC را با کلید محرمانه بررسی کرده، انقضا و سیاست سختی را میسنجد و با یک بار هش SHA-256 در کمتر از ۰.۰۵ میلیثانیه اعتبار اثبات کار را تأیید میکند.
Business transaction executes: user account registered, payment invoice generated, or comment published immediately.
تراکنش بدون معطلی پردازش میشود: حساب کاربری ایجاد شده، فاکتور صادر میگردد یا یادداشت با موفقیت ثبت میشود.
Forged difficulty, rogue server token, replayed nonce, or expired challenge immediately rejected in O(1) time without DB impact.
سختی دستکاریشده، توکن جعلی سرور ناشناس، نانس بازپخششده یا چالش منقضیشده در زمان O(1) بلافاصله دفع میگردد.
Client & Backend Implementations
Self-contained solvers, drop-in browser client, and verification middleware for Go, JavaScript/TypeScript, Python, PHP, and POSIX Shell.
کتابخانههای مستقل کلاینت، سالورهای چندزبانه و میدلورهای اعتبارسنجی برای Go، جاوااسکریپت، پایتون، PHP و POSIX Shell.
1<!-- 1. Include the drop-in library -->
2<script src="https://pow.mehrnet.com/pow-client.js"></script>
3
4<!-- 2. Your standard HTML form -->
5<form id="signup-form" action="https://api.example.com/register" method="POST">
6 <input type="email" name="email" required />
7 <input type="password" name="password" required />
8 <button type="submit">Register</button>
9</form>
10
11<!-- 3. Auto-protect with optional cross-origin domain -->
12<script>
13 MehrPoW.protect('#signup-form', {
14 // Optional: for cross-domain API setups (e.g. api.example.com)
15 domain: 'https://api.example.com',
16 endpoint: '/api/pow/challenge',
17 action: 'account.register',
18 mode: 'background' // Solves non-blockingly while user fills form
19 });
20</script>
1package main
2
3import (
4 "crypto/hmac"
5 "crypto/sha256"
6 "encoding/hex"
7 "fmt"
8 "math/bits"
9 "net/http"
10 "strconv"
11 "strings"
12)
13
14// VerifyPoW verifies client proof in O(1) time
15func VerifyPoW(secretKey, token string, nonce int64, context string) (bool, error) {
16 parts := strings.Split(token, ".")
17 if len(parts) != 2 {
18 return false, fmt.Errorf("invalid token format")
19 }
20 payloadB64, sig := parts[0], parts[1]
21
22 // 1. Verify HMAC-SHA256 signature
23 mac := hmac.New(sha256.New, []byte(secretKey))
24 mac.Write([]byte(payloadB64))
25 expectedSig := hex.EncodeToString(mac.Sum(nil))
26 if !hmac.Equal([]byte(sig), []byte(expectedSig)) {
27 return false, fmt.Errorf("signature mismatch")
28 }
29
30 // 2. Count leading zero bits of candidate hash
31 candidate := fmt.Sprintf("salt:%d:%s", nonce, context)
32 h := sha256.Sum256([]byte(candidate))
33
34 var zeroBits int
35 for _, b := range h {
36 if b == 0 {
37 zeroBits += 8
38 } else {
39 zeroBits += bits.LeadingZeros8(b)
40 break
41 }
42 }
43 return zeroBits >= 16, nil
44}
1// Background Web Worker PoW Solver (worker.js)
2self.onmessage = async (e) => {
3 const { salt, context, difficulty } = e.data;
4 const encoder = new TextEncoder();
5 let nonce = 0;
6
7 while (true) {
8 const candidate = `${salt}:${nonce}:${context}`;
9 const buf = await crypto.subtle.digest("SHA-256", encoder.encode(candidate));
10 const bytes = new Uint8Array(buf);
11
12 // Count leading zero bits
13 let zeroBits = 0;
14 for (let i = 0; i < bytes.length; i++) {
15 if (bytes[i] === 0) zeroBits += 8;
16 else { zeroBits += Math.clz32(bytes[i]) - 24; break; }
17 }
18
19 if (zeroBits >= difficulty) {
20 self.postMessage({ solved: true, nonce });
21 return;
22 }
23 nonce++;
24 }
25};
1import hashlib, hmac
2
3def verify_pow(secret_key: str, token: str, nonce: int, context: str) -> bool:
4 parts = token.split(".")
5 if len(parts) != 2:
6 return False
7 payload_b64, signature = parts
8
9 # 1. Verify HMAC
10 expected = hmac.new(secret_key.encode(), payload_b64.encode(), hashlib.sha256).hexdigest()
11 if not hmac.compare_digest(signature, expected):
12 return False
13
14 # 2. Check hash difficulty
15 candidate = f"salt:{nonce}:{context}".encode()
16 digest = hashlib.sha256(candidate).digest()
17
18 zero_bits = 0
19 for byte in digest:
20 if byte == 0:
21 zero_bits += 8
22 else:
23 zero_bits += (8 - byte.bit_length())
24 break
25
26 return zero_bits >= 16
1<?php
2function verify_pow($secret_key, $token, $nonce, $context) {
3 $parts = explode(".", $token);
4 if (count($parts) !== 2) return false;
5 list($payload_b64, $signature) = $parts;
6
7 // 1. Verify HMAC
8 $expected = hash_hmac("sha256", $payload_b64, $secret_key);
9 if (!hash_equals($signature, $expected)) return false;
10
11 // 2. Check hash candidate
12 $candidate = "salt:" . $nonce . ":" . $context;
13 $raw_hash = hash("sha256", $candidate, true);
14
15 $zero_bits = 0;
16 for ($i = 0; $i < strlen($raw_hash); $i++) {
17 $byte = ord($raw_hash[$i]);
18 if ($byte === 0) {
19 $zero_bits += 8;
20 } else {
21 $zero_bits += (8 - strlen(decbin($byte)));
22 break;
23 }
24 }
25 return $zero_bits >= 16;
26}
1#!/bin/sh
2# POSIX-compliant PoW solver
3SALT="a1b2c3d4e5f67890"
4CTX="job_context_fingerprint"
5
6nonce=0
7while :; do
8 hash=$(printf "%s:%s:%s" "$SALT" "$nonce" "$CTX" | sha256sum | awk "{print \$1}")
9 case "$hash" in
10 0000*)
11 printf "Solved! Nonce: %s Hash: %s\n" "$nonce" "$hash"
12 break
13 ;;
14 esac
15 nonce=$((nonce + 1))
16done