Technical Spec · Level 3

BCS Level 3 — Ed25519 Cryptographic Identity

Full spec for the highest identity tier of Bot Conduct Standard. Integration time: 10–15 minutes.

1. Overview 2. Generate keypair 3. Upload public key 4. Sign production requests 5. Why Level 3 is the Fast Pass 6. How sites verify 7. Rotation and revocation 8. Security operational guidance 9. Libraries 10. Contact

1. Overview

Level 3 identity binds every production request your bot makes to a cryptographic proof of origin. Sites integrating BCS verify the signature server-side before accepting the request with elevated trust.

Three properties matter:

2. Generate keypair

BCS uses Ed25519 (Edwards-curve Digital Signature Algorithm, RFC 8032). 32-byte public key, 64-byte signatures, constant-time verification, quantum-unsafe (acknowledged, not a 2026 concern).

Python

from nacl.signing import SigningKey
from nacl.encoding import HexEncoder

signing_key = SigningKey.generate()
private_key_hex = signing_key.encode(encoder=HexEncoder).decode()
public_key_hex = signing_key.verify_key.encode(encoder=HexEncoder).decode()

print("PRIVATE (keep secret):", private_key_hex)
print("PUBLIC  (upload this):", public_key_hex)

Node.js

const nacl = require('tweetnacl');
const kp = nacl.sign.keyPair();
const privateKey = Buffer.from(kp.secretKey).toString('hex');
const publicKey  = Buffer.from(kp.publicKey).toString('hex');

Go

import "crypto/ed25519"
pub, priv, _ := ed25519.GenerateKey(rand.Reader)
// store hex-encoded
Private key handling: never in source control, never in logs, never in plaintext env shared across environments. Use a secret manager (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager) or an HSM for production.

3. Upload public key to BCS

First, obtain operator_id and api_key via:

  1. POST /api/operator/register with {email, operator_name} — triggers verification email
  2. POST /api/operator/verify with {email, code} — returns operator_id and api_key

Then upload your public key:

curl -X POST https://botconduct.org/api/operator/upload-key \
  -H "Content-Type: application/json" \
  -d '{
    "operator_id": "op-xxxxxxxxxxxx",
    "api_key": "bcs-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "public_key": "<64-char hex public key>"
  }'

Response:

{
  "status": "key_registered",
  "identity_level": 3,
  "key_fingerprint": "<first 16 chars of sha256(public_key_bytes)>",
  "message": "Public key registered."
}

4. Sign production requests

For every outbound request your bot makes, compute the canonical message and sign it.

Canonical message format

BCS-v1\n
<HTTP_METHOD>\n
<TARGET_URL_exact_string>\n
<ISO8601_TIMESTAMP_UTC>\n
<NONCE_UUID_v4>\n
<SHA256(request_body)_hex or empty string>

Note: newline delimiter is LF (\n), not CRLF. The URL must be the exact string sent (including query string as given, not re-canonicalized).

Example signing function (Python)

from nacl.signing import SigningKey
import hashlib, uuid, datetime

def sign_request(method, url, body_bytes, private_key_hex, operator_id):
    ts = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
    nonce = str(uuid.uuid4())
    body_sha = hashlib.sha256(body_bytes).hexdigest() if body_bytes else ""

    message = f"BCS-v1\n{method}\n{url}\n{ts}\n{nonce}\n{body_sha}"
    sk = SigningKey(bytes.fromhex(private_key_hex))
    sig_bytes = sk.sign(message.encode()).signature
    sig_hex = sig_bytes.hex()

    return {
        "X-BCS-Operator":  operator_id,
        "X-BCS-Timestamp": ts,
        "X-BCS-Nonce":     nonce,
        "X-BCS-Signature": sig_hex,
    }

Required headers

Include these four on every request your bot makes in production:

X-BCS-Operator:  op-xxxxxxxxxxxx
X-BCS-Timestamp: 2026-04-16T15:30:00Z
X-BCS-Nonce:     3f7b8c2e-9a1d-4b6e-8f5a-1c2d3e4f5a6b
X-BCS-Signature: <128-char hex Ed25519 signature>

5. Why Level 3 is the Fast Pass

Level 3 certification makes your agent recognizable at every BCS-integrated site without bilateral setup. Sites trust your signature because our engine validates it — you don't negotiate access with each site individually.

For a site integrating BCS, the common pattern is a two-layer policy: Fast Pass for verified high-score operators, and fall-through to their existing security stack for everyone else:

# In the site's middleware — conceptual
verdict = bcs.score(request)

if verdict["score"] >= 90 and verdict["certified"]:
    allow()  # Fast Pass: skip further checks for certified good actors
else:
    # fall through to existing Cloudflare / DataDome / rules
    existing_security_stack.process(request)

This is why Level 3 matters more than it looks. The cryptographic signature is what lets sites trust the score without calling our API for every single check — they can cache the signature and the per-operator public key, reducing API load and letting Fast Pass work even at CDN edge.

6. How sites verify (what happens server-side)

When a site integrating BCS receives your request, they call our verdict API. The engine:

  1. Resolves your public key by operator_id (indexed lookup).
  2. Reconstructs the canonical message from headers and request metadata.
  3. Verifies the Ed25519 signature.
  4. Checks timestamp freshness: |now − timestamp| ≤ 30 seconds.
  5. Checks nonce uniqueness within a 5-minute window (in-memory nonce cache).
  6. Returns the verdict, including identity_level: 3 when verification succeeds.
Graceful degradation. If signature verification fails or timestamp is stale, the request is scored as Level 1 (UA-only) rather than rejected outright. Your bot is never blocked because of a signing bug — it loses the cryptographic trust bonus until fixed.

7. Rotation and revocation

Rotate public key (routine)

Upload a new public key using the same /api/operator/upload-key endpoint. The previous key enters a 7-day grace period and is then discarded. During the grace period, both keys verify.

Revoke key (emergency — key compromise)

POST /api/operator/revoke-key
{
  "operator_id": "op-xxxxxxxxxxxx",
  "api_key":     "bcs-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "reason":      "key_compromised | routine_rotation | other",
  "replacement_public_key": "<optional new key hex>"
}

Revocation propagates to all BCS-integrated sites via the /api/revocations endpoint. Sites polling every 5 minutes (default) pick up the change; Enterprise sites with webhook push get it immediately.

Certificate lifecycle

Level 3 certificates are valid 90 days from issuance. You can renew by running the active test again or by demonstrating sustained acceptable passive behavior. Renewed cert retains the same operator_id and public key (unless you rotate).

8. Security operational guidance

9. Recommended libraries

LanguageLibrary
Pythonpynacl (pip install pynacl)
Node.jstweetnacl (npm install tweetnacl)
Gocrypto/ed25519 (stdlib)
Rusted25519-dalek
Rubyrbnacl
Java / JVMcom.google.crypto.tink or BouncyCastle
PHPsodium_* functions (PHP 7.2+)

Level 3 certification is free during early access.

Get started →

10. Contact

Technical questions: hello@botconduct.org
X: @botconduct
Reference integration: importsignals.com/security

Spec version 1.0 — last updated 2026-04-16.
Comments welcome. Security issues: email hello@botconduct.org with subject "security".