Download src/lib/validator.ts from wuhp/pqc: direct link, hf CLI and curl.
- Browser
- Download file 4.23 kB
-
https://huggingface.co/spaces/wuhp/pqc/resolve/main/src/lib/validator.ts
- Command line
-
hf download hf://spaces/wuhp/pqc/src/lib/validator.ts
-
curl -L -o validator.ts https://huggingface.co/spaces/wuhp/pqc/resolve/main/src/lib/validator.ts
4.23 kB
| export enum Severity { | |
| Critical = "Critical", | |
| Warning = "Warning", | |
| Info = "Info", | |
| } | |
| export interface ParamDiagnostic { | |
| severity: Severity; | |
| message: String; | |
| suggestedFix?: String; | |
| } | |
| export interface ValidationResult { | |
| n: number; | |
| q: number; | |
| betaOrSigma: number; | |
| isCbd: boolean; | |
| noiseBudgetMax: number; | |
| noiseBudgetRms: number; | |
| decryptionBudget: number; | |
| failureProb: number; | |
| expectedFailuresIn500: number; | |
| passes: boolean; | |
| diagnostics: ParamDiagnostic[]; | |
| suggestedBeta: number; | |
| suggestedQ: number; | |
| } | |
| export class ParamValidator { | |
| public static validateKyber(n: number, q: number, eta: number): ValidationResult { | |
| const sigma = Math.sqrt(eta / 2.0); | |
| const r = this.validateInner(n, q, sigma, true); | |
| r.betaOrSigma = eta; | |
| return r; | |
| } | |
| public static validateGaussian(n: number, q: number, sigma: number): ValidationResult { | |
| return this.validateInner(n, q, sigma, false); | |
| } | |
| private static validateInner(n: number, q: number, noiseParam: number, isCbd: boolean): ValidationResult { | |
| const qF = q; | |
| const nF = n; | |
| const stdPerCoeff = isCbd ? Math.sqrt(noiseParam / 2.0) : noiseParam; | |
| const betaMax = isCbd ? noiseParam : 3.0 * stdPerCoeff; | |
| // noise ≈ beta * sqrt(3 * n) * std_per_coeff | |
| const noiseBudgetRms = stdPerCoeff * Math.sqrt(3.0 * nF) * betaMax; | |
| const noiseBudgetMax = betaMax * betaMax * nF * 3.0; | |
| const decryptionBudget = qF / 4.0; | |
| const totalStd = stdPerCoeff * betaMax * Math.sqrt(3.0 * nF); | |
| const z = decryptionBudget / Math.max(totalStd, 1e-10); | |
| const failureProb = 2.0 * this.gaussianQFunction(z); | |
| const expectedFailuresIn500 = failureProb * 500.0; | |
| const passes = noiseBudgetRms < decryptionBudget * 0.8; | |
| const diagnostics: ParamDiagnostic[] = []; | |
| if (noiseBudgetMax >= decryptionBudget) { | |
| diagnostics.push({ | |
| severity: Severity.Critical, | |
| message: `WORST-CASE noise (${noiseBudgetMax.toFixed(1)}) EXCEEDS decryption budget (${decryptionBudget.toFixed(1)} = q/4). Decryption WILL fail for some inputs.`, | |
| suggestedFix: `Either: (a) reduce β to ≤${Math.sqrt(decryptionBudget / (nF * 3.0)).toFixed(1)}, or (b) increase q to ≥${Math.ceil(noiseBudgetMax * 4.0)}`, | |
| }); | |
| } else if (noiseBudgetRms >= decryptionBudget * 0.5) { | |
| diagnostics.push({ | |
| severity: Severity.Warning, | |
| message: `RMS noise (${noiseBudgetRms.toFixed(1)}) is ${(100.0 * noiseBudgetRms / decryptionBudget).toFixed(0)}% of budget. Failure rate ≈${(failureProb * 100).toFixed(2)}%.`, | |
| suggestedFix: "Increase q by 2x or decrease β by √2", | |
| }); | |
| } else { | |
| diagnostics.push({ | |
| severity: Severity.Info, | |
| message: `Noise budget OK: RMS noise ${noiseBudgetRms.toFixed(1)} is ${(100.0 * noiseBudgetRms / decryptionBudget).toFixed(0)}% of q/4.`, | |
| }); | |
| } | |
| const estimatedSecurity = this.estimateSecurityBits(n, q, stdPerCoeff); | |
| if (estimatedSecurity < 80.0) { | |
| diagnostics.push({ | |
| severity: Severity.Critical, | |
| message: `Parameters provide only ~${estimatedSecurity.toFixed(0)} bits of security (need ≥128).`, | |
| suggestedFix: "Use n≥256 and q≥3329 for any security claim", | |
| }); | |
| } | |
| return { | |
| n, | |
| q, | |
| betaOrSigma: noiseParam, | |
| isCbd, | |
| noiseBudgetMax, | |
| noiseBudgetRms, | |
| decryptionBudget, | |
| failureProb, | |
| expectedFailuresIn500, | |
| passes, | |
| diagnostics, | |
| suggestedBeta: Math.sqrt(decryptionBudget / (nF * 3.0)) * 0.5, | |
| suggestedQ: Math.ceil(noiseBudgetMax * 8.0), | |
| }; | |
| } | |
| private static gaussianQFunction(z: number): number { | |
| if (z > 10.0) return 0.0; | |
| if (z < 0.0) return 1.0; | |
| const t = 1.0 / (1.0 + 0.2316419 * z); | |
| const poly = t * (0.319381530 | |
| + t * (-0.356563782 | |
| + t * (1.781477937 | |
| + t * (-1.821255978 | |
| + t * 1.330274429)))); | |
| const phi = Math.exp(-z * z / 2.0) / Math.sqrt(2.0 * Math.PI); | |
| return phi * poly; | |
| } | |
| private static estimateSecurityBits(n: number, q: number, sigma: number): number { | |
| const nF = n; | |
| const qF = q; | |
| const alpha = sigma / qF; | |
| if (alpha <= 0.0) return 0.0; | |
| return 0.265 * nF * (-Math.log2(alpha)); | |
| } | |
| } | |