Privacy Score — Zig source
One number for your privacy health: your browser fingerprint, a test password's strength and breach exposure, and a site's security headers — four checks, one score, concrete fixes. Runs in your browser; only a 5-character hash prefix ever leaves it.
This is the Zig implementation — the same logic the interactive tool runs, in a shareable, citable form.
// privacy-score — composite privacy scoring engine.
//
// Language: Zig (0.13+, standard library only)
// Source: CosmoDev polyglot showcase port of the Privacy Score tool,
// ported from src/lib/privacy-score.ts (canonical TypeScript).
// License: display source — part of CosmoDev's polyglot tool pages.
//
// Four category checks, each scored out of 25; the overall percent is
// renormalized over the categories that actually ran — skipping a check
// never lowers your score. Letter bands: >=85 A, >=70 B, >=50 C, else D.
const std = @import("std");
/// Round to the nearest point and pin into the 0..25 window.
fn clamp25(points: f64) i32 {
const r: i32 = @intFromFloat(@round(points));
return @min(25, @max(0, r));
}
/// More distinguishable signals make a browser more unique: high-risk
/// signals cost 4 each, medium 1.5, and a large surface costs a little more.
fn fingerprintPoints(signal_count: i32, high_risk: i32, medium_risk: i32) i32 {
const surface = @as(f64, @floatFromInt(@max(0, signal_count - 12))) * 0.5;
return clamp25(25.0 - @as(f64, @floatFromInt(high_risk)) * 4.0 - @as(f64, @floatFromInt(medium_risk)) * 1.5 - surface);
}
fn passwordPoints(score: i32, breached: bool) i32 {
const base = @as(f64, @floatFromInt(std.math.clamp(score, 0, 4))) / 4.0 * 25.0;
// Breached is urgent regardless of strength: x0.32 floors even a
// score-4 password at 8 points -> bad -> the change-it recommendation.
return clamp25(if (breached) base * 0.32 else base);
}
/// grades is a string of 'A'..'F' characters, e.g. "AAB".
fn headersPoints(grades: []const u8) i32 {
var f: i32 = 0;
var c: i32 = 0;
var b: i32 = 0;
for (grades) |g| switch (g) {
'F' => f += 1,
'C' => c += 1,
'B' => b += 1,
else => {},
};
if (f > 0) return 0;
if (c > 0) return 10;
if (b > 0) return 18;
return if (grades.len > 0) 25 else 0;
}
fn breachPoints(pwned: bool) i32 {
return if (pwned) 0 else 25;
}
fn letterFor(percent: i32, max: i32) u8 {
if (max == 0) return '-';
if (percent >= 85) return 'A';
if (percent >= 70) return 'B';
if (percent >= 50) return 'C';
return 'D';
}
pub fn main() void {
const checks = [_]i32{
fingerprintPoints(18, 2, 4), // 8
passwordPoints(4, true), // 8 (breach floor)
headersPoints("AAB"), // 18
breachPoints(false), // 25
};
var total: i32 = 0;
for (checks) |p| total += p;
const max: i32 = @as(i32, @intCast(checks.len)) * 25;
const percent: i32 = @intFromFloat(@round(
@as(f64, @floatFromInt(total)) / @as(f64, @floatFromInt(max)) * 100.0,
));
std.debug.print("total {d}/{d} = {d}% -> {c}\n", .{ total, max, percent, letterFor(percent, max) });
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →