aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorW. Kosior <koszko@koszko.org>2025-01-25 19:11:14 +0100
committerW. Kosior <koszko@koszko.org>2025-01-25 19:13:14 +0100
commita47507f8c03886ab50bbc4125b93ffd2d825ed85 (patch)
tree80e9d2846fcd1de22fed2f55a1859d1e1e9a9da5
parentf73883a5dc0b68c03ccc0cfdde39686fd1adb6e2 (diff)
downloadpq-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.md96
-rw-r--r--pqcrypto_blind_sig.c2
-rw-r--r--pqcrypto_blind_sig_example.c255
3 files changed, 334 insertions, 19 deletions
diff --git a/README.md b/README.md
index 6948ce2..2e7274b 100644
--- a/README.md
+++ b/README.md
@@ -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;
}