/*
* SPDX-License-Identifier: CC0-1.0
*
* Copyright (C) 2025 W. Kosior <koszko@koszko.org>
*/
#define _POSIX_C_SOURCE 200809L /* for getline() */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pqcrypto_blind_sig.h"
static const char sample_message[] = "This is a message to blind-sign.";
#define RETRIES_MAX 1000U
static void signing_example(blind_sig_ctx_t const ctx) {
unsigned long retries_left = RETRIES_MAX;
blind_sig_priv_key_t priv_key;
blind_sig_pub_key_t pub_key;
blind_sig_signer_state_t signer_state;
blind_sig_user_state_t user_state;
blind_sig_proto_p1_t p1_result;
blind_sig_proto_p2_t p2_result;
blind_sig_proto_p3_t p3_result;
blind_sig_proto_p4_t p4_result;
blind_sig_proto_p5_t p5_result;
blind_sig_t sig;
blind_sig_key_init_gen(priv_key, pub_key, ctx);
blind_sig_signer_state_init(signer_state, ctx);
blind_sig_user_state_init(user_state, ctx);
p1:
blind_sig_proto_p1_init_do(p1_result, signer_state, ctx);
/* p2: */
blind_sig_proto_p2_init_do(p2_result, user_state, pub_key,
sample_message, sizeof(sample_message),
p1_result, &retries_left, ctx);
if (!p2_result->ok) {
blind_sig_proto_p1_clear(p1_result, ctx);
blind_sig_proto_p2_clear(p2_result, ctx);
goto too_many_retries;
}
/* p3: */
blind_sig_proto_p3_init_do(p3_result, signer_state, priv_key,
p2_result, ctx);
if (!p3_result->ok) {
blind_sig_proto_p1_clear(p1_result, ctx);
blind_sig_proto_p2_clear(p2_result, ctx);
blind_sig_proto_p3_clear(p3_result, ctx);
if (!(retries_left && retries_left--))
goto too_many_retries;
goto p1;
}
/* p4: */
blind_sig_proto_p4_init_do(p4_result, sig, user_state, p3_result, ctx);
/* p5: */
blind_sig_proto_p5_init_do(p5_result, signer_state, pub_key, p4_result,
ctx);
if (!p5_result->ok) {
blind_sig_proto_p1_clear(p1_result, ctx);
blind_sig_proto_p2_clear(p2_result, ctx);
blind_sig_proto_p3_clear(p3_result, ctx);
blind_sig_proto_p4_clear(p4_result, ctx);
blind_sig_proto_p5_clear(p5_result, ctx);
if (!(retries_left && retries_left--))
goto too_many_retries;
goto p1;
}
/* verification: */
if (!p4_result->needs_restart) {
if (blind_sig_verify(sig, pub_key, ctx))
fprintf(stderr, "Signature verified successfully.\n");
else
fprintf(stderr, "Signature not valid.\n");
}
/* out: */
if (!p4_result->needs_restart)
blind_sig_clear(sig, ctx);
blind_sig_priv_key_clear(priv_key, ctx);
blind_sig_pub_key_clear(pub_key, ctx);
blind_sig_signer_state_clear(signer_state, ctx);
blind_sig_user_state_clear(user_state, ctx);
blind_sig_proto_p1_clear(p1_result, ctx);
blind_sig_proto_p2_clear(p2_result, ctx);
blind_sig_proto_p3_clear(p3_result, ctx);
blind_sig_proto_p4_clear(p4_result, ctx);
blind_sig_proto_p5_clear(p5_result, ctx);
return;
too_many_retries:
fprintf(stderr, "Too many retries.\n");
};
static int perform_key_gen(blind_sig_ctx_t ctx) {
blind_sig_priv_key_t priv_key;
blind_sig_pub_key_t pub_key;
blind_sig_key_init_gen(priv_key, pub_key, ctx);
blind_sig_priv_key_file_serialize("priv_key.example", priv_key, ctx);
blind_sig_pub_key_file_serialize("pub_key.example", pub_key, ctx);
blind_sig_priv_key_clear(priv_key, ctx);
blind_sig_pub_key_clear(pub_key, ctx);
return EXIT_SUCCESS;
}
static int perform_signing_p1(blind_sig_ctx_t ctx) {
blind_sig_signer_state_t signer_state;
blind_sig_proto_p1_t p1_result;
blind_sig_signer_state_init(signer_state, ctx);
blind_sig_proto_p1_init_do(p1_result, signer_state, ctx);
blind_sig_signer_state_file_serialize("signer_state.example",
signer_state, ctx);
blind_sig_proto_p1_file_serialize("p1_result.example", p1_result, ctx);
blind_sig_signer_state_clear(signer_state, ctx);
blind_sig_proto_p1_clear(p1_result, ctx);
return EXIT_SUCCESS;
}
static int perform_signing_p2(blind_sig_ctx_t ctx) {
blind_sig_user_state_t user_state;
blind_sig_pub_key_t pub_key;
ssize_t message_bytes;
char * message_buf = NULL;
size_t message_buf_bytes;
blind_sig_proto_p1_t p1_result;
unsigned long retries_left = RETRIES_MAX;
blind_sig_proto_p2_t p2_result;
int result = EXIT_SUCCESS;
blind_sig_user_state_init(user_state, ctx);
blind_sig_pub_key_file_deserialize("pub_key.example", pub_key, ctx);
printf("Write a line-one message to blind-sign.\n> ");
fflush(stdout);
message_bytes = getline(&message_buf, &message_buf_bytes, stdin);
if (message_bytes <= 0)
abort();
putchar('\n');
blind_sig_proto_p1_file_deserialize("p1_result.example", p1_result,
ctx);
blind_sig_proto_p2_init_do(p2_result, user_state, pub_key, message_buf,
message_bytes, p1_result, &retries_left,
ctx);
if (!p2_result->ok) {
fprintf(stderr, "Too many retries.\n");
result = EXIT_FAILURE;
}
blind_sig_user_state_file_serialize("user_state.example", user_state,
ctx);
blind_sig_proto_p2_file_serialize("p2_result.example", p2_result, ctx);
blind_sig_user_state_clear(user_state, ctx);
blind_sig_pub_key_clear(pub_key, ctx);
free(message_buf);
blind_sig_proto_p1_clear(p1_result, ctx);
blind_sig_proto_p2_clear(p2_result, ctx);
return result;
}
static int perform_signing_p3(blind_sig_ctx_t ctx) {
blind_sig_signer_state_t signer_state;
blind_sig_priv_key_t priv_key;
blind_sig_proto_p2_t p2_result;
blind_sig_proto_p3_t p3_result;
int result;
blind_sig_signer_state_file_deserialize("signer_state.example",
signer_state, ctx);
blind_sig_priv_key_file_deserialize("priv_key.example", priv_key, ctx);
blind_sig_proto_p2_file_deserialize("p2_result.example", p2_result,
ctx);
blind_sig_proto_p3_init_do(p3_result, signer_state, priv_key, p2_result,
ctx);
result = p3_result->ok ? EXIT_SUCCESS : EXIT_FAILURE;
blind_sig_signer_state_file_serialize("signer_state.example",
signer_state, ctx);
blind_sig_proto_p3_file_serialize("p3_result.example", p3_result, ctx);
blind_sig_signer_state_clear(signer_state, ctx);
blind_sig_priv_key_clear(priv_key, ctx);
blind_sig_proto_p2_clear(p2_result, ctx);
blind_sig_proto_p3_clear(p3_result, ctx);
return result;
}
static int perform_signing_p4(blind_sig_ctx_t ctx) {
blind_sig_t sig;
blind_sig_user_state_t user_state;
blind_sig_proto_p3_t p3_result;
blind_sig_proto_p4_t p4_result;
int result;
blind_sig_user_state_file_deserialize("user_state.example", user_state,
ctx);
blind_sig_proto_p3_file_deserialize("p3_result.example", p3_result,
ctx);
blind_sig_proto_p4_init_do(p4_result, sig, user_state, p3_result, ctx);
result = p4_result->needs_restart? EXIT_FAILURE : EXIT_SUCCESS;
/* No serialization of state — it doesn't get modified here. */
if (!p4_result->needs_restart)
blind_sig_file_serialize("sig.example", sig, ctx);
blind_sig_proto_p4_file_serialize("p4_result.example", p4_result, ctx);
if (!p4_result->needs_restart)
blind_sig_clear(sig, ctx);
blind_sig_user_state_clear(user_state, ctx);
blind_sig_proto_p3_clear(p3_result, ctx);
blind_sig_proto_p4_clear(p4_result, ctx);
return result;
}
static int perform_signing_p5(blind_sig_ctx_t ctx) {
blind_sig_signer_state_t signer_state;
blind_sig_pub_key_t pub_key;
blind_sig_proto_p4_t p4_result;
blind_sig_proto_p5_t p5_result;
int result;
blind_sig_signer_state_file_deserialize("signer_state.example",
signer_state, ctx);
blind_sig_pub_key_file_deserialize("pub_key.example", pub_key, ctx);
blind_sig_proto_p4_file_deserialize("p4_result.example", p4_result,
ctx);
blind_sig_proto_p5_init_do(p5_result, signer_state, pub_key, p4_result,
ctx);
result = p5_result->ok ? EXIT_SUCCESS : EXIT_FAILURE;
/* Again, no serialization of state — it doesn't get modified here. */
blind_sig_proto_p5_file_serialize("p5_result.example", p5_result, ctx);
blind_sig_signer_state_clear(signer_state, ctx);
blind_sig_pub_key_clear(pub_key, ctx);
blind_sig_proto_p4_clear(p4_result, ctx);
blind_sig_proto_p5_clear(p5_result, ctx);
return result;
}
static int perform_verification(blind_sig_ctx_t ctx) {
blind_sig_t sig;
blind_sig_pub_key_t pub_key;
int result;
blind_sig_file_deserialize("sig.example", sig, ctx);
blind_sig_pub_key_file_deserialize("pub_key.example", pub_key, ctx);
if (blind_sig_verify(sig, pub_key, ctx)) {
fprintf(stderr, "Got valid signature for message.\n");
fwrite(sig->message->buf, sig->message->bytes, 1, stdout);
result = EXIT_SUCCESS;
} else {
fprintf(stderr, "Got invalid signature.\n");
result = EXIT_FAILURE;
}
blind_sig_clear(sig, ctx);
blind_sig_pub_key_clear(pub_key, ctx);
return result;
}
static void perform_example(void) {
blind_sig_params_t params;
blind_sig_ctx_t ctx;
fprintf(stderr, "Preparing blind signature context (\"Current III\" set"
" from Rückert's paper).\n");
*params = *blind_sig_params_current_III;
params->log_level = BLIND_SIG_LOG_INFO_2_PARAMETERS;
/* fprintf(stderr, "Preparing blind signature context (toy set of" */
/* " parameters).\n"); */
/* *params = *blind_sig_params_toy; */
blind_sig_ctx_init(ctx, params);
fprintf(stderr, "Making a test signature for ASCII buffer: \"%s\".\n",
sample_message);
signing_example(ctx);
fprintf(stderr, "Done, cleaning up.\n");
blind_sig_ctx_clear(ctx);
}
int main(const int argc, const char * const * argv) {
blind_sig_params_t params;
blind_sig_ctx_t ctx;
char const * action = argc > 1 ? argv[1] : "example";
int result = EXIT_SUCCESS;
if (!strcmp(action, "example")) {
perform_example();
goto out;
}
*params = *blind_sig_params_current_III;
params->log_level = BLIND_SIG_LOG_INFO_1_CONTROL;
blind_sig_ctx_init(ctx, params);
#define X(action_name) \
!strcmp(action, #action_name) ? perform_##action_name(ctx) :
result =
X(key_gen)
X(signing_p1)
X(signing_p2)
X(signing_p3)
X(signing_p4)
X(signing_p5)
X(verification)
(fprintf(stderr, "Bad action `%s'.\n", action), EXIT_FAILURE);
#undef X
out:
flint_cleanup();
return result;
}