packages feed

KpqC-0.1.0: cbits/third_party/SMAUG-T/src/dg.c

// SPDX-License-Identifier: MIT

#include "dg.h"
#include "fips202.h"

#include <string.h>

/*************************************************
 * Name:        load64_littleendian
 *
 * Description: load 8 bytes into a 64-bit integer
 *              in little-endian order
 *
 * Arguments:   - uint64_t *out: pointer to output int64_t array
 *              - size_t outlen: output length (should be a multiple of 10)
 *              - const uint8_t *in: pointer to input byte array
 **************************************************/
#define load64_littleendian SMAUGT_NAMESPACE(load64_littleendian)
static void load64_littleendian(uint64_t *out, size_t outlen,
                                const uint8_t *in) {
    unsigned int i, j, pos = 0;
    for (i = 0; i < outlen / 10; ++i) {
        for (j = 0; j < 10; j++) {
            out[10 * i + j] = ((uint64_t)(in[pos + j])) |
                              ((uint64_t)(in[pos + 10 + j]) << 8) |
                              ((uint64_t)(in[pos + 20 + j]) << 16) |
                              ((uint64_t)(in[pos + 30 + j]) << 24) |
                              ((uint64_t)(in[pos + 40 + j]) << 32) |
                              ((uint64_t)(in[pos + 50 + j]) << 40) |
                              ((uint64_t)(in[pos + 60 + j]) << 48) |
                              ((uint64_t)(in[pos + 70 + j]) << 56);
        }
        pos += 80;
    }
}

// referenced
// A. Karmakar, S. S. Roy, O. Reparaz, F. Vercauteren and I.
// Verbauwhede, "Constant-Time Discrete Gaussian Sampling," in IEEE Transactions
// on Computers, vol. 67, no. 11, pp. 1561-1571, 1 Nov. 2018,
// doi: 10.1109/TC.2018.2814587.

// for python metacode that generates this code, please refer to notion page
// https://www.notion.so/Constant-Time-Discrete-Gaussian-Sampling-25cc46cdf40549eabd4923d01d8ce259

/*************************************************
 * Name:        d_gaussian_poly
 *
 * Description: Sample a discrete Gaussian noise e and add the noise e to the
 * output vector op
 *
 * Arguments:   - poly *op: pointer to output vector op
 *              - const uint8_t *seed: pointer to input seed (of length
 *              SMAUGT_CRYPTO_BYTES+1)
 *
 * Specification: Implements @[KS X 123456, Algorithm 11, dGaussianPoly]
 **************************************************/
int d_gaussian_poly(poly *op, const uint8_t *seed) {
    unsigned int i = 0, j = 0, k = 0;
    uint64_t seed_temp[SMAUGT_DG_SMAUGT_SEED_LEN] = {0};
    uint8_t buf[SMAUGT_DG_SMAUGT_SEED_LEN * 8] = {0};
    uint64_t s[SMAUGT_DG_SMAUGT_SLEN] = {0};
    uint64_t *x = NULL;

    shake256(buf, SMAUGT_DG_SMAUGT_SEED_LEN * 8, seed, SMAUGT_CRYPTO_BYTES + 1);
    load64_littleendian(seed_temp, SMAUGT_DG_SMAUGT_SEED_LEN, buf);

    for (i = 0; i < SMAUGT_N; i += 64) {
        x = seed_temp + j;
        s[0] = (x[0] & x[1] & x[2] & x[3] & x[4] & x[5] & x[7] & ~x[8]) |
               (x[0] & x[3] & x[4] & x[5] & x[6] & x[8]) |
               (x[1] & x[3] & x[4] & x[5] & x[6] & x[8]) |
               (x[2] & x[3] & x[4] & x[5] & x[6] & x[8]) |
               (~x[2] & ~x[3] & ~x[6] & x[8]) | (~x[1] & ~x[3] & ~x[6] & x[8]) |
               (x[6] & x[7] & ~x[8]) | (~x[5] & ~x[6] & x[8]) |
               (~x[4] & ~x[6] & x[8]) | (~x[7] & x[8]);
        s[1] = (x[1] & x[2] & x[4] & x[5] & x[7] & x[8]) |
               (x[3] & x[4] & x[5] & x[7] & x[8]) | (x[6] & x[7] & x[8]);
        for (k = 0; k < 64; ++k) {
            op->coeffs[i + k] =
                ((s[0] >> k) & 0x01) | (((s[1] >> k) & 0x01) << 1);
            uint16_t sign = (x[9] >> k) & 0x01;
            uint16_t signed_coefficient =
                (uint16_t)(((uint16_t)(0u - sign) ^
                            (uint16_t)op->coeffs[i + k]) +
                           sign);
            op->coeffs[i + k] =
                (int16_t)(uint16_t)((uint32_t)signed_coefficient
                                    << SMAUGT_MODULUS_16_LOG_Q);
        }
        j += SMAUGT_DG_RAND_BITS;
    }
    return 0;
}

/*************************************************
 * Name:        d_gaussian
 *
 * Description: Given an array of seed bytes, compute
 *              polynomial with coefficients sampled from a discrete gaussian
 * distribution
 *
 * Arguments:   - polyvec *op: pointer to output polynomial vector
 *              - const uint8_t seed[SMAUGT_CRYPTO_BYTES]: pointer to input byte
 * array
 *
 * Specification: Implements @[KS X 123456, Algorithm 10, dGaussian]
 **************************************************/
void d_gaussian(polyvec *op, const uint8_t seed[SMAUGT_CRYPTO_BYTES]) {
    unsigned int i;
    uint8_t extseed[SMAUGT_CRYPTO_BYTES + 1] = {0};
    memcpy(extseed, seed, SMAUGT_CRYPTO_BYTES);
    for (i = 0; i < SMAUGT_K; ++i) {
        extseed[SMAUGT_CRYPTO_BYTES] = SMAUGT_K * i;
        d_gaussian_poly(&(op->vec[i]), extseed);
    }
}