summaryrefslogtreecommitdiff
path: root/lib/liboqs/src/sig/falcon/pqclean_falcon-512_clean/pqclean.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/liboqs/src/sig/falcon/pqclean_falcon-512_clean/pqclean.c')
-rw-r--r--lib/liboqs/src/sig/falcon/pqclean_falcon-512_clean/pqclean.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/lib/liboqs/src/sig/falcon/pqclean_falcon-512_clean/pqclean.c b/lib/liboqs/src/sig/falcon/pqclean_falcon-512_clean/pqclean.c
new file mode 100644
index 000000000..3abf68149
--- /dev/null
+++ b/lib/liboqs/src/sig/falcon/pqclean_falcon-512_clean/pqclean.c
@@ -0,0 +1,384 @@
+#include "api.h"
+#include "inner.h"
+#include "randombytes.h"
+#include <stddef.h>
+#include <string.h>
+/*
+ * Wrapper for implementing the PQClean API.
+ */
+
+
+
+#define NONCELEN 40
+#define SEEDLEN 48
+
+/*
+ * Encoding formats (nnnn = log of degree, 9 for Falcon-512, 10 for Falcon-1024)
+ *
+ * private key:
+ * header byte: 0101nnnn
+ * private f (6 or 5 bits by element, depending on degree)
+ * private g (6 or 5 bits by element, depending on degree)
+ * private F (8 bits by element)
+ *
+ * public key:
+ * header byte: 0000nnnn
+ * public h (14 bits by element)
+ *
+ * signature:
+ * header byte: 0011nnnn
+ * nonce 40 bytes
+ * value (12 bits by element)
+ *
+ * message + signature:
+ * signature length (2 bytes, big-endian)
+ * nonce 40 bytes
+ * message
+ * header byte: 0010nnnn
+ * value (12 bits by element)
+ * (signature length is 1+len(value), not counting the nonce)
+ */
+
+/* see api.h */
+int
+PQCLEAN_FALCON512_CLEAN_crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
+ union {
+ uint8_t b[FALCON_KEYGEN_TEMP_9];
+ uint64_t dummy_u64;
+ fpr dummy_fpr;
+ } tmp;
+ int8_t f[512], g[512], F[512];
+ uint16_t h[512];
+ unsigned char seed[SEEDLEN];
+ inner_shake256_context rng;
+ size_t u, v;
+
+ /*
+ * Generate key pair.
+ */
+ randombytes(seed, sizeof seed);
+ inner_shake256_init(&rng);
+ inner_shake256_inject(&rng, seed, sizeof seed);
+ inner_shake256_flip(&rng);
+ PQCLEAN_FALCON512_CLEAN_keygen(&rng, f, g, F, NULL, h, 9, tmp.b);
+ inner_shake256_ctx_release(&rng);
+
+ /*
+ * Encode private key.
+ */
+ sk[0] = 0x50 + 9;
+ u = 1;
+ v = PQCLEAN_FALCON512_CLEAN_trim_i8_encode(
+ sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u,
+ f, 9, PQCLEAN_FALCON512_CLEAN_max_fg_bits[9]);
+ if (v == 0) {
+ return -1;
+ }
+ u += v;
+ v = PQCLEAN_FALCON512_CLEAN_trim_i8_encode(
+ sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u,
+ g, 9, PQCLEAN_FALCON512_CLEAN_max_fg_bits[9]);
+ if (v == 0) {
+ return -1;
+ }
+ u += v;
+ v = PQCLEAN_FALCON512_CLEAN_trim_i8_encode(
+ sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u,
+ F, 9, PQCLEAN_FALCON512_CLEAN_max_FG_bits[9]);
+ if (v == 0) {
+ return -1;
+ }
+ u += v;
+ if (u != PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES) {
+ return -1;
+ }
+
+ /*
+ * Encode public key.
+ */
+ pk[0] = 0x00 + 9;
+ v = PQCLEAN_FALCON512_CLEAN_modq_encode(
+ pk + 1, PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1,
+ h, 9);
+ if (v != PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Compute the signature. nonce[] receives the nonce and must have length
+ * NONCELEN bytes. sigbuf[] receives the signature value (without nonce
+ * or header byte), with *sigbuflen providing the maximum value length and
+ * receiving the actual value length.
+ *
+ * If a signature could be computed but not encoded because it would
+ * exceed the output buffer size, then a new signature is computed. If
+ * the provided buffer size is too low, this could loop indefinitely, so
+ * the caller must provide a size that can accommodate signatures with a
+ * large enough probability.
+ *
+ * Return value: 0 on success, -1 on error.
+ */
+static int
+do_sign(uint8_t *nonce, uint8_t *sigbuf, size_t *sigbuflen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ union {
+ uint8_t b[72 * 512];
+ uint64_t dummy_u64;
+ fpr dummy_fpr;
+ } tmp;
+ int8_t f[512], g[512], F[512], G[512];
+ union {
+ int16_t sig[512];
+ uint16_t hm[512];
+ } r;
+ unsigned char seed[SEEDLEN];
+ inner_shake256_context sc;
+ size_t u, v;
+
+ /*
+ * Decode the private key.
+ */
+ if (sk[0] != 0x50 + 9) {
+ return -1;
+ }
+ u = 1;
+ v = PQCLEAN_FALCON512_CLEAN_trim_i8_decode(
+ f, 9, PQCLEAN_FALCON512_CLEAN_max_fg_bits[9],
+ sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u);
+ if (v == 0) {
+ return -1;
+ }
+ u += v;
+ v = PQCLEAN_FALCON512_CLEAN_trim_i8_decode(
+ g, 9, PQCLEAN_FALCON512_CLEAN_max_fg_bits[9],
+ sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u);
+ if (v == 0) {
+ return -1;
+ }
+ u += v;
+ v = PQCLEAN_FALCON512_CLEAN_trim_i8_decode(
+ F, 9, PQCLEAN_FALCON512_CLEAN_max_FG_bits[9],
+ sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u);
+ if (v == 0) {
+ return -1;
+ }
+ u += v;
+ if (u != PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES) {
+ return -1;
+ }
+ if (!PQCLEAN_FALCON512_CLEAN_complete_private(G, f, g, F, 9, tmp.b)) {
+ return -1;
+ }
+
+ /*
+ * Create a random nonce (40 bytes).
+ */
+ randombytes(nonce, NONCELEN);
+
+ /*
+ * Hash message nonce + message into a vector.
+ */
+ inner_shake256_init(&sc);
+ inner_shake256_inject(&sc, nonce, NONCELEN);
+ inner_shake256_inject(&sc, m, mlen);
+ inner_shake256_flip(&sc);
+ PQCLEAN_FALCON512_CLEAN_hash_to_point_ct(&sc, r.hm, 9, tmp.b);
+ inner_shake256_ctx_release(&sc);
+
+ /*
+ * Initialize a RNG.
+ */
+ randombytes(seed, sizeof seed);
+ inner_shake256_init(&sc);
+ inner_shake256_inject(&sc, seed, sizeof seed);
+ inner_shake256_flip(&sc);
+
+ /*
+ * Compute and return the signature. This loops until a signature
+ * value is found that fits in the provided buffer.
+ */
+ for (;;) {
+ PQCLEAN_FALCON512_CLEAN_sign_dyn(r.sig, &sc, f, g, F, G, r.hm, 9, tmp.b);
+ v = PQCLEAN_FALCON512_CLEAN_comp_encode(sigbuf, *sigbuflen, r.sig, 9);
+ if (v != 0) {
+ inner_shake256_ctx_release(&sc);
+ *sigbuflen = v;
+ return 0;
+ }
+ }
+}
+
+/*
+ * Verify a sigature. The nonce has size NONCELEN bytes. sigbuf[]
+ * (of size sigbuflen) contains the signature value, not including the
+ * header byte or nonce. Return value is 0 on success, -1 on error.
+ */
+static int
+do_verify(
+ const uint8_t *nonce, const uint8_t *sigbuf, size_t sigbuflen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ union {
+ uint8_t b[2 * 512];
+ uint64_t dummy_u64;
+ fpr dummy_fpr;
+ } tmp;
+ uint16_t h[512], hm[512];
+ int16_t sig[512];
+ inner_shake256_context sc;
+
+ /*
+ * Decode public key.
+ */
+ if (pk[0] != 0x00 + 9) {
+ return -1;
+ }
+ if (PQCLEAN_FALCON512_CLEAN_modq_decode(h, 9,
+ pk + 1, PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1)
+ != PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1) {
+ return -1;
+ }
+ PQCLEAN_FALCON512_CLEAN_to_ntt_monty(h, 9);
+
+ /*
+ * Decode signature.
+ */
+ if (sigbuflen == 0) {
+ return -1;
+ }
+ if (PQCLEAN_FALCON512_CLEAN_comp_decode(sig, 9, sigbuf, sigbuflen) != sigbuflen) {
+ return -1;
+ }
+
+ /*
+ * Hash nonce + message into a vector.
+ */
+ inner_shake256_init(&sc);
+ inner_shake256_inject(&sc, nonce, NONCELEN);
+ inner_shake256_inject(&sc, m, mlen);
+ inner_shake256_flip(&sc);
+ PQCLEAN_FALCON512_CLEAN_hash_to_point_ct(&sc, hm, 9, tmp.b);
+ inner_shake256_ctx_release(&sc);
+
+ /*
+ * Verify signature.
+ */
+ if (!PQCLEAN_FALCON512_CLEAN_verify_raw(hm, sig, h, 9, tmp.b)) {
+ return -1;
+ }
+ return 0;
+}
+
+/* see api.h */
+int
+PQCLEAN_FALCON512_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ /*
+ * The PQCLEAN_FALCON512_CLEAN_CRYPTO_BYTES constant is used for
+ * the signed message object (as produced by PQCLEAN_FALCON512_CLEAN_crypto_sign())
+ * and includes a two-byte length value, so we take care here
+ * to only generate signatures that are two bytes shorter than
+ * the maximum. This is done to ensure that PQCLEAN_FALCON512_CLEAN_crypto_sign()
+ * and PQCLEAN_FALCON512_CLEAN_crypto_sign_signature() produce the exact same signature
+ * value, if used on the same message, with the same private key,
+ * and using the same output from randombytes() (this is for
+ * reproducibility of tests).
+ */
+ size_t vlen;
+
+ vlen = PQCLEAN_FALCON512_CLEAN_CRYPTO_BYTES - NONCELEN - 3;
+ if (do_sign(sig + 1, sig + 1 + NONCELEN, &vlen, m, mlen, sk) < 0) {
+ return -1;
+ }
+ sig[0] = 0x30 + 9;
+ *siglen = 1 + NONCELEN + vlen;
+ return 0;
+}
+
+/* see api.h */
+int
+PQCLEAN_FALCON512_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ if (siglen < 1 + NONCELEN) {
+ return -1;
+ }
+ if (sig[0] != 0x30 + 9) {
+ return -1;
+ }
+ return do_verify(sig + 1,
+ sig + 1 + NONCELEN, siglen - 1 - NONCELEN, m, mlen, pk);
+}
+
+/* see api.h */
+int
+PQCLEAN_FALCON512_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ uint8_t *pm, *sigbuf;
+ size_t sigbuflen;
+
+ /*
+ * Move the message to its final location; this is a memmove() so
+ * it handles overlaps properly.
+ */
+ memmove(sm + 2 + NONCELEN, m, mlen);
+ pm = sm + 2 + NONCELEN;
+ sigbuf = pm + 1 + mlen;
+ sigbuflen = PQCLEAN_FALCON512_CLEAN_CRYPTO_BYTES - NONCELEN - 3;
+ if (do_sign(sm + 2, sigbuf, &sigbuflen, pm, mlen, sk) < 0) {
+ return -1;
+ }
+ pm[mlen] = 0x20 + 9;
+ sigbuflen ++;
+ sm[0] = (uint8_t)(sigbuflen >> 8);
+ sm[1] = (uint8_t)sigbuflen;
+ *smlen = mlen + 2 + NONCELEN + sigbuflen;
+ return 0;
+}
+
+/* see api.h */
+int
+PQCLEAN_FALCON512_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk) {
+ const uint8_t *sigbuf;
+ size_t pmlen, sigbuflen;
+
+ if (smlen < 3 + NONCELEN) {
+ return -1;
+ }
+ sigbuflen = ((size_t)sm[0] << 8) | (size_t)sm[1];
+ if (sigbuflen < 2 || sigbuflen > (smlen - NONCELEN - 2)) {
+ return -1;
+ }
+ sigbuflen --;
+ pmlen = smlen - NONCELEN - 3 - sigbuflen;
+ if (sm[2 + NONCELEN + pmlen] != 0x20 + 9) {
+ return -1;
+ }
+ sigbuf = sm + 2 + NONCELEN + pmlen + 1;
+
+ /*
+ * The 2-byte length header and the one-byte signature header
+ * have been verified. Nonce is at sm+2, followed by the message
+ * itself. Message length is in pmlen. sigbuf/sigbuflen point to
+ * the signature value (excluding the header byte).
+ */
+ if (do_verify(sm + 2, sigbuf, sigbuflen,
+ sm + 2 + NONCELEN, pmlen, pk) < 0) {
+ return -1;
+ }
+
+ /*
+ * Signature is correct, we just have to copy/move the message
+ * to its final destination. The memmove() properly handles
+ * overlaps.
+ */
+ memmove(m, sm + 2 + NONCELEN, pmlen);
+ *mlen = pmlen;
+ return 0;
+}