Skip to main content

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

MethodReturnsDescription
isLoggedIn()booleanWhether a valid token exists
getUser()object | null{ id, displayName, avatarColor, authMethod }
getToken()string | nullRaw JWT token for API calls
showLoginModal()voidOpens the Sign In / Register modal
shouldPromptLogin()booleanTrue when usage limit exceeded
onAuthChange(callback)voidRegister a callback for login/logout events

Auth Endpoints

All endpoints are served at /auth/ (proxied to port 3015):

MethodEndpointAuthDescription
POST/auth/registerNoRegister with { displayName, equation }
POST/auth/loginNoLogin with { equation, zid? }
POST/auth/verifyNoVerify { token }{ valid, zid, displayName }
GET/auth/profileBearerGet user profile
GET/auth/healthNoService health check

Token Format

Tokens are Base64url-encoded JSON:

{ "zid": "zeq-a1b2c3d4e5f6", "exp": 1772589248018 }
  • TTL: 7 days from issuance
  • Storage: localStorage key zeq_token
  • User data: localStorage key zeq_user
  • Cross-tab: Login in one tab is reflected in all other tabs via storage events

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';