Initial commit: WireGuard config generator (génération de clés côté navigateur)

This commit is contained in:
florian committed 2026-08-27 15:06:00 +02:00
commit 581a7c9ed3
11 files changed
+3014

No files matched your search

+257
View File
@@ -0,0 +1,257 @@
(() => {
"use strict";
// ---------- base64 helpers ----------
function toBase64(bytes) {
let bin = "";
for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
return btoa(bin);
}
// ---------- WireGuard key generation (X25519 via TweetNaCl) ----------
function genKeyPair() {
const kp = nacl.box.keyPair();
return {
privateKey: toBase64(kp.secretKey),
publicKey: toBase64(kp.publicKey),
};
}
function genPresharedKey() {
return toBase64(nacl.randomBytes(32));
}
// ---------- IP helpers (IPv4 only) ----------
function parseCidr(cidr) {
const [ip, prefixStr] = cidr.trim().split("/");
const prefix = parseInt(prefixStr, 10);
const parts = ip.split(".").map(Number);
if (parts.length !== 4 || parts.some((p) => isNaN(p) || p < 0 || p > 255) || isNaN(prefix)) {
throw new Error("Réseau CIDR invalide: " + cidr);
}
const base = ((parts[0] << 24) >>> 0) + (parts[1] << 16) + (parts[2] << 8) + parts[3];
return { base: base >>> 0, prefix };
}
function intToIp(int) {
return [
(int >>> 24) & 255,
(int >>> 16) & 255,
(int >>> 8) & 255,
int & 255,
].join(".");
}
function nthAddress(cidr, n) {
const { base, prefix } = parseCidr(cidr);
const hostBits = 32 - prefix;
const maxHosts = Math.pow(2, hostBits);
if (n >= maxHosts) throw new Error("Le réseau " + cidr + " est trop petit pour ce nombre de pairs.");
const network = (base >>> hostBits) << hostBits;
return intToIp((network >>> 0) + n);
}
// ---------- DOM ----------
const clientsList = document.getElementById("clients-list");
const addClientBtn = document.getElementById("add-client");
const generateBtn = document.getElementById("generate-btn");
const resetBtn = document.getElementById("reset-btn");
const resultsEl = document.getElementById("results");
const serverSummary = document.getElementById("server-summary");
const serverConfText = document.getElementById("server-conf-text");
let clientCounter = 0;
function addClientRow(name) {
clientCounter++;
const row = document.createElement("div");
row.className = "client-row";
row.innerHTML = `
<input type="text" class="client-name" placeholder="Nom du client" value="${name || "client" + clientCounter}" />
<button class="btn-danger remove-client" title="Supprimer">✕</button>
`;
row.querySelector(".remove-client").addEventListener("click", () => {
row.remove();
});
clientsList.appendChild(row);
}
addClientBtn.addEventListener("click", () => addClientRow());
addClientRow("client1");
resetBtn.addEventListener("click", () => {
clientsList.innerHTML = "";
clientCounter = 0;
addClientRow("client1");
resultsEl.innerHTML = "";
serverSummary.style.display = "none";
});
document.addEventListener("click", (e) => {
if (e.target.matches("[data-copy-target]")) {
const targetId = e.target.getAttribute("data-copy-target");
const el = document.getElementById(targetId);
const text = el.tagName === "TEXTAREA" || el.tagName === "INPUT" ? el.value : el.textContent;
navigator.clipboard.writeText(text).then(() => {
const original = e.target.textContent;
e.target.textContent = "Copié !";
setTimeout(() => (e.target.textContent = original), 1200);
});
}
});
function buildClientConfig({ clientPrivateKey, clientIp, network, dns, serverPubKey, endpoint, port, allowedIps, psk }) {
const prefixLen = network.split("/")[1];
let conf = `[Interface]\n`;
conf += `PrivateKey = ${clientPrivateKey}\n`;
conf += `Address = ${clientIp}/${prefixLen}\n`;
if (dns) conf += `DNS = ${dns}\n`;
conf += `\n[Peer]\n`;
conf += `PublicKey = ${serverPubKey}\n`;
if (psk) conf += `PresharedKey = ${psk}\n`;
conf += `Endpoint = ${endpoint}:${port}\n`;
conf += `AllowedIPs = ${allowedIps}\n`;
conf += `PersistentKeepalive = 25\n`;
return conf;
}
function buildServerPeerBlock({ name, clientPubKey, clientIp, psk }) {
let block = `# ${name}\n[Peer]\n`;
block += `PublicKey = ${clientPubKey}\n`;
if (psk) block += `PresharedKey = ${psk}\n`;
block += `AllowedIPs = ${clientIp}/32\n`;
return block;
}
function renderQr(container, text) {
try {
const qr = qrcode(0, "M");
qr.addData(text);
qr.make();
container.innerHTML = qr.createSvgTag(4, 8);
} catch (err) {
container.textContent = "QR indisponible (config trop longue)";
}
}
function downloadFile(filename, content) {
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
generateBtn.addEventListener("click", () => {
resultsEl.innerHTML = "";
serverSummary.style.display = "none";
try {
const endpoint = document.getElementById("srv-endpoint").value.trim();
const port = document.getElementById("srv-port").value.trim() || "51820";
const network = document.getElementById("srv-network").value.trim();
const serverIp = document.getElementById("srv-server-ip").value.trim();
const dns = document.getElementById("srv-dns").value.trim();
const allowedIps = document.getElementById("srv-allowed-ips").value.trim() || "0.0.0.0/0, ::/0";
const usePsk = document.getElementById("use-psk").checked;
let serverPubKeyInput = document.getElementById("srv-pubkey").value.trim();
if (!endpoint) {
alert("Merci de renseigner l'endpoint du serveur.");
return;
}
parseCidr(network); // validate
const clientNames = Array.from(document.querySelectorAll(".client-name"))
.map((i) => i.value.trim())
.filter((v) => v.length > 0);
if (clientNames.length === 0) {
alert("Ajoutez au moins un client.");
return;
}
let serverKeyPair = null;
let serverPubKey = serverPubKeyInput;
if (!serverPubKey) {
serverKeyPair = genKeyPair();
serverPubKey = serverKeyPair.publicKey;
}
const serverPeerBlocks = [];
const resultCards = [];
clientNames.forEach((name, idx) => {
const clientIp = nthAddress(network, idx + 2); // .1 reserved for server
const clientKeys = genKeyPair();
const psk = usePsk ? genPresharedKey() : null;
const clientConf = buildClientConfig({
clientPrivateKey: clientKeys.privateKey,
clientIp,
network,
dns,
serverPubKey,
endpoint,
port,
allowedIps,
psk,
});
serverPeerBlocks.push(
buildServerPeerBlock({ name, clientPubKey: clientKeys.publicKey, clientIp, psk })
);
resultCards.push({ name, clientIp, clientConf });
});
// Server config summary
let serverConf = `[Interface]\n`;
serverConf += `Address = ${serverIp}/${network.split("/")[1]}\n`;
serverConf += `ListenPort = ${port}\n`;
if (serverKeyPair) {
serverConf += `PrivateKey = ${serverKeyPair.privateKey}\n`;
} else {
serverConf += `PrivateKey = <votre clé privée serveur existante>\n`;
}
serverConf += `\n` + serverPeerBlocks.join("\n");
serverConfText.textContent = serverConf;
serverSummary.style.display = "block";
resultCards.forEach((card, i) => {
const wrapper = document.createElement("div");
wrapper.className = "panel result-card";
const preId = `client-conf-${i}`;
wrapper.innerHTML = `
<h3>${card.name} — ${card.clientIp}</h3>
<div class="result-body">
<pre id="${preId}">${card.clientConf}</pre>
<div class="qr-wrap">
<div class="qr-canvas"></div>
<span class="hint">Scanner avec l'app WireGuard mobile</span>
</div>
</div>
<div class="actions">
<button class="btn-secondary copy-btn" data-copy-target="${preId}">Copier la config</button>
<button class="btn-secondary download-btn">Télécharger .conf</button>
</div>
`;
wrapper.querySelector(".download-btn").addEventListener("click", () => {
downloadFile(`${card.name}.conf`, card.clientConf);
});
renderQr(wrapper.querySelector(".qr-canvas"), card.clientConf);
resultsEl.appendChild(wrapper);
});
resultsEl.scrollIntoView({ behavior: "smooth", block: "start" });
} catch (err) {
alert(err.message || String(err));
}
});
})();
+91
View File
@@ -0,0 +1,91 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>WireGuard Config Generator</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<header>
<h1>WireGuard <span>Config Generator</span></h1>
<p>Générez des configurations WireGuard prêtes à l'emploi.</p>
<span class="badge">🔒 100% local — aucune clé ne quitte votre navigateur</span>
</header>
<main>
<section class="panel">
<h2>Paramètres du serveur</h2>
<div class="grid">
<div class="field">
<label for="srv-endpoint">Endpoint (hôte ou IP publique)</label>
<input type="text" id="srv-endpoint" placeholder="vpn.example.com" />
</div>
<div class="field">
<label for="srv-port">Port d'écoute</label>
<input type="number" id="srv-port" value="51820" min="1" max="65535" />
</div>
<div class="field">
<label for="srv-network">Réseau VPN (CIDR)</label>
<input type="text" id="srv-network" value="10.10.0.0/24" placeholder="10.10.0.0/24" />
</div>
<div class="field">
<label for="srv-server-ip">IP du serveur dans le VPN</label>
<input type="text" id="srv-server-ip" value="10.10.0.1" />
</div>
<div class="field">
<label for="srv-dns">DNS pour les clients (optionnel)</label>
<input type="text" id="srv-dns" placeholder="1.1.1.1" />
</div>
<div class="field">
<label for="srv-allowed-ips">AllowedIPs côté client</label>
<input type="text" id="srv-allowed-ips" value="0.0.0.0/0, ::/0" />
</div>
</div>
<div class="field">
<label for="srv-pubkey">Clé publique du serveur (laisser vide pour en générer une nouvelle)</label>
<input type="text" id="srv-pubkey" placeholder="générée automatiquement si vide" />
</div>
<div class="checkbox-row field">
<input type="checkbox" id="use-psk" checked />
<label for="use-psk" style="margin:0;">Ajouter une clé pré-partagée (PresharedKey) par client</label>
</div>
</section>
<section class="panel">
<div class="section-title-row">
<h2 style="margin:0;">Clients</h2>
<button class="btn-secondary" id="add-client">+ Ajouter un client</button>
</div>
<div class="clients-list" id="clients-list"></div>
<p class="hint">L'adresse IP de chaque client est attribuée automatiquement à partir du réseau VPN défini ci-dessus (serveur = .1, premier client = .2, etc.).</p>
</section>
<div class="actions">
<button class="btn-primary" id="generate-btn">Générer les configurations</button>
<button class="btn-secondary" id="reset-btn">Réinitialiser</button>
</div>
<section class="panel" id="server-summary" style="display:none;">
<div class="section-title-row">
<h2 style="margin:0;">Configuration serveur (wg0.conf)</h2>
<button class="btn-secondary copy-btn" data-copy-target="server-conf-text">Copier</button>
</div>
<div class="server-block" id="server-conf-text"></div>
<p class="hint">À placer sur le serveur WireGuard (ex. <code>/etc/wireguard/wg0.conf</code>). Contient la clé privée du serveur : gardez-la secrète.</p>
</section>
<section id="results"></section>
</main>
<footer>
Générateur WireGuard — aucune donnée n'est envoyée à un serveur, tout est calculé dans votre navigateur (tweetnacl / X25519).
</footer>
<script src="vendor/tweetnacl.min.js"></script>
<script src="vendor/qrcode.min.js"></script>
<script src="app.js"></script>
</body>
</html>
+272
View File
@@ -0,0 +1,272 @@
:root {
--bg: #0f1420;
--bg-elevated: #171d2c;
--surface: #1e263a;
--surface-hover: #262f47;
--border: #2a3349;
--border-strong: #3a4560;
--text: #e6e9f0;
--text-muted: #8a93a8;
--text-faint: #6b7690;
--accent: #7c5cff;
--accent-strong: #9c85ff;
--accent-contrast: #ffffff;
--accent-soft: rgba(124, 92, 255, 0.12);
--ok: #4fd1c5;
--ok-soft: rgba(79, 209, 197, 0.12);
--warn: #fbbf24;
--warn-soft: rgba(251, 191, 36, 0.12);
--danger: #ff6b6b;
--danger-soft: rgba(255, 107, 107, 0.12);
--radius-sm: 6px;
--radius-md: 10px;
--radius-lg: 16px;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.5;
}
header {
padding: 2.5rem 1.5rem 1rem;
text-align: center;
}
header h1 {
margin: 0 0 0.4rem;
font-size: 1.7rem;
}
header h1 span {
color: var(--accent-strong);
}
header p {
margin: 0;
color: var(--text-muted);
font-size: 0.95rem;
}
.badge {
display: inline-block;
margin-top: 0.7rem;
padding: 0.25rem 0.7rem;
border-radius: 999px;
background: var(--ok-soft);
color: var(--ok);
border: 1px solid rgba(52, 211, 153, 0.3);
font-size: 0.78rem;
}
main {
max-width: 980px;
margin: 0 auto;
padding: 1rem 1.5rem 4rem;
display: grid;
gap: 1.5rem;
}
.panel {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 1.25rem 1.5rem;
}
.panel h2 {
margin-top: 0;
font-size: 1.1rem;
color: var(--text);
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1rem;
}
label {
display: block;
font-size: 0.85rem;
color: var(--text-muted);
margin-bottom: 0.3rem;
}
input[type="text"], input[type="number"], select {
width: 100%;
padding: 0.55rem 0.7rem;
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text);
font-size: 0.9rem;
font-family: inherit;
}
input:focus, select:focus {
outline: 2px solid var(--accent-strong);
outline-offset: 1px;
border-color: var(--accent);
}
.field {
margin-bottom: 0.9rem;
}
.checkbox-row {
display: flex;
align-items: center;
gap: 0.5rem;
}
.checkbox-row input { width: auto; }
.clients-list {
display: grid;
gap: 0.6rem;
margin-bottom: 1rem;
}
.client-row {
display: flex;
gap: 0.6rem;
align-items: center;
}
.client-row input { flex: 1; }
button {
cursor: pointer;
border: none;
border-radius: var(--radius-sm);
padding: 0.55rem 1rem;
font-size: 0.9rem;
font-family: inherit;
font-weight: 600;
}
.btn-primary {
background: var(--accent);
color: var(--accent-contrast);
}
.btn-primary:hover { background: var(--accent-strong); }
.btn-secondary {
background: var(--surface-hover);
color: var(--text);
border: 1px solid var(--border-strong);
}
.btn-secondary:hover { border-color: var(--accent); color: var(--accent-strong); background: var(--accent-soft); }
.btn-danger {
background: transparent;
color: var(--danger);
border: 1px solid rgba(248, 113, 113, 0.4);
padding: 0.4rem 0.6rem;
}
.btn-danger:hover { background: var(--danger-soft); }
.actions {
display: flex;
gap: 0.7rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.result-card {
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 1rem;
background: var(--bg-elevated);
margin-bottom: 1rem;
border-top: 3px solid var(--accent);
}
.result-card h3 {
margin: 0 0 0.6rem;
font-size: 1rem;
color: var(--accent-strong);
}
.result-body {
display: flex;
gap: 1.2rem;
flex-wrap: wrap;
}
pre {
flex: 1;
min-width: 260px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 0.8rem;
font-size: 0.8rem;
overflow-x: auto;
margin: 0;
white-space: pre-wrap;
word-break: break-all;
}
.qr-wrap {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.qr-wrap canvas, .qr-wrap img {
background: white;
padding: 8px;
border-radius: var(--radius-sm);
}
.server-block {
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 0.8rem;
font-size: 0.8rem;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-all;
}
.hint {
color: var(--text-faint);
font-size: 0.8rem;
margin-top: 0.3rem;
}
footer {
text-align: center;
color: var(--text-faint);
font-size: 0.78rem;
padding: 1rem 1.5rem 2.5rem;
}
.copy-btn {
font-size: 0.78rem;
padding: 0.3rem 0.6rem;
margin-left: 0.4rem;
}
.section-title-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.6rem;
}
+2297
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
!function(i){"use strict";var m=function(r,n){this.hi=0|r,this.lo=0|n},v=function(r){var n,e=new Float64Array(16);if(r)for(n=0;n<r.length;n++)e[n]=r[n];return e},a=function(){throw new Error("no PRNG")},o=new Uint8Array(16),e=new Uint8Array(32);e[0]=9;var c=v(),w=v([1]),g=v([56129,1]),y=v([30883,4953,19914,30187,55467,16705,2637,112,59544,30585,16505,36039,65139,11119,27886,20995]),l=v([61785,9906,39828,60374,45398,33411,5274,224,53552,61171,33010,6542,64743,22239,55772,9222]),t=v([54554,36645,11616,51542,42930,38181,51040,26924,56412,64982,57905,49316,21502,52590,14035,8553]),f=v([26200,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214]),s=v([41136,18958,6951,50414,58488,44335,6150,12099,55207,15867,153,11085,57099,20417,9344,11139]);function h(r,n){return r<<n|r>>>32-n}function b(r,n){var e=255&r[n+3];return(e=(e=e<<8|255&r[n+2])<<8|255&r[n+1])<<8|255&r[n+0]}function B(r,n){var e=r[n]<<24|r[n+1]<<16|r[n+2]<<8|r[n+3],t=r[n+4]<<24|r[n+5]<<16|r[n+6]<<8|r[n+7];return new m(e,t)}function p(r,n,e){var t;for(t=0;t<4;t++)r[n+t]=255&e,e>>>=8}function S(r,n,e){r[n]=e.hi>>24&255,r[n+1]=e.hi>>16&255,r[n+2]=e.hi>>8&255,r[n+3]=255&e.hi,r[n+4]=e.lo>>24&255,r[n+5]=e.lo>>16&255,r[n+6]=e.lo>>8&255,r[n+7]=255&e.lo}function u(r,n,e,t,o){var i,a=0;for(i=0;i<o;i++)a|=r[n+i]^e[t+i];return(1&a-1>>>8)-1}function A(r,n,e,t){return u(r,n,e,t,16)}function _(r,n,e,t){return u(r,n,e,t,32)}function U(r,n,e,t,o){var i,a,f,u=new Uint32Array(16),c=new Uint32Array(16),w=new Uint32Array(16),y=new Uint32Array(4);for(i=0;i<4;i++)c[5*i]=b(t,4*i),c[1+i]=b(e,4*i),c[6+i]=b(n,4*i),c[11+i]=b(e,16+4*i);for(i=0;i<16;i++)w[i]=c[i];for(i=0;i<20;i++){for(a=0;a<4;a++){for(f=0;f<4;f++)y[f]=c[(5*a+4*f)%16];for(y[1]^=h(y[0]+y[3]|0,7),y[2]^=h(y[1]+y[0]|0,9),y[3]^=h(y[2]+y[1]|0,13),y[0]^=h(y[3]+y[2]|0,18),f=0;f<4;f++)u[4*a+(a+f)%4]=y[f]}for(f=0;f<16;f++)c[f]=u[f]}if(o){for(i=0;i<16;i++)c[i]=c[i]+w[i]|0;for(i=0;i<4;i++)c[5*i]=c[5*i]-b(t,4*i)|0,c[6+i]=c[6+i]-b(n,4*i)|0;for(i=0;i<4;i++)p(r,4*i,c[5*i]),p(r,16+4*i,c[6+i])}else for(i=0;i<16;i++)p(r,4*i,c[i]+w[i]|0)}function E(r,n,e,t){U(r,n,e,t,!1)}function x(r,n,e,t){return U(r,n,e,t,!0),0}var d=new Uint8Array([101,120,112,97,110,100,32,51,50,45,98,121,116,101,32,107]);function K(r,n,e,t,o,i,a){var f,u,c=new Uint8Array(16),w=new Uint8Array(64);if(!o)return 0;for(u=0;u<16;u++)c[u]=0;for(u=0;u<8;u++)c[u]=i[u];for(;64<=o;){for(E(w,c,a,d),u=0;u<64;u++)r[n+u]=(e?e[t+u]:0)^w[u];for(f=1,u=8;u<16;u++)f=f+(255&c[u])|0,c[u]=255&f,f>>>=8;o-=64,n+=64,e&&(t+=64)}if(0<o)for(E(w,c,a,d),u=0;u<o;u++)r[n+u]=(e?e[t+u]:0)^w[u];return 0}function Y(r,n,e,t,o){return K(r,n,null,0,e,t,o)}function L(r,n,e,t,o){var i=new Uint8Array(32);return x(i,t,o,d),Y(r,n,e,t.subarray(16),i)}function T(r,n,e,t,o,i,a){var f=new Uint8Array(32);return x(f,i,a,d),K(r,n,e,t,o,i.subarray(16),f)}function k(r,n){var e,t=0;for(e=0;e<17;e++)t=t+(r[e]+n[e]|0)|0,r[e]=255&t,t>>>=8}var z=new Uint32Array([5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,252]);function R(r,n,e,t,o,i){var a,f,u,c,w=new Uint32Array(17),y=new Uint32Array(17),l=new Uint32Array(17),s=new Uint32Array(17),h=new Uint32Array(17);for(u=0;u<17;u++)y[u]=l[u]=0;for(u=0;u<16;u++)y[u]=i[u];for(y[3]&=15,y[4]&=252,y[7]&=15,y[8]&=252,y[11]&=15,y[12]&=252,y[15]&=15;0<o;){for(u=0;u<17;u++)s[u]=0;for(u=0;u<16&&u<o;++u)s[u]=e[t+u];for(s[u]=1,t+=u,o-=u,k(l,s),f=0;f<17;f++)for(u=w[f]=0;u<17;u++)w[f]=w[f]+l[u]*(u<=f?y[f-u]:320*y[f+17-u]|0)|0;for(f=0;f<17;f++)l[f]=w[f];for(u=c=0;u<16;u++)c=c+l[u]|0,l[u]=255&c,c>>>=8;for(c=c+l[16]|0,l[16]=3&c,c=5*(c>>>2)|0,u=0;u<16;u++)c=c+l[u]|0,l[u]=255&c,c>>>=8;c=c+l[16]|0,l[16]=c}for(u=0;u<17;u++)h[u]=l[u];for(k(l,z),a=0|-(l[16]>>>7),u=0;u<17;u++)l[u]^=a&(h[u]^l[u]);for(u=0;u<16;u++)s[u]=i[u+16];for(s[16]=0,k(l,s),u=0;u<16;u++)r[n+u]=l[u];return 0}function P(r,n,e,t,o,i){var a=new Uint8Array(16);return R(a,0,e,t,o,i),A(r,n,a,0)}function M(r,n,e,t,o){var i;if(e<32)return-1;for(T(r,0,n,0,e,t,o),R(r,16,r,32,e-32,r),i=0;i<16;i++)r[i]=0;return 0}function N(r,n,e,t,o){var i,a=new Uint8Array(32);if(e<32)return-1;if(L(a,0,32,t,o),0!==P(n,16,n,32,e-32,a))return-1;for(T(r,0,n,0,e,t,o),i=0;i<32;i++)r[i]=0;return 0}function O(r,n){var e;for(e=0;e<16;e++)r[e]=0|n[e]}function C(r){var n,e;for(e=0;e<16;e++)r[e]+=65536,n=Math.floor(r[e]/65536),r[(e+1)*(e<15?1:0)]+=n-1+37*(n-1)*(15===e?1:0),r[e]-=65536*n}function F(r,n,e){for(var t,o=~(e-1),i=0;i<16;i++)t=o&(r[i]^n[i]),r[i]^=t,n[i]^=t}function Z(r,n){var e,t,o,i=v(),a=v();for(e=0;e<16;e++)a[e]=n[e];for(C(a),C(a),C(a),t=0;t<2;t++){for(i[0]=a[0]-65517,e=1;e<15;e++)i[e]=a[e]-65535-(i[e-1]>>16&1),i[e-1]&=65535;i[15]=a[15]-32767-(i[14]>>16&1),o=i[15]>>16&1,i[14]&=65535,F(a,i,1-o)}for(e=0;e<16;e++)r[2*e]=255&a[e],r[2*e+1]=a[e]>>8}function G(r,n){var e=new Uint8Array(32),t=new Uint8Array(32);return Z(e,r),Z(t,n),_(e,0,t,0)}function q(r){var n=new Uint8Array(32);return Z(n,r),1&n[0]}function D(r,n){var e;for(e=0;e<16;e++)r[e]=n[2*e]+(n[2*e+1]<<8);r[15]&=32767}function I(r,n,e){var t;for(t=0;t<16;t++)r[t]=n[t]+e[t]|0}functionLine truncated