Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

swh:1:snp:418f8417068b61dc00572c13ca3d8ff0c2f214db
  • Code
  • Branches (10)
  • Releases (0)
    • Branches
    • Releases
    • HEAD
    • refs/heads/efm32gg11b
    • refs/heads/github-actions-test
    • refs/heads/master
    • refs/heads/qemu-gcc11-fix
    • refs/heads/setupscript
    • refs/heads/sikefix-rpls
    • refs/remotes/amin/kyberintt
    • refs/tags/Round1
    • refs/tags/Round2
    • refs/tags/Round3
    No releases to show
  • f8fa7f7
  • /
  • crypto_sign
  • /
  • falcon-512
  • /
  • m4-ct
  • /
  • pqm4.c
Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
  • revision
  • snapshot
content badge
swh:1:cnt:31d562a199bc28cfe0d1bc811a8ccd4e59889828
directory badge
swh:1:dir:17ab525370ec7e27e54c1c6e13a7c135e32d0318
revision badge
swh:1:rev:26f810d332b829a2c16220294db7a882b2072f4d
snapshot badge
swh:1:snp:418f8417068b61dc00572c13ca3d8ff0c2f214db

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
  • revision
  • snapshot
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
Tip revision: 26f810d332b829a2c16220294db7a882b2072f4d authored by rugo on 07 June 2022, 08:39:12 UTC
Fix alignment issues in Kyber (#236)
Tip revision: 26f810d
pqm4.c
#include <stddef.h>
#include <string.h>

#include "api.h"
#include "inner.h"

/* ==================================================================== */

/*
 * Falcon degree is N = 2^LOGN, where LOGN=9 (for Falcon-512) or 10
 * (for Falcon-1024). We use the advertised public key size to know
 * which degree is used.
 */
#if CRYPTO_PUBLICKEYBYTES == 897
#define LOGN   9
#elif CRYPTO_PUBLICKEYBYTES == 1793
#define LOGN   10
#else
#error Unknown Falcon degree (unexpected public key size)
#endif

#define N   ((size_t)1 << LOGN)
#define NONCELEN   40
#define SEEDLEN    48

/*
 * If the private key length is larger than 10000, then this is the
 * variant with precomputed expanded keys.
 */
#if CRYPTO_SECRETKEYBYTES > 10000
#define KG_EXPAND   1
#else
#define KG_EXPAND   0
#endif

/*
 * Common buffer, to avoid bulky stack allocation. The buffer sizes are
 * all expressed in bytes, but the buffer must be suitably aligned for
 * 64-bit integers and floating-point values.
 *
 * Required size (in bytes):
 *
 *   With expanded key:
 *      keygen:  48*N + 6*N = 54*N
 *      sign:    48*N + 2*N = 50*N
 *      vrfy:    8*N
 *
 *   Without expanded key:
 *      keygen:  28*N + 5*N = 33*N
 *      sign:    72*N + 6*N = 78*N
 *      vrfy:    8*N
 */
static union {
#if KG_EXPAND
	uint8_t b[54 * N];
#else
	uint8_t b[78 * N];
#endif
	uint64_t dummy_u64;
	fpr dummy_fp;
} tmp;

int randombytes(unsigned char *dst, size_t len);

int
crypto_sign_keypair(unsigned char *pk, unsigned char *sk)
{
	int8_t *f, *g, *F, *G;
	uint16_t *h;
	inner_shake256_context rng;
	unsigned char seed[SEEDLEN];
#if KG_EXPAND
	size_t v;
#else
	size_t u, v;
#endif
	unsigned sav_cw;

#if KG_EXPAND
	f = (int8_t *)&tmp.b[48 * N];
	g = f + N;
	F = g + N;
	G = F + N;
	h = (uint16_t *)(G + N);
#else
	f = (int8_t *)&tmp.b[28 * N];
	g = f + N;
	F = g + N;
	G = NULL;
	h = (uint16_t *)(F + N);
#endif

	randombytes(seed, SEEDLEN);
	inner_shake256_init(&rng);
	inner_shake256_inject(&rng, seed, SEEDLEN);
	inner_shake256_flip(&rng);
	sav_cw = set_fpu_cw(2);
	Zf(keygen)(&rng, f, g, F, G, h, LOGN, tmp.b);

#if KG_EXPAND
	/*
	 * Expand private key.
	 */
	Zf(expand_privkey)((fpr *)sk, f, g, F, G, LOGN, tmp.b);
	set_fpu_cw(sav_cw);
#else
	set_fpu_cw(sav_cw);

	/*
	 * Encode private key.
	 */
	sk[0] = 0x50 + LOGN;
	u = 1;
	v = Zf(trim_i8_encode)(sk + u, CRYPTO_SECRETKEYBYTES - u,
		f, LOGN, Zf(max_fg_bits)[LOGN]);
	if (v == 0) {
		return -1;
	}
	u += v;
	v = Zf(trim_i8_encode)(sk + u, CRYPTO_SECRETKEYBYTES - u,
		g, LOGN, Zf(max_fg_bits)[LOGN]);
	if (v == 0) {
		return -1;
	}
	u += v;
	v = Zf(trim_i8_encode)(sk + u, CRYPTO_SECRETKEYBYTES - u,
		F, LOGN, Zf(max_FG_bits)[LOGN]);
	if (v == 0) {
		return -1;
	}
	u += v;
	if (u != CRYPTO_SECRETKEYBYTES) {
		return -1;
	}
#endif

	/*
	 * Encode public key.
	 */
	pk[0] = 0x00 + LOGN;
	v = Zf(modq_encode)(pk + 1, CRYPTO_PUBLICKEYBYTES - 1, h, LOGN);
	if (v != CRYPTO_PUBLICKEYBYTES - 1) {
		return -1;
	}

	return 0;
}

int
crypto_sign(unsigned char *sm, size_t *smlen,
	const unsigned char *m, size_t mlen,
	const unsigned char *sk)
{
#if KG_EXPAND
	const fpr *expanded_key;
#else
	int8_t *f, *g, *F, *G;
	size_t u, v;
#endif
	int16_t *sig;
	uint16_t *hm;
	unsigned char seed[SEEDLEN], nonce[NONCELEN];
	unsigned char *esig;
	inner_shake256_context sc;
	size_t sig_len;
	unsigned sav_cw;

#if KG_EXPAND
	sig = (int16_t *)&tmp.b[48 * N];
#else
	f = (int8_t *)&tmp.b[72 * N];
	g = f + N;
	F = g + N;
	G = F + N;
	sig = (int16_t *)(G + N);
#endif
	hm = (uint16_t *)sig;  /* hm[] is shared with sig[] */
	esig = (unsigned char *)tmp.b;

#if KG_EXPAND
	/*
	 * Expanded key is provided "as is".
	 */
	expanded_key = (const fpr *)sk;
#else
	/*
	 * Decode the private key.
	 */
	if (sk[0] != 0x50 + LOGN) {
		return -1;
	}
	u = 1;
	v = Zf(trim_i8_decode)(f, LOGN, Zf(max_fg_bits)[LOGN],
		sk + u, CRYPTO_SECRETKEYBYTES - u);
	if (v == 0) {
		return -1;
	}
	u += v;
	v = Zf(trim_i8_decode)(g, LOGN, Zf(max_fg_bits)[LOGN],
		sk + u, CRYPTO_SECRETKEYBYTES - u);
	if (v == 0) {
		return -1;
	}
	u += v;
	v = Zf(trim_i8_decode)(F, LOGN, Zf(max_FG_bits)[LOGN],
		sk + u, CRYPTO_SECRETKEYBYTES - u);
	if (v == 0) {
		return -1;
	}
	u += v;
	if (u != CRYPTO_SECRETKEYBYTES) {
		return -1;
	}
	if (!Zf(complete_private)(G, f, g, F, LOGN, tmp.b)) {
		return -1;
	}
#endif

	/*
	 * 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);
	Zf(hash_to_point_vartime)(&sc, hm, LOGN);

	/*
	 * Initialize a RNG.
	 */
	randombytes(seed, SEEDLEN);
	inner_shake256_init(&sc);
	inner_shake256_inject(&sc, seed, SEEDLEN);
	inner_shake256_flip(&sc);

	/*
	 * Compute the signature.
	 */
	sav_cw = set_fpu_cw(2);
#if KG_EXPAND
	Zf(sign_tree)(sig, &sc, expanded_key, hm, LOGN, tmp.b);
#else
	Zf(sign_dyn)(sig, &sc, f, g, F, G, hm, LOGN, tmp.b);
#endif
	set_fpu_cw(sav_cw);

	/*
	 * Encode the signature and bundle it with the message. Format is:
	 *   signature length     2 bytes, big-endian
	 *   nonce                40 bytes
	 *   message              mlen bytes
	 *   signature            slen bytes
	 */
	esig[0] = 0x20 + LOGN;
	sig_len = Zf(comp_encode)(esig + 1, CRYPTO_BYTES - 1, sig, LOGN);
	if (sig_len == 0) {
		return -1;
	}
	sig_len ++;
	memmove(sm + 2 + NONCELEN, m, mlen);
	sm[0] = (unsigned char)(sig_len >> 8);
	sm[1] = (unsigned char)sig_len;
	memcpy(sm + 2, nonce, NONCELEN);
	memcpy(sm + 2 + NONCELEN + mlen, esig, sig_len);
	*smlen = 2 + NONCELEN + mlen + sig_len;
	return 0;
}

int
crypto_sign_open(unsigned char *m, size_t *mlen,
	const unsigned char *sm, size_t smlen,
	const unsigned char *pk)
{
	uint16_t *h, *hm;
	int16_t *sig;
	const unsigned char *esig;
	inner_shake256_context sc;
	size_t sig_len, msg_len;

	h = (uint16_t *)&tmp.b[2 * N];
	hm = h + N;
	sig = (int16_t *)(hm + N);

	/*
	 * Decode public key.
	 */
	if (pk[0] != 0x00 + LOGN) {
		return -1;
	}
	if (Zf(modq_decode)(h, LOGN, pk + 1, CRYPTO_PUBLICKEYBYTES - 1)
		!= CRYPTO_PUBLICKEYBYTES - 1)
	{
		return -1;
	}
	Zf(to_ntt_monty)(h, LOGN);

	/*
	 * Find nonce, signature, message length.
	 */
	if (smlen < 2 + NONCELEN) {
		return -1;
	}
	sig_len = ((size_t)sm[0] << 8) | (size_t)sm[1];
	if (sig_len > (smlen - 2 - NONCELEN)) {
		return -1;
	}
	msg_len = smlen - 2 - NONCELEN - sig_len;

	/*
	 * Decode signature.
	 */
	esig = sm + 2 + NONCELEN + msg_len;
	if (sig_len < 1 || esig[0] != 0x20 + LOGN) {
		return -1;
	}
	if (Zf(comp_decode)(sig, LOGN,
		esig + 1, sig_len - 1) != sig_len - 1)
	{
		return -1;
	}

	/*
	 * Hash nonce + message into a vector.
	 */
	inner_shake256_init(&sc);
	inner_shake256_inject(&sc, sm + 2, NONCELEN + msg_len);
	inner_shake256_flip(&sc);
	Zf(hash_to_point_vartime)(&sc, hm, LOGN);

	/*
	 * Verify signature.
	 */
	if (!Zf(verify_raw)(hm, sig, h, LOGN, tmp.b)) {
		return -1;
	}

	/*
	 * Return plaintext.
	 */
	memmove(m, sm + 2 + NONCELEN, msg_len);
	*mlen = msg_len;
	return 0;
}

back to top

Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API