diff options
author | W. Kosior <koszko@koszko.org> | 2025-01-25 19:11:14 +0100 |
---|---|---|
committer | W. Kosior <koszko@koszko.org> | 2025-01-25 19:13:14 +0100 |
commit | a47507f8c03886ab50bbc4125b93ffd2d825ed85 (patch) | |
tree | 80e9d2846fcd1de22fed2f55a1859d1e1e9a9da5 | |
parent | f73883a5dc0b68c03ccc0cfdde39686fd1adb6e2 (diff) | |
download | pq-blind-sigs-impl-a47507f8c03886ab50bbc4125b93ffd2d825ed85.tar.gz pq-blind-sigs-impl-a47507f8c03886ab50bbc4125b93ffd2d825ed85.zip |
Make the sample program able to use files to store data.
-rw-r--r-- | README.md | 96 | ||||
-rw-r--r-- | pqcrypto_blind_sig.c | 2 | ||||
-rw-r--r-- | pqcrypto_blind_sig_example.c | 255 |
3 files changed, 334 insertions, 19 deletions
@@ -7,15 +7,23 @@ Please consider it a toy program — it's being developed with shortcuts (e.g. using a big scientific library (FLINT[2]) for efficient polynomial multiplication). Also, there are possibly better BS algorithms by now. -## How it works +## How to build it + +First, make sure make and GCC, as well as the libraries FLINT and Libgcrypt are +installed. Then, make use of the included `Makefile`. + +``` +make +``` + +## How to run it This implementation includes a simple program that generates a keypair, signs something in memory (while printing some diagnostic messages), verifies the signature and discards everything. It can be invoked like this. ``` -$ make run_blind_sig_example -guix shell qemu -- qemu-x86_64 -cpu max blind_sig_example +$ ./run_blind_sig_example Preparing blind signature context ("Current III" set from Rückert's paper). n = 1024 d_s = 283 @@ -53,7 +61,7 @@ d_beta = 402860937956032512 d_g = 402850009653679104 q = 1208925819614629174706189 Making a test signature for ASCII buffer: "This is a message to blind-sign.". -User could not obtain signature, restart is being requested from signer. +User couldn't get a signature in step 4, restart is being requested from signer. Restart triggered by signer from step 5. User retries with new alpha. Restart triggered by signer from step 3. @@ -64,6 +72,86 @@ Signature verified successfully. Done, cleaning up. ``` +The individual steps can also be performed one-by-one, with intermediary data +used by the protocol written to files named `*.example` (because implementing a +networked protocol would be an overkill for a sample implementation like this). +You can choose your own 1-line message to blind-sign in this case. + +``` +$ STEPS="key_gen $(seq 1 5 | awk '{print "signing_p" $0}') verification" +$ go() { [ 0 = $# ] || (./blind_sig_example "$1" && shift && go "$@"); } +$ while ! (echo 'Hello World' | go $STEPS); do echo 'Restart from step 1.'; done +Write a line-one message to blind-sign. +> +Restart triggered by signer from step 3. +Restart from step 1. +Write a line-one message to blind-sign. +> +User couldn't get a signature in step 4, restart is being requested from signer. +Restart from step 1. +Write a line-one message to blind-sign. +> +User retries with new alpha. +User couldn't get a signature in step 4, restart is being requested from signer. +Restart from step 1. +Write a line-one message to blind-sign. +> +User couldn't get a signature in step 4, restart is being requested from signer. +Restart from step 1. +Write a line-one message to blind-sign. +> +User retries with new alpha. +User retries with new alpha. +User retries with new alpha. +User retries with new alpha. +User retries with new alpha. +User retries with new alpha. +User retries with new alpha. +User retries with new alpha. +User retries with new alpha. +User retries with new alpha. +User successfully obtained signature in step 4. +Signer acknowledged success in signing. +Got valid signature for message. +Hello World +``` + +You can also use the `*.example` files to experiment. E.g., try to substitute +the signed message and see that verification now fails. + +``` +$ echo Funny | dd bs=1 seek=8 count=5 conv=notrunc of=sig.example 2>/dev/null +$ dd bs=1 skip=8 count=12 if=sig.example 2>/dev/null +Funny World +$ ./blind_sig_example verification +Got invalid signature. +``` + +It's easy to see how much space (more or less) the signature and intermediate +protocol messages take. + +``` +$ ls -lh *.example +-rw-r--r-- 1 user user 15K Jan 25 18:23 p1_result.example +-rw-r--r-- 1 user user 5.8K Jan 25 18:23 p2_result.example +-rw-r--r-- 1 user user 90K Jan 25 18:23 p3_result.example +-rw-r--r-- 1 user user 1 Jan 25 18:23 p4_result.example +-rw-r--r-- 1 user user 199K Jan 25 18:23 p5_result.example +-rw-r--r-- 1 user user 46K Jan 25 18:23 priv_key.example +-rw-r--r-- 1 user user 14K Jan 25 18:23 pub_key.example +-rw-r--r-- 1 user user 112K Jan 25 18:23 sig.example +-rw-r--r-- 1 user user 199K Jan 25 18:23 signer_state.example +-rw-r--r-- 1 user user 123K Jan 25 18:23 user_state.example +``` + +The parameters (the "Current III" set from Rückert's paper in this case) are +implicit and not encoded in the signature nor in other files. You can see that +the signature is nevertheless significantly bigger (~112 kB) than what Rückert +gives for this parameter set (66.9 kB). Most of it likely comes from the +encoding of coefficients where only ~81 bits are really needed for each one. +Here, FLINT's (actually, GMP's) serialization is used to encode them. It adds 4 +bytes of length information to each coefficient and doesn't do any bit-packing. + There is also a program (remnant of initial development) that serves as an example of polynomial operations in a ring modulo X^m+1 over a modulo field with non-canonical range — [-(n-1)/2, (n-1)/2] rather than [0, n-1]. diff --git a/pqcrypto_blind_sig.c b/pqcrypto_blind_sig.c index 30c811f..1e14c0d 100644 --- a/pqcrypto_blind_sig.c +++ b/pqcrypto_blind_sig.c @@ -473,7 +473,7 @@ blind_sig_params_t const blind_sig_params_current_III = { .psi = 1, .d_s = 283, .m = 9, - .log_level = BLIND_SIG_LOG_INFO_2_PARAMETERS, + .log_level = BLIND_SIG_LOG_ERROR, } }; diff --git a/pqcrypto_blind_sig_example.c b/pqcrypto_blind_sig_example.c index f471f8f..fd44aee 100644 --- a/pqcrypto_blind_sig_example.c +++ b/pqcrypto_blind_sig_example.c @@ -4,16 +4,19 @@ * 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 test_message[] = "This is a message to blind-sign."; +static const char sample_message[] = "This is a message to blind-sign."; #define RETRIES_MAX 1000U -static void perform_signing(blind_sig_ctx_t const ctx) { +static void signing_example(blind_sig_ctx_t const ctx) { unsigned long retries_left = RETRIES_MAX; blind_sig_priv_key_t priv_key; @@ -39,9 +42,9 @@ 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, test_message, - sizeof(test_message), p1_result, - &retries_left, ctx); + 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); @@ -66,8 +69,7 @@ p1: } /* p4: */ - blind_sig_proto_p4_init_do(p4_result, sig, user_state, test_message, - sizeof(test_message), p3_result, ctx); + 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, @@ -118,17 +120,209 @@ too_many_retries: fprintf(stderr, "Too many retries.\n"); }; -int main(const int argc, const char* const* const argv) { +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; - (void) argc; - (void) argv; - 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"); */ @@ -138,15 +332,48 @@ int main(const int argc, const char* const* const argv) { blind_sig_ctx_init(ctx, params); fprintf(stderr, "Making a test signature for ASCII buffer: \"%s\".\n", - test_message); + sample_message); - perform_signing(ctx); + 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 EXIT_SUCCESS; + return result; } |