secubox-openwrt/package/secubox/zkp-hamiltonian/tools/zkp_keygen.c
CyberMind-FR 6553936886 feat(zkp-hamiltonian): Add Zero-Knowledge Proof library based on Hamiltonian Cycle
Implements NIZK (Non-Interactive Zero-Knowledge) proof protocol using
Blum's Hamiltonian Cycle construction with Fiat-Shamir transformation.

Features:
- Complete C99 library with SHA3-256 commitments (via OpenSSL)
- Graph generation with embedded trapdoor (Hamiltonian cycle)
- NIZK proof generation and verification
- Binary serialization for proofs, graphs, and cycles
- CLI tools: zkp_keygen, zkp_prover, zkp_verifier
- Comprehensive test suite (41 tests)

Security properties:
- Completeness: honest prover always convinces verifier
- Soundness: cheater fails with probability >= 1 - 2^(-128)
- Zero-Knowledge: verifier learns nothing about the secret cycle

Target: OpenWrt ARM (SecuBox authentication module)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-24 09:59:16 +01:00

175 lines
5.0 KiB
C

/**
* @file zkp_keygen.c
* @brief CLI tool for generating ZKP key pairs (Graph G, Cycle H)
* @version 1.0
*
* Usage: zkp_keygen -n <nodes> [-r <ratio>] -o <output_prefix>
*
* Generates:
* <output_prefix>.graph - Public graph G (can be shared)
* <output_prefix>.key - Secret Hamiltonian cycle H (CONFIDENTIAL!)
*
* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright (C) 2026 CyberMind.FR / SecuBox
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include "zkp_hamiltonian.h"
#include "zkp_graph.h"
static void print_usage(const char *prog)
{
fprintf(stderr, "Usage: %s -n <nodes> [-r <ratio>] -o <output_prefix>\n", prog);
fprintf(stderr, "\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -n, --nodes <n> Number of nodes (3-%d, recommended 50-80)\n", ZKP_MAX_N);
fprintf(stderr, " -r, --ratio <r> Extra edge ratio (default 1.0, range 0.0-5.0)\n");
fprintf(stderr, " -o, --output <pfx> Output prefix (creates <pfx>.graph and <pfx>.key)\n");
fprintf(stderr, " -h, --help Show this help\n");
fprintf(stderr, "\n");
fprintf(stderr, "Example:\n");
fprintf(stderr, " %s -n 50 -r 1.0 -o /etc/secubox/zkp/identity\n", prog);
fprintf(stderr, "\n");
fprintf(stderr, "Output:\n");
fprintf(stderr, " <prefix>.graph Public graph (share with verifiers)\n");
fprintf(stderr, " <prefix>.key Secret cycle (KEEP CONFIDENTIAL!)\n");
}
static int write_file(const char *path, const uint8_t *data, size_t len)
{
FILE *f = fopen(path, "wb");
if (f == NULL) {
perror("fopen");
return -1;
}
size_t written = fwrite(data, 1, len, f);
fclose(f);
if (written != len) {
fprintf(stderr, "Error: only wrote %zu of %zu bytes\n", written, len);
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
int n = 0;
double ratio = 1.0;
const char *output_prefix = NULL;
static struct option long_options[] = {
{"nodes", required_argument, 0, 'n'},
{"ratio", required_argument, 0, 'r'},
{"output", required_argument, 0, 'o'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
int opt;
while ((opt = getopt_long(argc, argv, "n:r:o:h", long_options, NULL)) != -1) {
switch (opt) {
case 'n':
n = atoi(optarg);
break;
case 'r':
ratio = atof(optarg);
break;
case 'o':
output_prefix = optarg;
break;
case 'h':
print_usage(argv[0]);
return 0;
default:
print_usage(argv[0]);
return 2;
}
}
/* Validate arguments */
if (n < 3 || n > ZKP_MAX_N) {
fprintf(stderr, "Error: nodes must be between 3 and %d\n", ZKP_MAX_N);
return 2;
}
if (ratio < 0.0 || ratio > 5.0) {
fprintf(stderr, "Error: ratio must be between 0.0 and 5.0\n");
return 2;
}
if (output_prefix == NULL) {
fprintf(stderr, "Error: output prefix required (-o)\n");
print_usage(argv[0]);
return 2;
}
/* Generate graph and cycle */
printf("Generating ZKP key pair (n=%d, ratio=%.2f)...\n", n, ratio);
Graph G;
HamiltonianCycle H;
ZKPResult res = zkp_generate_graph((uint8_t)n, ratio, &G, &H);
if (res != ZKP_OK) {
fprintf(stderr, "Error: generation failed (code %d)\n", res);
return 1;
}
printf("Generated graph with %u nodes and %u edges\n", G.n, zkp_graph_edge_count(&G));
/* Serialize graph */
uint8_t graph_buf[8192];
size_t graph_len = sizeof(graph_buf);
res = zkp_graph_serialize(&G, graph_buf, &graph_len);
if (res != ZKP_OK) {
fprintf(stderr, "Error: graph serialization failed\n");
return 1;
}
/* Serialize cycle */
uint8_t cycle_buf[256];
size_t cycle_len = sizeof(cycle_buf);
res = zkp_cycle_serialize(&H, cycle_buf, &cycle_len);
if (res != ZKP_OK) {
fprintf(stderr, "Error: cycle serialization failed\n");
return 1;
}
/* Write files */
char graph_path[512];
char key_path[512];
snprintf(graph_path, sizeof(graph_path), "%s.graph", output_prefix);
snprintf(key_path, sizeof(key_path), "%s.key", output_prefix);
if (write_file(graph_path, graph_buf, graph_len) != 0) {
fprintf(stderr, "Error: failed to write %s\n", graph_path);
return 1;
}
printf("Wrote public graph: %s (%zu bytes)\n", graph_path, graph_len);
if (write_file(key_path, cycle_buf, cycle_len) != 0) {
fprintf(stderr, "Error: failed to write %s\n", key_path);
return 1;
}
printf("Wrote secret key: %s (%zu bytes)\n", key_path, cycle_len);
printf("\nIMPORTANT:\n");
printf(" - %s can be shared with verifiers\n", graph_path);
printf(" - %s is SECRET! Do NOT share it.\n", key_path);
/* Zero sensitive data */
zkp_secure_zero(&H, sizeof(H));
zkp_secure_zero(cycle_buf, sizeof(cycle_buf));
return 0;
}