Equation Auth — Identity Without Passwords
Zeq OS uses mathematical equations as authentication keys. Instead of passwords, users choose an equation (e.g., x^2 + sin(y*pi) + phi). The server evaluates it at the universal constants x = 1.287 and y = 0.777, hashes the result with SHA-256, and derives a unique ZID (Zeq Identity).
The equation is never stored — only its hash. The same equation always produces the same identity.
How It Works
1. User enters equation: x^2 + sin(y) - 7
2. Server evaluates at x=1.287, y=0.777 → result
3. SHA-256( "x^2 + sin(y) - 7" + ":" + result ) → hash
4. ZID = "zeq-" + first 12 hex chars of hash
5. Avatar color = "#" + first 6 hex chars of hash
6. Only the hash is stored in the database
Quick Start
Install
npm install @zeq-os/auth
JavaScript / TypeScript
import { ZeqAuthClient, safeEvaluate, hashEquation, deriveZid } from '@zeq-os/auth';
// Client-side evaluation (instant, no network)
const result = safeEvaluate('x^2 + sin(y*pi) + phi');
console.log(result); // 3.917...
// Derive ZID locally
const hash = await hashEquation('x^2 + sin(y*pi) + phi');
const zid = deriveZid(hash); // zeq-a1b2c3d4e5f6
// API client for auth endpoints
const auth = new ZeqAuthClient('/auth');
// Register a new account
const reg = await auth.register('Alice', 'x^2 + sin(y*pi) + phi');
// → { ok: true, zid: 'zeq-...', displayName: 'Alice', token: '...' }
// Login with the same equation
const login = await auth.login('x^2 + sin(y*pi) + phi');
// → { ok: true, zid: 'zeq-...', token: '...' }
// Verify a token
const check = await auth.verify(login.token);
// → { ok: true, valid: true, zid: 'zeq-...', displayName: 'Alice' }
Python
import hashlib, math, json, urllib.request
def safe_evaluate(eq):
"""Evaluate equation at x=1.287, y=0.777 (simplified — use full parser for production)"""
x, y = 1.287, 0.777
return eval(eq, {"__builtins__": {}}, {
"x": x, "y": y, "pi": math.pi, "e": math.e,
"sin": math.sin, "cos": math.cos, "sqrt": math.sqrt,
"phi": (1 + math.sqrt(5)) / 2
})
def hash_equation(eq):
result = safe_evaluate(eq)
input_str = eq.lower().strip() + ":" + str(result)
return hashlib.sha256(input_str.encode()).hexdigest()
def derive_zid(h):
return "zeq-" + h[:12]
# Example
h = hash_equation("x**2 + sin(y)")
print(derive_zid(h)) # zeq-...
Browser Integration (window.ZeqAuth)
The global navigation bar (injected on every page) exposes window.ZeqAuth for client-side auth:
// Check if user is logged in
if (window.ZeqAuth && window.ZeqAuth.isLoggedIn()) {
const user = window.ZeqAuth.getUser();
console.log(user.id); // zeq-a1b2c3d4e5f6
console.log(user.displayName); // Alice
console.log(user.avatarColor); // #a1b2c3
const token = window.ZeqAuth.getToken();
// Use token for authenticated API calls
}
// Open the login modal programmatically
window.ZeqAuth.showLoginModal();
// Listen for auth changes (login/logout)
window.ZeqAuth.onAuthChange(function(user) {
if (user) {
console.log('Logged in as', user.displayName);
} else {
console.log('Logged out');
}
});
// Check if rate limit prompt should show
window.ZeqAuth.shouldPromptLogin(); // true after 20 unauthenticated page views
API Reference
| Method | Returns | Description |
|---|---|---|
isLoggedIn() | boolean | Whether a valid token exists |
getUser() | object | null | { id, displayName, avatarColor, authMethod } |
getToken() | string | null | Raw JWT token for API calls |
showLoginModal() | void | Opens the Sign In / Register modal |
shouldPromptLogin() | boolean | True when usage limit exceeded |
onAuthChange(callback) | void | Register a callback for login/logout events |
Auth Endpoints
All endpoints are served at /auth/ (proxied to port 3015):
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /auth/register | No | Register with { displayName, equation } |
| POST | /auth/login | No | Login with { equation, zid? } |
| POST | /auth/verify | No | Verify { token } → { valid, zid, displayName } |
| GET | /auth/profile | Bearer | Get user profile |
| GET | /auth/health | No | Service health check |
Token Format
Tokens are Base64url-encoded JSON:
{ "zid": "zeq-a1b2c3d4e5f6", "exp": 1772589248018 }
- TTL: 7 days from issuance
- Storage:
localStoragekeyzeq_token - User data:
localStoragekeyzeq_user - Cross-tab: Login in one tab is reflected in all other tabs via
storageevents
Rate Limiting (Try Before You Sign Up)
Zeq OS allows unauthenticated users to explore freely. After 20 page views, a non-blocking banner encourages sign-in. Users can dismiss it for 10 additional free views.
Apps can check this via:
if (window.ZeqAuth.shouldPromptLogin()) {
// Show your own in-app prompt, or rely on the global banner
}
Supported Equation Features
Functions (16): sin, cos, tan, asin, acos, atan, sqrt, abs, log, ln, log10, exp, floor, ceil, round, sign
Constants: pi (π), e (Euler's number), phi (φ, golden ratio)
Variables: x = 1.287, y = 0.777
Operators: +, -, *, /, ^ (right-associative), unary +/-, parentheses
Limits: Max 500 characters. Division by zero and non-finite results are rejected.
Security
- Equations are never stored — only
SHA-256(equation + ":" + result)is persisted - The parser uses no
eval()— safe recursive descent with a whitelist of functions - ZID collisions are astronomically unlikely (12 hex chars = 48 bits of entropy)
- All computation is deterministic — same equation always gives same identity
For security architecture details, see Security: Equation Auth.
Package Exports
// @zeq-os/auth
import { ZeqAuthClient } from '@zeq-os/auth'; // HTTP client
import { safeEvaluate } from '@zeq-os/auth'; // Parser
import { hashEquation, deriveZid } from '@zeq-os/auth'; // Hashing
import { safeEvaluate as EquationParser } from '@zeq-os/auth'; // Alias
// Subpath imports
import { ZeqAuthClient } from '@zeq-os/auth/client';
import { safeEvaluate } from '@zeq-os/auth/parser';
import { hashEquation } from '@zeq-os/auth/hash';