diff --git a/crypto_sign/rainbowIIIc-classic/META.yml b/crypto_sign/rainbowIIIc-classic/META.yml
new file mode 100644
index 00000000..28184eb1
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/META.yml
@@ -0,0 +1,18 @@
+name: Rainbow-IIIc-classic
+type: signature
+claimed-nist-level: 3
+length-public-key: 710640
+length-secret-key: 511448
+length-signature: 156
+nistkat-sha256: 199cf313d96a4fbb481c50e568ac0222ec955b3e20551d0fadbb6c5e97bd1ada
+testvectors-sha256: e738081bcc34228184645dd79237daabc89b7ed22172637b6c10f51dd1e417d9
+principal-submitters:
+ - Jintai Ding
+auxiliary-submitters:
+ - Ming-Shing Chen
+ - Albrecht Petzoldt
+ - Dieter Schmidt
+ - Bo-Yin Yang
+implementations:
+ - name: clean
+ version: https://github.com/fast-crypto-lab/rainbow-submission-round2/commit/af826fcb78f6af51a02d0352cff28a9690467bfd
diff --git a/crypto_sign/rainbowIIIc-classic/clean/LICENSE b/crypto_sign/rainbowIIIc-classic/clean/LICENSE
new file mode 100644
index 00000000..cb00a6e3
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/LICENSE
@@ -0,0 +1,8 @@
+`Software implementation of Rainbow for NIST R2 submission' by Ming-Shing Chen
+
+To the extent possible under law, the person who associated CC0 with
+`Software implementation of Rainbow for NIST R2 submission' has waived all copyright and related or neighboring rights
+to `Software implementation of Rainbow for NIST R2 submission'.
+
+You should have received a copy of the CC0 legalcode along with this
+work. If not, see .
diff --git a/crypto_sign/rainbowIIIc-classic/clean/Makefile b/crypto_sign/rainbowIIIc-classic/clean/Makefile
new file mode 100644
index 00000000..3da2aefd
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=librainbowIIIc-classic_clean.a
+
+HEADERS = api.h blas_comm.h blas.h blas_u32.h gf.h parallel_matrix_op.h rainbow_blas.h rainbow_config.h rainbow.h rainbow_keypair_computation.h rainbow_keypair.h utils_hash.h utils_prng.h
+OBJECTS = blas_comm.o parallel_matrix_op.o rainbow.o rainbow_keypair.o rainbow_keypair_computation.o sign.o utils_hash.o utils_prng.o blas_u32.o gf.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/rainbowIIIc-classic/clean/Makefile.Microsoft_nmake b/crypto_sign/rainbowIIIc-classic/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..0ad2236e
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=librainbowIIIc-classic_clean.lib
+OBJECTS = blas_comm.obj parallel_matrix_op.obj rainbow.obj rainbow_keypair.obj rainbow_keypair_computation.obj sign.obj utils_hash.obj utils_prng.obj blas_u32.obj gf.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/rainbowIIIc-classic/clean/api.h b/crypto_sign/rainbowIIIc-classic/clean/api.h
new file mode 100644
index 00000000..9dc88a7d
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/api.h
@@ -0,0 +1,32 @@
+#ifndef PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_API_H
+#define PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_CRYPTO_SECRETKEYBYTES 511448
+#define PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_CRYPTO_PUBLICKEYBYTES 710640
+#define PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_CRYPTO_BYTES 156
+#define PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_CRYPTO_ALGNAME "RAINBOW(256,68,36,36) - classic"
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
+
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen,
+ const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen,
+ const uint8_t *pk);
+
+
+#endif
diff --git a/crypto_sign/rainbowIIIc-classic/clean/blas.h b/crypto_sign/rainbowIIIc-classic/clean/blas.h
new file mode 100644
index 00000000..ca7ce548
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/blas.h
@@ -0,0 +1,19 @@
+#ifndef _BLAS_H_
+#define _BLAS_H_
+/// @file blas.h
+/// @brief Defining the implementations for linear algebra functions depending on the machine architecture.
+///
+
+#include "blas_comm.h"
+#include "blas_u32.h"
+#include "rainbow_config.h"
+
+#define gf256v_predicated_add PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_predicated_add_u32
+#define gf256v_add PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_add_u32
+
+
+#define gf256v_mul_scalar PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_mul_scalar_u32
+#define gf256v_madd PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_madd_u32
+
+
+#endif // _BLAS_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/blas_comm.c b/crypto_sign/rainbowIIIc-classic/clean/blas_comm.c
new file mode 100644
index 00000000..03db4d45
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/blas_comm.c
@@ -0,0 +1,142 @@
+/// @file blas_comm.c
+/// @brief The standard implementations for blas_comm.h
+///
+
+#include "blas_comm.h"
+#include "blas.h"
+#include "gf.h"
+#include "rainbow_config.h"
+
+#include
+#include
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte) {
+ gf256v_add(b, b, _num_byte);
+}
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i) {
+ return a[i];
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte) {
+ uint8_t r = 0;
+ while (_num_byte--) {
+ r |= a[0];
+ a++;
+ }
+ return (0 == r);
+}
+
+/// polynomial multplication
+/// School boook
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num) {
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(c, _num * 2 - 1);
+ for (unsigned int i = 0; i < _num; i++) {
+ gf256v_madd(c + i, a, b[i], _num);
+ }
+}
+
+static void gf256mat_prod_ref(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(c, n_A_vec_byte);
+ for (unsigned int i = 0; i < n_A_width; i++) {
+ gf256v_madd(c, matA, b[i], n_A_vec_byte);
+ matA += n_A_vec_byte;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec) {
+ unsigned int n_vec_byte = len_vec;
+ for (unsigned int k = 0; k < len_vec; k++) {
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(c, n_vec_byte);
+ const uint8_t *bk = b + n_vec_byte * k;
+ for (unsigned int i = 0; i < len_vec; i++) {
+ gf256v_madd(c, a + n_vec_byte * i, bk[i], n_vec_byte);
+ }
+ c += n_vec_byte;
+ }
+}
+
+static unsigned int gf256mat_gauss_elim_ref(uint8_t *mat, unsigned int h, unsigned int w) {
+ unsigned int r8 = 1;
+
+ for (unsigned int i = 0; i < h; i++) {
+ uint8_t *ai = mat + w * i;
+ unsigned int skip_len_align4 = i & ((unsigned int)~0x3);
+
+ for (unsigned int j = i + 1; j < h; j++) {
+ uint8_t *aj = mat + w * j;
+ gf256v_predicated_add(ai + skip_len_align4, !PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256_is_nonzero(ai[i]), aj + skip_len_align4, w - skip_len_align4);
+ }
+ r8 &= PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256_is_nonzero(ai[i]);
+ uint8_t pivot = ai[i];
+ pivot = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256_inv(pivot);
+ gf256v_mul_scalar(ai + skip_len_align4, pivot, w - skip_len_align4);
+ for (unsigned int j = 0; j < h; j++) {
+ if (i == j) {
+ continue;
+ }
+ uint8_t *aj = mat + w * j;
+ gf256v_madd(aj + skip_len_align4, ai + skip_len_align4, aj[i], w - skip_len_align4);
+ }
+ }
+
+ return r8;
+}
+
+static unsigned int gf256mat_solve_linear_eq_ref(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ uint8_t mat[64 * 64];
+ for (unsigned int i = 0; i < n; i++) {
+ memcpy(mat + i * (n + 1), inp_mat + i * n, n);
+ mat[i * (n + 1) + n] = c_terms[i];
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_gauss_elim(mat, n, n + 1);
+ for (unsigned int i = 0; i < n; i++) {
+ sol[i] = mat[i * (n + 1) + n];
+ }
+ return r8;
+}
+
+static inline void gf256mat_submat(uint8_t *mat2, unsigned int w2, unsigned int st, const uint8_t *mat, unsigned int w, unsigned int h) {
+ for (unsigned int i = 0; i < h; i++) {
+ for (unsigned int j = 0; j < w2; j++) {
+ mat2[i * w2 + j] = mat[i * w + st + j];
+ }
+ }
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer) {
+ uint8_t *aa = buffer;
+ for (unsigned int i = 0; i < H; i++) {
+ uint8_t *ai = aa + i * 2 * H;
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(ai, 2 * H);
+ gf256v_add(ai, a + i * H, H);
+ ai[H + i] = 1;
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_gauss_elim(aa, H, 2 * H);
+ gf256mat_submat(inv_a, H, H, aa, 2 * H, H);
+ return r8;
+}
+
+
+// choosing the implementations depends on the macros _BLAS_AVX2_ and _BLAS_SSE
+
+#define gf256mat_prod_impl gf256mat_prod_ref
+#define gf256mat_gauss_elim_impl gf256mat_gauss_elim_ref
+#define gf256mat_solve_linear_eq_impl gf256mat_solve_linear_eq_ref
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ gf256mat_prod_impl(c, matA, n_A_vec_byte, n_A_width, b);
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w) {
+ return gf256mat_gauss_elim_impl(mat, h, w);
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ return gf256mat_solve_linear_eq_impl(sol, inp_mat, c_terms, n);
+}
+
diff --git a/crypto_sign/rainbowIIIc-classic/clean/blas_comm.h b/crypto_sign/rainbowIIIc-classic/clean/blas_comm.h
new file mode 100644
index 00000000..6357c0ab
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/blas_comm.h
@@ -0,0 +1,90 @@
+#ifndef _BLAS_COMM_H_
+#define _BLAS_COMM_H_
+/// @file blas_comm.h
+/// @brief Common functions for linear algebra.
+///
+
+#include "rainbow_config.h"
+#include
+
+/// @brief set a vector to 0.
+///
+/// @param[in,out] b - the vector b.
+/// @param[in] _num_byte - number of bytes for the vector b.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte);
+
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i);
+
+/// @brief check if a vector is 0.
+///
+/// @param[in] a - the vector a.
+/// @param[in] _num_byte - number of bytes for the vector a.
+/// @return 1(true) if a is 0. 0(false) else.
+///
+unsigned int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte);
+
+/// @brief polynomial multiplication: c = a*b
+///
+/// @param[out] c - the output polynomial c
+/// @param[in] a - the vector a.
+/// @param[in] b - the vector b.
+/// @param[in] _num - number of elements for the polynomials a and b.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num);
+
+/// @brief matrix-vector multiplication: c = matA * b , in GF(256)
+///
+/// @param[out] c - the output vector c
+/// @param[in] matA - a column-major matrix A.
+/// @param[in] n_A_vec_byte - the size of column vectors in bytes.
+/// @param[in] n_A_width - the width of matrix A.
+/// @param[in] b - the vector b.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b);
+
+/// @brief matrix-matrix multiplication: c = a * b , in GF(256)
+///
+/// @param[out] c - the output matrix c
+/// @param[in] c - a matrix a.
+/// @param[in] b - a matrix b.
+/// @param[in] len_vec - the length of column vectors.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec);
+
+/// @brief Gauss elimination for a matrix, in GF(256)
+///
+/// @param[in,out] mat - the matrix.
+/// @param[in] h - the height of the matrix.
+/// @param[in] w - the width of the matrix.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w);
+
+/// @brief Solving linear equations, in GF(256)
+///
+/// @param[out] sol - the solutions.
+/// @param[in] inp_mat - the matrix parts of input equations.
+/// @param[in] c_terms - the constant terms of the input equations.
+/// @param[in] n - the number of equations.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n);
+
+/// @brief Computing the inverse matrix, in GF(256)
+///
+/// @param[out] inv_a - the output of matrix a.
+/// @param[in] a - a matrix a.
+/// @param[in] H - height of matrix a, i.e., matrix a is an HxH matrix.
+/// @param[in] buffer - The buffer for computations. it has to be as large as 2 input matrixes.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer);
+
+#endif // _BLAS_COMM_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/blas_u32.c b/crypto_sign/rainbowIIIc-classic/clean/blas_u32.c
new file mode 100644
index 00000000..7e1bcba6
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/blas_u32.c
@@ -0,0 +1,87 @@
+#include "blas_u32.h"
+#include "gf.h"
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte) {
+ uint32_t pr_u32 = ((uint32_t)0) - ((uint32_t)predicate);
+ uint8_t pr_u8 = pr_u32 & 0xff;
+
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= (a_u32[i] & pr_u32);
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= (a[i] & pr_u8);
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= a_u32[i];
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= a[i];
+ }
+}
+
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *a_u32 = (uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ a_u32[i] = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_mul_u32(a_u32[i], b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_mul_u32(t.u32, b);
+ for (unsigned int i = 0; i < rem; i++) {
+ a[i] = t.u8[i];
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *c_u32 = (uint32_t *)accu_c;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ c_u32[i] ^= PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_mul_u32(a_u32[i], gf256_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ accu_c += (n_u32 << 2);
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_mul_u32(t.u32, gf256_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_c[i] ^= t.u8[i];
+ }
+}
+
diff --git a/crypto_sign/rainbowIIIc-classic/clean/blas_u32.h b/crypto_sign/rainbowIIIc-classic/clean/blas_u32.h
new file mode 100644
index 00000000..1675a602
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/blas_u32.h
@@ -0,0 +1,18 @@
+#ifndef _BLAS_U32_H_
+#define _BLAS_U32_H_
+/// @file blas_u32.h
+/// @brief Inlined functions for implementing basic linear algebra functions for uint32 arch.
+///
+
+#include "rainbow_config.h"
+#include
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte);
+
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte);
+
+
+#endif // _BLAS_U32_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/gf.c b/crypto_sign/rainbowIIIc-classic/clean/gf.c
new file mode 100644
index 00000000..e70613d2
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/gf.c
@@ -0,0 +1,134 @@
+#include "gf.h"
+
+//// gf4 := gf2[x]/x^2+x+1
+static inline uint8_t gf4_mul_2(uint8_t a) {
+ uint8_t r = (uint8_t)(a << 1);
+ r ^= (uint8_t)((a >> 1) * 7);
+ return r;
+}
+
+static inline uint8_t gf4_mul(uint8_t a, uint8_t b) {
+ uint8_t r = (uint8_t)(a * (b & 1));
+ return r ^ (uint8_t)(gf4_mul_2(a) * (b >> 1));
+}
+
+static inline uint8_t gf4_squ(uint8_t a) {
+ return a ^ (a >> 1);
+}
+
+static inline uint32_t gf4v_mul_2_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit1 ^ (bit1 >> 1);
+}
+
+static inline uint32_t gf4v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t bit0_b = ((uint32_t)0) - ((uint32_t)(b & 1));
+ uint32_t bit1_b = ((uint32_t)0) - ((uint32_t)((b >> 1) & 1));
+ return (a & bit0_b) ^ (bit1_b & gf4v_mul_2_u32(a));
+}
+
+//// gf16 := gf4[y]/y^2+y+x
+static inline uint8_t gf16_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ uint8_t b0 = b & 3;
+ uint8_t b1 = (b >> 2);
+ uint8_t a0b0 = gf4_mul(a0, b0);
+ uint8_t a1b1 = gf4_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf4_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x2 = gf4_mul_2(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 2 ^ a0b0 ^ a1b1_x2);
+}
+
+static inline uint8_t gf16_squ(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ a1 = gf4_squ(a1);
+ uint8_t a1squ_x2 = gf4_mul_2(a1);
+ return (uint8_t)((a1 << 2) ^ a1squ_x2 ^ gf4_squ(a0));
+}
+
+// gf16 := gf4[y]/y^2+y+x
+uint32_t PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = gf4v_mul_u32(a, b);
+ uint32_t axb1 = gf4v_mul_u32(a, b >> 2);
+ uint32_t a0b1 = (axb1 << 2) & 0xcccccccc;
+ uint32_t a1b1 = axb1 & 0xcccccccc;
+ uint32_t a1b1_2 = a1b1 >> 2;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf4v_mul_2_u32(a1b1_2);
+}
+
+uint8_t PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256_is_nonzero(uint8_t a) {
+ unsigned int a8 = a;
+ unsigned int r = ((unsigned int)0) - a8;
+ r >>= 8;
+ return r & 1;
+}
+
+static inline uint8_t gf4_mul_3(uint8_t a) {
+ uint8_t msk = (uint8_t)((a - 2) >> 1);
+ return (uint8_t)((msk & ((int)a * 3)) | ((~msk) & ((int)a - 1)));
+}
+static inline uint8_t gf16_mul_8(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = a >> 2;
+ return (uint8_t)((gf4_mul_2(a0 ^ a1) << 2) | gf4_mul_3(a1));
+}
+
+// gf256 := gf16[X]/X^2+X+xy
+static inline uint8_t gf256_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ uint8_t b0 = b & 15;
+ uint8_t b1 = (b >> 4);
+ uint8_t a0b0 = gf16_mul(a0, b0);
+ uint8_t a1b1 = gf16_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf16_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x8 = gf16_mul_8(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 4 ^ a0b0 ^ a1b1_x8);
+}
+
+static inline uint8_t gf256_squ(uint8_t a) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ a1 = gf16_squ(a1);
+ uint8_t a1squ_x8 = gf16_mul_8(a1);
+ return (uint8_t)((a1 << 4) ^ a1squ_x8 ^ gf16_squ(a0));
+}
+
+uint8_t PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256_inv(uint8_t a) {
+ // 128+64+32+16+8+4+2 = 254
+ uint8_t a2 = gf256_squ(a);
+ uint8_t a4 = gf256_squ(a2);
+ uint8_t a8 = gf256_squ(a4);
+ uint8_t a4_2 = gf256_mul(a4, a2);
+ uint8_t a8_4_2 = gf256_mul(a4_2, a8);
+ uint8_t a64_ = gf256_squ(a8_4_2);
+ a64_ = gf256_squ(a64_);
+ a64_ = gf256_squ(a64_);
+ uint8_t a64_2 = gf256_mul(a64_, a8_4_2);
+ uint8_t a128_ = gf256_squ(a64_2);
+ return gf256_mul(a2, a128_);
+}
+
+static inline uint32_t gf4v_mul_3_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit0 ^ (bit1 >> 1);
+}
+static inline uint32_t gf16v_mul_8_u32(uint32_t a) {
+ uint32_t a1 = a & 0xcccccccc;
+ uint32_t a0 = (a << 2) & 0xcccccccc;
+ return gf4v_mul_2_u32(a0 ^ a1) | gf4v_mul_3_u32(a1 >> 2);
+}
+uint32_t PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf16v_mul_u32(a, b);
+ uint32_t axb1 = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf16v_mul_u32(a, b >> 4);
+ uint32_t a0b1 = (axb1 << 4) & 0xf0f0f0f0;
+ uint32_t a1b1 = axb1 & 0xf0f0f0f0;
+ uint32_t a1b1_4 = a1b1 >> 4;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf16v_mul_8_u32(a1b1_4);
+}
diff --git a/crypto_sign/rainbowIIIc-classic/clean/gf.h b/crypto_sign/rainbowIIIc-classic/clean/gf.h
new file mode 100644
index 00000000..14530418
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/gf.h
@@ -0,0 +1,19 @@
+#ifndef _GF16_H_
+#define _GF16_H_
+
+#include "rainbow_config.h"
+#include
+
+/// @file gf16.h
+/// @brief Library for arithmetics in GF(16) and GF(256)
+///
+
+uint32_t PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b);
+
+
+uint8_t PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256_is_nonzero(uint8_t a);
+uint8_t PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256_inv(uint8_t a);
+uint32_t PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b);
+
+
+#endif // _GF16_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/parallel_matrix_op.c b/crypto_sign/rainbowIIIc-classic/clean/parallel_matrix_op.c
new file mode 100644
index 00000000..74285568
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/parallel_matrix_op.c
@@ -0,0 +1,183 @@
+/// @file parallel_matrix_op.c
+/// @brief the standard implementations for functions in parallel_matrix_op.h
+///
+/// the standard implementations for functions in parallel_matrix_op.h
+///
+
+#include "parallel_matrix_op.h"
+#include "blas.h"
+#include "blas_comm.h"
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim) {
+ return (dim + dim - i_row + 1) * i_row / 2 + j_col - i_row;
+}
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle or lower-triangle matrix.
+///
+/// @param[in] i_row - the i-th row in a triangle matrix.
+/// @param[in] j_col - the j-th column in a triangle matrix.
+/// @param[in] dim - the dimension of the triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+static inline unsigned int idx_of_2trimat(unsigned int i_row, unsigned int j_col, unsigned int n_var) {
+ if (i_row > j_col) {
+ return PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(j_col, i_row, n_var);
+ }
+ return PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(i_row, j_col, n_var);
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch) {
+ unsigned char *runningC = btriC;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < i; j++) {
+ unsigned int idx = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(j, i, Aheight);
+ gf256v_add(btriC + idx * size_batch, bA + size_batch * (i * Awidth + j), size_batch);
+ }
+ gf256v_add(runningC, bA + size_batch * (i * Awidth + i), size_batch * (Aheight - i));
+ runningC += size_batch * (Aheight - i);
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (k < i) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[(k - i) * size_batch], PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ btriA += (Aheight - i) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i < k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(k, i, Aheight))], PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i == k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (idx_of_2trimat(i, k, Aheight))], PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_matTr_madd_gf256(unsigned char *bC, const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Atr_height = Awidth;
+ unsigned int Atr_width = Aheight;
+ for (unsigned int i = 0; i < Atr_height; i++) {
+ for (unsigned int j = 0; j < Atr_width; j++) {
+ gf256v_madd(bC, &bB[j * Bwidth * size_batch], PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(&A_to_tr[size_Acolvec * i], j), size_batch * Bwidth);
+ }
+ bC += size_batch * Bwidth;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ const unsigned char *bA = bA_to_tr;
+ unsigned int Aheight = Awidth_before_tr;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[size_batch * (i + k * Aheight)], PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[k * size_batch], PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ bA += (Awidth) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch) {
+ unsigned char tmp[256];
+
+ unsigned char _x[256];
+ for (unsigned int i = 0; i < dim; i++) {
+ _x[i] = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(x, i);
+ }
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(y, size_batch);
+ for (unsigned int i = 0; i < dim; i++) {
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = i; j < dim; j++) {
+ gf256v_madd(tmp, trimat, _x[j], size_batch);
+ trimat += size_batch;
+ }
+ gf256v_madd(y, tmp, _x[i], size_batch);
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y, const unsigned char *mat,
+ const unsigned char *x, unsigned dim_x, unsigned size_batch) {
+ unsigned char tmp[128];
+
+ unsigned char _x[128];
+ for (unsigned int i = 0; i < dim_x; i++) {
+ _x[i] = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(x, i);
+ }
+ unsigned char _y[128];
+ for (unsigned int i = 0; i < dim_y; i++) {
+ _y[i] = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele(y, i);
+ }
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(z, size_batch);
+ for (unsigned int i = 0; i < dim_y; i++) {
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = 0; j < dim_x; j++) {
+ gf256v_madd(tmp, mat, _x[j], size_batch);
+ mat += size_batch;
+ }
+ gf256v_madd(z, tmp, _y[i], size_batch);
+ }
+}
+
diff --git a/crypto_sign/rainbowIIIc-classic/clean/parallel_matrix_op.h b/crypto_sign/rainbowIIIc-classic/clean/parallel_matrix_op.h
new file mode 100644
index 00000000..78c1e83f
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/parallel_matrix_op.h
@@ -0,0 +1,260 @@
+#ifndef _P_MATRIX_OP_H_
+#define _P_MATRIX_OP_H_
+/// @file parallel_matrix_op.h
+/// @brief Librarys for operations of batched matrixes.
+///
+///
+
+//////////////// Section: triangle matrix <-> rectangle matrix ///////////////////////////////////
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim);
+
+///
+/// @brief Upper trianglize a rectangle matrix to the corresponding upper-trangle matrix.
+///
+/// @param[out] btriC - the batched upper-trianglized matrix C.
+/// @param[in] bA - a batched retangle matrix A.
+/// @param[in] bwidth - the width of the batched matrix A, i.e., A is a Awidth x Awidth matrix.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch);
+
+//////////////////// Section: matrix multiplications ///////////////////////////////
+
+///
+/// @brief bC += btriA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. A will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A, which will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_matTr_madd_gf16(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_matTr_madd_gf256(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+//////////////////// Section: "quadratric" matrix evaluation ///////////////////////////////
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(16)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(256)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(16)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(256)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+#endif // _P_MATRIX_OP_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/rainbow.c b/crypto_sign/rainbowIIIc-classic/clean/rainbow.c
new file mode 100644
index 00000000..dc68af43
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/rainbow.c
@@ -0,0 +1,169 @@
+/// @file rainbow.c
+/// @brief The standard implementations for functions in rainbow.h
+///
+
+#include "rainbow.h"
+#include "blas.h"
+#include "rainbow_blas.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "utils_hash.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+#define MAX_ATTEMPT_FRMAT 128
+#define _MAX_O ((_O1 > _O2) ? _O1 : _O2)
+#define _MAX_O_BYTE ((_O1_BYTE > _O2_BYTE) ? _O1_BYTE : _O2_BYTE)
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *_digest) {
+ uint8_t mat_l1[_O1 * _O1_BYTE];
+ uint8_t mat_l2[_O2 * _O2_BYTE];
+ uint8_t mat_buffer[2 * _MAX_O * _MAX_O_BYTE];
+
+ // setup PRNG
+ prng_t prng_sign;
+ uint8_t prng_preseed[LEN_SKSEED + _HASH_LEN];
+ memcpy(prng_preseed, sk->sk_seed, LEN_SKSEED);
+ memcpy(prng_preseed + LEN_SKSEED, _digest, _HASH_LEN); // prng_preseed = sk_seed || digest
+ uint8_t prng_seed[_HASH_LEN];
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_hash_msg(prng_seed, _HASH_LEN, prng_preseed, _HASH_LEN + LEN_SKSEED);
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_set(&prng_sign, prng_seed, _HASH_LEN); // seed = H( sk_seed || digest )
+ for (unsigned int i = 0; i < LEN_SKSEED + _HASH_LEN; i++) {
+ prng_preseed[i] ^= prng_preseed[i]; // clean
+ }
+ for (unsigned int i = 0; i < _HASH_LEN; i++) {
+ prng_seed[i] ^= prng_seed[i]; // clean
+ }
+
+ // roll vinegars.
+ uint8_t vinegar[_V1_BYTE];
+ unsigned int n_attempt = 0;
+ unsigned int l1_succ = 0;
+ while (!l1_succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(&prng_sign, vinegar, _V1_BYTE); // generating vinegars
+ gfmat_prod(mat_l1, sk->l1_F2, _O1 * _O1_BYTE, _V1, vinegar); // generating the linear equations for layer 1
+ l1_succ = gfmat_inv(mat_l1, mat_l1, _O1, mat_buffer); // check if the linear equation solvable
+ n_attempt++;
+ }
+
+ // Given the vinegars, pre-compute variables needed for layer 2
+ uint8_t r_l1_F1[_O1_BYTE] = {0};
+ uint8_t r_l2_F1[_O2_BYTE] = {0};
+ batch_quad_trimat_eval(r_l1_F1, sk->l1_F1, vinegar, _V1, _O1_BYTE);
+ batch_quad_trimat_eval(r_l2_F1, sk->l2_F1, vinegar, _V1, _O2_BYTE);
+ uint8_t mat_l2_F3[_O2 * _O2_BYTE];
+ uint8_t mat_l2_F2[_O1 * _O2_BYTE];
+ gfmat_prod(mat_l2_F3, sk->l2_F3, _O2 * _O2_BYTE, _V1, vinegar);
+ gfmat_prod(mat_l2_F2, sk->l2_F2, _O1 * _O2_BYTE, _V1, vinegar);
+
+ // Some local variables.
+ uint8_t _z[_PUB_M_BYTE];
+ uint8_t y[_PUB_M_BYTE];
+ uint8_t *x_v1 = vinegar;
+ uint8_t x_o1[_O1_BYTE];
+ uint8_t x_o2[_O1_BYTE];
+
+ uint8_t digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, _digest, _HASH_LEN);
+ uint8_t *salt = digest_salt + _HASH_LEN;
+
+ uint8_t temp_o[_MAX_O_BYTE + 32] = {0};
+ unsigned int succ = 0;
+ while (!succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ // The computation: H(digest||salt) --> z --S--> y --C-map--> x --T--> w
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(&prng_sign, salt, _SALT_BYTE); // roll the salt
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_hash_msg(_z, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H(digest||salt)
+
+ // y = S^-1 * z
+ memcpy(y, _z, _PUB_M_BYTE); // identity part of S
+ gfmat_prod(temp_o, sk->s1, _O1_BYTE, _O2, _z + _O1_BYTE);
+ gf256v_add(y, temp_o, _O1_BYTE);
+
+ // Central Map:
+ // layer 1: calculate x_o1
+ memcpy(temp_o, r_l1_F1, _O1_BYTE);
+ gf256v_add(temp_o, y, _O1_BYTE);
+ gfmat_prod(x_o1, mat_l1, _O1_BYTE, _O1, temp_o);
+
+ // layer 2: calculate x_o2
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_set_zero(temp_o, _O2_BYTE);
+ gfmat_prod(temp_o, mat_l2_F2, _O2_BYTE, _O1, x_o1); // F2
+ batch_quad_trimat_eval(mat_l2, sk->l2_F5, x_o1, _O1, _O2_BYTE); // F5
+ gf256v_add(temp_o, mat_l2, _O2_BYTE);
+ gf256v_add(temp_o, r_l2_F1, _O2_BYTE); // F1
+ gf256v_add(temp_o, y + _O1_BYTE, _O2_BYTE);
+
+ // generate the linear equations of the 2nd layer
+ gfmat_prod(mat_l2, sk->l2_F6, _O2 * _O2_BYTE, _O1, x_o1); // F6
+ gf256v_add(mat_l2, mat_l2_F3, _O2 * _O2_BYTE); // F3
+ succ = gfmat_inv(mat_l2, mat_l2, _O2, mat_buffer);
+ gfmat_prod(x_o2, mat_l2, _O2_BYTE, _O2, temp_o); // solve l2 eqs
+
+ n_attempt++;
+ };
+ // w = T^-1 * y
+ uint8_t w[_PUB_N_BYTE];
+ // identity part of T.
+ memcpy(w, x_v1, _V1_BYTE);
+ memcpy(w + _V1_BYTE, x_o1, _O1_BYTE);
+ memcpy(w + _V2_BYTE, x_o2, _O2_BYTE);
+ // Computing the t1 part.
+ gfmat_prod(y, sk->t1, _V1_BYTE, _O1, x_o1);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t4 part.
+ gfmat_prod(y, sk->t4, _V1_BYTE, _O2, x_o2);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t3 part.
+ gfmat_prod(y, sk->t3, _O1_BYTE, _O2, x_o2);
+ gf256v_add(w + _V1_BYTE, y, _O1_BYTE);
+
+ memset(signature, 0, _SIGNATURE_BYTE); // set the output 0
+ // clean
+ memset(&prng_sign, 0, sizeof(prng_t));
+ memset(vinegar, 0, _V1_BYTE);
+ memset(r_l1_F1, 0, _O1_BYTE);
+ memset(r_l2_F1, 0, _O2_BYTE);
+ memset(_z, 0, _PUB_M_BYTE);
+ memset(y, 0, _PUB_M_BYTE);
+ memset(x_o1, 0, _O1_BYTE);
+ memset(x_o2, 0, _O2_BYTE);
+ memset(temp_o, 0, sizeof(temp_o));
+
+ // return: copy w and salt to the signature.
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ return -1;
+ }
+ gf256v_add(signature, w, _PUB_N_BYTE);
+ gf256v_add(signature + _PUB_N_BYTE, salt, _SALT_BYTE);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk) {
+ unsigned char digest_ck[_PUB_M_BYTE];
+ // public_map( digest_ck , pk , signature ); Evaluating the quadratic public polynomials.
+ batch_quad_trimat_eval(digest_ck, pk->pk, signature, _PUB_N, _PUB_M_BYTE);
+
+ unsigned char correct[_PUB_M_BYTE];
+ unsigned char digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, digest, _HASH_LEN);
+ memcpy(digest_salt + _HASH_LEN, signature + _PUB_N_BYTE, _SALT_BYTE);
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_hash_msg(correct, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H( digest || salt )
+
+ // check consistancy.
+ unsigned char cc = 0;
+ for (unsigned int i = 0; i < _PUB_M_BYTE; i++) {
+ cc |= (digest_ck[i] ^ correct[i]);
+ }
+ return (0 == cc) ? 0 : -1;
+}
+
+
diff --git a/crypto_sign/rainbowIIIc-classic/clean/rainbow.h b/crypto_sign/rainbowIIIc-classic/clean/rainbow.h
new file mode 100644
index 00000000..9d3aad32
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/rainbow.h
@@ -0,0 +1,33 @@
+#ifndef _RAINBOW_H_
+#define _RAINBOW_H_
+/// @file rainbow.h
+/// @brief APIs for rainbow.
+///
+
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+
+#include
+
+///
+/// @brief Signing function for classical secret key.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk);
+
+
+
+#endif // _RAINBOW_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/rainbow_blas.h b/crypto_sign/rainbowIIIc-classic/clean/rainbow_blas.h
new file mode 100644
index 00000000..c4e0612f
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/rainbow_blas.h
@@ -0,0 +1,31 @@
+#ifndef _RAINBOW_BLAS_H_
+#define _RAINBOW_BLAS_H_
+/// @file rainbow_blas.h
+/// @brief Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+///
+/// Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+
+#include "blas.h"
+#include "parallel_matrix_op.h"
+#include "rainbow_config.h"
+
+
+#define gfv_get_ele PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_get_ele
+#define gfv_mul_scalar PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_mul_scalar
+#define gfv_madd PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256v_madd
+
+#define gfmat_prod PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_prod
+#define gfmat_inv PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_gf256mat_inv
+
+#define batch_trimat_madd PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_trimat_madd_gf256
+#define batch_trimatTr_madd PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_trimatTr_madd_gf256
+#define batch_2trimat_madd PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_2trimat_madd_gf256
+#define batch_matTr_madd PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_matTr_madd_gf256
+#define batch_bmatTr_madd PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_bmatTr_madd_gf256
+#define batch_mat_madd PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_mat_madd_gf256
+
+#define batch_quad_trimat_eval PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_quad_trimat_eval_gf256
+#define batch_quad_recmat_eval PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_batch_quad_recmat_eval_gf256
+
+
+#endif // _RAINBOW_BLAS_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/rainbow_config.h b/crypto_sign/rainbowIIIc-classic/clean/rainbow_config.h
new file mode 100644
index 00000000..6d9aa270
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/rainbow_config.h
@@ -0,0 +1,46 @@
+#ifndef _H_RAINBOW_CONFIG_H_
+#define _H_RAINBOW_CONFIG_H_
+
+/// @file rainbow_config.h
+/// @brief Defining the parameters of the Rainbow and the corresponding constants.
+///
+
+#define _GFSIZE 256
+#define _V1 68
+#define _O1 36
+#define _O2 36
+#define _HASH_LEN 48
+
+
+#define _V2 ((_V1) + (_O1))
+
+/// size of N, in # of gf elements.
+#define _PUB_N (_V1 + _O1 + _O2)
+
+/// size of M, in # gf elements.
+#define _PUB_M (_O1 + _O2)
+
+/// size of variables, in # bytes.
+
+// GF256
+#define _V1_BYTE (_V1)
+#define _V2_BYTE (_V2)
+#define _O1_BYTE (_O1)
+#define _O2_BYTE (_O2)
+#define _PUB_N_BYTE (_PUB_N)
+#define _PUB_M_BYTE (_PUB_M)
+
+
+/// length of seed for public key, in # bytes
+#define LEN_PKSEED 32
+
+/// length of seed for secret key, in # bytes
+#define LEN_SKSEED 32
+
+/// length of salt for a signature, in # bytes
+#define _SALT_BYTE 16
+
+/// length of a signature
+#define _SIGNATURE_BYTE (_PUB_N_BYTE + _SALT_BYTE)
+
+#endif // _H_RAINBOW_CONFIG_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair.c b/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair.c
new file mode 100644
index 00000000..b0cc6617
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair.c
@@ -0,0 +1,126 @@
+/// @file rainbow_keypair.c
+/// @brief implementations of functions in rainbow_keypair.h
+///
+
+#include "rainbow_keypair.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair_computation.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+static void generate_S_T(unsigned char *s_and_t, prng_t *prng0) {
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // S1
+ s_and_t += _O1_BYTE * _O2;
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O1); // T1
+ s_and_t += _V1_BYTE * _O1;
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O2); // T2
+ s_and_t += _V1_BYTE * _O2;
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // T3
+}
+
+static unsigned int generate_l1_F12(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * N_TRIANGLE_TERMS(_V1)); // l1_F1
+ sk += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * _V1 * _O1); // l1_F2
+ n_byte_generated += _O1_BYTE * _V1 * _O1;
+ return n_byte_generated;
+}
+
+static unsigned int generate_l2_F12356(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // l2_F1
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O1); // l2_F2
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O2); // l2_F3
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // l2_F5
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _O1 * _O2); // l2_F6
+ n_byte_generated += _O2_BYTE * _O1 * _O2;
+
+ return n_byte_generated;
+}
+
+static void generate_B1_B2(unsigned char *sk, prng_t *prng0) {
+ sk += generate_l1_F12(sk, prng0);
+ generate_l2_F12356(sk, prng0);
+}
+
+static void calculate_t4(unsigned char *t2_to_t4, const unsigned char *t1, const unsigned char *t3) {
+ // t4 = T_sk.t1 * T_sk.t3 - T_sk.t2
+ unsigned char temp[_V1_BYTE + 32];
+ unsigned char *t4 = t2_to_t4;
+ for (unsigned int i = 0; i < _O2; i++) { /// t3 width
+ gfmat_prod(temp, t1, _V1_BYTE, _O1, t3);
+ gf256v_add(t4, temp, _V1_BYTE);
+ t4 += _V1_BYTE;
+ t3 += _O1_BYTE;
+ }
+}
+
+static void obsfucate_l1_polys(unsigned char *l1_polys, const unsigned char *l2_polys, unsigned int n_terms, const unsigned char *s1) {
+ unsigned char temp[_O1_BYTE + 32];
+ while (n_terms--) {
+ gfmat_prod(temp, s1, _O1_BYTE, _O2, l2_polys);
+ gf256v_add(l1_polys, temp, _O1_BYTE);
+ l1_polys += _O1_BYTE;
+ l2_polys += _O2_BYTE;
+ }
+}
+
+/////////////////// Classic //////////////////////////////////
+
+static void _generate_secretkey(sk_t *sk, const unsigned char *sk_seed) {
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // set up prng
+ prng_t prng0;
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_set(&prng0, sk_seed, LEN_SKSEED);
+
+ // generating secret key with prng.
+ generate_S_T(sk->s1, &prng0);
+ generate_B1_B2(sk->l1_F1, &prng0);
+
+ // clean prng
+ memset(&prng0, 0, sizeof(prng_t));
+}
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_generate_keypair(pk_t *rpk, sk_t *sk, const unsigned char *sk_seed) {
+ _generate_secretkey(sk, sk_seed);
+
+ // set up a temporary structure ext_cpk_t for calculating public key.
+ ext_cpk_t pk;
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_calculate_Q_from_F(&pk, sk, sk); // compute the public key in ext_cpk_t format.
+ calculate_t4(sk->t4, sk->t1, sk->t3);
+
+ obsfucate_l1_polys(pk.l1_Q1, pk.l2_Q1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(pk.l1_Q2, pk.l2_Q2, _V1 * _O1, sk->s1);
+ obsfucate_l1_polys(pk.l1_Q3, pk.l2_Q3, _V1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk.l1_Q5, pk.l2_Q5, N_TRIANGLE_TERMS(_O1), sk->s1);
+ obsfucate_l1_polys(pk.l1_Q6, pk.l2_Q6, _O1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk.l1_Q9, pk.l2_Q9, N_TRIANGLE_TERMS(_O2), sk->s1);
+ // so far, the pk contains the full pk but in ext_cpk_t format.
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_extcpk_to_pk(rpk, &pk); // convert the public key from ext_cpk_t to pk_t.
+}
+
+
+
diff --git a/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair.h b/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair.h
new file mode 100644
index 00000000..3fd34570
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair.h
@@ -0,0 +1,61 @@
+#ifndef _RAINBOW_KEYPAIR_H_
+#define _RAINBOW_KEYPAIR_H_
+/// @file rainbow_keypair.h
+/// @brief Formats of key pairs and functions for generating key pairs.
+/// Formats of key pairs and functions for generating key pairs.
+///
+
+#include "rainbow_config.h"
+
+#define N_TRIANGLE_TERMS(n_var) ((n_var) * ((n_var) + 1) / 2)
+
+/// @brief public key for classic rainbow
+///
+/// public key for classic rainbow
+///
+typedef struct rainbow_publickey {
+ unsigned char pk[(_PUB_M_BYTE)*N_TRIANGLE_TERMS(_PUB_N)];
+} pk_t;
+
+/// @brief secret key for classic rainbow
+///
+/// secret key for classic rainbow
+///
+typedef struct rainbow_secretkey {
+ ///
+ /// seed for generating secret key.
+ /// Generating S, T, and F for classic rainbow.
+ /// Generating S and T only for cyclic rainbow.
+ unsigned char sk_seed[LEN_SKSEED];
+
+ unsigned char s1[_O1_BYTE * _O2]; ///< part of S map
+ unsigned char t1[_V1_BYTE * _O1]; ///< part of T map
+ unsigned char t4[_V1_BYTE * _O2]; ///< part of T map
+ unsigned char t3[_O1_BYTE * _O2]; ///< part of T map
+
+ unsigned char l1_F1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer1
+ unsigned char l1_F2[_O1_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer1
+
+ unsigned char l2_F1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer2
+ unsigned char l2_F2[_O2_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer2
+
+ unsigned char l2_F3[_O2_BYTE * _V1 * _O2]; ///< part of C-map, F3, Layer2
+ unsigned char l2_F5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< part of C-map, F5, Layer2
+ unsigned char l2_F6[_O2_BYTE * _O1 * _O2]; ///< part of C-map, F6, Layer2
+} sk_t;
+
+
+///
+/// @brief Generate key pairs for classic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the secret key.
+/// @param[in] sk_seed - seed for generating the secret key.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_generate_keypair(pk_t *pk, sk_t *sk, const unsigned char *sk_seed);
+
+
+
+
+
+#endif // _RAINBOW_KEYPAIR_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair_computation.c b/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair_computation.c
new file mode 100644
index 00000000..796b7de2
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair_computation.c
@@ -0,0 +1,189 @@
+/// @file rainbow_keypair_computation.c
+/// @brief Implementations for functions in rainbow_keypair_computation.h
+///
+
+#include "rainbow_keypair_computation.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair.h"
+#include
+#include
+#include
+
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk) {
+ const unsigned char *idx_l1 = cpk->l1_Q1;
+ const unsigned char *idx_l2 = cpk->l2_Q1;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = i; j < _V1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q2;
+ idx_l2 = cpk->l2_Q2;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q3;
+ idx_l2 = cpk->l2_Q3;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q5;
+ idx_l2 = cpk->l2_Q5;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = i; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q6;
+ idx_l2 = cpk->l2_Q6;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q9;
+ idx_l2 = cpk->l2_Q9;
+ for (unsigned int i = _V1 + _O1; i < _PUB_N; i++) {
+ for (unsigned int j = i; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+}
+
+static void calculate_Q_from_F_ref(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ /*
+ Layer 1
+ Computing :
+ Q_pk.l1_F1s[i] = F_sk.l1_F1s[i]
+
+ Q_pk.l1_F2s[i] = (F1* T1 + F2) + F1tr * t1
+ Q_pk.l1_F5s[i] = UT( T1tr* (F1 * T1 + F2) )
+ */
+ const unsigned char *t2 = Ts->t4;
+
+ memcpy(Qs->l1_Q1, Fs->l1_F1, _O1_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ memcpy(Qs->l1_Q2, Fs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_trimat_madd(Qs->l1_Q2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // F1*T1 + F2
+
+ memset(Qs->l1_Q3, 0, _O1_BYTE * _V1 * _O2);
+ memset(Qs->l1_Q5, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O1));
+ memset(Qs->l1_Q6, 0, _O1_BYTE * _O1 * _O2);
+ memset(Qs->l1_Q9, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ // l1_Q5 : _O1_BYTE * _O1 * _O1
+ // l1_Q9 : _O1_BYTE * _O2 * _O2
+ // l2_Q5 : _O2_BYTE * _V1 * _O1
+ // l2_Q9 : _O2_BYTE * _V1 * _O2
+
+ unsigned char tempQ[_O1_BYTE * _O1 * _O1 + 32];
+
+ memset(tempQ, 0, _O1_BYTE * _O1 * _O1); // l1_Q5
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q2, _O1, _O1_BYTE); // t1_tr*(F1*T1 + F2)
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_UpperTrianglize(Qs->l1_Q5, tempQ, _O1, _O1_BYTE); // UT( ... ) // Q5
+
+ batch_trimatTr_madd(Qs->l1_Q2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // Q2
+ /*
+ Computing:
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+ Q_pk.l1_F3s[i] = F1_F1T_T2 + F2_T3
+ Q_pk.l1_F6s[i] = T1tr* ( F1_F1T_T2 + F2_T3 ) + F2tr * t2
+ Q_pk.l1_F9s[i] = UT( T2tr* ( F1_T2 + F2_T3 ) )
+ */
+ batch_trimat_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1*T2
+ batch_mat_madd(Qs->l1_Q3, Fs->l1_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O1_BYTE); // F1_T2 + F2_T3
+
+ memset(tempQ, 0, _O1_BYTE * _O2 * _O2); // l1_Q9
+ batch_matTr_madd(tempQ, t2, _V1, _V1_BYTE, _O2, Qs->l1_Q3, _O2, _O1_BYTE); // T2tr * ( F1_T2 + F2_T3 )
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_UpperTrianglize(Qs->l1_Q9, tempQ, _O2, _O1_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1_F1T_T2 + F2_T3 // Q3
+
+ batch_bmatTr_madd(Qs->l1_Q6, Fs->l1_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F2tr*T2
+ batch_matTr_madd(Qs->l1_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q3, _O2, _O1_BYTE); // Q6
+
+ /*
+ layer 2
+ Computing:
+ Q1 = F1
+ Q2 = F1_F1T*T1 + F2
+ Q5 = UT( T1tr( F1*T1 + F2 ) + F5 )
+ */
+ memcpy(Qs->l2_Q1, Fs->l2_F1, _O2_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ memcpy(Qs->l2_Q2, Fs->l2_F2, _O2_BYTE * _V1 * _O1);
+ batch_trimat_madd(Qs->l2_Q2, Fs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // F1*T1 + F2
+
+ memcpy(Qs->l2_Q5, Fs->l2_F5, _O2_BYTE * N_TRIANGLE_TERMS(_O1));
+ memset(tempQ, 0, _O2_BYTE * _O1 * _O1); // l2_Q5
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l2_Q2, _O1, _O2_BYTE); // t1_tr*(F1*T1 + F2)
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_UpperTrianglize(Qs->l2_Q5, tempQ, _O1, _O2_BYTE); // UT( ... ) // Q5
+
+ batch_trimatTr_madd(Qs->l2_Q2, Fs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // Q2
+
+ /*
+ Computing:
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+
+ Q3 = F1_F1T*T2 + F2*T3 + F3
+ Q9 = UT( T2tr*( F1*T2 + F2*T3 + F3 ) + T3tr*( F5*T3 + F6 ) )
+ Q6 = T1tr*( F1_F1T*T2 + F2*T3 + F3 ) + F2Tr*T2 + F5_F5T*T3 + F6
+ */
+ memcpy(Qs->l2_Q3, Fs->l2_F3, _O2_BYTE * _V1 * _O2);
+ batch_trimat_madd(Qs->l2_Q3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1*T2 + F3
+ batch_mat_madd(Qs->l2_Q3, Fs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F1_T2 + F2_T3 + F3
+
+ memset(tempQ, 0, _O2_BYTE * _O2 * _O2); // l2_Q9
+ batch_matTr_madd(tempQ, t2, _V1, _V1_BYTE, _O2, Qs->l2_Q3, _O2, _O2_BYTE); // T2tr * ( ..... )
+
+ memcpy(Qs->l2_Q6, Fs->l2_F6, _O2_BYTE * _O1 * _O2);
+
+ batch_trimat_madd(Qs->l2_Q6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6
+ batch_matTr_madd(tempQ, Ts->t3, _O1, _O1_BYTE, _O2, Qs->l2_Q6, _O2, _O2_BYTE); // T2tr*( ..... ) + T3tr*( ..... )
+ memset(Qs->l2_Q9, 0, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_UpperTrianglize(Qs->l2_Q9, tempQ, _O2, _O2_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l2_Q3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1_F1T_T2 + F2_T3 + F3 // Q3
+
+ batch_bmatTr_madd(Qs->l2_Q6, Fs->l2_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6 + F2tr*T2
+ batch_trimatTr_madd(Qs->l2_Q6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F2tr*T2 + F5_F5T*T3 + F6
+ batch_matTr_madd(Qs->l2_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l2_Q3, _O2, _O2_BYTE); // Q6
+}
+#define calculate_Q_from_F_impl calculate_Q_from_F_ref
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ calculate_Q_from_F_impl(Qs, Fs, Ts);
+}
diff --git a/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair_computation.h b/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair_computation.h
new file mode 100644
index 00000000..d9aa3446
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/rainbow_keypair_computation.h
@@ -0,0 +1,53 @@
+#ifndef _RAINBOW_KEYPAIR_COMP_H_
+#define _RAINBOW_KEYPAIR_COMP_H_
+/// @file rainbow_keypair_computation.h
+/// @brief Functions for calculating pk/sk while generating keys.
+///
+/// Defining an internal structure of public key.
+/// Functions for calculating pk/sk for key generation.
+///
+
+#include "rainbow_keypair.h"
+
+/// @brief The (internal use) public key for rainbow
+///
+/// The (internal use) public key for rainbow. The public
+/// polynomials are divided into l1_Q1, l1_Q2, ... l1_Q9,
+/// l2_Q1, .... , l2_Q9.
+///
+typedef struct rainbow_extend_publickey {
+ unsigned char l1_Q1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l1_Q2[_O1_BYTE * _V1 * _O1];
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2];
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2];
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)];
+
+ unsigned char l2_Q1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l2_Q2[_O2_BYTE * _V1 * _O1];
+ unsigned char l2_Q3[_O2_BYTE * _V1 * _O2];
+ unsigned char l2_Q5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l2_Q6[_O2_BYTE * _O1 * _O2];
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)];
+} ext_cpk_t;
+
+///
+/// @brief converting formats of public keys : from ext_cpk_t version to pk_t
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the internel public key.
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk);
+/////////////////////////////////////////////////
+
+///
+/// @brief Computing public key from secret key
+///
+/// @param[out] Qs - the public key
+/// @param[in] Fs - parts of the secret key: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the secret key: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+
+#endif // _RAINBOW_KEYPAIR_COMP_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/sign.c b/crypto_sign/rainbowIIIc-classic/clean/sign.c
new file mode 100644
index 00000000..e724420c
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/sign.c
@@ -0,0 +1,74 @@
+/// @file sign.c
+/// @brief the implementations for functions in api.h
+///
+///
+
+#include "api.h"
+#include "rainbow.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
+ unsigned char sk_seed[LEN_SKSEED] = {0};
+ randombytes(sk_seed, LEN_SKSEED);
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_generate_keypair((pk_t *)pk, (sk_t *)sk, sk_seed);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_crypto_sign(unsigned char *sm, size_t *smlen, const unsigned char *m, size_t mlen, const unsigned char *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+
+ memcpy(sm, m, mlen);
+ smlen[0] = mlen + _SIGNATURE_BYTE;
+
+ return PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_rainbow_sign(sm + mlen, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_crypto_sign_open(unsigned char *m, size_t *mlen, const unsigned char *sm, size_t smlen, const unsigned char *pk) {
+ int rc;
+ if (_SIGNATURE_BYTE > smlen) {
+ rc = -1;
+ } else {
+ *mlen = smlen - _SIGNATURE_BYTE;
+
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, sm, *mlen);
+
+ rc = PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_rainbow_verify(digest, sm + mlen[0], (const pk_t *)pk);
+ }
+ if (!rc) {
+ memcpy(m, sm, smlen - _SIGNATURE_BYTE);
+ } else { // bad signature
+ *mlen = (size_t) -1;
+ memset(m, 0, smlen);
+ }
+ return rc;
+}
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ *siglen = _SIGNATURE_BYTE;
+ return PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_rainbow_sign(sig, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ if (siglen != _SIGNATURE_BYTE) {
+ return -1;
+ }
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ return PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_rainbow_verify(digest, sig, (const pk_t *)pk);
+}
diff --git a/crypto_sign/rainbowIIIc-classic/clean/utils_hash.c b/crypto_sign/rainbowIIIc-classic/clean/utils_hash.c
new file mode 100644
index 00000000..58948cd9
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/utils_hash.c
@@ -0,0 +1,50 @@
+/// @file utils_hash.c
+/// @brief the adapter for SHA2 families.
+///
+///
+
+#include "utils_hash.h"
+#include "rainbow_config.h"
+#include "sha2.h"
+
+static inline int _hash(unsigned char *digest, const unsigned char *m, size_t mlen) {
+ sha384(digest, m, mlen);
+ return 0;
+}
+
+static inline int expand_hash(unsigned char *digest, size_t n_digest, const unsigned char *hash) {
+ if (_HASH_LEN >= n_digest) {
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[i] = hash[i];
+ }
+ return 0;
+ }
+ for (size_t i = 0; i < _HASH_LEN; i++) {
+ digest[i] = hash[i];
+ }
+ n_digest -= _HASH_LEN;
+
+ while (_HASH_LEN <= n_digest) {
+ _hash(digest + _HASH_LEN, digest, _HASH_LEN);
+
+ n_digest -= _HASH_LEN;
+ digest += _HASH_LEN;
+ }
+ unsigned char temp[_HASH_LEN];
+ if (n_digest) {
+ _hash(temp, digest, _HASH_LEN);
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[_HASH_LEN + i] = temp[i];
+ }
+ }
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_hash_msg(unsigned char *digest,
+ size_t len_digest,
+ const unsigned char *m,
+ size_t mlen) {
+ unsigned char buf[_HASH_LEN];
+ _hash(buf, m, mlen);
+ return expand_hash(digest, len_digest, buf);
+}
diff --git a/crypto_sign/rainbowIIIc-classic/clean/utils_hash.h b/crypto_sign/rainbowIIIc-classic/clean/utils_hash.h
new file mode 100644
index 00000000..7e7babfb
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/utils_hash.h
@@ -0,0 +1,11 @@
+#ifndef _UTILS_HASH_H_
+#define _UTILS_HASH_H_
+/// @file utils_hash.h
+/// @brief the interface for adapting hash functions.
+///
+
+#include
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_hash_msg(unsigned char *digest, size_t len_digest, const unsigned char *m, size_t mlen);
+
+#endif // _UTILS_HASH_H_
diff --git a/crypto_sign/rainbowIIIc-classic/clean/utils_prng.c b/crypto_sign/rainbowIIIc-classic/clean/utils_prng.c
new file mode 100644
index 00000000..5f627f37
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/utils_prng.c
@@ -0,0 +1,95 @@
+/// @file utils_prng.c
+/// @brief The implementation of PRNG related functions.
+///
+
+#include "utils_prng.h"
+#include "aes.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+static void prng_update(const unsigned char *provided_data,
+ unsigned char *Key,
+ unsigned char *V) {
+ unsigned char temp[48];
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, Key);
+ for (int i = 0; i < 3; i++) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (V[j] == 0xff) {
+ V[j] = 0x00;
+ } else {
+ V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(temp + 16 * i, V, 1, &ctx);
+ }
+ if (provided_data != NULL) {
+ for (int i = 0; i < 48; i++) {
+ temp[i] ^= provided_data[i];
+ }
+ }
+ memcpy(Key, temp, 32);
+ memcpy(V, temp + 32, 16);
+}
+static void randombytes_init_with_state(prng_t *state,
+ unsigned char *entropy_input_48bytes) {
+ memset(state->Key, 0x00, 32);
+ memset(state->V, 0x00, 16);
+ prng_update(entropy_input_48bytes, state->Key, state->V);
+}
+
+static int randombytes_with_state(prng_t *state,
+ unsigned char *x,
+ size_t xlen) {
+
+ unsigned char block[16];
+ int i = 0;
+
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, state->Key);
+
+ while (xlen > 0) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (state->V[j] == 0xff) {
+ state->V[j] = 0x00;
+ } else {
+ state->V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(block, state->V, 1, &ctx);
+ if (xlen > 15) {
+ memcpy(x + i, block, 16);
+ i += 16;
+ xlen -= 16;
+ } else {
+ memcpy(x + i, block, xlen);
+ xlen = 0;
+ }
+ }
+ prng_update(NULL, state->Key, state->V);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen) {
+ unsigned char seed[48];
+ if (prng_seedlen >= 48) {
+ memcpy(seed, prng_seed, 48);
+ } else {
+ memcpy(seed, prng_seed, prng_seedlen);
+ PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_hash_msg(seed + prng_seedlen, 48 - (unsigned)prng_seedlen, (const unsigned char *)prng_seed, prng_seedlen);
+ }
+
+ randombytes_init_with_state(ctx, seed);
+
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen) {
+ return randombytes_with_state(ctx, out, outlen);
+}
diff --git a/crypto_sign/rainbowIIIc-classic/clean/utils_prng.h b/crypto_sign/rainbowIIIc-classic/clean/utils_prng.h
new file mode 100644
index 00000000..6b4999c7
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-classic/clean/utils_prng.h
@@ -0,0 +1,18 @@
+#ifndef _UTILS_PRNG_H_
+#define _UTILS_PRNG_H_
+/// @file utils_prng.h
+/// @brief the interface for adapting PRNG functions.
+///
+///
+
+#include "randombytes.h"
+
+typedef struct {
+ unsigned char Key[32];
+ unsigned char V[16];
+} prng_t;
+
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen);
+int PQCLEAN_RAINBOWIIICCLASSIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen);
+
+#endif // _UTILS_PRNG_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/META.yml b/crypto_sign/rainbowIIIc-cyclic-compressed/META.yml
new file mode 100644
index 00000000..67b361df
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/META.yml
@@ -0,0 +1,18 @@
+name: Rainbow-IIIc-cyclic-compressed
+type: signature
+claimed-nist-level: 3
+length-public-key: 206744
+length-secret-key: 64
+length-signature: 156
+nistkat-sha256: 1ad6d22a9e98c3e05a6aceb5b892dd75908924733aadfe074b6556e1dbd881c0
+testvectors-sha256: 40df2d3b2eb52aada14469c95e6890c486eaf22dcfca9604bbf528a0b7b75070
+principal-submitters:
+ - Jintai Ding
+auxiliary-submitters:
+ - Ming-Shing Chen
+ - Albrecht Petzoldt
+ - Dieter Schmidt
+ - Bo-Yin Yang
+implementations:
+ - name: clean
+ version: https://github.com/fast-crypto-lab/rainbow-submission-round2/commit/af826fcb78f6af51a02d0352cff28a9690467bfd
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/LICENSE b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/LICENSE
new file mode 100644
index 00000000..cb00a6e3
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/LICENSE
@@ -0,0 +1,8 @@
+`Software implementation of Rainbow for NIST R2 submission' by Ming-Shing Chen
+
+To the extent possible under law, the person who associated CC0 with
+`Software implementation of Rainbow for NIST R2 submission' has waived all copyright and related or neighboring rights
+to `Software implementation of Rainbow for NIST R2 submission'.
+
+You should have received a copy of the CC0 legalcode along with this
+work. If not, see .
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/Makefile b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/Makefile
new file mode 100644
index 00000000..602a3d19
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=librainbowIIIc-cyclic-compressed_clean.a
+
+HEADERS = api.h blas_comm.h blas.h blas_u32.h gf.h parallel_matrix_op.h rainbow_blas.h rainbow_config.h rainbow.h rainbow_keypair_computation.h rainbow_keypair.h utils_hash.h utils_prng.h
+OBJECTS = blas_comm.o parallel_matrix_op.o rainbow.o rainbow_keypair.o rainbow_keypair_computation.o sign.o utils_hash.o utils_prng.o blas_u32.o gf.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/Makefile.Microsoft_nmake b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..0b89148a
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=librainbowIIIc-cyclic-compressed_clean.lib
+OBJECTS = blas_comm.obj parallel_matrix_op.obj rainbow.obj rainbow_keypair.obj rainbow_keypair_computation.obj sign.obj utils_hash.obj utils_prng.obj blas_u32.obj gf.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/api.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/api.h
new file mode 100644
index 00000000..a4a171a9
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/api.h
@@ -0,0 +1,32 @@
+#ifndef PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_API_H
+#define PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_CRYPTO_SECRETKEYBYTES 64
+#define PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_CRYPTO_PUBLICKEYBYTES 206744
+#define PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_CRYPTO_BYTES 156
+#define PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_CRYPTO_ALGNAME "RAINBOW(256,68,36,36) - cyclic compressed"
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
+
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen,
+ const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen,
+ const uint8_t *pk);
+
+
+#endif
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas.h
new file mode 100644
index 00000000..c46edf8c
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas.h
@@ -0,0 +1,19 @@
+#ifndef _BLAS_H_
+#define _BLAS_H_
+/// @file blas.h
+/// @brief Defining the implementations for linear algebra functions depending on the machine architecture.
+///
+
+#include "blas_comm.h"
+#include "blas_u32.h"
+#include "rainbow_config.h"
+
+#define gf256v_predicated_add PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_predicated_add_u32
+#define gf256v_add PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_add_u32
+
+
+#define gf256v_mul_scalar PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_mul_scalar_u32
+#define gf256v_madd PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_madd_u32
+
+
+#endif // _BLAS_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_comm.c b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_comm.c
new file mode 100644
index 00000000..e0e550a5
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_comm.c
@@ -0,0 +1,142 @@
+/// @file blas_comm.c
+/// @brief The standard implementations for blas_comm.h
+///
+
+#include "blas_comm.h"
+#include "blas.h"
+#include "gf.h"
+#include "rainbow_config.h"
+
+#include
+#include
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte) {
+ gf256v_add(b, b, _num_byte);
+}
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i) {
+ return a[i];
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte) {
+ uint8_t r = 0;
+ while (_num_byte--) {
+ r |= a[0];
+ a++;
+ }
+ return (0 == r);
+}
+
+/// polynomial multplication
+/// School boook
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num) {
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(c, _num * 2 - 1);
+ for (unsigned int i = 0; i < _num; i++) {
+ gf256v_madd(c + i, a, b[i], _num);
+ }
+}
+
+static void gf256mat_prod_ref(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(c, n_A_vec_byte);
+ for (unsigned int i = 0; i < n_A_width; i++) {
+ gf256v_madd(c, matA, b[i], n_A_vec_byte);
+ matA += n_A_vec_byte;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec) {
+ unsigned int n_vec_byte = len_vec;
+ for (unsigned int k = 0; k < len_vec; k++) {
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(c, n_vec_byte);
+ const uint8_t *bk = b + n_vec_byte * k;
+ for (unsigned int i = 0; i < len_vec; i++) {
+ gf256v_madd(c, a + n_vec_byte * i, bk[i], n_vec_byte);
+ }
+ c += n_vec_byte;
+ }
+}
+
+static unsigned int gf256mat_gauss_elim_ref(uint8_t *mat, unsigned int h, unsigned int w) {
+ unsigned int r8 = 1;
+
+ for (unsigned int i = 0; i < h; i++) {
+ uint8_t *ai = mat + w * i;
+ unsigned int skip_len_align4 = i & ((unsigned int)~0x3);
+
+ for (unsigned int j = i + 1; j < h; j++) {
+ uint8_t *aj = mat + w * j;
+ gf256v_predicated_add(ai + skip_len_align4, !PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256_is_nonzero(ai[i]), aj + skip_len_align4, w - skip_len_align4);
+ }
+ r8 &= PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256_is_nonzero(ai[i]);
+ uint8_t pivot = ai[i];
+ pivot = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256_inv(pivot);
+ gf256v_mul_scalar(ai + skip_len_align4, pivot, w - skip_len_align4);
+ for (unsigned int j = 0; j < h; j++) {
+ if (i == j) {
+ continue;
+ }
+ uint8_t *aj = mat + w * j;
+ gf256v_madd(aj + skip_len_align4, ai + skip_len_align4, aj[i], w - skip_len_align4);
+ }
+ }
+
+ return r8;
+}
+
+static unsigned int gf256mat_solve_linear_eq_ref(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ uint8_t mat[64 * 64];
+ for (unsigned int i = 0; i < n; i++) {
+ memcpy(mat + i * (n + 1), inp_mat + i * n, n);
+ mat[i * (n + 1) + n] = c_terms[i];
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_gauss_elim(mat, n, n + 1);
+ for (unsigned int i = 0; i < n; i++) {
+ sol[i] = mat[i * (n + 1) + n];
+ }
+ return r8;
+}
+
+static inline void gf256mat_submat(uint8_t *mat2, unsigned int w2, unsigned int st, const uint8_t *mat, unsigned int w, unsigned int h) {
+ for (unsigned int i = 0; i < h; i++) {
+ for (unsigned int j = 0; j < w2; j++) {
+ mat2[i * w2 + j] = mat[i * w + st + j];
+ }
+ }
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer) {
+ uint8_t *aa = buffer;
+ for (unsigned int i = 0; i < H; i++) {
+ uint8_t *ai = aa + i * 2 * H;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(ai, 2 * H);
+ gf256v_add(ai, a + i * H, H);
+ ai[H + i] = 1;
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_gauss_elim(aa, H, 2 * H);
+ gf256mat_submat(inv_a, H, H, aa, 2 * H, H);
+ return r8;
+}
+
+
+// choosing the implementations depends on the macros _BLAS_AVX2_ and _BLAS_SSE
+
+#define gf256mat_prod_impl gf256mat_prod_ref
+#define gf256mat_gauss_elim_impl gf256mat_gauss_elim_ref
+#define gf256mat_solve_linear_eq_impl gf256mat_solve_linear_eq_ref
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ gf256mat_prod_impl(c, matA, n_A_vec_byte, n_A_width, b);
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w) {
+ return gf256mat_gauss_elim_impl(mat, h, w);
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ return gf256mat_solve_linear_eq_impl(sol, inp_mat, c_terms, n);
+}
+
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_comm.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_comm.h
new file mode 100644
index 00000000..e86298fe
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_comm.h
@@ -0,0 +1,90 @@
+#ifndef _BLAS_COMM_H_
+#define _BLAS_COMM_H_
+/// @file blas_comm.h
+/// @brief Common functions for linear algebra.
+///
+
+#include "rainbow_config.h"
+#include
+
+/// @brief set a vector to 0.
+///
+/// @param[in,out] b - the vector b.
+/// @param[in] _num_byte - number of bytes for the vector b.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte);
+
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i);
+
+/// @brief check if a vector is 0.
+///
+/// @param[in] a - the vector a.
+/// @param[in] _num_byte - number of bytes for the vector a.
+/// @return 1(true) if a is 0. 0(false) else.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte);
+
+/// @brief polynomial multiplication: c = a*b
+///
+/// @param[out] c - the output polynomial c
+/// @param[in] a - the vector a.
+/// @param[in] b - the vector b.
+/// @param[in] _num - number of elements for the polynomials a and b.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num);
+
+/// @brief matrix-vector multiplication: c = matA * b , in GF(256)
+///
+/// @param[out] c - the output vector c
+/// @param[in] matA - a column-major matrix A.
+/// @param[in] n_A_vec_byte - the size of column vectors in bytes.
+/// @param[in] n_A_width - the width of matrix A.
+/// @param[in] b - the vector b.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b);
+
+/// @brief matrix-matrix multiplication: c = a * b , in GF(256)
+///
+/// @param[out] c - the output matrix c
+/// @param[in] c - a matrix a.
+/// @param[in] b - a matrix b.
+/// @param[in] len_vec - the length of column vectors.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec);
+
+/// @brief Gauss elimination for a matrix, in GF(256)
+///
+/// @param[in,out] mat - the matrix.
+/// @param[in] h - the height of the matrix.
+/// @param[in] w - the width of the matrix.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w);
+
+/// @brief Solving linear equations, in GF(256)
+///
+/// @param[out] sol - the solutions.
+/// @param[in] inp_mat - the matrix parts of input equations.
+/// @param[in] c_terms - the constant terms of the input equations.
+/// @param[in] n - the number of equations.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n);
+
+/// @brief Computing the inverse matrix, in GF(256)
+///
+/// @param[out] inv_a - the output of matrix a.
+/// @param[in] a - a matrix a.
+/// @param[in] H - height of matrix a, i.e., matrix a is an HxH matrix.
+/// @param[in] buffer - The buffer for computations. it has to be as large as 2 input matrixes.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer);
+
+#endif // _BLAS_COMM_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_u32.c b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_u32.c
new file mode 100644
index 00000000..81f1afca
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_u32.c
@@ -0,0 +1,87 @@
+#include "blas_u32.h"
+#include "gf.h"
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte) {
+ uint32_t pr_u32 = ((uint32_t)0) - ((uint32_t)predicate);
+ uint8_t pr_u8 = pr_u32 & 0xff;
+
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= (a_u32[i] & pr_u32);
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= (a[i] & pr_u8);
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= a_u32[i];
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= a[i];
+ }
+}
+
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *a_u32 = (uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ a_u32[i] = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(a_u32[i], b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(t.u32, b);
+ for (unsigned int i = 0; i < rem; i++) {
+ a[i] = t.u8[i];
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *c_u32 = (uint32_t *)accu_c;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ c_u32[i] ^= PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(a_u32[i], gf256_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ accu_c += (n_u32 << 2);
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(t.u32, gf256_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_c[i] ^= t.u8[i];
+ }
+}
+
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_u32.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_u32.h
new file mode 100644
index 00000000..d94c03ed
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/blas_u32.h
@@ -0,0 +1,18 @@
+#ifndef _BLAS_U32_H_
+#define _BLAS_U32_H_
+/// @file blas_u32.h
+/// @brief Inlined functions for implementing basic linear algebra functions for uint32 arch.
+///
+
+#include "rainbow_config.h"
+#include
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte);
+
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte);
+
+
+#endif // _BLAS_U32_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/gf.c b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/gf.c
new file mode 100644
index 00000000..98cf167c
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/gf.c
@@ -0,0 +1,134 @@
+#include "gf.h"
+
+//// gf4 := gf2[x]/x^2+x+1
+static inline uint8_t gf4_mul_2(uint8_t a) {
+ uint8_t r = (uint8_t)(a << 1);
+ r ^= (uint8_t)((a >> 1) * 7);
+ return r;
+}
+
+static inline uint8_t gf4_mul(uint8_t a, uint8_t b) {
+ uint8_t r = (uint8_t)(a * (b & 1));
+ return r ^ (uint8_t)(gf4_mul_2(a) * (b >> 1));
+}
+
+static inline uint8_t gf4_squ(uint8_t a) {
+ return a ^ (a >> 1);
+}
+
+static inline uint32_t gf4v_mul_2_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit1 ^ (bit1 >> 1);
+}
+
+static inline uint32_t gf4v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t bit0_b = ((uint32_t)0) - ((uint32_t)(b & 1));
+ uint32_t bit1_b = ((uint32_t)0) - ((uint32_t)((b >> 1) & 1));
+ return (a & bit0_b) ^ (bit1_b & gf4v_mul_2_u32(a));
+}
+
+//// gf16 := gf4[y]/y^2+y+x
+static inline uint8_t gf16_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ uint8_t b0 = b & 3;
+ uint8_t b1 = (b >> 2);
+ uint8_t a0b0 = gf4_mul(a0, b0);
+ uint8_t a1b1 = gf4_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf4_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x2 = gf4_mul_2(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 2 ^ a0b0 ^ a1b1_x2);
+}
+
+static inline uint8_t gf16_squ(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ a1 = gf4_squ(a1);
+ uint8_t a1squ_x2 = gf4_mul_2(a1);
+ return (uint8_t)((a1 << 2) ^ a1squ_x2 ^ gf4_squ(a0));
+}
+
+// gf16 := gf4[y]/y^2+y+x
+uint32_t PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = gf4v_mul_u32(a, b);
+ uint32_t axb1 = gf4v_mul_u32(a, b >> 2);
+ uint32_t a0b1 = (axb1 << 2) & 0xcccccccc;
+ uint32_t a1b1 = axb1 & 0xcccccccc;
+ uint32_t a1b1_2 = a1b1 >> 2;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf4v_mul_2_u32(a1b1_2);
+}
+
+uint8_t PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256_is_nonzero(uint8_t a) {
+ unsigned int a8 = a;
+ unsigned int r = ((unsigned int)0) - a8;
+ r >>= 8;
+ return r & 1;
+}
+
+static inline uint8_t gf4_mul_3(uint8_t a) {
+ uint8_t msk = (uint8_t)((a - 2) >> 1);
+ return (uint8_t)((msk & ((int)a * 3)) | ((~msk) & ((int)a - 1)));
+}
+static inline uint8_t gf16_mul_8(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = a >> 2;
+ return (uint8_t)((gf4_mul_2(a0 ^ a1) << 2) | gf4_mul_3(a1));
+}
+
+// gf256 := gf16[X]/X^2+X+xy
+static inline uint8_t gf256_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ uint8_t b0 = b & 15;
+ uint8_t b1 = (b >> 4);
+ uint8_t a0b0 = gf16_mul(a0, b0);
+ uint8_t a1b1 = gf16_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf16_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x8 = gf16_mul_8(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 4 ^ a0b0 ^ a1b1_x8);
+}
+
+static inline uint8_t gf256_squ(uint8_t a) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ a1 = gf16_squ(a1);
+ uint8_t a1squ_x8 = gf16_mul_8(a1);
+ return (uint8_t)((a1 << 4) ^ a1squ_x8 ^ gf16_squ(a0));
+}
+
+uint8_t PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256_inv(uint8_t a) {
+ // 128+64+32+16+8+4+2 = 254
+ uint8_t a2 = gf256_squ(a);
+ uint8_t a4 = gf256_squ(a2);
+ uint8_t a8 = gf256_squ(a4);
+ uint8_t a4_2 = gf256_mul(a4, a2);
+ uint8_t a8_4_2 = gf256_mul(a4_2, a8);
+ uint8_t a64_ = gf256_squ(a8_4_2);
+ a64_ = gf256_squ(a64_);
+ a64_ = gf256_squ(a64_);
+ uint8_t a64_2 = gf256_mul(a64_, a8_4_2);
+ uint8_t a128_ = gf256_squ(a64_2);
+ return gf256_mul(a2, a128_);
+}
+
+static inline uint32_t gf4v_mul_3_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit0 ^ (bit1 >> 1);
+}
+static inline uint32_t gf16v_mul_8_u32(uint32_t a) {
+ uint32_t a1 = a & 0xcccccccc;
+ uint32_t a0 = (a << 2) & 0xcccccccc;
+ return gf4v_mul_2_u32(a0 ^ a1) | gf4v_mul_3_u32(a1 >> 2);
+}
+uint32_t PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(a, b);
+ uint32_t axb1 = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(a, b >> 4);
+ uint32_t a0b1 = (axb1 << 4) & 0xf0f0f0f0;
+ uint32_t a1b1 = axb1 & 0xf0f0f0f0;
+ uint32_t a1b1_4 = a1b1 >> 4;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf16v_mul_8_u32(a1b1_4);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/gf.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/gf.h
new file mode 100644
index 00000000..55b49591
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/gf.h
@@ -0,0 +1,19 @@
+#ifndef _GF16_H_
+#define _GF16_H_
+
+#include "rainbow_config.h"
+#include
+
+/// @file gf16.h
+/// @brief Library for arithmetics in GF(16) and GF(256)
+///
+
+uint32_t PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b);
+
+
+uint8_t PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256_is_nonzero(uint8_t a);
+uint8_t PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256_inv(uint8_t a);
+uint32_t PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b);
+
+
+#endif // _GF16_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/parallel_matrix_op.c b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/parallel_matrix_op.c
new file mode 100644
index 00000000..18962545
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/parallel_matrix_op.c
@@ -0,0 +1,183 @@
+/// @file parallel_matrix_op.c
+/// @brief the standard implementations for functions in parallel_matrix_op.h
+///
+/// the standard implementations for functions in parallel_matrix_op.h
+///
+
+#include "parallel_matrix_op.h"
+#include "blas.h"
+#include "blas_comm.h"
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim) {
+ return (dim + dim - i_row + 1) * i_row / 2 + j_col - i_row;
+}
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle or lower-triangle matrix.
+///
+/// @param[in] i_row - the i-th row in a triangle matrix.
+/// @param[in] j_col - the j-th column in a triangle matrix.
+/// @param[in] dim - the dimension of the triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+static inline unsigned int idx_of_2trimat(unsigned int i_row, unsigned int j_col, unsigned int n_var) {
+ if (i_row > j_col) {
+ return PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(j_col, i_row, n_var);
+ }
+ return PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i_row, j_col, n_var);
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch) {
+ unsigned char *runningC = btriC;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < i; j++) {
+ unsigned int idx = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(j, i, Aheight);
+ gf256v_add(btriC + idx * size_batch, bA + size_batch * (i * Awidth + j), size_batch);
+ }
+ gf256v_add(runningC, bA + size_batch * (i * Awidth + i), size_batch * (Aheight - i));
+ runningC += size_batch * (Aheight - i);
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (k < i) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[(k - i) * size_batch], PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ btriA += (Aheight - i) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i < k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(k, i, Aheight))], PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i == k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (idx_of_2trimat(i, k, Aheight))], PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf256(unsigned char *bC, const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Atr_height = Awidth;
+ unsigned int Atr_width = Aheight;
+ for (unsigned int i = 0; i < Atr_height; i++) {
+ for (unsigned int j = 0; j < Atr_width; j++) {
+ gf256v_madd(bC, &bB[j * Bwidth * size_batch], PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&A_to_tr[size_Acolvec * i], j), size_batch * Bwidth);
+ }
+ bC += size_batch * Bwidth;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ const unsigned char *bA = bA_to_tr;
+ unsigned int Aheight = Awidth_before_tr;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[size_batch * (i + k * Aheight)], PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[k * size_batch], PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ bA += (Awidth) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch) {
+ unsigned char tmp[256];
+
+ unsigned char _x[256];
+ for (unsigned int i = 0; i < dim; i++) {
+ _x[i] = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(x, i);
+ }
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(y, size_batch);
+ for (unsigned int i = 0; i < dim; i++) {
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = i; j < dim; j++) {
+ gf256v_madd(tmp, trimat, _x[j], size_batch);
+ trimat += size_batch;
+ }
+ gf256v_madd(y, tmp, _x[i], size_batch);
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y, const unsigned char *mat,
+ const unsigned char *x, unsigned dim_x, unsigned size_batch) {
+ unsigned char tmp[128];
+
+ unsigned char _x[128];
+ for (unsigned int i = 0; i < dim_x; i++) {
+ _x[i] = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(x, i);
+ }
+ unsigned char _y[128];
+ for (unsigned int i = 0; i < dim_y; i++) {
+ _y[i] = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(y, i);
+ }
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(z, size_batch);
+ for (unsigned int i = 0; i < dim_y; i++) {
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = 0; j < dim_x; j++) {
+ gf256v_madd(tmp, mat, _x[j], size_batch);
+ mat += size_batch;
+ }
+ gf256v_madd(z, tmp, _y[i], size_batch);
+ }
+}
+
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/parallel_matrix_op.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/parallel_matrix_op.h
new file mode 100644
index 00000000..63d82311
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/parallel_matrix_op.h
@@ -0,0 +1,260 @@
+#ifndef _P_MATRIX_OP_H_
+#define _P_MATRIX_OP_H_
+/// @file parallel_matrix_op.h
+/// @brief Librarys for operations of batched matrixes.
+///
+///
+
+//////////////// Section: triangle matrix <-> rectangle matrix ///////////////////////////////////
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim);
+
+///
+/// @brief Upper trianglize a rectangle matrix to the corresponding upper-trangle matrix.
+///
+/// @param[out] btriC - the batched upper-trianglized matrix C.
+/// @param[in] bA - a batched retangle matrix A.
+/// @param[in] bwidth - the width of the batched matrix A, i.e., A is a Awidth x Awidth matrix.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch);
+
+//////////////////// Section: matrix multiplications ///////////////////////////////
+
+///
+/// @brief bC += btriA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. A will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A, which will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf16(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf256(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+//////////////////// Section: "quadratric" matrix evaluation ///////////////////////////////
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(16)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(256)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(16)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(256)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+#endif // _P_MATRIX_OP_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow.c b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow.c
new file mode 100644
index 00000000..9da0c4e3
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow.c
@@ -0,0 +1,180 @@
+/// @file rainbow.c
+/// @brief The standard implementations for functions in rainbow.h
+///
+
+#include "rainbow.h"
+#include "blas.h"
+#include "rainbow_blas.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "utils_hash.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+#define MAX_ATTEMPT_FRMAT 128
+#define _MAX_O ((_O1 > _O2) ? _O1 : _O2)
+#define _MAX_O_BYTE ((_O1_BYTE > _O2_BYTE) ? _O1_BYTE : _O2_BYTE)
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *_digest) {
+ uint8_t mat_l1[_O1 * _O1_BYTE];
+ uint8_t mat_l2[_O2 * _O2_BYTE];
+ uint8_t mat_buffer[2 * _MAX_O * _MAX_O_BYTE];
+
+ // setup PRNG
+ prng_t prng_sign;
+ uint8_t prng_preseed[LEN_SKSEED + _HASH_LEN];
+ memcpy(prng_preseed, sk->sk_seed, LEN_SKSEED);
+ memcpy(prng_preseed + LEN_SKSEED, _digest, _HASH_LEN); // prng_preseed = sk_seed || digest
+ uint8_t prng_seed[_HASH_LEN];
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_hash_msg(prng_seed, _HASH_LEN, prng_preseed, _HASH_LEN + LEN_SKSEED);
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_set(&prng_sign, prng_seed, _HASH_LEN); // seed = H( sk_seed || digest )
+ for (unsigned int i = 0; i < LEN_SKSEED + _HASH_LEN; i++) {
+ prng_preseed[i] ^= prng_preseed[i]; // clean
+ }
+ for (unsigned int i = 0; i < _HASH_LEN; i++) {
+ prng_seed[i] ^= prng_seed[i]; // clean
+ }
+
+ // roll vinegars.
+ uint8_t vinegar[_V1_BYTE];
+ unsigned int n_attempt = 0;
+ unsigned int l1_succ = 0;
+ while (!l1_succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(&prng_sign, vinegar, _V1_BYTE); // generating vinegars
+ gfmat_prod(mat_l1, sk->l1_F2, _O1 * _O1_BYTE, _V1, vinegar); // generating the linear equations for layer 1
+ l1_succ = gfmat_inv(mat_l1, mat_l1, _O1, mat_buffer); // check if the linear equation solvable
+ n_attempt++;
+ }
+
+ // Given the vinegars, pre-compute variables needed for layer 2
+ uint8_t r_l1_F1[_O1_BYTE] = {0};
+ uint8_t r_l2_F1[_O2_BYTE] = {0};
+ batch_quad_trimat_eval(r_l1_F1, sk->l1_F1, vinegar, _V1, _O1_BYTE);
+ batch_quad_trimat_eval(r_l2_F1, sk->l2_F1, vinegar, _V1, _O2_BYTE);
+ uint8_t mat_l2_F3[_O2 * _O2_BYTE];
+ uint8_t mat_l2_F2[_O1 * _O2_BYTE];
+ gfmat_prod(mat_l2_F3, sk->l2_F3, _O2 * _O2_BYTE, _V1, vinegar);
+ gfmat_prod(mat_l2_F2, sk->l2_F2, _O1 * _O2_BYTE, _V1, vinegar);
+
+ // Some local variables.
+ uint8_t _z[_PUB_M_BYTE];
+ uint8_t y[_PUB_M_BYTE];
+ uint8_t *x_v1 = vinegar;
+ uint8_t x_o1[_O1_BYTE];
+ uint8_t x_o2[_O1_BYTE];
+
+ uint8_t digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, _digest, _HASH_LEN);
+ uint8_t *salt = digest_salt + _HASH_LEN;
+
+ uint8_t temp_o[_MAX_O_BYTE + 32] = {0};
+ unsigned int succ = 0;
+ while (!succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ // The computation: H(digest||salt) --> z --S--> y --C-map--> x --T--> w
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(&prng_sign, salt, _SALT_BYTE); // roll the salt
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_hash_msg(_z, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H(digest||salt)
+
+ // y = S^-1 * z
+ memcpy(y, _z, _PUB_M_BYTE); // identity part of S
+ gfmat_prod(temp_o, sk->s1, _O1_BYTE, _O2, _z + _O1_BYTE);
+ gf256v_add(y, temp_o, _O1_BYTE);
+
+ // Central Map:
+ // layer 1: calculate x_o1
+ memcpy(temp_o, r_l1_F1, _O1_BYTE);
+ gf256v_add(temp_o, y, _O1_BYTE);
+ gfmat_prod(x_o1, mat_l1, _O1_BYTE, _O1, temp_o);
+
+ // layer 2: calculate x_o2
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(temp_o, _O2_BYTE);
+ gfmat_prod(temp_o, mat_l2_F2, _O2_BYTE, _O1, x_o1); // F2
+ batch_quad_trimat_eval(mat_l2, sk->l2_F5, x_o1, _O1, _O2_BYTE); // F5
+ gf256v_add(temp_o, mat_l2, _O2_BYTE);
+ gf256v_add(temp_o, r_l2_F1, _O2_BYTE); // F1
+ gf256v_add(temp_o, y + _O1_BYTE, _O2_BYTE);
+
+ // generate the linear equations of the 2nd layer
+ gfmat_prod(mat_l2, sk->l2_F6, _O2 * _O2_BYTE, _O1, x_o1); // F6
+ gf256v_add(mat_l2, mat_l2_F3, _O2 * _O2_BYTE); // F3
+ succ = gfmat_inv(mat_l2, mat_l2, _O2, mat_buffer);
+ gfmat_prod(x_o2, mat_l2, _O2_BYTE, _O2, temp_o); // solve l2 eqs
+
+ n_attempt++;
+ };
+ // w = T^-1 * y
+ uint8_t w[_PUB_N_BYTE];
+ // identity part of T.
+ memcpy(w, x_v1, _V1_BYTE);
+ memcpy(w + _V1_BYTE, x_o1, _O1_BYTE);
+ memcpy(w + _V2_BYTE, x_o2, _O2_BYTE);
+ // Computing the t1 part.
+ gfmat_prod(y, sk->t1, _V1_BYTE, _O1, x_o1);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t4 part.
+ gfmat_prod(y, sk->t4, _V1_BYTE, _O2, x_o2);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t3 part.
+ gfmat_prod(y, sk->t3, _O1_BYTE, _O2, x_o2);
+ gf256v_add(w + _V1_BYTE, y, _O1_BYTE);
+
+ memset(signature, 0, _SIGNATURE_BYTE); // set the output 0
+ // clean
+ memset(&prng_sign, 0, sizeof(prng_t));
+ memset(vinegar, 0, _V1_BYTE);
+ memset(r_l1_F1, 0, _O1_BYTE);
+ memset(r_l2_F1, 0, _O2_BYTE);
+ memset(_z, 0, _PUB_M_BYTE);
+ memset(y, 0, _PUB_M_BYTE);
+ memset(x_o1, 0, _O1_BYTE);
+ memset(x_o2, 0, _O2_BYTE);
+ memset(temp_o, 0, sizeof(temp_o));
+
+ // return: copy w and salt to the signature.
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ return -1;
+ }
+ gf256v_add(signature, w, _PUB_N_BYTE);
+ gf256v_add(signature + _PUB_N_BYTE, salt, _SALT_BYTE);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk) {
+ unsigned char digest_ck[_PUB_M_BYTE];
+ // public_map( digest_ck , pk , signature ); Evaluating the quadratic public polynomials.
+ batch_quad_trimat_eval(digest_ck, pk->pk, signature, _PUB_N, _PUB_M_BYTE);
+
+ unsigned char correct[_PUB_M_BYTE];
+ unsigned char digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, digest, _HASH_LEN);
+ memcpy(digest_salt + _HASH_LEN, signature + _PUB_N_BYTE, _SALT_BYTE);
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_hash_msg(correct, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H( digest || salt )
+
+ // check consistancy.
+ unsigned char cc = 0;
+ for (unsigned int i = 0; i < _PUB_M_BYTE; i++) {
+ cc |= (digest_ck[i] ^ correct[i]);
+ }
+ return (0 == cc) ? 0 : -1;
+}
+
+/////////////// cyclic version ///////////////////////////
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(uint8_t *signature, const csk_t *csk, const uint8_t *digest) {
+ unsigned char sk[sizeof(sk_t) + 32];
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_generate_secretkey_cyclic((sk_t *)sk, csk->pk_seed, csk->sk_seed); // generating classic secret key.
+ return PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_sign(signature, (sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *_pk) {
+ unsigned char pk[sizeof(pk_t) + 32];
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_cpk_to_pk((pk_t *)pk, _pk); // generating classic public key.
+ return PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_verify(digest, signature, (pk_t *)pk);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow.h
new file mode 100644
index 00000000..7decea2a
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow.h
@@ -0,0 +1,50 @@
+#ifndef _RAINBOW_H_
+#define _RAINBOW_H_
+/// @file rainbow.h
+/// @brief APIs for rainbow.
+///
+
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+
+#include
+
+///
+/// @brief Signing function for classical secret key.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk);
+
+///
+/// @brief Signing function for compressed secret key of the cyclic rainbow.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the compressed secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(uint8_t *signature, const csk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function for cyclic public keys.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key of cyclic rainbow.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *pk);
+
+#endif // _RAINBOW_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_blas.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_blas.h
new file mode 100644
index 00000000..120973c6
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_blas.h
@@ -0,0 +1,31 @@
+#ifndef _RAINBOW_BLAS_H_
+#define _RAINBOW_BLAS_H_
+/// @file rainbow_blas.h
+/// @brief Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+///
+/// Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+
+#include "blas.h"
+#include "parallel_matrix_op.h"
+#include "rainbow_config.h"
+
+
+#define gfv_get_ele PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_get_ele
+#define gfv_mul_scalar PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_mul_scalar
+#define gfv_madd PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256v_madd
+
+#define gfmat_prod PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_prod
+#define gfmat_inv PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_gf256mat_inv
+
+#define batch_trimat_madd PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf256
+#define batch_trimatTr_madd PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf256
+#define batch_2trimat_madd PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf256
+#define batch_matTr_madd PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf256
+#define batch_bmatTr_madd PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf256
+#define batch_mat_madd PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf256
+
+#define batch_quad_trimat_eval PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf256
+#define batch_quad_recmat_eval PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf256
+
+
+#endif // _RAINBOW_BLAS_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_config.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_config.h
new file mode 100644
index 00000000..6d9aa270
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_config.h
@@ -0,0 +1,46 @@
+#ifndef _H_RAINBOW_CONFIG_H_
+#define _H_RAINBOW_CONFIG_H_
+
+/// @file rainbow_config.h
+/// @brief Defining the parameters of the Rainbow and the corresponding constants.
+///
+
+#define _GFSIZE 256
+#define _V1 68
+#define _O1 36
+#define _O2 36
+#define _HASH_LEN 48
+
+
+#define _V2 ((_V1) + (_O1))
+
+/// size of N, in # of gf elements.
+#define _PUB_N (_V1 + _O1 + _O2)
+
+/// size of M, in # gf elements.
+#define _PUB_M (_O1 + _O2)
+
+/// size of variables, in # bytes.
+
+// GF256
+#define _V1_BYTE (_V1)
+#define _V2_BYTE (_V2)
+#define _O1_BYTE (_O1)
+#define _O2_BYTE (_O2)
+#define _PUB_N_BYTE (_PUB_N)
+#define _PUB_M_BYTE (_PUB_M)
+
+
+/// length of seed for public key, in # bytes
+#define LEN_PKSEED 32
+
+/// length of seed for secret key, in # bytes
+#define LEN_SKSEED 32
+
+/// length of salt for a signature, in # bytes
+#define _SALT_BYTE 16
+
+/// length of a signature
+#define _SIGNATURE_BYTE (_PUB_N_BYTE + _SALT_BYTE)
+
+#endif // _H_RAINBOW_CONFIG_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair.c b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair.c
new file mode 100644
index 00000000..648dc106
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair.c
@@ -0,0 +1,188 @@
+/// @file rainbow_keypair.c
+/// @brief implementations of functions in rainbow_keypair.h
+///
+
+#include "rainbow_keypair.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair_computation.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+static void generate_S_T(unsigned char *s_and_t, prng_t *prng0) {
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // S1
+ s_and_t += _O1_BYTE * _O2;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O1); // T1
+ s_and_t += _V1_BYTE * _O1;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O2); // T2
+ s_and_t += _V1_BYTE * _O2;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // T3
+}
+
+static unsigned int generate_l1_F12(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O1_BYTE * N_TRIANGLE_TERMS(_V1)); // l1_F1
+ sk += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O1_BYTE * _V1 * _O1); // l1_F2
+ n_byte_generated += _O1_BYTE * _V1 * _O1;
+ return n_byte_generated;
+}
+
+static unsigned int generate_l2_F12356(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // l2_F1
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O1); // l2_F2
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O2); // l2_F3
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // l2_F5
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _O1 * _O2); // l2_F6
+ n_byte_generated += _O2_BYTE * _O1 * _O2;
+
+ return n_byte_generated;
+}
+
+static void generate_B1_B2(unsigned char *sk, prng_t *prng0) {
+ sk += generate_l1_F12(sk, prng0);
+ generate_l2_F12356(sk, prng0);
+}
+
+static void calculate_t4(unsigned char *t2_to_t4, const unsigned char *t1, const unsigned char *t3) {
+ // t4 = T_sk.t1 * T_sk.t3 - T_sk.t2
+ unsigned char temp[_V1_BYTE + 32];
+ unsigned char *t4 = t2_to_t4;
+ for (unsigned int i = 0; i < _O2; i++) { /// t3 width
+ gfmat_prod(temp, t1, _V1_BYTE, _O1, t3);
+ gf256v_add(t4, temp, _V1_BYTE);
+ t4 += _V1_BYTE;
+ t3 += _O1_BYTE;
+ }
+}
+
+static void obsfucate_l1_polys(unsigned char *l1_polys, const unsigned char *l2_polys, unsigned int n_terms, const unsigned char *s1) {
+ unsigned char temp[_O1_BYTE + 32];
+ while (n_terms--) {
+ gfmat_prod(temp, s1, _O1_BYTE, _O2, l2_polys);
+ gf256v_add(l1_polys, temp, _O1_BYTE);
+ l1_polys += _O1_BYTE;
+ l2_polys += _O2_BYTE;
+ }
+}
+
+/////////////////// Classic //////////////////////////////////
+
+
+///////////////////// Cyclic //////////////////////////////////
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(pk->pk_seed, pk_seed, LEN_PKSEED);
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // prng for sk
+ prng_t prng;
+ prng_t *prng0 = &prng;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_set(prng0, sk_seed, LEN_SKSEED);
+ generate_S_T(sk->s1, prng0); // S,T: only a part of sk
+
+ unsigned char t2[sizeof(sk->t4)];
+ memcpy(t2, sk->t4, _V1_BYTE * _O2); // temporarily store t2
+ calculate_t4(sk->t4, sk->t1, sk->t3); // t2 <- t4
+
+ // prng for pk
+ sk_t inst_Qs;
+ sk_t *Qs = &inst_Qs;
+ prng_t *prng1 = &prng;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_set(prng1, pk_seed, LEN_PKSEED);
+ generate_B1_B2(Qs->l1_F1, prng1); // generating l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+ obsfucate_l1_polys(Qs->l1_F1, Qs->l2_F1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(Qs->l1_F2, Qs->l2_F2, _V1 * _O1, sk->s1);
+ // so far, the Qs contains l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6.
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk, Qs, sk); // calcuate the rest parts of secret key from Qs and S,T
+
+ unsigned char t4[sizeof(sk->t4)];
+ memcpy(t4, sk->t4, _V1_BYTE * _O2); // temporarily store t4
+ memcpy(sk->t4, t2, _V1_BYTE * _O2); // restore t2
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_calculate_Q_from_F_cyclic(pk, sk, sk); // calculate the rest parts of public key: l1_Q3, l1_Q5, l1_Q6, l1_Q9, l2_Q9
+ memcpy(sk->t4, t4, _V1_BYTE * _O2); // restore t4
+
+ obsfucate_l1_polys(pk->l1_Q3, Qs->l2_F3, _V1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q5, Qs->l2_F5, N_TRIANGLE_TERMS(_O1), sk->s1);
+ obsfucate_l1_polys(pk->l1_Q6, Qs->l2_F6, _O1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q9, pk->l2_Q9, N_TRIANGLE_TERMS(_O2), sk->s1);
+
+ // clean
+ memset(&prng, 0, sizeof(prng_t));
+}
+
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_generate_compact_keypair_cyclic(cpk_t *pk, csk_t *rsk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(rsk->pk_seed, pk_seed, LEN_PKSEED);
+ memcpy(rsk->sk_seed, sk_seed, LEN_SKSEED);
+ sk_t sk;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_generate_keypair_cyclic(pk, &sk, pk_seed, sk_seed);
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_generate_secretkey_cyclic(sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // prng for sk
+ prng_t prng0;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_set(&prng0, sk_seed, LEN_SKSEED);
+ generate_S_T(sk->s1, &prng0);
+ calculate_t4(sk->t4, sk->t1, sk->t3);
+
+ // prng for pk
+ sk_t inst_Qs;
+ sk_t *Qs = &inst_Qs;
+ prng_t prng1;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_set(&prng1, pk_seed, LEN_PKSEED);
+ generate_B1_B2(Qs->l1_F1, &prng1);
+
+ obsfucate_l1_polys(Qs->l1_F1, Qs->l2_F1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(Qs->l1_F2, Qs->l2_F2, _V1 * _O1, sk->s1);
+
+ // calcuate the parts of sk according to pk.
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk, Qs, sk);
+
+ // clean prng for sk
+ memset(&prng0, 0, sizeof(prng_t));
+}
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_cpk_to_pk(pk_t *rpk, const cpk_t *cpk) {
+ // procedure: cpk_t --> extcpk_t --> pk_t
+
+ // convert from cpk_t to extcpk_t
+ ext_cpk_t pk;
+
+ // setup prng
+ prng_t prng0;
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_set(&prng0, cpk->pk_seed, LEN_SKSEED);
+
+ // generating parts of key with prng
+ generate_l1_F12(pk.l1_Q1, &prng0);
+ // copying parts of key from input. l1_Q3, l1_Q5, l1_Q6, l1_Q9
+ memcpy(pk.l1_Q3, cpk->l1_Q3, _O1_BYTE * (_V1 * _O2 + N_TRIANGLE_TERMS(_O1) + _O1 * _O2 + N_TRIANGLE_TERMS(_O2)));
+
+ // generating parts of key with prng
+ generate_l2_F12356(pk.l2_Q1, &prng0);
+ // copying parts of key from input: l2_Q9
+ memcpy(pk.l2_Q9, cpk->l2_Q9, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ // convert from extcpk_t to pk_t
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_extcpk_to_pk(rpk, &pk);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair.h
new file mode 100644
index 00000000..4ca8876e
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair.h
@@ -0,0 +1,111 @@
+#ifndef _RAINBOW_KEYPAIR_H_
+#define _RAINBOW_KEYPAIR_H_
+/// @file rainbow_keypair.h
+/// @brief Formats of key pairs and functions for generating key pairs.
+/// Formats of key pairs and functions for generating key pairs.
+///
+
+#include "rainbow_config.h"
+
+#define N_TRIANGLE_TERMS(n_var) ((n_var) * ((n_var) + 1) / 2)
+
+/// @brief public key for classic rainbow
+///
+/// public key for classic rainbow
+///
+typedef struct rainbow_publickey {
+ unsigned char pk[(_PUB_M_BYTE)*N_TRIANGLE_TERMS(_PUB_N)];
+} pk_t;
+
+/// @brief secret key for classic rainbow
+///
+/// secret key for classic rainbow
+///
+typedef struct rainbow_secretkey {
+ ///
+ /// seed for generating secret key.
+ /// Generating S, T, and F for classic rainbow.
+ /// Generating S and T only for cyclic rainbow.
+ unsigned char sk_seed[LEN_SKSEED];
+
+ unsigned char s1[_O1_BYTE * _O2]; ///< part of S map
+ unsigned char t1[_V1_BYTE * _O1]; ///< part of T map
+ unsigned char t4[_V1_BYTE * _O2]; ///< part of T map
+ unsigned char t3[_O1_BYTE * _O2]; ///< part of T map
+
+ unsigned char l1_F1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer1
+ unsigned char l1_F2[_O1_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer1
+
+ unsigned char l2_F1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer2
+ unsigned char l2_F2[_O2_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer2
+
+ unsigned char l2_F3[_O2_BYTE * _V1 * _O2]; ///< part of C-map, F3, Layer2
+ unsigned char l2_F5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< part of C-map, F5, Layer2
+ unsigned char l2_F6[_O2_BYTE * _O1 * _O2]; ///< part of C-map, F6, Layer2
+} sk_t;
+
+/// @brief public key for cyclic rainbow
+///
+/// public key for cyclic rainbow
+///
+typedef struct rainbow_publickey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating l1_Q1,l1_Q2,l2_Q1,l2_Q2,l2_Q3,l2_Q5,l2_Q6
+
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2]; ///< Q3, layer1
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< Q5, layer1
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2]; ///< Q6, layer1
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer1
+
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer2
+} cpk_t;
+
+/// @brief compressed secret key for cyclic rainbow
+///
+/// compressed secret key for cyclic rainbow
+///
+typedef struct rainbow_secretkey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating a part of public key.
+ unsigned char sk_seed[LEN_SKSEED]; ///< seed for generating a part of secret key.
+} csk_t;
+
+
+///
+/// @brief Generate key pairs for cyclic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the secret key.
+/// @param[in] pk_seed - seed for generating parts of public key.
+/// @param[in] sk_seed - seed for generating secret key.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+///
+/// @brief Generate compressed key pairs for cyclic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the compressed secret key.
+/// @param[in] pk_seed - seed for generating parts of the public key.
+/// @param[in] sk_seed - seed for generating the secret key.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_generate_compact_keypair_cyclic(cpk_t *pk, csk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+///
+/// @brief Generate secret key for cyclic rainbow.
+///
+/// @param[out] sk - the secret key.
+/// @param[in] pk_seed - seed for generating parts of the pbulic key.
+/// @param[in] sk_seed - seed for generating the secret key.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_generate_secretkey_cyclic(sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+////////////////////////////////////
+
+///
+/// @brief converting formats of public keys : from cyclic version to classic key
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the cyclic public key.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_cpk_to_pk(pk_t *pk, const cpk_t *cpk);
+
+#endif // _RAINBOW_KEYPAIR_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair_computation.c b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair_computation.c
new file mode 100644
index 00000000..2e577e03
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair_computation.c
@@ -0,0 +1,213 @@
+/// @file rainbow_keypair_computation.c
+/// @brief Implementations for functions in rainbow_keypair_computation.h
+///
+
+#include "rainbow_keypair_computation.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair.h"
+#include
+#include
+#include
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk) {
+ const unsigned char *idx_l1 = cpk->l1_Q1;
+ const unsigned char *idx_l2 = cpk->l2_Q1;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = i; j < _V1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q2;
+ idx_l2 = cpk->l2_Q2;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q3;
+ idx_l2 = cpk->l2_Q3;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q5;
+ idx_l2 = cpk->l2_Q5;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = i; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q6;
+ idx_l2 = cpk->l2_Q6;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q9;
+ idx_l2 = cpk->l2_Q9;
+ for (unsigned int i = _V1 + _O1; i < _PUB_N; i++) {
+ for (unsigned int j = i; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+}
+
+static void calculate_F_from_Q_ref(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ // Layer 1
+ // F_sk.l1_F1s[i] = Q_pk.l1_F1s[i]
+ memcpy(Fs->l1_F1, Qs->l1_F1, _O1_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ // F_sk.l1_F2s[i] = ( Q_pk.l1_F1s[i] + Q_pk.l1_F1s[i].transpose() ) * T_sk.t1 + Q_pk.l1_F2s[i]
+ memcpy(Fs->l1_F2, Qs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_2trimat_madd(Fs->l1_F2, Qs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE);
+
+ /*
+ Layer 2
+ computations:
+
+ F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ Q1_T1 = Q_pk.l2_F1s[i]*T_sk.t1
+ F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+
+ Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ #Q1_Q1T_T4 = Q1_Q1T * t4
+ Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ + Q_pk.l2_F2s[i].transpose() * t4
+ + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+
+ */
+ memcpy(Fs->l2_F1, Qs->l2_F1, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ // F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ // F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+ memcpy(Fs->l2_F2, Qs->l2_F2, _O2_BYTE * _V1 * _O1);
+ batch_trimat_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // Q1_T1+ Q2
+
+ unsigned char tempQ[_O1 * _O1 * _O2_BYTE + 32];
+ memset(tempQ, 0, _O1 * _O1 * _O2_BYTE);
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F2, _O1, _O2_BYTE); // t1_tr*(Q1_T1+Q2)
+ memcpy(Fs->l2_F5, Qs->l2_F5, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // F5
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_UpperTrianglize(Fs->l2_F5, tempQ, _O1, _O2_BYTE); // UT( ... )
+
+ batch_trimatTr_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // F2 = Q1_T1 + Q2 + Q1^tr*t1
+
+ // Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ // Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ // F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ memcpy(Fs->l2_F3, Qs->l2_F3, _V1 * _O2 * _O2_BYTE);
+ batch_2trimat_madd(Fs->l2_F3, Qs->l2_F1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE); // Q1_Q1T_T4
+ batch_mat_madd(Fs->l2_F3, Qs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // Q2_T3
+
+ // F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ // + Q_pk.l2_F2s[i].transpose() * t4
+ // + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+ memcpy(Fs->l2_F6, Qs->l2_F6, _O1 * _O2 * _O2_BYTE);
+ batch_matTr_madd(Fs->l2_F6, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F3, _O2, _O2_BYTE); // t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ batch_2trimat_madd(Fs->l2_F6, Qs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3
+ batch_bmatTr_madd(Fs->l2_F6, Qs->l2_F2, _O1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE);
+}
+
+static void calculate_Q_from_F_cyclic_ref(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ // Layer 1: Computing Q5, Q3, Q6, Q9
+
+ // Q_pk.l1_F5s[i] = UT( T1tr* (F1 * T1 + F2) )
+ const unsigned char *t2 = Ts->t4;
+ sk_t tempQ;
+ memcpy(tempQ.l1_F2, Fs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_trimat_madd(tempQ.l1_F2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // F1*T1 + F2
+ memset(tempQ.l2_F1, 0, sizeof(tempQ.l2_F1));
+ memset(tempQ.l2_F2, 0, sizeof(tempQ.l2_F2));
+ batch_matTr_madd(tempQ.l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, tempQ.l1_F2, _O1, _O1_BYTE); // T1tr*(F1*T1 + F2)
+ memset(Qs->l1_Q5, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O1));
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_UpperTrianglize(Qs->l1_Q5, tempQ.l2_F1, _O1, _O1_BYTE); // UT( ... ) // Q5
+
+ /*
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+ Q_pk.l1_F3s[i] = F1_F1T_T2 + F2_T3
+ Q_pk.l1_F6s[i] = T1tr* ( F1_F1T_T2 + F2_T3 ) + F2tr * t2
+ Q_pk.l1_F9s[i] = UT( T2tr* ( F1_T2 + F2_T3 ) )
+ */
+ memset(Qs->l1_Q3, 0, _O1_BYTE * _V1 * _O2);
+ memset(Qs->l1_Q6, 0, _O1_BYTE * _O1 * _O2);
+ memset(Qs->l1_Q9, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ batch_trimat_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1*T2
+ batch_mat_madd(Qs->l1_Q3, Fs->l1_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O1_BYTE); // F1_T2 + F2_T3
+
+ memset(tempQ.l1_F2, 0, _O1_BYTE * _V1 * _O2); // should be F3. assuming: _O1 >= _O2
+ batch_matTr_madd(tempQ.l1_F2, t2, _V1, _V1_BYTE, _O2, Qs->l1_Q3, _O2, _O1_BYTE); // T2tr * ( F1_T2 + F2_T3 )
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_UpperTrianglize(Qs->l1_Q9, tempQ.l1_F2, _O2, _O1_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1_F1T_T2 + F2_T3 // Q3
+
+ batch_bmatTr_madd(Qs->l1_Q6, Fs->l1_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F2tr*T2
+ batch_matTr_madd(Qs->l1_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q3, _O2, _O1_BYTE); // Q6
+ /*
+ Layer 2
+ Computing Q9:
+
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ Q9 = UT( T2tr*( F1*T2 + F2*T3 + F3 ) + T3tr*( F5*T3 + F6 ) )
+ */
+ sk_t tempQ2;
+ memcpy(tempQ2.l2_F3, Fs->l2_F3, _O2_BYTE * _V1 * _O2); /// F3 actually.
+ batch_trimat_madd(tempQ2.l2_F3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1*T2 + F3
+ batch_mat_madd(tempQ2.l2_F3, Fs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F1_T2 + F2_T3 + F3
+
+ memset(tempQ.l2_F3, 0, _O2_BYTE * _V1 * _O2);
+ batch_matTr_madd(tempQ.l2_F3, t2, _V1, _V1_BYTE, _O2, tempQ2.l2_F3, _O2, _O2_BYTE); // T2tr * ( ..... )
+
+ memcpy(tempQ.l2_F6, Fs->l2_F6, _O2_BYTE * _O1 * _O2);
+ batch_trimat_madd(tempQ.l2_F6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6
+
+ batch_matTr_madd(tempQ.l2_F3, Ts->t3, _O1, _O1_BYTE, _O2, tempQ.l2_F6, _O2, _O2_BYTE); // T2tr*( ..... ) + T3tr*( ..... )
+ memset(Qs->l2_Q9, 0, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_UpperTrianglize(Qs->l2_Q9, tempQ.l2_F3, _O2, _O2_BYTE); // Q9
+}
+
+// Choosing implementations depends on the macros: _BLAS_SSE_ and _BLAS_AVX2_
+#define calculate_F_from_Q_impl calculate_F_from_Q_ref
+#define calculate_Q_from_F_cyclic_impl calculate_Q_from_F_cyclic_ref
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ calculate_F_from_Q_impl(Fs, Qs, Ts);
+}
+
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ calculate_Q_from_F_cyclic_impl(Qs, Fs, Ts);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair_computation.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair_computation.h
new file mode 100644
index 00000000..22bb2c08
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/rainbow_keypair_computation.h
@@ -0,0 +1,71 @@
+#ifndef _RAINBOW_KEYPAIR_COMP_H_
+#define _RAINBOW_KEYPAIR_COMP_H_
+/// @file rainbow_keypair_computation.h
+/// @brief Functions for calculating pk/sk while generating keys.
+///
+/// Defining an internal structure of public key.
+/// Functions for calculating pk/sk for key generation.
+///
+
+#include "rainbow_keypair.h"
+
+/// @brief The (internal use) public key for rainbow
+///
+/// The (internal use) public key for rainbow. The public
+/// polynomials are divided into l1_Q1, l1_Q2, ... l1_Q9,
+/// l2_Q1, .... , l2_Q9.
+///
+typedef struct rainbow_extend_publickey {
+ unsigned char l1_Q1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l1_Q2[_O1_BYTE * _V1 * _O1];
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2];
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2];
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)];
+
+ unsigned char l2_Q1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l2_Q2[_O2_BYTE * _V1 * _O1];
+ unsigned char l2_Q3[_O2_BYTE * _V1 * _O2];
+ unsigned char l2_Q5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l2_Q6[_O2_BYTE * _O1 * _O2];
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)];
+} ext_cpk_t;
+
+///
+/// @brief converting formats of public keys : from ext_cpk_t version to pk_t
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the internel public key.
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk);
+/////////////////////////////////////////////////
+
+///
+/// @brief Computing public key from secret key
+///
+/// @param[out] Qs - the public key
+/// @param[in] Fs - parts of the secret key: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the secret key: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+
+///
+/// @brief Computing parts of the sk from parts of pk and sk
+///
+/// @param[out] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Qs - parts of the pk: l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts);
+
+///
+/// @brief Computing parts of the pk from the secret key
+///
+/// @param[out] Qs - parts of the pk: l1_Q3, l1_Q5, l2_Q6, l1_Q9, l2_Q9
+/// @param[in] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+#endif // _RAINBOW_KEYPAIR_COMP_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/sign.c b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/sign.c
new file mode 100644
index 00000000..1dcc20d2
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/sign.c
@@ -0,0 +1,76 @@
+/// @file sign.c
+/// @brief the implementations for functions in api.h
+///
+///
+
+#include "api.h"
+#include "rainbow.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
+ unsigned char sk_seed[LEN_SKSEED] = {0};
+ randombytes(sk_seed, LEN_SKSEED);
+
+ unsigned char pk_seed[LEN_PKSEED] = {0};
+ randombytes(pk_seed, LEN_PKSEED);
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_generate_compact_keypair_cyclic((cpk_t *)pk, (csk_t *)sk, pk_seed, sk_seed);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_crypto_sign(unsigned char *sm, size_t *smlen, const unsigned char *m, size_t mlen, const unsigned char *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+
+ memcpy(sm, m, mlen);
+ smlen[0] = mlen + _SIGNATURE_BYTE;
+
+ return PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(sm + mlen, (const csk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_crypto_sign_open(unsigned char *m, size_t *mlen, const unsigned char *sm, size_t smlen, const unsigned char *pk) {
+ int rc;
+ if (_SIGNATURE_BYTE > smlen) {
+ rc = -1;
+ } else {
+ *mlen = smlen - _SIGNATURE_BYTE;
+
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, sm, *mlen);
+
+ rc = PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(digest, sm + mlen[0], (const cpk_t *)pk);
+ }
+ if (!rc) {
+ memcpy(m, sm, smlen - _SIGNATURE_BYTE);
+ } else { // bad signature
+ *mlen = (size_t) -1;
+ memset(m, 0, smlen);
+ }
+ return rc;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ *siglen = _SIGNATURE_BYTE;
+ return PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(sig, (const csk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ if (siglen != _SIGNATURE_BYTE) {
+ return -1;
+ }
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ return PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(digest, sig, (const cpk_t *)pk);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_hash.c b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_hash.c
new file mode 100644
index 00000000..77cbed93
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_hash.c
@@ -0,0 +1,50 @@
+/// @file utils_hash.c
+/// @brief the adapter for SHA2 families.
+///
+///
+
+#include "utils_hash.h"
+#include "rainbow_config.h"
+#include "sha2.h"
+
+static inline int _hash(unsigned char *digest, const unsigned char *m, size_t mlen) {
+ sha384(digest, m, mlen);
+ return 0;
+}
+
+static inline int expand_hash(unsigned char *digest, size_t n_digest, const unsigned char *hash) {
+ if (_HASH_LEN >= n_digest) {
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[i] = hash[i];
+ }
+ return 0;
+ }
+ for (size_t i = 0; i < _HASH_LEN; i++) {
+ digest[i] = hash[i];
+ }
+ n_digest -= _HASH_LEN;
+
+ while (_HASH_LEN <= n_digest) {
+ _hash(digest + _HASH_LEN, digest, _HASH_LEN);
+
+ n_digest -= _HASH_LEN;
+ digest += _HASH_LEN;
+ }
+ unsigned char temp[_HASH_LEN];
+ if (n_digest) {
+ _hash(temp, digest, _HASH_LEN);
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[_HASH_LEN + i] = temp[i];
+ }
+ }
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_hash_msg(unsigned char *digest,
+ size_t len_digest,
+ const unsigned char *m,
+ size_t mlen) {
+ unsigned char buf[_HASH_LEN];
+ _hash(buf, m, mlen);
+ return expand_hash(digest, len_digest, buf);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_hash.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_hash.h
new file mode 100644
index 00000000..0f034bfc
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_hash.h
@@ -0,0 +1,11 @@
+#ifndef _UTILS_HASH_H_
+#define _UTILS_HASH_H_
+/// @file utils_hash.h
+/// @brief the interface for adapting hash functions.
+///
+
+#include
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_hash_msg(unsigned char *digest, size_t len_digest, const unsigned char *m, size_t mlen);
+
+#endif // _UTILS_HASH_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_prng.c b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_prng.c
new file mode 100644
index 00000000..40b489f0
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_prng.c
@@ -0,0 +1,95 @@
+/// @file utils_prng.c
+/// @brief The implementation of PRNG related functions.
+///
+
+#include "utils_prng.h"
+#include "aes.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+static void prng_update(const unsigned char *provided_data,
+ unsigned char *Key,
+ unsigned char *V) {
+ unsigned char temp[48];
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, Key);
+ for (int i = 0; i < 3; i++) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (V[j] == 0xff) {
+ V[j] = 0x00;
+ } else {
+ V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(temp + 16 * i, V, 1, &ctx);
+ }
+ if (provided_data != NULL) {
+ for (int i = 0; i < 48; i++) {
+ temp[i] ^= provided_data[i];
+ }
+ }
+ memcpy(Key, temp, 32);
+ memcpy(V, temp + 32, 16);
+}
+static void randombytes_init_with_state(prng_t *state,
+ unsigned char *entropy_input_48bytes) {
+ memset(state->Key, 0x00, 32);
+ memset(state->V, 0x00, 16);
+ prng_update(entropy_input_48bytes, state->Key, state->V);
+}
+
+static int randombytes_with_state(prng_t *state,
+ unsigned char *x,
+ size_t xlen) {
+
+ unsigned char block[16];
+ int i = 0;
+
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, state->Key);
+
+ while (xlen > 0) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (state->V[j] == 0xff) {
+ state->V[j] = 0x00;
+ } else {
+ state->V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(block, state->V, 1, &ctx);
+ if (xlen > 15) {
+ memcpy(x + i, block, 16);
+ i += 16;
+ xlen -= 16;
+ } else {
+ memcpy(x + i, block, xlen);
+ xlen = 0;
+ }
+ }
+ prng_update(NULL, state->Key, state->V);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen) {
+ unsigned char seed[48];
+ if (prng_seedlen >= 48) {
+ memcpy(seed, prng_seed, 48);
+ } else {
+ memcpy(seed, prng_seed, prng_seedlen);
+ PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_hash_msg(seed + prng_seedlen, 48 - (unsigned)prng_seedlen, (const unsigned char *)prng_seed, prng_seedlen);
+ }
+
+ randombytes_init_with_state(ctx, seed);
+
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen) {
+ return randombytes_with_state(ctx, out, outlen);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_prng.h b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_prng.h
new file mode 100644
index 00000000..9e47af8a
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic-compressed/clean/utils_prng.h
@@ -0,0 +1,18 @@
+#ifndef _UTILS_PRNG_H_
+#define _UTILS_PRNG_H_
+/// @file utils_prng.h
+/// @brief the interface for adapting PRNG functions.
+///
+///
+
+#include "randombytes.h"
+
+typedef struct {
+ unsigned char Key[32];
+ unsigned char V[16];
+} prng_t;
+
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen);
+int PQCLEAN_RAINBOWIIICCYCLICCOMPRESSED_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen);
+
+#endif // _UTILS_PRNG_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/META.yml b/crypto_sign/rainbowIIIc-cyclic/META.yml
new file mode 100644
index 00000000..5956088f
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/META.yml
@@ -0,0 +1,18 @@
+name: Rainbow-IIIc-cyclic
+type: signature
+claimed-nist-level: 3
+length-public-key: 206744
+length-secret-key: 511448
+length-signature: 156
+nistkat-sha256: 607fa94312778210c443431974087ce99357494ab16c8ad5a8418784b811223d
+testvectors-sha256: 51559c38aefe636abd36094741be3b5f65de9e09cf9a5d37866b2e8d0eb58d22
+principal-submitters:
+ - Jintai Ding
+auxiliary-submitters:
+ - Ming-Shing Chen
+ - Albrecht Petzoldt
+ - Dieter Schmidt
+ - Bo-Yin Yang
+implementations:
+ - name: clean
+ version: https://github.com/fast-crypto-lab/rainbow-submission-round2/commit/af826fcb78f6af51a02d0352cff28a9690467bfd
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/LICENSE b/crypto_sign/rainbowIIIc-cyclic/clean/LICENSE
new file mode 100644
index 00000000..cb00a6e3
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/LICENSE
@@ -0,0 +1,8 @@
+`Software implementation of Rainbow for NIST R2 submission' by Ming-Shing Chen
+
+To the extent possible under law, the person who associated CC0 with
+`Software implementation of Rainbow for NIST R2 submission' has waived all copyright and related or neighboring rights
+to `Software implementation of Rainbow for NIST R2 submission'.
+
+You should have received a copy of the CC0 legalcode along with this
+work. If not, see .
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/Makefile b/crypto_sign/rainbowIIIc-cyclic/clean/Makefile
new file mode 100644
index 00000000..d6161c21
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=librainbowIIIc-cyclic_clean.a
+
+HEADERS = api.h blas_comm.h blas.h blas_u32.h gf.h parallel_matrix_op.h rainbow_blas.h rainbow_config.h rainbow.h rainbow_keypair_computation.h rainbow_keypair.h utils_hash.h utils_prng.h
+OBJECTS = blas_comm.o parallel_matrix_op.o rainbow.o rainbow_keypair.o rainbow_keypair_computation.o sign.o utils_hash.o utils_prng.o blas_u32.o gf.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/Makefile.Microsoft_nmake b/crypto_sign/rainbowIIIc-cyclic/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..c2fc2f6f
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=librainbowIIIc-cyclic_clean.lib
+OBJECTS = blas_comm.obj parallel_matrix_op.obj rainbow.obj rainbow_keypair.obj rainbow_keypair_computation.obj sign.obj utils_hash.obj utils_prng.obj blas_u32.obj gf.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/api.h b/crypto_sign/rainbowIIIc-cyclic/clean/api.h
new file mode 100644
index 00000000..cf8628c2
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/api.h
@@ -0,0 +1,32 @@
+#ifndef PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_API_H
+#define PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_CRYPTO_SECRETKEYBYTES 511448
+#define PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_CRYPTO_PUBLICKEYBYTES 206744
+#define PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_CRYPTO_BYTES 156
+#define PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_CRYPTO_ALGNAME "RAINBOW(256,68,36,36) - cyclic"
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
+
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen,
+ const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen,
+ const uint8_t *pk);
+
+
+#endif
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/blas.h b/crypto_sign/rainbowIIIc-cyclic/clean/blas.h
new file mode 100644
index 00000000..5b3d374e
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/blas.h
@@ -0,0 +1,19 @@
+#ifndef _BLAS_H_
+#define _BLAS_H_
+/// @file blas.h
+/// @brief Defining the implementations for linear algebra functions depending on the machine architecture.
+///
+
+#include "blas_comm.h"
+#include "blas_u32.h"
+#include "rainbow_config.h"
+
+#define gf256v_predicated_add PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_predicated_add_u32
+#define gf256v_add PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_add_u32
+
+
+#define gf256v_mul_scalar PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_mul_scalar_u32
+#define gf256v_madd PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_madd_u32
+
+
+#endif // _BLAS_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/blas_comm.c b/crypto_sign/rainbowIIIc-cyclic/clean/blas_comm.c
new file mode 100644
index 00000000..d5363105
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/blas_comm.c
@@ -0,0 +1,142 @@
+/// @file blas_comm.c
+/// @brief The standard implementations for blas_comm.h
+///
+
+#include "blas_comm.h"
+#include "blas.h"
+#include "gf.h"
+#include "rainbow_config.h"
+
+#include
+#include
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte) {
+ gf256v_add(b, b, _num_byte);
+}
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i) {
+ return a[i];
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte) {
+ uint8_t r = 0;
+ while (_num_byte--) {
+ r |= a[0];
+ a++;
+ }
+ return (0 == r);
+}
+
+/// polynomial multplication
+/// School boook
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num) {
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(c, _num * 2 - 1);
+ for (unsigned int i = 0; i < _num; i++) {
+ gf256v_madd(c + i, a, b[i], _num);
+ }
+}
+
+static void gf256mat_prod_ref(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(c, n_A_vec_byte);
+ for (unsigned int i = 0; i < n_A_width; i++) {
+ gf256v_madd(c, matA, b[i], n_A_vec_byte);
+ matA += n_A_vec_byte;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec) {
+ unsigned int n_vec_byte = len_vec;
+ for (unsigned int k = 0; k < len_vec; k++) {
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(c, n_vec_byte);
+ const uint8_t *bk = b + n_vec_byte * k;
+ for (unsigned int i = 0; i < len_vec; i++) {
+ gf256v_madd(c, a + n_vec_byte * i, bk[i], n_vec_byte);
+ }
+ c += n_vec_byte;
+ }
+}
+
+static unsigned int gf256mat_gauss_elim_ref(uint8_t *mat, unsigned int h, unsigned int w) {
+ unsigned int r8 = 1;
+
+ for (unsigned int i = 0; i < h; i++) {
+ uint8_t *ai = mat + w * i;
+ unsigned int skip_len_align4 = i & ((unsigned int)~0x3);
+
+ for (unsigned int j = i + 1; j < h; j++) {
+ uint8_t *aj = mat + w * j;
+ gf256v_predicated_add(ai + skip_len_align4, !PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256_is_nonzero(ai[i]), aj + skip_len_align4, w - skip_len_align4);
+ }
+ r8 &= PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256_is_nonzero(ai[i]);
+ uint8_t pivot = ai[i];
+ pivot = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256_inv(pivot);
+ gf256v_mul_scalar(ai + skip_len_align4, pivot, w - skip_len_align4);
+ for (unsigned int j = 0; j < h; j++) {
+ if (i == j) {
+ continue;
+ }
+ uint8_t *aj = mat + w * j;
+ gf256v_madd(aj + skip_len_align4, ai + skip_len_align4, aj[i], w - skip_len_align4);
+ }
+ }
+
+ return r8;
+}
+
+static unsigned int gf256mat_solve_linear_eq_ref(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ uint8_t mat[64 * 64];
+ for (unsigned int i = 0; i < n; i++) {
+ memcpy(mat + i * (n + 1), inp_mat + i * n, n);
+ mat[i * (n + 1) + n] = c_terms[i];
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_gauss_elim(mat, n, n + 1);
+ for (unsigned int i = 0; i < n; i++) {
+ sol[i] = mat[i * (n + 1) + n];
+ }
+ return r8;
+}
+
+static inline void gf256mat_submat(uint8_t *mat2, unsigned int w2, unsigned int st, const uint8_t *mat, unsigned int w, unsigned int h) {
+ for (unsigned int i = 0; i < h; i++) {
+ for (unsigned int j = 0; j < w2; j++) {
+ mat2[i * w2 + j] = mat[i * w + st + j];
+ }
+ }
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer) {
+ uint8_t *aa = buffer;
+ for (unsigned int i = 0; i < H; i++) {
+ uint8_t *ai = aa + i * 2 * H;
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(ai, 2 * H);
+ gf256v_add(ai, a + i * H, H);
+ ai[H + i] = 1;
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_gauss_elim(aa, H, 2 * H);
+ gf256mat_submat(inv_a, H, H, aa, 2 * H, H);
+ return r8;
+}
+
+
+// choosing the implementations depends on the macros _BLAS_AVX2_ and _BLAS_SSE
+
+#define gf256mat_prod_impl gf256mat_prod_ref
+#define gf256mat_gauss_elim_impl gf256mat_gauss_elim_ref
+#define gf256mat_solve_linear_eq_impl gf256mat_solve_linear_eq_ref
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ gf256mat_prod_impl(c, matA, n_A_vec_byte, n_A_width, b);
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w) {
+ return gf256mat_gauss_elim_impl(mat, h, w);
+}
+
+unsigned int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ return gf256mat_solve_linear_eq_impl(sol, inp_mat, c_terms, n);
+}
+
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/blas_comm.h b/crypto_sign/rainbowIIIc-cyclic/clean/blas_comm.h
new file mode 100644
index 00000000..96ac02d7
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/blas_comm.h
@@ -0,0 +1,90 @@
+#ifndef _BLAS_COMM_H_
+#define _BLAS_COMM_H_
+/// @file blas_comm.h
+/// @brief Common functions for linear algebra.
+///
+
+#include "rainbow_config.h"
+#include
+
+/// @brief set a vector to 0.
+///
+/// @param[in,out] b - the vector b.
+/// @param[in] _num_byte - number of bytes for the vector b.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte);
+
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i);
+
+/// @brief check if a vector is 0.
+///
+/// @param[in] a - the vector a.
+/// @param[in] _num_byte - number of bytes for the vector a.
+/// @return 1(true) if a is 0. 0(false) else.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte);
+
+/// @brief polynomial multiplication: c = a*b
+///
+/// @param[out] c - the output polynomial c
+/// @param[in] a - the vector a.
+/// @param[in] b - the vector b.
+/// @param[in] _num - number of elements for the polynomials a and b.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num);
+
+/// @brief matrix-vector multiplication: c = matA * b , in GF(256)
+///
+/// @param[out] c - the output vector c
+/// @param[in] matA - a column-major matrix A.
+/// @param[in] n_A_vec_byte - the size of column vectors in bytes.
+/// @param[in] n_A_width - the width of matrix A.
+/// @param[in] b - the vector b.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b);
+
+/// @brief matrix-matrix multiplication: c = a * b , in GF(256)
+///
+/// @param[out] c - the output matrix c
+/// @param[in] c - a matrix a.
+/// @param[in] b - a matrix b.
+/// @param[in] len_vec - the length of column vectors.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec);
+
+/// @brief Gauss elimination for a matrix, in GF(256)
+///
+/// @param[in,out] mat - the matrix.
+/// @param[in] h - the height of the matrix.
+/// @param[in] w - the width of the matrix.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w);
+
+/// @brief Solving linear equations, in GF(256)
+///
+/// @param[out] sol - the solutions.
+/// @param[in] inp_mat - the matrix parts of input equations.
+/// @param[in] c_terms - the constant terms of the input equations.
+/// @param[in] n - the number of equations.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n);
+
+/// @brief Computing the inverse matrix, in GF(256)
+///
+/// @param[out] inv_a - the output of matrix a.
+/// @param[in] a - a matrix a.
+/// @param[in] H - height of matrix a, i.e., matrix a is an HxH matrix.
+/// @param[in] buffer - The buffer for computations. it has to be as large as 2 input matrixes.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer);
+
+#endif // _BLAS_COMM_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/blas_u32.c b/crypto_sign/rainbowIIIc-cyclic/clean/blas_u32.c
new file mode 100644
index 00000000..b8965553
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/blas_u32.c
@@ -0,0 +1,87 @@
+#include "blas_u32.h"
+#include "gf.h"
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte) {
+ uint32_t pr_u32 = ((uint32_t)0) - ((uint32_t)predicate);
+ uint8_t pr_u8 = pr_u32 & 0xff;
+
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= (a_u32[i] & pr_u32);
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= (a[i] & pr_u8);
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= a_u32[i];
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= a[i];
+ }
+}
+
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *a_u32 = (uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ a_u32[i] = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_mul_u32(a_u32[i], b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_mul_u32(t.u32, b);
+ for (unsigned int i = 0; i < rem; i++) {
+ a[i] = t.u8[i];
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *c_u32 = (uint32_t *)accu_c;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ c_u32[i] ^= PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_mul_u32(a_u32[i], gf256_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ accu_c += (n_u32 << 2);
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_mul_u32(t.u32, gf256_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_c[i] ^= t.u8[i];
+ }
+}
+
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/blas_u32.h b/crypto_sign/rainbowIIIc-cyclic/clean/blas_u32.h
new file mode 100644
index 00000000..9779dd9c
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/blas_u32.h
@@ -0,0 +1,18 @@
+#ifndef _BLAS_U32_H_
+#define _BLAS_U32_H_
+/// @file blas_u32.h
+/// @brief Inlined functions for implementing basic linear algebra functions for uint32 arch.
+///
+
+#include "rainbow_config.h"
+#include
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte);
+
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte);
+
+
+#endif // _BLAS_U32_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/gf.c b/crypto_sign/rainbowIIIc-cyclic/clean/gf.c
new file mode 100644
index 00000000..c5cece1d
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/gf.c
@@ -0,0 +1,134 @@
+#include "gf.h"
+
+//// gf4 := gf2[x]/x^2+x+1
+static inline uint8_t gf4_mul_2(uint8_t a) {
+ uint8_t r = (uint8_t)(a << 1);
+ r ^= (uint8_t)((a >> 1) * 7);
+ return r;
+}
+
+static inline uint8_t gf4_mul(uint8_t a, uint8_t b) {
+ uint8_t r = (uint8_t)(a * (b & 1));
+ return r ^ (uint8_t)(gf4_mul_2(a) * (b >> 1));
+}
+
+static inline uint8_t gf4_squ(uint8_t a) {
+ return a ^ (a >> 1);
+}
+
+static inline uint32_t gf4v_mul_2_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit1 ^ (bit1 >> 1);
+}
+
+static inline uint32_t gf4v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t bit0_b = ((uint32_t)0) - ((uint32_t)(b & 1));
+ uint32_t bit1_b = ((uint32_t)0) - ((uint32_t)((b >> 1) & 1));
+ return (a & bit0_b) ^ (bit1_b & gf4v_mul_2_u32(a));
+}
+
+//// gf16 := gf4[y]/y^2+y+x
+static inline uint8_t gf16_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ uint8_t b0 = b & 3;
+ uint8_t b1 = (b >> 2);
+ uint8_t a0b0 = gf4_mul(a0, b0);
+ uint8_t a1b1 = gf4_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf4_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x2 = gf4_mul_2(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 2 ^ a0b0 ^ a1b1_x2);
+}
+
+static inline uint8_t gf16_squ(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ a1 = gf4_squ(a1);
+ uint8_t a1squ_x2 = gf4_mul_2(a1);
+ return (uint8_t)((a1 << 2) ^ a1squ_x2 ^ gf4_squ(a0));
+}
+
+// gf16 := gf4[y]/y^2+y+x
+uint32_t PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = gf4v_mul_u32(a, b);
+ uint32_t axb1 = gf4v_mul_u32(a, b >> 2);
+ uint32_t a0b1 = (axb1 << 2) & 0xcccccccc;
+ uint32_t a1b1 = axb1 & 0xcccccccc;
+ uint32_t a1b1_2 = a1b1 >> 2;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf4v_mul_2_u32(a1b1_2);
+}
+
+uint8_t PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256_is_nonzero(uint8_t a) {
+ unsigned int a8 = a;
+ unsigned int r = ((unsigned int)0) - a8;
+ r >>= 8;
+ return r & 1;
+}
+
+static inline uint8_t gf4_mul_3(uint8_t a) {
+ uint8_t msk = (uint8_t)((a - 2) >> 1);
+ return (uint8_t)((msk & ((int)a * 3)) | ((~msk) & ((int)a - 1)));
+}
+static inline uint8_t gf16_mul_8(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = a >> 2;
+ return (uint8_t)((gf4_mul_2(a0 ^ a1) << 2) | gf4_mul_3(a1));
+}
+
+// gf256 := gf16[X]/X^2+X+xy
+static inline uint8_t gf256_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ uint8_t b0 = b & 15;
+ uint8_t b1 = (b >> 4);
+ uint8_t a0b0 = gf16_mul(a0, b0);
+ uint8_t a1b1 = gf16_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf16_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x8 = gf16_mul_8(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 4 ^ a0b0 ^ a1b1_x8);
+}
+
+static inline uint8_t gf256_squ(uint8_t a) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ a1 = gf16_squ(a1);
+ uint8_t a1squ_x8 = gf16_mul_8(a1);
+ return (uint8_t)((a1 << 4) ^ a1squ_x8 ^ gf16_squ(a0));
+}
+
+uint8_t PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256_inv(uint8_t a) {
+ // 128+64+32+16+8+4+2 = 254
+ uint8_t a2 = gf256_squ(a);
+ uint8_t a4 = gf256_squ(a2);
+ uint8_t a8 = gf256_squ(a4);
+ uint8_t a4_2 = gf256_mul(a4, a2);
+ uint8_t a8_4_2 = gf256_mul(a4_2, a8);
+ uint8_t a64_ = gf256_squ(a8_4_2);
+ a64_ = gf256_squ(a64_);
+ a64_ = gf256_squ(a64_);
+ uint8_t a64_2 = gf256_mul(a64_, a8_4_2);
+ uint8_t a128_ = gf256_squ(a64_2);
+ return gf256_mul(a2, a128_);
+}
+
+static inline uint32_t gf4v_mul_3_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit0 ^ (bit1 >> 1);
+}
+static inline uint32_t gf16v_mul_8_u32(uint32_t a) {
+ uint32_t a1 = a & 0xcccccccc;
+ uint32_t a0 = (a << 2) & 0xcccccccc;
+ return gf4v_mul_2_u32(a0 ^ a1) | gf4v_mul_3_u32(a1 >> 2);
+}
+uint32_t PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf16v_mul_u32(a, b);
+ uint32_t axb1 = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf16v_mul_u32(a, b >> 4);
+ uint32_t a0b1 = (axb1 << 4) & 0xf0f0f0f0;
+ uint32_t a1b1 = axb1 & 0xf0f0f0f0;
+ uint32_t a1b1_4 = a1b1 >> 4;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf16v_mul_8_u32(a1b1_4);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/gf.h b/crypto_sign/rainbowIIIc-cyclic/clean/gf.h
new file mode 100644
index 00000000..a57b6fa7
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/gf.h
@@ -0,0 +1,19 @@
+#ifndef _GF16_H_
+#define _GF16_H_
+
+#include "rainbow_config.h"
+#include
+
+/// @file gf16.h
+/// @brief Library for arithmetics in GF(16) and GF(256)
+///
+
+uint32_t PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b);
+
+
+uint8_t PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256_is_nonzero(uint8_t a);
+uint8_t PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256_inv(uint8_t a);
+uint32_t PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b);
+
+
+#endif // _GF16_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/parallel_matrix_op.c b/crypto_sign/rainbowIIIc-cyclic/clean/parallel_matrix_op.c
new file mode 100644
index 00000000..7cb5244e
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/parallel_matrix_op.c
@@ -0,0 +1,183 @@
+/// @file parallel_matrix_op.c
+/// @brief the standard implementations for functions in parallel_matrix_op.h
+///
+/// the standard implementations for functions in parallel_matrix_op.h
+///
+
+#include "parallel_matrix_op.h"
+#include "blas.h"
+#include "blas_comm.h"
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim) {
+ return (dim + dim - i_row + 1) * i_row / 2 + j_col - i_row;
+}
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle or lower-triangle matrix.
+///
+/// @param[in] i_row - the i-th row in a triangle matrix.
+/// @param[in] j_col - the j-th column in a triangle matrix.
+/// @param[in] dim - the dimension of the triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+static inline unsigned int idx_of_2trimat(unsigned int i_row, unsigned int j_col, unsigned int n_var) {
+ if (i_row > j_col) {
+ return PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(j_col, i_row, n_var);
+ }
+ return PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(i_row, j_col, n_var);
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch) {
+ unsigned char *runningC = btriC;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < i; j++) {
+ unsigned int idx = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(j, i, Aheight);
+ gf256v_add(btriC + idx * size_batch, bA + size_batch * (i * Awidth + j), size_batch);
+ }
+ gf256v_add(runningC, bA + size_batch * (i * Awidth + i), size_batch * (Aheight - i));
+ runningC += size_batch * (Aheight - i);
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (k < i) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[(k - i) * size_batch], PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ btriA += (Aheight - i) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i < k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(k, i, Aheight))], PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i == k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (idx_of_2trimat(i, k, Aheight))], PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_matTr_madd_gf256(unsigned char *bC, const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Atr_height = Awidth;
+ unsigned int Atr_width = Aheight;
+ for (unsigned int i = 0; i < Atr_height; i++) {
+ for (unsigned int j = 0; j < Atr_width; j++) {
+ gf256v_madd(bC, &bB[j * Bwidth * size_batch], PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(&A_to_tr[size_Acolvec * i], j), size_batch * Bwidth);
+ }
+ bC += size_batch * Bwidth;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ const unsigned char *bA = bA_to_tr;
+ unsigned int Aheight = Awidth_before_tr;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[size_batch * (i + k * Aheight)], PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[k * size_batch], PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ bA += (Awidth) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch) {
+ unsigned char tmp[256];
+
+ unsigned char _x[256];
+ for (unsigned int i = 0; i < dim; i++) {
+ _x[i] = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(x, i);
+ }
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(y, size_batch);
+ for (unsigned int i = 0; i < dim; i++) {
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = i; j < dim; j++) {
+ gf256v_madd(tmp, trimat, _x[j], size_batch);
+ trimat += size_batch;
+ }
+ gf256v_madd(y, tmp, _x[i], size_batch);
+ }
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y, const unsigned char *mat,
+ const unsigned char *x, unsigned dim_x, unsigned size_batch) {
+ unsigned char tmp[128];
+
+ unsigned char _x[128];
+ for (unsigned int i = 0; i < dim_x; i++) {
+ _x[i] = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(x, i);
+ }
+ unsigned char _y[128];
+ for (unsigned int i = 0; i < dim_y; i++) {
+ _y[i] = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele(y, i);
+ }
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(z, size_batch);
+ for (unsigned int i = 0; i < dim_y; i++) {
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = 0; j < dim_x; j++) {
+ gf256v_madd(tmp, mat, _x[j], size_batch);
+ mat += size_batch;
+ }
+ gf256v_madd(z, tmp, _y[i], size_batch);
+ }
+}
+
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/parallel_matrix_op.h b/crypto_sign/rainbowIIIc-cyclic/clean/parallel_matrix_op.h
new file mode 100644
index 00000000..62dd1404
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/parallel_matrix_op.h
@@ -0,0 +1,260 @@
+#ifndef _P_MATRIX_OP_H_
+#define _P_MATRIX_OP_H_
+/// @file parallel_matrix_op.h
+/// @brief Librarys for operations of batched matrixes.
+///
+///
+
+//////////////// Section: triangle matrix <-> rectangle matrix ///////////////////////////////////
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim);
+
+///
+/// @brief Upper trianglize a rectangle matrix to the corresponding upper-trangle matrix.
+///
+/// @param[out] btriC - the batched upper-trianglized matrix C.
+/// @param[in] bA - a batched retangle matrix A.
+/// @param[in] bwidth - the width of the batched matrix A, i.e., A is a Awidth x Awidth matrix.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch);
+
+//////////////////// Section: matrix multiplications ///////////////////////////////
+
+///
+/// @brief bC += btriA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. A will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A, which will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_matTr_madd_gf16(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_matTr_madd_gf256(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+//////////////////// Section: "quadratric" matrix evaluation ///////////////////////////////
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(16)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(256)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(16)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(256)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+#endif // _P_MATRIX_OP_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/rainbow.c b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow.c
new file mode 100644
index 00000000..3379c7fe
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow.c
@@ -0,0 +1,174 @@
+/// @file rainbow.c
+/// @brief The standard implementations for functions in rainbow.h
+///
+
+#include "rainbow.h"
+#include "blas.h"
+#include "rainbow_blas.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "utils_hash.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+#define MAX_ATTEMPT_FRMAT 128
+#define _MAX_O ((_O1 > _O2) ? _O1 : _O2)
+#define _MAX_O_BYTE ((_O1_BYTE > _O2_BYTE) ? _O1_BYTE : _O2_BYTE)
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *_digest) {
+ uint8_t mat_l1[_O1 * _O1_BYTE];
+ uint8_t mat_l2[_O2 * _O2_BYTE];
+ uint8_t mat_buffer[2 * _MAX_O * _MAX_O_BYTE];
+
+ // setup PRNG
+ prng_t prng_sign;
+ uint8_t prng_preseed[LEN_SKSEED + _HASH_LEN];
+ memcpy(prng_preseed, sk->sk_seed, LEN_SKSEED);
+ memcpy(prng_preseed + LEN_SKSEED, _digest, _HASH_LEN); // prng_preseed = sk_seed || digest
+ uint8_t prng_seed[_HASH_LEN];
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_hash_msg(prng_seed, _HASH_LEN, prng_preseed, _HASH_LEN + LEN_SKSEED);
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_set(&prng_sign, prng_seed, _HASH_LEN); // seed = H( sk_seed || digest )
+ for (unsigned int i = 0; i < LEN_SKSEED + _HASH_LEN; i++) {
+ prng_preseed[i] ^= prng_preseed[i]; // clean
+ }
+ for (unsigned int i = 0; i < _HASH_LEN; i++) {
+ prng_seed[i] ^= prng_seed[i]; // clean
+ }
+
+ // roll vinegars.
+ uint8_t vinegar[_V1_BYTE];
+ unsigned int n_attempt = 0;
+ unsigned int l1_succ = 0;
+ while (!l1_succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(&prng_sign, vinegar, _V1_BYTE); // generating vinegars
+ gfmat_prod(mat_l1, sk->l1_F2, _O1 * _O1_BYTE, _V1, vinegar); // generating the linear equations for layer 1
+ l1_succ = gfmat_inv(mat_l1, mat_l1, _O1, mat_buffer); // check if the linear equation solvable
+ n_attempt++;
+ }
+
+ // Given the vinegars, pre-compute variables needed for layer 2
+ uint8_t r_l1_F1[_O1_BYTE] = {0};
+ uint8_t r_l2_F1[_O2_BYTE] = {0};
+ batch_quad_trimat_eval(r_l1_F1, sk->l1_F1, vinegar, _V1, _O1_BYTE);
+ batch_quad_trimat_eval(r_l2_F1, sk->l2_F1, vinegar, _V1, _O2_BYTE);
+ uint8_t mat_l2_F3[_O2 * _O2_BYTE];
+ uint8_t mat_l2_F2[_O1 * _O2_BYTE];
+ gfmat_prod(mat_l2_F3, sk->l2_F3, _O2 * _O2_BYTE, _V1, vinegar);
+ gfmat_prod(mat_l2_F2, sk->l2_F2, _O1 * _O2_BYTE, _V1, vinegar);
+
+ // Some local variables.
+ uint8_t _z[_PUB_M_BYTE];
+ uint8_t y[_PUB_M_BYTE];
+ uint8_t *x_v1 = vinegar;
+ uint8_t x_o1[_O1_BYTE];
+ uint8_t x_o2[_O1_BYTE];
+
+ uint8_t digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, _digest, _HASH_LEN);
+ uint8_t *salt = digest_salt + _HASH_LEN;
+
+ uint8_t temp_o[_MAX_O_BYTE + 32] = {0};
+ unsigned int succ = 0;
+ while (!succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ // The computation: H(digest||salt) --> z --S--> y --C-map--> x --T--> w
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(&prng_sign, salt, _SALT_BYTE); // roll the salt
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_hash_msg(_z, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H(digest||salt)
+
+ // y = S^-1 * z
+ memcpy(y, _z, _PUB_M_BYTE); // identity part of S
+ gfmat_prod(temp_o, sk->s1, _O1_BYTE, _O2, _z + _O1_BYTE);
+ gf256v_add(y, temp_o, _O1_BYTE);
+
+ // Central Map:
+ // layer 1: calculate x_o1
+ memcpy(temp_o, r_l1_F1, _O1_BYTE);
+ gf256v_add(temp_o, y, _O1_BYTE);
+ gfmat_prod(x_o1, mat_l1, _O1_BYTE, _O1, temp_o);
+
+ // layer 2: calculate x_o2
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_set_zero(temp_o, _O2_BYTE);
+ gfmat_prod(temp_o, mat_l2_F2, _O2_BYTE, _O1, x_o1); // F2
+ batch_quad_trimat_eval(mat_l2, sk->l2_F5, x_o1, _O1, _O2_BYTE); // F5
+ gf256v_add(temp_o, mat_l2, _O2_BYTE);
+ gf256v_add(temp_o, r_l2_F1, _O2_BYTE); // F1
+ gf256v_add(temp_o, y + _O1_BYTE, _O2_BYTE);
+
+ // generate the linear equations of the 2nd layer
+ gfmat_prod(mat_l2, sk->l2_F6, _O2 * _O2_BYTE, _O1, x_o1); // F6
+ gf256v_add(mat_l2, mat_l2_F3, _O2 * _O2_BYTE); // F3
+ succ = gfmat_inv(mat_l2, mat_l2, _O2, mat_buffer);
+ gfmat_prod(x_o2, mat_l2, _O2_BYTE, _O2, temp_o); // solve l2 eqs
+
+ n_attempt++;
+ };
+ // w = T^-1 * y
+ uint8_t w[_PUB_N_BYTE];
+ // identity part of T.
+ memcpy(w, x_v1, _V1_BYTE);
+ memcpy(w + _V1_BYTE, x_o1, _O1_BYTE);
+ memcpy(w + _V2_BYTE, x_o2, _O2_BYTE);
+ // Computing the t1 part.
+ gfmat_prod(y, sk->t1, _V1_BYTE, _O1, x_o1);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t4 part.
+ gfmat_prod(y, sk->t4, _V1_BYTE, _O2, x_o2);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t3 part.
+ gfmat_prod(y, sk->t3, _O1_BYTE, _O2, x_o2);
+ gf256v_add(w + _V1_BYTE, y, _O1_BYTE);
+
+ memset(signature, 0, _SIGNATURE_BYTE); // set the output 0
+ // clean
+ memset(&prng_sign, 0, sizeof(prng_t));
+ memset(vinegar, 0, _V1_BYTE);
+ memset(r_l1_F1, 0, _O1_BYTE);
+ memset(r_l2_F1, 0, _O2_BYTE);
+ memset(_z, 0, _PUB_M_BYTE);
+ memset(y, 0, _PUB_M_BYTE);
+ memset(x_o1, 0, _O1_BYTE);
+ memset(x_o2, 0, _O2_BYTE);
+ memset(temp_o, 0, sizeof(temp_o));
+
+ // return: copy w and salt to the signature.
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ return -1;
+ }
+ gf256v_add(signature, w, _PUB_N_BYTE);
+ gf256v_add(signature + _PUB_N_BYTE, salt, _SALT_BYTE);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk) {
+ unsigned char digest_ck[_PUB_M_BYTE];
+ // public_map( digest_ck , pk , signature ); Evaluating the quadratic public polynomials.
+ batch_quad_trimat_eval(digest_ck, pk->pk, signature, _PUB_N, _PUB_M_BYTE);
+
+ unsigned char correct[_PUB_M_BYTE];
+ unsigned char digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, digest, _HASH_LEN);
+ memcpy(digest_salt + _HASH_LEN, signature + _PUB_N_BYTE, _SALT_BYTE);
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_hash_msg(correct, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H( digest || salt )
+
+ // check consistancy.
+ unsigned char cc = 0;
+ for (unsigned int i = 0; i < _PUB_M_BYTE; i++) {
+ cc |= (digest_ck[i] ^ correct[i]);
+ }
+ return (0 == cc) ? 0 : -1;
+}
+
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *_pk) {
+ unsigned char pk[sizeof(pk_t) + 32];
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_cpk_to_pk((pk_t *)pk, _pk); // generating classic public key.
+ return PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_verify(digest, signature, (pk_t *)pk);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/rainbow.h b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow.h
new file mode 100644
index 00000000..08353041
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow.h
@@ -0,0 +1,42 @@
+#ifndef _RAINBOW_H_
+#define _RAINBOW_H_
+/// @file rainbow.h
+/// @brief APIs for rainbow.
+///
+
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+
+#include
+
+///
+/// @brief Signing function for classical secret key.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk);
+
+
+///
+/// @brief Verifying function for cyclic public keys.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key of cyclic rainbow.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *pk);
+
+#endif // _RAINBOW_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_blas.h b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_blas.h
new file mode 100644
index 00000000..adcc2032
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_blas.h
@@ -0,0 +1,31 @@
+#ifndef _RAINBOW_BLAS_H_
+#define _RAINBOW_BLAS_H_
+/// @file rainbow_blas.h
+/// @brief Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+///
+/// Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+
+#include "blas.h"
+#include "parallel_matrix_op.h"
+#include "rainbow_config.h"
+
+
+#define gfv_get_ele PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_get_ele
+#define gfv_mul_scalar PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_mul_scalar
+#define gfv_madd PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256v_madd
+
+#define gfmat_prod PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_prod
+#define gfmat_inv PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_gf256mat_inv
+
+#define batch_trimat_madd PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_trimat_madd_gf256
+#define batch_trimatTr_madd PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_trimatTr_madd_gf256
+#define batch_2trimat_madd PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_2trimat_madd_gf256
+#define batch_matTr_madd PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_matTr_madd_gf256
+#define batch_bmatTr_madd PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_bmatTr_madd_gf256
+#define batch_mat_madd PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_mat_madd_gf256
+
+#define batch_quad_trimat_eval PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_quad_trimat_eval_gf256
+#define batch_quad_recmat_eval PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_batch_quad_recmat_eval_gf256
+
+
+#endif // _RAINBOW_BLAS_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_config.h b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_config.h
new file mode 100644
index 00000000..6d9aa270
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_config.h
@@ -0,0 +1,46 @@
+#ifndef _H_RAINBOW_CONFIG_H_
+#define _H_RAINBOW_CONFIG_H_
+
+/// @file rainbow_config.h
+/// @brief Defining the parameters of the Rainbow and the corresponding constants.
+///
+
+#define _GFSIZE 256
+#define _V1 68
+#define _O1 36
+#define _O2 36
+#define _HASH_LEN 48
+
+
+#define _V2 ((_V1) + (_O1))
+
+/// size of N, in # of gf elements.
+#define _PUB_N (_V1 + _O1 + _O2)
+
+/// size of M, in # gf elements.
+#define _PUB_M (_O1 + _O2)
+
+/// size of variables, in # bytes.
+
+// GF256
+#define _V1_BYTE (_V1)
+#define _V2_BYTE (_V2)
+#define _O1_BYTE (_O1)
+#define _O2_BYTE (_O2)
+#define _PUB_N_BYTE (_PUB_N)
+#define _PUB_M_BYTE (_PUB_M)
+
+
+/// length of seed for public key, in # bytes
+#define LEN_PKSEED 32
+
+/// length of seed for secret key, in # bytes
+#define LEN_SKSEED 32
+
+/// length of salt for a signature, in # bytes
+#define _SALT_BYTE 16
+
+/// length of a signature
+#define _SIGNATURE_BYTE (_PUB_N_BYTE + _SALT_BYTE)
+
+#endif // _H_RAINBOW_CONFIG_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair.c b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair.c
new file mode 100644
index 00000000..e7ee2b3c
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair.c
@@ -0,0 +1,157 @@
+/// @file rainbow_keypair.c
+/// @brief implementations of functions in rainbow_keypair.h
+///
+
+#include "rainbow_keypair.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair_computation.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+static void generate_S_T(unsigned char *s_and_t, prng_t *prng0) {
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // S1
+ s_and_t += _O1_BYTE * _O2;
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O1); // T1
+ s_and_t += _V1_BYTE * _O1;
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O2); // T2
+ s_and_t += _V1_BYTE * _O2;
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // T3
+}
+
+static unsigned int generate_l1_F12(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * N_TRIANGLE_TERMS(_V1)); // l1_F1
+ sk += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * _V1 * _O1); // l1_F2
+ n_byte_generated += _O1_BYTE * _V1 * _O1;
+ return n_byte_generated;
+}
+
+static unsigned int generate_l2_F12356(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // l2_F1
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O1); // l2_F2
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O2); // l2_F3
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // l2_F5
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _O1 * _O2); // l2_F6
+ n_byte_generated += _O2_BYTE * _O1 * _O2;
+
+ return n_byte_generated;
+}
+
+static void generate_B1_B2(unsigned char *sk, prng_t *prng0) {
+ sk += generate_l1_F12(sk, prng0);
+ generate_l2_F12356(sk, prng0);
+}
+
+static void calculate_t4(unsigned char *t2_to_t4, const unsigned char *t1, const unsigned char *t3) {
+ // t4 = T_sk.t1 * T_sk.t3 - T_sk.t2
+ unsigned char temp[_V1_BYTE + 32];
+ unsigned char *t4 = t2_to_t4;
+ for (unsigned int i = 0; i < _O2; i++) { /// t3 width
+ gfmat_prod(temp, t1, _V1_BYTE, _O1, t3);
+ gf256v_add(t4, temp, _V1_BYTE);
+ t4 += _V1_BYTE;
+ t3 += _O1_BYTE;
+ }
+}
+
+static void obsfucate_l1_polys(unsigned char *l1_polys, const unsigned char *l2_polys, unsigned int n_terms, const unsigned char *s1) {
+ unsigned char temp[_O1_BYTE + 32];
+ while (n_terms--) {
+ gfmat_prod(temp, s1, _O1_BYTE, _O2, l2_polys);
+ gf256v_add(l1_polys, temp, _O1_BYTE);
+ l1_polys += _O1_BYTE;
+ l2_polys += _O2_BYTE;
+ }
+}
+
+/////////////////// Classic //////////////////////////////////
+
+
+///////////////////// Cyclic //////////////////////////////////
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(pk->pk_seed, pk_seed, LEN_PKSEED);
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // prng for sk
+ prng_t prng;
+ prng_t *prng0 = &prng;
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_set(prng0, sk_seed, LEN_SKSEED);
+ generate_S_T(sk->s1, prng0); // S,T: only a part of sk
+
+ unsigned char t2[sizeof(sk->t4)];
+ memcpy(t2, sk->t4, _V1_BYTE * _O2); // temporarily store t2
+ calculate_t4(sk->t4, sk->t1, sk->t3); // t2 <- t4
+
+ // prng for pk
+ sk_t inst_Qs;
+ sk_t *Qs = &inst_Qs;
+ prng_t *prng1 = &prng;
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_set(prng1, pk_seed, LEN_PKSEED);
+ generate_B1_B2(Qs->l1_F1, prng1); // generating l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+ obsfucate_l1_polys(Qs->l1_F1, Qs->l2_F1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(Qs->l1_F2, Qs->l2_F2, _V1 * _O1, sk->s1);
+ // so far, the Qs contains l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6.
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_calculate_F_from_Q(sk, Qs, sk); // calcuate the rest parts of secret key from Qs and S,T
+
+ unsigned char t4[sizeof(sk->t4)];
+ memcpy(t4, sk->t4, _V1_BYTE * _O2); // temporarily store t4
+ memcpy(sk->t4, t2, _V1_BYTE * _O2); // restore t2
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_calculate_Q_from_F_cyclic(pk, sk, sk); // calculate the rest parts of public key: l1_Q3, l1_Q5, l1_Q6, l1_Q9, l2_Q9
+ memcpy(sk->t4, t4, _V1_BYTE * _O2); // restore t4
+
+ obsfucate_l1_polys(pk->l1_Q3, Qs->l2_F3, _V1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q5, Qs->l2_F5, N_TRIANGLE_TERMS(_O1), sk->s1);
+ obsfucate_l1_polys(pk->l1_Q6, Qs->l2_F6, _O1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q9, pk->l2_Q9, N_TRIANGLE_TERMS(_O2), sk->s1);
+
+ // clean
+ memset(&prng, 0, sizeof(prng_t));
+}
+
+
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_cpk_to_pk(pk_t *rpk, const cpk_t *cpk) {
+ // procedure: cpk_t --> extcpk_t --> pk_t
+
+ // convert from cpk_t to extcpk_t
+ ext_cpk_t pk;
+
+ // setup prng
+ prng_t prng0;
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_set(&prng0, cpk->pk_seed, LEN_SKSEED);
+
+ // generating parts of key with prng
+ generate_l1_F12(pk.l1_Q1, &prng0);
+ // copying parts of key from input. l1_Q3, l1_Q5, l1_Q6, l1_Q9
+ memcpy(pk.l1_Q3, cpk->l1_Q3, _O1_BYTE * (_V1 * _O2 + N_TRIANGLE_TERMS(_O1) + _O1 * _O2 + N_TRIANGLE_TERMS(_O2)));
+
+ // generating parts of key with prng
+ generate_l2_F12356(pk.l2_Q1, &prng0);
+ // copying parts of key from input: l2_Q9
+ memcpy(pk.l2_Q9, cpk->l2_Q9, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ // convert from extcpk_t to pk_t
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_extcpk_to_pk(rpk, &pk);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair.h b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair.h
new file mode 100644
index 00000000..33f55e32
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair.h
@@ -0,0 +1,94 @@
+#ifndef _RAINBOW_KEYPAIR_H_
+#define _RAINBOW_KEYPAIR_H_
+/// @file rainbow_keypair.h
+/// @brief Formats of key pairs and functions for generating key pairs.
+/// Formats of key pairs and functions for generating key pairs.
+///
+
+#include "rainbow_config.h"
+
+#define N_TRIANGLE_TERMS(n_var) ((n_var) * ((n_var) + 1) / 2)
+
+/// @brief public key for classic rainbow
+///
+/// public key for classic rainbow
+///
+typedef struct rainbow_publickey {
+ unsigned char pk[(_PUB_M_BYTE)*N_TRIANGLE_TERMS(_PUB_N)];
+} pk_t;
+
+/// @brief secret key for classic rainbow
+///
+/// secret key for classic rainbow
+///
+typedef struct rainbow_secretkey {
+ ///
+ /// seed for generating secret key.
+ /// Generating S, T, and F for classic rainbow.
+ /// Generating S and T only for cyclic rainbow.
+ unsigned char sk_seed[LEN_SKSEED];
+
+ unsigned char s1[_O1_BYTE * _O2]; ///< part of S map
+ unsigned char t1[_V1_BYTE * _O1]; ///< part of T map
+ unsigned char t4[_V1_BYTE * _O2]; ///< part of T map
+ unsigned char t3[_O1_BYTE * _O2]; ///< part of T map
+
+ unsigned char l1_F1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer1
+ unsigned char l1_F2[_O1_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer1
+
+ unsigned char l2_F1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer2
+ unsigned char l2_F2[_O2_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer2
+
+ unsigned char l2_F3[_O2_BYTE * _V1 * _O2]; ///< part of C-map, F3, Layer2
+ unsigned char l2_F5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< part of C-map, F5, Layer2
+ unsigned char l2_F6[_O2_BYTE * _O1 * _O2]; ///< part of C-map, F6, Layer2
+} sk_t;
+
+/// @brief public key for cyclic rainbow
+///
+/// public key for cyclic rainbow
+///
+typedef struct rainbow_publickey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating l1_Q1,l1_Q2,l2_Q1,l2_Q2,l2_Q3,l2_Q5,l2_Q6
+
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2]; ///< Q3, layer1
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< Q5, layer1
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2]; ///< Q6, layer1
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer1
+
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer2
+} cpk_t;
+
+/// @brief compressed secret key for cyclic rainbow
+///
+/// compressed secret key for cyclic rainbow
+///
+typedef struct rainbow_secretkey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating a part of public key.
+ unsigned char sk_seed[LEN_SKSEED]; ///< seed for generating a part of secret key.
+} csk_t;
+
+
+///
+/// @brief Generate key pairs for cyclic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the secret key.
+/// @param[in] pk_seed - seed for generating parts of public key.
+/// @param[in] sk_seed - seed for generating secret key.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+
+
+////////////////////////////////////
+
+///
+/// @brief converting formats of public keys : from cyclic version to classic key
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the cyclic public key.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_cpk_to_pk(pk_t *pk, const cpk_t *cpk);
+
+#endif // _RAINBOW_KEYPAIR_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair_computation.c b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair_computation.c
new file mode 100644
index 00000000..ab38bca7
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair_computation.c
@@ -0,0 +1,213 @@
+/// @file rainbow_keypair_computation.c
+/// @brief Implementations for functions in rainbow_keypair_computation.h
+///
+
+#include "rainbow_keypair_computation.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair.h"
+#include
+#include
+#include
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk) {
+ const unsigned char *idx_l1 = cpk->l1_Q1;
+ const unsigned char *idx_l2 = cpk->l2_Q1;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = i; j < _V1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q2;
+ idx_l2 = cpk->l2_Q2;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q3;
+ idx_l2 = cpk->l2_Q3;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q5;
+ idx_l2 = cpk->l2_Q5;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = i; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q6;
+ idx_l2 = cpk->l2_Q6;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q9;
+ idx_l2 = cpk->l2_Q9;
+ for (unsigned int i = _V1 + _O1; i < _PUB_N; i++) {
+ for (unsigned int j = i; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+}
+
+static void calculate_F_from_Q_ref(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ // Layer 1
+ // F_sk.l1_F1s[i] = Q_pk.l1_F1s[i]
+ memcpy(Fs->l1_F1, Qs->l1_F1, _O1_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ // F_sk.l1_F2s[i] = ( Q_pk.l1_F1s[i] + Q_pk.l1_F1s[i].transpose() ) * T_sk.t1 + Q_pk.l1_F2s[i]
+ memcpy(Fs->l1_F2, Qs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_2trimat_madd(Fs->l1_F2, Qs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE);
+
+ /*
+ Layer 2
+ computations:
+
+ F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ Q1_T1 = Q_pk.l2_F1s[i]*T_sk.t1
+ F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+
+ Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ #Q1_Q1T_T4 = Q1_Q1T * t4
+ Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ + Q_pk.l2_F2s[i].transpose() * t4
+ + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+
+ */
+ memcpy(Fs->l2_F1, Qs->l2_F1, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ // F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ // F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+ memcpy(Fs->l2_F2, Qs->l2_F2, _O2_BYTE * _V1 * _O1);
+ batch_trimat_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // Q1_T1+ Q2
+
+ unsigned char tempQ[_O1 * _O1 * _O2_BYTE + 32];
+ memset(tempQ, 0, _O1 * _O1 * _O2_BYTE);
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F2, _O1, _O2_BYTE); // t1_tr*(Q1_T1+Q2)
+ memcpy(Fs->l2_F5, Qs->l2_F5, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // F5
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_UpperTrianglize(Fs->l2_F5, tempQ, _O1, _O2_BYTE); // UT( ... )
+
+ batch_trimatTr_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // F2 = Q1_T1 + Q2 + Q1^tr*t1
+
+ // Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ // Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ // F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ memcpy(Fs->l2_F3, Qs->l2_F3, _V1 * _O2 * _O2_BYTE);
+ batch_2trimat_madd(Fs->l2_F3, Qs->l2_F1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE); // Q1_Q1T_T4
+ batch_mat_madd(Fs->l2_F3, Qs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // Q2_T3
+
+ // F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ // + Q_pk.l2_F2s[i].transpose() * t4
+ // + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+ memcpy(Fs->l2_F6, Qs->l2_F6, _O1 * _O2 * _O2_BYTE);
+ batch_matTr_madd(Fs->l2_F6, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F3, _O2, _O2_BYTE); // t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ batch_2trimat_madd(Fs->l2_F6, Qs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3
+ batch_bmatTr_madd(Fs->l2_F6, Qs->l2_F2, _O1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE);
+}
+
+static void calculate_Q_from_F_cyclic_ref(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ // Layer 1: Computing Q5, Q3, Q6, Q9
+
+ // Q_pk.l1_F5s[i] = UT( T1tr* (F1 * T1 + F2) )
+ const unsigned char *t2 = Ts->t4;
+ sk_t tempQ;
+ memcpy(tempQ.l1_F2, Fs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_trimat_madd(tempQ.l1_F2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // F1*T1 + F2
+ memset(tempQ.l2_F1, 0, sizeof(tempQ.l2_F1));
+ memset(tempQ.l2_F2, 0, sizeof(tempQ.l2_F2));
+ batch_matTr_madd(tempQ.l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, tempQ.l1_F2, _O1, _O1_BYTE); // T1tr*(F1*T1 + F2)
+ memset(Qs->l1_Q5, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O1));
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_UpperTrianglize(Qs->l1_Q5, tempQ.l2_F1, _O1, _O1_BYTE); // UT( ... ) // Q5
+
+ /*
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+ Q_pk.l1_F3s[i] = F1_F1T_T2 + F2_T3
+ Q_pk.l1_F6s[i] = T1tr* ( F1_F1T_T2 + F2_T3 ) + F2tr * t2
+ Q_pk.l1_F9s[i] = UT( T2tr* ( F1_T2 + F2_T3 ) )
+ */
+ memset(Qs->l1_Q3, 0, _O1_BYTE * _V1 * _O2);
+ memset(Qs->l1_Q6, 0, _O1_BYTE * _O1 * _O2);
+ memset(Qs->l1_Q9, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ batch_trimat_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1*T2
+ batch_mat_madd(Qs->l1_Q3, Fs->l1_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O1_BYTE); // F1_T2 + F2_T3
+
+ memset(tempQ.l1_F2, 0, _O1_BYTE * _V1 * _O2); // should be F3. assuming: _O1 >= _O2
+ batch_matTr_madd(tempQ.l1_F2, t2, _V1, _V1_BYTE, _O2, Qs->l1_Q3, _O2, _O1_BYTE); // T2tr * ( F1_T2 + F2_T3 )
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_UpperTrianglize(Qs->l1_Q9, tempQ.l1_F2, _O2, _O1_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1_F1T_T2 + F2_T3 // Q3
+
+ batch_bmatTr_madd(Qs->l1_Q6, Fs->l1_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F2tr*T2
+ batch_matTr_madd(Qs->l1_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q3, _O2, _O1_BYTE); // Q6
+ /*
+ Layer 2
+ Computing Q9:
+
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ Q9 = UT( T2tr*( F1*T2 + F2*T3 + F3 ) + T3tr*( F5*T3 + F6 ) )
+ */
+ sk_t tempQ2;
+ memcpy(tempQ2.l2_F3, Fs->l2_F3, _O2_BYTE * _V1 * _O2); /// F3 actually.
+ batch_trimat_madd(tempQ2.l2_F3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1*T2 + F3
+ batch_mat_madd(tempQ2.l2_F3, Fs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F1_T2 + F2_T3 + F3
+
+ memset(tempQ.l2_F3, 0, _O2_BYTE * _V1 * _O2);
+ batch_matTr_madd(tempQ.l2_F3, t2, _V1, _V1_BYTE, _O2, tempQ2.l2_F3, _O2, _O2_BYTE); // T2tr * ( ..... )
+
+ memcpy(tempQ.l2_F6, Fs->l2_F6, _O2_BYTE * _O1 * _O2);
+ batch_trimat_madd(tempQ.l2_F6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6
+
+ batch_matTr_madd(tempQ.l2_F3, Ts->t3, _O1, _O1_BYTE, _O2, tempQ.l2_F6, _O2, _O2_BYTE); // T2tr*( ..... ) + T3tr*( ..... )
+ memset(Qs->l2_Q9, 0, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_UpperTrianglize(Qs->l2_Q9, tempQ.l2_F3, _O2, _O2_BYTE); // Q9
+}
+
+// Choosing implementations depends on the macros: _BLAS_SSE_ and _BLAS_AVX2_
+#define calculate_F_from_Q_impl calculate_F_from_Q_ref
+#define calculate_Q_from_F_cyclic_impl calculate_Q_from_F_cyclic_ref
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ calculate_F_from_Q_impl(Fs, Qs, Ts);
+}
+
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ calculate_Q_from_F_cyclic_impl(Qs, Fs, Ts);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair_computation.h b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair_computation.h
new file mode 100644
index 00000000..6e6eeef9
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/rainbow_keypair_computation.h
@@ -0,0 +1,71 @@
+#ifndef _RAINBOW_KEYPAIR_COMP_H_
+#define _RAINBOW_KEYPAIR_COMP_H_
+/// @file rainbow_keypair_computation.h
+/// @brief Functions for calculating pk/sk while generating keys.
+///
+/// Defining an internal structure of public key.
+/// Functions for calculating pk/sk for key generation.
+///
+
+#include "rainbow_keypair.h"
+
+/// @brief The (internal use) public key for rainbow
+///
+/// The (internal use) public key for rainbow. The public
+/// polynomials are divided into l1_Q1, l1_Q2, ... l1_Q9,
+/// l2_Q1, .... , l2_Q9.
+///
+typedef struct rainbow_extend_publickey {
+ unsigned char l1_Q1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l1_Q2[_O1_BYTE * _V1 * _O1];
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2];
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2];
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)];
+
+ unsigned char l2_Q1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l2_Q2[_O2_BYTE * _V1 * _O1];
+ unsigned char l2_Q3[_O2_BYTE * _V1 * _O2];
+ unsigned char l2_Q5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l2_Q6[_O2_BYTE * _O1 * _O2];
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)];
+} ext_cpk_t;
+
+///
+/// @brief converting formats of public keys : from ext_cpk_t version to pk_t
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the internel public key.
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk);
+/////////////////////////////////////////////////
+
+///
+/// @brief Computing public key from secret key
+///
+/// @param[out] Qs - the public key
+/// @param[in] Fs - parts of the secret key: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the secret key: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+
+///
+/// @brief Computing parts of the sk from parts of pk and sk
+///
+/// @param[out] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Qs - parts of the pk: l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts);
+
+///
+/// @brief Computing parts of the pk from the secret key
+///
+/// @param[out] Qs - parts of the pk: l1_Q3, l1_Q5, l2_Q6, l1_Q9, l2_Q9
+/// @param[in] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+#endif // _RAINBOW_KEYPAIR_COMP_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/sign.c b/crypto_sign/rainbowIIIc-cyclic/clean/sign.c
new file mode 100644
index 00000000..0f558c48
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/sign.c
@@ -0,0 +1,76 @@
+/// @file sign.c
+/// @brief the implementations for functions in api.h
+///
+///
+
+#include "api.h"
+#include "rainbow.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
+ unsigned char sk_seed[LEN_SKSEED] = {0};
+ randombytes(sk_seed, LEN_SKSEED);
+
+ unsigned char pk_seed[LEN_PKSEED] = {0};
+ randombytes(pk_seed, LEN_PKSEED);
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_generate_keypair_cyclic((cpk_t *)pk, (sk_t *)sk, pk_seed, sk_seed);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_crypto_sign(unsigned char *sm, size_t *smlen, const unsigned char *m, size_t mlen, const unsigned char *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+
+ memcpy(sm, m, mlen);
+ smlen[0] = mlen + _SIGNATURE_BYTE;
+
+ return PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_sign(sm + mlen, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_crypto_sign_open(unsigned char *m, size_t *mlen, const unsigned char *sm, size_t smlen, const unsigned char *pk) {
+ int rc;
+ if (_SIGNATURE_BYTE > smlen) {
+ rc = -1;
+ } else {
+ *mlen = smlen - _SIGNATURE_BYTE;
+
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, sm, *mlen);
+
+ rc = PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_verify_cyclic(digest, sm + mlen[0], (const cpk_t *)pk);
+ }
+ if (!rc) {
+ memcpy(m, sm, smlen - _SIGNATURE_BYTE);
+ } else { // bad signature
+ *mlen = (size_t) -1;
+ memset(m, 0, smlen);
+ }
+ return rc;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ *siglen = _SIGNATURE_BYTE;
+ return PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_sign(sig, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ if (siglen != _SIGNATURE_BYTE) {
+ return -1;
+ }
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ return PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_rainbow_verify_cyclic(digest, sig, (const cpk_t *)pk);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/utils_hash.c b/crypto_sign/rainbowIIIc-cyclic/clean/utils_hash.c
new file mode 100644
index 00000000..4219df75
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/utils_hash.c
@@ -0,0 +1,50 @@
+/// @file utils_hash.c
+/// @brief the adapter for SHA2 families.
+///
+///
+
+#include "utils_hash.h"
+#include "rainbow_config.h"
+#include "sha2.h"
+
+static inline int _hash(unsigned char *digest, const unsigned char *m, size_t mlen) {
+ sha384(digest, m, mlen);
+ return 0;
+}
+
+static inline int expand_hash(unsigned char *digest, size_t n_digest, const unsigned char *hash) {
+ if (_HASH_LEN >= n_digest) {
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[i] = hash[i];
+ }
+ return 0;
+ }
+ for (size_t i = 0; i < _HASH_LEN; i++) {
+ digest[i] = hash[i];
+ }
+ n_digest -= _HASH_LEN;
+
+ while (_HASH_LEN <= n_digest) {
+ _hash(digest + _HASH_LEN, digest, _HASH_LEN);
+
+ n_digest -= _HASH_LEN;
+ digest += _HASH_LEN;
+ }
+ unsigned char temp[_HASH_LEN];
+ if (n_digest) {
+ _hash(temp, digest, _HASH_LEN);
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[_HASH_LEN + i] = temp[i];
+ }
+ }
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_hash_msg(unsigned char *digest,
+ size_t len_digest,
+ const unsigned char *m,
+ size_t mlen) {
+ unsigned char buf[_HASH_LEN];
+ _hash(buf, m, mlen);
+ return expand_hash(digest, len_digest, buf);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/utils_hash.h b/crypto_sign/rainbowIIIc-cyclic/clean/utils_hash.h
new file mode 100644
index 00000000..24231e34
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/utils_hash.h
@@ -0,0 +1,11 @@
+#ifndef _UTILS_HASH_H_
+#define _UTILS_HASH_H_
+/// @file utils_hash.h
+/// @brief the interface for adapting hash functions.
+///
+
+#include
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_hash_msg(unsigned char *digest, size_t len_digest, const unsigned char *m, size_t mlen);
+
+#endif // _UTILS_HASH_H_
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/utils_prng.c b/crypto_sign/rainbowIIIc-cyclic/clean/utils_prng.c
new file mode 100644
index 00000000..142e653e
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/utils_prng.c
@@ -0,0 +1,95 @@
+/// @file utils_prng.c
+/// @brief The implementation of PRNG related functions.
+///
+
+#include "utils_prng.h"
+#include "aes.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+static void prng_update(const unsigned char *provided_data,
+ unsigned char *Key,
+ unsigned char *V) {
+ unsigned char temp[48];
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, Key);
+ for (int i = 0; i < 3; i++) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (V[j] == 0xff) {
+ V[j] = 0x00;
+ } else {
+ V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(temp + 16 * i, V, 1, &ctx);
+ }
+ if (provided_data != NULL) {
+ for (int i = 0; i < 48; i++) {
+ temp[i] ^= provided_data[i];
+ }
+ }
+ memcpy(Key, temp, 32);
+ memcpy(V, temp + 32, 16);
+}
+static void randombytes_init_with_state(prng_t *state,
+ unsigned char *entropy_input_48bytes) {
+ memset(state->Key, 0x00, 32);
+ memset(state->V, 0x00, 16);
+ prng_update(entropy_input_48bytes, state->Key, state->V);
+}
+
+static int randombytes_with_state(prng_t *state,
+ unsigned char *x,
+ size_t xlen) {
+
+ unsigned char block[16];
+ int i = 0;
+
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, state->Key);
+
+ while (xlen > 0) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (state->V[j] == 0xff) {
+ state->V[j] = 0x00;
+ } else {
+ state->V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(block, state->V, 1, &ctx);
+ if (xlen > 15) {
+ memcpy(x + i, block, 16);
+ i += 16;
+ xlen -= 16;
+ } else {
+ memcpy(x + i, block, xlen);
+ xlen = 0;
+ }
+ }
+ prng_update(NULL, state->Key, state->V);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen) {
+ unsigned char seed[48];
+ if (prng_seedlen >= 48) {
+ memcpy(seed, prng_seed, 48);
+ } else {
+ memcpy(seed, prng_seed, prng_seedlen);
+ PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_hash_msg(seed + prng_seedlen, 48 - (unsigned)prng_seedlen, (const unsigned char *)prng_seed, prng_seedlen);
+ }
+
+ randombytes_init_with_state(ctx, seed);
+
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen) {
+ return randombytes_with_state(ctx, out, outlen);
+}
diff --git a/crypto_sign/rainbowIIIc-cyclic/clean/utils_prng.h b/crypto_sign/rainbowIIIc-cyclic/clean/utils_prng.h
new file mode 100644
index 00000000..403a4230
--- /dev/null
+++ b/crypto_sign/rainbowIIIc-cyclic/clean/utils_prng.h
@@ -0,0 +1,18 @@
+#ifndef _UTILS_PRNG_H_
+#define _UTILS_PRNG_H_
+/// @file utils_prng.h
+/// @brief the interface for adapting PRNG functions.
+///
+///
+
+#include "randombytes.h"
+
+typedef struct {
+ unsigned char Key[32];
+ unsigned char V[16];
+} prng_t;
+
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen);
+int PQCLEAN_RAINBOWIIICCYCLIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen);
+
+#endif // _UTILS_PRNG_H_
diff --git a/crypto_sign/rainbowIa-classic/META.yml b/crypto_sign/rainbowIa-classic/META.yml
new file mode 100644
index 00000000..5ddca83a
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/META.yml
@@ -0,0 +1,18 @@
+name: Rainbow-Ia-classic
+type: signature
+claimed-nist-level: 1
+length-public-key: 148992
+length-secret-key: 92960
+length-signature: 64
+nistkat-sha256: b75c6fcda2100e2f6f56e9b97c4cbdda4b533116ab217f24f12e08788eb37fd0
+testvectors-sha256: edc48db3f93a66c0aa497fbbdba0bad173e3ab9cd0e3f651004b3e94d2187b75
+principal-submitters:
+ - Jintai Ding
+auxiliary-submitters:
+ - Ming-Shing Chen
+ - Albrecht Petzoldt
+ - Dieter Schmidt
+ - Bo-Yin Yang
+implementations:
+ - name: clean
+ version: https://github.com/fast-crypto-lab/rainbow-submission-round2/commit/af826fcb78f6af51a02d0352cff28a9690467bfd
diff --git a/crypto_sign/rainbowIa-classic/clean/LICENSE b/crypto_sign/rainbowIa-classic/clean/LICENSE
new file mode 100644
index 00000000..cb00a6e3
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/LICENSE
@@ -0,0 +1,8 @@
+`Software implementation of Rainbow for NIST R2 submission' by Ming-Shing Chen
+
+To the extent possible under law, the person who associated CC0 with
+`Software implementation of Rainbow for NIST R2 submission' has waived all copyright and related or neighboring rights
+to `Software implementation of Rainbow for NIST R2 submission'.
+
+You should have received a copy of the CC0 legalcode along with this
+work. If not, see .
diff --git a/crypto_sign/rainbowIa-classic/clean/Makefile b/crypto_sign/rainbowIa-classic/clean/Makefile
new file mode 100644
index 00000000..0792549f
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=librainbowIa-classic_clean.a
+
+HEADERS = api.h blas_comm.h blas.h blas_u32.h gf.h parallel_matrix_op.h rainbow_blas.h rainbow_config.h rainbow.h rainbow_keypair_computation.h rainbow_keypair.h utils_hash.h utils_prng.h
+OBJECTS = blas_comm.o parallel_matrix_op.o rainbow.o rainbow_keypair.o rainbow_keypair_computation.o sign.o utils_hash.o utils_prng.o blas_u32.o gf.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/rainbowIa-classic/clean/Makefile.Microsoft_nmake b/crypto_sign/rainbowIa-classic/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..9bdc010b
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=librainbowIa-classic_clean.lib
+OBJECTS = blas_comm.obj parallel_matrix_op.obj rainbow.obj rainbow_keypair.obj rainbow_keypair_computation.obj sign.obj utils_hash.obj utils_prng.obj blas_u32.obj gf.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/rainbowIa-classic/clean/api.h b/crypto_sign/rainbowIa-classic/clean/api.h
new file mode 100644
index 00000000..f4447b75
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/api.h
@@ -0,0 +1,32 @@
+#ifndef PQCLEAN_RAINBOWIACLASSIC_CLEAN_API_H
+#define PQCLEAN_RAINBOWIACLASSIC_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_RAINBOWIACLASSIC_CLEAN_CRYPTO_SECRETKEYBYTES 92960
+#define PQCLEAN_RAINBOWIACLASSIC_CLEAN_CRYPTO_PUBLICKEYBYTES 148992
+#define PQCLEAN_RAINBOWIACLASSIC_CLEAN_CRYPTO_BYTES 64
+#define PQCLEAN_RAINBOWIACLASSIC_CLEAN_CRYPTO_ALGNAME "RAINBOW(16,32,32,32) - classic"
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
+
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen,
+ const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen,
+ const uint8_t *pk);
+
+
+#endif
diff --git a/crypto_sign/rainbowIa-classic/clean/blas.h b/crypto_sign/rainbowIa-classic/clean/blas.h
new file mode 100644
index 00000000..22b7809e
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/blas.h
@@ -0,0 +1,20 @@
+#ifndef _BLAS_H_
+#define _BLAS_H_
+/// @file blas.h
+/// @brief Defining the implementations for linear algebra functions depending on the machine architecture.
+///
+
+#include "blas_comm.h"
+#include "blas_u32.h"
+#include "rainbow_config.h"
+
+#define gf256v_predicated_add PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_predicated_add_u32
+#define gf256v_add PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_add_u32
+
+
+#define gf16v_mul_scalar PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_scalar_u32
+#define gf16v_madd PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_madd_u32
+#define gf16v_dot PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_dot_u32
+
+
+#endif // _BLAS_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/blas_comm.c b/crypto_sign/rainbowIa-classic/clean/blas_comm.c
new file mode 100644
index 00000000..3c67c694
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/blas_comm.c
@@ -0,0 +1,150 @@
+/// @file blas_comm.c
+/// @brief The standard implementations for blas_comm.h
+///
+
+#include "blas_comm.h"
+#include "blas.h"
+#include "gf.h"
+#include "rainbow_config.h"
+
+#include
+#include
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte) {
+ gf256v_add(b, b, _num_byte);
+}
+
+/// @brief get an element from GF(16) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(const uint8_t *a, unsigned int i) {
+ uint8_t r = a[i >> 1];
+ uint8_t r0 = r & 0xf;
+ uint8_t r1 = r >> 4;
+ uint8_t m = (uint8_t)(-((int8_t)i & 1));
+ return (uint8_t)((r1 & m) | ((~m) & r0));
+}
+
+/// @brief set an element for a GF(16) vector .
+///
+/// @param[in,out] a - the vector a.
+/// @param[in] i - the index in the vector a.
+/// @param[in] v - the value for the i-th element in vector a.
+/// @return the value of the element.
+///
+static uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_set_ele(uint8_t *a, unsigned int i, uint8_t v) {
+ uint8_t m = (uint8_t)(0xf ^ (-((int8_t)i & 1))); /// 1--> 0xf0 , 0--> 0x0f
+ uint8_t ai_remaining = (uint8_t)(a[i >> 1] & (~m)); /// erase
+ a[i >> 1] = (uint8_t)(ai_remaining | (m & (v << 4)) | (m & v & 0xf)); /// set
+ return v;
+}
+
+static void gf16mat_prod_ref(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_set_zero(c, n_A_vec_byte);
+ for (unsigned int i = 0; i < n_A_width; i++) {
+ uint8_t bb = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(b, i);
+ gf16v_madd(c, matA, bb, n_A_vec_byte);
+ matA += n_A_vec_byte;
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec) {
+ unsigned int n_vec_byte = (len_vec + 1) / 2;
+ for (unsigned int k = 0; k < len_vec; k++) {
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_set_zero(c, n_vec_byte);
+ const uint8_t *bk = b + n_vec_byte * k;
+ for (unsigned int i = 0; i < len_vec; i++) {
+ uint8_t bb = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(bk, i);
+ gf16v_madd(c, a + n_vec_byte * i, bb, n_vec_byte);
+ }
+ c += n_vec_byte;
+ }
+}
+
+static unsigned int gf16mat_gauss_elim_ref(uint8_t *mat, unsigned int h, unsigned int w) {
+ unsigned int n_w_byte = (w + 1) / 2;
+ unsigned int r8 = 1;
+ for (unsigned int i = 0; i < h; i++) {
+ unsigned int offset_byte = i >> 1;
+ uint8_t *ai = mat + n_w_byte * i;
+ for (unsigned int j = i + 1; j < h; j++) {
+ uint8_t *aj = mat + n_w_byte * j;
+ gf256v_predicated_add(ai + offset_byte, !PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16_is_nonzero(PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(ai, i)), aj + offset_byte, n_w_byte - offset_byte);
+ }
+ uint8_t pivot = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(ai, i);
+ r8 &= PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16_is_nonzero(pivot);
+ pivot = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16_inv(pivot);
+ offset_byte = (i + 1) >> 1;
+ gf16v_mul_scalar(ai + offset_byte, pivot, n_w_byte - offset_byte);
+ for (unsigned int j = 0; j < h; j++) {
+ if (i == j) {
+ continue;
+ }
+ uint8_t *aj = mat + n_w_byte * j;
+ gf16v_madd(aj + offset_byte, ai + offset_byte, PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(aj, i), n_w_byte - offset_byte);
+ }
+ }
+ return r8;
+}
+
+static unsigned int gf16mat_solve_linear_eq_ref(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ uint8_t mat[64 * 33];
+ unsigned int n_byte = (n + 1) >> 1;
+ for (unsigned int i = 0; i < n; i++) {
+ memcpy(mat + i * (n_byte + 1), inp_mat + i * n_byte, n_byte);
+ mat[i * (n_byte + 1) + n_byte] = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(c_terms, i);
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_gauss_elim(mat, n, n + 2);
+ for (unsigned int i = 0; i < n; i++) {
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_set_ele(sol, i, mat[i * (n_byte + 1) + n_byte]);
+ }
+ return r8;
+}
+
+static inline void gf16mat_submat(uint8_t *mat2, unsigned int w2, unsigned int st, const uint8_t *mat, unsigned int w, unsigned int h) {
+ unsigned int n_byte_w1 = (w + 1) / 2;
+ unsigned int n_byte_w2 = (w2 + 1) / 2;
+ unsigned int st_2 = st / 2;
+ for (unsigned int i = 0; i < h; i++) {
+ for (unsigned int j = 0; j < n_byte_w2; j++) {
+ mat2[i * n_byte_w2 + j] = mat[i * n_byte_w1 + st_2 + j];
+ }
+ }
+}
+
+unsigned int PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer) {
+ unsigned int n_w_byte = (H + 1) / 2;
+
+ uint8_t *aa = buffer;
+ for (unsigned int i = 0; i < H; i++) {
+ uint8_t *ai = aa + i * 2 * n_w_byte;
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_set_zero(ai, 2 * n_w_byte);
+ gf256v_add(ai, a + i * n_w_byte, n_w_byte);
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_set_ele(ai + n_w_byte, i, 1);
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_gauss_elim(aa, H, 2 * H);
+ gf16mat_submat(inv_a, H, H, aa, 2 * H, H);
+ return r8;
+}
+
+// choosing the implementations depends on the macros _BLAS_AVX2_ and _BLAS_SSE
+
+#define gf16mat_prod_impl gf16mat_prod_ref
+#define gf16mat_gauss_elim_impl gf16mat_gauss_elim_ref
+#define gf16mat_solve_linear_eq_impl gf16mat_solve_linear_eq_ref
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ gf16mat_prod_impl(c, matA, n_A_vec_byte, n_A_width, b);
+}
+
+unsigned int PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w) {
+ return gf16mat_gauss_elim_impl(mat, h, w);
+}
+
+unsigned int PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ return gf16mat_solve_linear_eq_impl(sol, inp_mat, c_terms, n);
+}
+
diff --git a/crypto_sign/rainbowIa-classic/clean/blas_comm.h b/crypto_sign/rainbowIa-classic/clean/blas_comm.h
new file mode 100644
index 00000000..9cbe8ff1
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/blas_comm.h
@@ -0,0 +1,74 @@
+#ifndef _BLAS_COMM_H_
+#define _BLAS_COMM_H_
+/// @file blas_comm.h
+/// @brief Common functions for linear algebra.
+///
+
+#include "rainbow_config.h"
+#include
+
+/// @brief set a vector to 0.
+///
+/// @param[in,out] b - the vector b.
+/// @param[in] _num_byte - number of bytes for the vector b.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte);
+
+/// @brief get an element from GF(16) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(const uint8_t *a, unsigned int i);
+
+/// @brief matrix-matrix multiplication: c = a * b , in GF(16)
+///
+/// @param[out] c - the output matrix c
+/// @param[in] c - a matrix a.
+/// @param[in] b - a matrix b.
+/// @param[in] len_vec - the length of column vectors.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec);
+
+/// @brief Gauss elimination for a matrix, in GF(16)
+///
+/// @param[in,out] mat - the matrix.
+/// @param[in] h - the height of the matrix.
+/// @param[in] w - the width of the matrix.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w);
+
+/// @brief Solving linear equations, in GF(16)
+///
+/// @param[out] sol - the solutions.
+/// @param[in] inp_mat - the matrix parts of input equations.
+/// @param[in] c_terms - the constant terms of the input equations.
+/// @param[in] n - the number of equations.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n);
+
+/// @brief Computing the inverse matrix, in GF(16)
+///
+/// @param[out] inv_a - the output of matrix a.
+/// @param[in] a - a matrix a.
+/// @param[in] H - height of matrix a, i.e., matrix a is an HxH matrix.
+/// @param[in] buffer - The buffer for computations. it has to be as large as 2 input matrixes.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer);
+
+/// @brief matrix-vector multiplication: c = matA * b , in GF(16)
+///
+/// @param[out] c - the output vector c
+/// @param[in] matA - a column-major matrix A.
+/// @param[in] n_A_vec_byte - the size of column vectors in bytes.
+/// @param[in] n_A_width - the width of matrix A.
+/// @param[in] b - the vector b.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b);
+
+
+#endif // _BLAS_COMM_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/blas_u32.c b/crypto_sign/rainbowIa-classic/clean/blas_u32.c
new file mode 100644
index 00000000..312eef5f
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/blas_u32.c
@@ -0,0 +1,115 @@
+#include "blas_u32.h"
+#include "gf.h"
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte) {
+ uint32_t pr_u32 = ((uint32_t)0) - ((uint32_t)predicate);
+ uint8_t pr_u8 = pr_u32 & 0xff;
+
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= (a_u32[i] & pr_u32);
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= (a[i] & pr_u8);
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= a_u32[i];
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= a[i];
+ }
+}
+
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_scalar_u32(uint8_t *a, uint8_t gf16_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *a_u32 = (uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ a_u32[i] = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_u32(a_u32[i], gf16_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_u32(t.u32, gf16_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ a[i] = t.u8[i];
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf16_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *c_u32 = (uint32_t *)accu_c;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ c_u32[i] ^= PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_u32(a_u32[i], gf16_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ accu_c += (n_u32 << 2);
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_u32(t.u32, gf16_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_c[i] ^= t.u8[i];
+ }
+}
+
+uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_dot_u32(const uint8_t *a, const uint8_t *b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ const uint32_t *b_u32 = (const uint32_t *)b;
+ uint32_t r = 0;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ r ^= PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_u32_u32(a_u32[i], b_u32[i]);
+ }
+
+ unsigned int rem = _num_byte & 3;
+ if (rem) {
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } ta, tb;
+ ta.u32 = 0;
+ tb.u32 = 0;
+ for (unsigned int i = 0; i < rem; i++) {
+ ta.u8[i] = a[(n_u32 << 2) + i];
+ }
+ for (unsigned int i = 0; i < rem; i++) {
+ tb.u8[i] = b[(n_u32 << 2) + i];
+ }
+ r ^= PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_u32_u32(ta.u32, tb.u32);
+ }
+ return PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_reduce_u32(r);
+}
+
diff --git a/crypto_sign/rainbowIa-classic/clean/blas_u32.h b/crypto_sign/rainbowIa-classic/clean/blas_u32.h
new file mode 100644
index 00000000..25005e14
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/blas_u32.h
@@ -0,0 +1,19 @@
+#ifndef _BLAS_U32_H_
+#define _BLAS_U32_H_
+/// @file blas_u32.h
+/// @brief Inlined functions for implementing basic linear algebra functions for uint32 arch.
+///
+
+#include "rainbow_config.h"
+#include
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte);
+
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf16_b, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_scalar_u32(uint8_t *a, uint8_t gf16_b, unsigned int _num_byte);
+uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_dot_u32(const uint8_t *a, const uint8_t *b, unsigned int _num_byte);
+
+
+#endif // _BLAS_U32_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/gf.c b/crypto_sign/rainbowIa-classic/clean/gf.c
new file mode 100644
index 00000000..cdad4492
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/gf.c
@@ -0,0 +1,124 @@
+#include "gf.h"
+
+//// gf4 := gf2[x]/x^2+x+1
+static inline uint8_t gf4_mul_2(uint8_t a) {
+ uint8_t r = (uint8_t)(a << 1);
+ r ^= (uint8_t)((a >> 1) * 7);
+ return r;
+}
+
+static inline uint8_t gf4_mul(uint8_t a, uint8_t b) {
+ uint8_t r = (uint8_t)(a * (b & 1));
+ return r ^ (uint8_t)(gf4_mul_2(a) * (b >> 1));
+}
+
+static inline uint8_t gf4_squ(uint8_t a) {
+ return a ^ (a >> 1);
+}
+
+static inline uint32_t gf4v_mul_2_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit1 ^ (bit1 >> 1);
+}
+
+static inline uint32_t gf4v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t bit0_b = ((uint32_t)0) - ((uint32_t)(b & 1));
+ uint32_t bit1_b = ((uint32_t)0) - ((uint32_t)((b >> 1) & 1));
+ return (a & bit0_b) ^ (bit1_b & gf4v_mul_2_u32(a));
+}
+
+//// gf16 := gf4[y]/y^2+y+x
+static inline uint8_t gf16_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ uint8_t b0 = b & 3;
+ uint8_t b1 = (b >> 2);
+ uint8_t a0b0 = gf4_mul(a0, b0);
+ uint8_t a1b1 = gf4_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf4_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x2 = gf4_mul_2(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 2 ^ a0b0 ^ a1b1_x2);
+}
+
+static inline uint8_t gf16_squ(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ a1 = gf4_squ(a1);
+ uint8_t a1squ_x2 = gf4_mul_2(a1);
+ return (uint8_t)((a1 << 2) ^ a1squ_x2 ^ gf4_squ(a0));
+}
+
+// gf16 := gf4[y]/y^2+y+x
+uint32_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = gf4v_mul_u32(a, b);
+ uint32_t axb1 = gf4v_mul_u32(a, b >> 2);
+ uint32_t a0b1 = (axb1 << 2) & 0xcccccccc;
+ uint32_t a1b1 = axb1 & 0xcccccccc;
+ uint32_t a1b1_2 = a1b1 >> 2;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf4v_mul_2_u32(a1b1_2);
+}
+
+
+static inline uint32_t _gf4v_mul_u32_u32(uint32_t a0, uint32_t a1, uint32_t b0, uint32_t b1) {
+ uint32_t c0 = a0 & b0;
+ uint32_t c2 = a1 & b1;
+ uint32_t c1_ = (a0 ^ a1) & (b0 ^ b1);
+ return ((c1_ ^ c0) << 1) ^ c0 ^ c2;
+}
+
+uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16_is_nonzero(uint8_t a) {
+ unsigned int a4 = a & 0xf;
+ unsigned int r = ((unsigned int)0) - a4;
+ r >>= 4;
+ return r & 1;
+}
+
+uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16_inv(uint8_t a) {
+ uint8_t a2 = gf16_squ(a);
+ uint8_t a4 = gf16_squ(a2);
+ uint8_t a8 = gf16_squ(a4);
+ uint8_t a6 = gf16_mul(a4, a2);
+ return gf16_mul(a8, a6);
+}
+
+static inline uint32_t _gf16v_mul_u32_u32(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) {
+ uint32_t c0 = _gf4v_mul_u32_u32(a0, a1, b0, b1);
+ uint32_t c1_ = _gf4v_mul_u32_u32(a0 ^ a2, a1 ^ a3, b0 ^ b2, b1 ^ b3);
+
+ uint32_t c2_0 = a2 & b2;
+ uint32_t c2_2 = a3 & b3;
+ uint32_t c2_1_ = (a2 ^ a3) & (b2 ^ b3);
+ uint32_t c2_r0 = c2_0 ^ c2_2;
+ uint32_t c2_r1 = c2_0 ^ c2_1_;
+ // GF(4) x2: (bit0<<1)^bit1^(bit1>>1);
+ return ((c1_ ^ c0) << 2) ^ c0 ^ (c2_r0 << 1) ^ c2_r1 ^ (c2_r1 << 1);
+}
+
+uint32_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_u32_u32(uint32_t a, uint32_t b) {
+ uint32_t a0 = a & 0x11111111;
+ uint32_t a1 = (a >> 1) & 0x11111111;
+ uint32_t a2 = (a >> 2) & 0x11111111;
+ uint32_t a3 = (a >> 3) & 0x11111111;
+ uint32_t b0 = b & 0x11111111;
+ uint32_t b1 = (b >> 1) & 0x11111111;
+ uint32_t b2 = (b >> 2) & 0x11111111;
+ uint32_t b3 = (b >> 3) & 0x11111111;
+
+ return _gf16v_mul_u32_u32(a0, a1, a2, a3, b0, b1, b2, b3);
+}
+
+static inline uint8_t gf256v_reduce_u32(uint32_t a) {
+ // https://godbolt.org/z/7hirMb
+ uint16_t *aa = (uint16_t *)(&a);
+ uint16_t r = aa[0] ^ aa[1];
+ uint8_t *rr = (uint8_t *)(&r);
+ return rr[0] ^ rr[1];
+}
+
+uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_reduce_u32(uint32_t a) {
+ uint8_t r256 = gf256v_reduce_u32(a);
+ return (uint8_t)((r256 & 0xf) ^ (r256 >> 4));
+}
+
diff --git a/crypto_sign/rainbowIa-classic/clean/gf.h b/crypto_sign/rainbowIa-classic/clean/gf.h
new file mode 100644
index 00000000..e84d086d
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/gf.h
@@ -0,0 +1,20 @@
+#ifndef _GF16_H_
+#define _GF16_H_
+
+#include "rainbow_config.h"
+#include
+
+/// @file gf16.h
+/// @brief Library for arithmetics in GF(16) and GF(256)
+///
+
+uint32_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b);
+
+
+uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16_is_nonzero(uint8_t a);
+uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16_inv(uint8_t a);
+uint32_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_u32_u32(uint32_t a, uint32_t b);
+uint8_t PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_reduce_u32(uint32_t a);
+
+
+#endif // _GF16_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/parallel_matrix_op.c b/crypto_sign/rainbowIa-classic/clean/parallel_matrix_op.c
new file mode 100644
index 00000000..8d1f0a95
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/parallel_matrix_op.c
@@ -0,0 +1,182 @@
+/// @file parallel_matrix_op.c
+/// @brief the standard implementations for functions in parallel_matrix_op.h
+///
+/// the standard implementations for functions in parallel_matrix_op.h
+///
+
+#include "parallel_matrix_op.h"
+#include "blas.h"
+#include "blas_comm.h"
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim) {
+ return (dim + dim - i_row + 1) * i_row / 2 + j_col - i_row;
+}
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle or lower-triangle matrix.
+///
+/// @param[in] i_row - the i-th row in a triangle matrix.
+/// @param[in] j_col - the j-th column in a triangle matrix.
+/// @param[in] dim - the dimension of the triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+static inline unsigned int idx_of_2trimat(unsigned int i_row, unsigned int j_col, unsigned int n_var) {
+ if (i_row > j_col) {
+ return PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(j_col, i_row, n_var);
+ }
+ return PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(i_row, j_col, n_var);
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch) {
+ unsigned char *runningC = btriC;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < i; j++) {
+ unsigned int idx = PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(j, i, Aheight);
+ gf256v_add(btriC + idx * size_batch, bA + size_batch * (i * Awidth + j), size_batch);
+ }
+ gf256v_add(runningC, bA + size_batch * (i * Awidth + i), size_batch * (Aheight - i));
+ runningC += size_batch * (Aheight - i);
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (k < i) {
+ continue;
+ }
+ gf16v_madd(bC, &btriA[(k - i) * size_batch], PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ btriA += (Aheight - i) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i < k) {
+ continue;
+ }
+ gf16v_madd(bC, &btriA[size_batch * (PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(k, i, Aheight))], PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i == k) {
+ continue;
+ }
+ gf16v_madd(bC, &btriA[size_batch * (idx_of_2trimat(i, k, Aheight))], PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_matTr_madd_gf16(unsigned char *bC, const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Atr_height = Awidth;
+ unsigned int Atr_width = Aheight;
+ for (unsigned int i = 0; i < Atr_height; i++) {
+ for (unsigned int j = 0; j < Atr_width; j++) {
+ gf16v_madd(bC, &bB[j * Bwidth * size_batch], PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(&A_to_tr[size_Acolvec * i], j), size_batch * Bwidth);
+ }
+ bC += size_batch * Bwidth;
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ const unsigned char *bA = bA_to_tr;
+ unsigned int Aheight = Awidth_before_tr;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf16v_madd(bC, &bA[size_batch * (i + k * Aheight)], PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf16v_madd(bC, &bA[k * size_batch], PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ bA += (Awidth) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y, const unsigned char *mat,
+ const unsigned char *x, unsigned int dim_x, unsigned int size_batch) {
+ unsigned char tmp[128];
+
+ unsigned char _x[128];
+ for (unsigned int i = 0; i < dim_x; i++) {
+ _x[i] = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(x, i);
+ }
+ unsigned char _y[128];
+ for (unsigned int i = 0; i < dim_y; i++) {
+ _y[i] = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(y, i);
+ }
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_set_zero(z, size_batch);
+ for (unsigned int i = 0; i < dim_y; i++) {
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = 0; j < dim_x; j++) {
+ gf16v_madd(tmp, mat, _x[j], size_batch);
+ mat += size_batch;
+ }
+ gf16v_madd(z, tmp, _y[i], size_batch);
+ }
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch) {
+ unsigned char tmp[256];
+
+ unsigned char _x[256];
+ for (unsigned int i = 0; i < dim; i++) {
+ _x[i] = PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele(x, i);
+ }
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_set_zero(y, size_batch);
+ for (unsigned int i = 0; i < dim; i++) {
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = i; j < dim; j++) {
+ gf16v_madd(tmp, trimat, _x[j], size_batch);
+ trimat += size_batch;
+ }
+ gf16v_madd(y, tmp, _x[i], size_batch);
+ }
+}
diff --git a/crypto_sign/rainbowIa-classic/clean/parallel_matrix_op.h b/crypto_sign/rainbowIa-classic/clean/parallel_matrix_op.h
new file mode 100644
index 00000000..b9f8b8c5
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/parallel_matrix_op.h
@@ -0,0 +1,260 @@
+#ifndef _P_MATRIX_OP_H_
+#define _P_MATRIX_OP_H_
+/// @file parallel_matrix_op.h
+/// @brief Librarys for operations of batched matrixes.
+///
+///
+
+//////////////// Section: triangle matrix <-> rectangle matrix ///////////////////////////////////
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim);
+
+///
+/// @brief Upper trianglize a rectangle matrix to the corresponding upper-trangle matrix.
+///
+/// @param[out] btriC - the batched upper-trianglized matrix C.
+/// @param[in] bA - a batched retangle matrix A.
+/// @param[in] bwidth - the width of the batched matrix A, i.e., A is a Awidth x Awidth matrix.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch);
+
+//////////////////// Section: matrix multiplications ///////////////////////////////
+
+///
+/// @brief bC += btriA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. A will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A, which will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_matTr_madd_gf16(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_matTr_madd_gf256(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+//////////////////// Section: "quadratric" matrix evaluation ///////////////////////////////
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(16)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(256)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(16)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(256)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+#endif // _P_MATRIX_OP_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/rainbow.c b/crypto_sign/rainbowIa-classic/clean/rainbow.c
new file mode 100644
index 00000000..e51d867c
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/rainbow.c
@@ -0,0 +1,169 @@
+/// @file rainbow.c
+/// @brief The standard implementations for functions in rainbow.h
+///
+
+#include "rainbow.h"
+#include "blas.h"
+#include "rainbow_blas.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "utils_hash.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+#define MAX_ATTEMPT_FRMAT 128
+#define _MAX_O ((_O1 > _O2) ? _O1 : _O2)
+#define _MAX_O_BYTE ((_O1_BYTE > _O2_BYTE) ? _O1_BYTE : _O2_BYTE)
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *_digest) {
+ uint8_t mat_l1[_O1 * _O1_BYTE];
+ uint8_t mat_l2[_O2 * _O2_BYTE];
+ uint8_t mat_buffer[2 * _MAX_O * _MAX_O_BYTE];
+
+ // setup PRNG
+ prng_t prng_sign;
+ uint8_t prng_preseed[LEN_SKSEED + _HASH_LEN];
+ memcpy(prng_preseed, sk->sk_seed, LEN_SKSEED);
+ memcpy(prng_preseed + LEN_SKSEED, _digest, _HASH_LEN); // prng_preseed = sk_seed || digest
+ uint8_t prng_seed[_HASH_LEN];
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_hash_msg(prng_seed, _HASH_LEN, prng_preseed, _HASH_LEN + LEN_SKSEED);
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_set(&prng_sign, prng_seed, _HASH_LEN); // seed = H( sk_seed || digest )
+ for (unsigned int i = 0; i < LEN_SKSEED + _HASH_LEN; i++) {
+ prng_preseed[i] ^= prng_preseed[i]; // clean
+ }
+ for (unsigned int i = 0; i < _HASH_LEN; i++) {
+ prng_seed[i] ^= prng_seed[i]; // clean
+ }
+
+ // roll vinegars.
+ uint8_t vinegar[_V1_BYTE];
+ unsigned int n_attempt = 0;
+ unsigned int l1_succ = 0;
+ while (!l1_succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(&prng_sign, vinegar, _V1_BYTE); // generating vinegars
+ gfmat_prod(mat_l1, sk->l1_F2, _O1 * _O1_BYTE, _V1, vinegar); // generating the linear equations for layer 1
+ l1_succ = gfmat_inv(mat_l1, mat_l1, _O1, mat_buffer); // check if the linear equation solvable
+ n_attempt++;
+ }
+
+ // Given the vinegars, pre-compute variables needed for layer 2
+ uint8_t r_l1_F1[_O1_BYTE] = {0};
+ uint8_t r_l2_F1[_O2_BYTE] = {0};
+ batch_quad_trimat_eval(r_l1_F1, sk->l1_F1, vinegar, _V1, _O1_BYTE);
+ batch_quad_trimat_eval(r_l2_F1, sk->l2_F1, vinegar, _V1, _O2_BYTE);
+ uint8_t mat_l2_F3[_O2 * _O2_BYTE];
+ uint8_t mat_l2_F2[_O1 * _O2_BYTE];
+ gfmat_prod(mat_l2_F3, sk->l2_F3, _O2 * _O2_BYTE, _V1, vinegar);
+ gfmat_prod(mat_l2_F2, sk->l2_F2, _O1 * _O2_BYTE, _V1, vinegar);
+
+ // Some local variables.
+ uint8_t _z[_PUB_M_BYTE];
+ uint8_t y[_PUB_M_BYTE];
+ uint8_t *x_v1 = vinegar;
+ uint8_t x_o1[_O1_BYTE];
+ uint8_t x_o2[_O1_BYTE];
+
+ uint8_t digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, _digest, _HASH_LEN);
+ uint8_t *salt = digest_salt + _HASH_LEN;
+
+ uint8_t temp_o[_MAX_O_BYTE + 32] = {0};
+ unsigned int succ = 0;
+ while (!succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ // The computation: H(digest||salt) --> z --S--> y --C-map--> x --T--> w
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(&prng_sign, salt, _SALT_BYTE); // roll the salt
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_hash_msg(_z, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H(digest||salt)
+
+ // y = S^-1 * z
+ memcpy(y, _z, _PUB_M_BYTE); // identity part of S
+ gfmat_prod(temp_o, sk->s1, _O1_BYTE, _O2, _z + _O1_BYTE);
+ gf256v_add(y, temp_o, _O1_BYTE);
+
+ // Central Map:
+ // layer 1: calculate x_o1
+ memcpy(temp_o, r_l1_F1, _O1_BYTE);
+ gf256v_add(temp_o, y, _O1_BYTE);
+ gfmat_prod(x_o1, mat_l1, _O1_BYTE, _O1, temp_o);
+
+ // layer 2: calculate x_o2
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf256v_set_zero(temp_o, _O2_BYTE);
+ gfmat_prod(temp_o, mat_l2_F2, _O2_BYTE, _O1, x_o1); // F2
+ batch_quad_trimat_eval(mat_l2, sk->l2_F5, x_o1, _O1, _O2_BYTE); // F5
+ gf256v_add(temp_o, mat_l2, _O2_BYTE);
+ gf256v_add(temp_o, r_l2_F1, _O2_BYTE); // F1
+ gf256v_add(temp_o, y + _O1_BYTE, _O2_BYTE);
+
+ // generate the linear equations of the 2nd layer
+ gfmat_prod(mat_l2, sk->l2_F6, _O2 * _O2_BYTE, _O1, x_o1); // F6
+ gf256v_add(mat_l2, mat_l2_F3, _O2 * _O2_BYTE); // F3
+ succ = gfmat_inv(mat_l2, mat_l2, _O2, mat_buffer);
+ gfmat_prod(x_o2, mat_l2, _O2_BYTE, _O2, temp_o); // solve l2 eqs
+
+ n_attempt++;
+ };
+ // w = T^-1 * y
+ uint8_t w[_PUB_N_BYTE];
+ // identity part of T.
+ memcpy(w, x_v1, _V1_BYTE);
+ memcpy(w + _V1_BYTE, x_o1, _O1_BYTE);
+ memcpy(w + _V2_BYTE, x_o2, _O2_BYTE);
+ // Computing the t1 part.
+ gfmat_prod(y, sk->t1, _V1_BYTE, _O1, x_o1);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t4 part.
+ gfmat_prod(y, sk->t4, _V1_BYTE, _O2, x_o2);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t3 part.
+ gfmat_prod(y, sk->t3, _O1_BYTE, _O2, x_o2);
+ gf256v_add(w + _V1_BYTE, y, _O1_BYTE);
+
+ memset(signature, 0, _SIGNATURE_BYTE); // set the output 0
+ // clean
+ memset(&prng_sign, 0, sizeof(prng_t));
+ memset(vinegar, 0, _V1_BYTE);
+ memset(r_l1_F1, 0, _O1_BYTE);
+ memset(r_l2_F1, 0, _O2_BYTE);
+ memset(_z, 0, _PUB_M_BYTE);
+ memset(y, 0, _PUB_M_BYTE);
+ memset(x_o1, 0, _O1_BYTE);
+ memset(x_o2, 0, _O2_BYTE);
+ memset(temp_o, 0, sizeof(temp_o));
+
+ // return: copy w and salt to the signature.
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ return -1;
+ }
+ gf256v_add(signature, w, _PUB_N_BYTE);
+ gf256v_add(signature + _PUB_N_BYTE, salt, _SALT_BYTE);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk) {
+ unsigned char digest_ck[_PUB_M_BYTE];
+ // public_map( digest_ck , pk , signature ); Evaluating the quadratic public polynomials.
+ batch_quad_trimat_eval(digest_ck, pk->pk, signature, _PUB_N, _PUB_M_BYTE);
+
+ unsigned char correct[_PUB_M_BYTE];
+ unsigned char digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, digest, _HASH_LEN);
+ memcpy(digest_salt + _HASH_LEN, signature + _PUB_N_BYTE, _SALT_BYTE);
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_hash_msg(correct, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H( digest || salt )
+
+ // check consistancy.
+ unsigned char cc = 0;
+ for (unsigned int i = 0; i < _PUB_M_BYTE; i++) {
+ cc |= (digest_ck[i] ^ correct[i]);
+ }
+ return (0 == cc) ? 0 : -1;
+}
+
+
diff --git a/crypto_sign/rainbowIa-classic/clean/rainbow.h b/crypto_sign/rainbowIa-classic/clean/rainbow.h
new file mode 100644
index 00000000..7cf8e077
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/rainbow.h
@@ -0,0 +1,33 @@
+#ifndef _RAINBOW_H_
+#define _RAINBOW_H_
+/// @file rainbow.h
+/// @brief APIs for rainbow.
+///
+
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+
+#include
+
+///
+/// @brief Signing function for classical secret key.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk);
+
+
+
+#endif // _RAINBOW_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/rainbow_blas.h b/crypto_sign/rainbowIa-classic/clean/rainbow_blas.h
new file mode 100644
index 00000000..773fa291
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/rainbow_blas.h
@@ -0,0 +1,31 @@
+#ifndef _RAINBOW_BLAS_H_
+#define _RAINBOW_BLAS_H_
+/// @file rainbow_blas.h
+/// @brief Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+///
+/// Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+
+#include "blas.h"
+#include "parallel_matrix_op.h"
+#include "rainbow_config.h"
+
+
+#define gfv_get_ele PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_get_ele
+#define gfv_mul_scalar PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_mul_scalar
+#define gfv_madd PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16v_madd
+
+#define gfmat_prod PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_prod
+#define gfmat_inv PQCLEAN_RAINBOWIACLASSIC_CLEAN_gf16mat_inv
+
+#define batch_trimat_madd PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_trimat_madd_gf16
+#define batch_trimatTr_madd PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_trimatTr_madd_gf16
+#define batch_2trimat_madd PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_2trimat_madd_gf16
+#define batch_matTr_madd PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_matTr_madd_gf16
+#define batch_bmatTr_madd PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_bmatTr_madd_gf16
+#define batch_mat_madd PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_mat_madd_gf16
+
+#define batch_quad_trimat_eval PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_quad_trimat_eval_gf16
+#define batch_quad_recmat_eval PQCLEAN_RAINBOWIACLASSIC_CLEAN_batch_quad_recmat_eval_gf16
+
+
+#endif // _RAINBOW_BLAS_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/rainbow_config.h b/crypto_sign/rainbowIa-classic/clean/rainbow_config.h
new file mode 100644
index 00000000..2222abe1
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/rainbow_config.h
@@ -0,0 +1,47 @@
+#ifndef _H_RAINBOW_CONFIG_H_
+#define _H_RAINBOW_CONFIG_H_
+
+/// @file rainbow_config.h
+/// @brief Defining the parameters of the Rainbow and the corresponding constants.
+///
+
+#define _USE_GF16
+#define _GFSIZE 16
+#define _V1 32
+#define _O1 32
+#define _O2 32
+#define _HASH_LEN 32
+
+
+#define _V2 ((_V1) + (_O1))
+
+/// size of N, in # of gf elements.
+#define _PUB_N (_V1 + _O1 + _O2)
+
+/// size of M, in # gf elements.
+#define _PUB_M (_O1 + _O2)
+
+/// size of variables, in # bytes.
+
+// GF16
+#define _V1_BYTE (_V1 / 2)
+#define _V2_BYTE (_V2 / 2)
+#define _O1_BYTE (_O1 / 2)
+#define _O2_BYTE (_O2 / 2)
+#define _PUB_N_BYTE (_PUB_N / 2)
+#define _PUB_M_BYTE (_PUB_M / 2)
+
+
+/// length of seed for public key, in # bytes
+#define LEN_PKSEED 32
+
+/// length of seed for secret key, in # bytes
+#define LEN_SKSEED 32
+
+/// length of salt for a signature, in # bytes
+#define _SALT_BYTE 16
+
+/// length of a signature
+#define _SIGNATURE_BYTE (_PUB_N_BYTE + _SALT_BYTE)
+
+#endif // _H_RAINBOW_CONFIG_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/rainbow_keypair.c b/crypto_sign/rainbowIa-classic/clean/rainbow_keypair.c
new file mode 100644
index 00000000..5abe1159
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/rainbow_keypair.c
@@ -0,0 +1,126 @@
+/// @file rainbow_keypair.c
+/// @brief implementations of functions in rainbow_keypair.h
+///
+
+#include "rainbow_keypair.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair_computation.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+static void generate_S_T(unsigned char *s_and_t, prng_t *prng0) {
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // S1
+ s_and_t += _O1_BYTE * _O2;
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O1); // T1
+ s_and_t += _V1_BYTE * _O1;
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O2); // T2
+ s_and_t += _V1_BYTE * _O2;
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // T3
+}
+
+static unsigned int generate_l1_F12(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * N_TRIANGLE_TERMS(_V1)); // l1_F1
+ sk += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * _V1 * _O1); // l1_F2
+ n_byte_generated += _O1_BYTE * _V1 * _O1;
+ return n_byte_generated;
+}
+
+static unsigned int generate_l2_F12356(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // l2_F1
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O1); // l2_F2
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O2); // l2_F3
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // l2_F5
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _O1 * _O2); // l2_F6
+ n_byte_generated += _O2_BYTE * _O1 * _O2;
+
+ return n_byte_generated;
+}
+
+static void generate_B1_B2(unsigned char *sk, prng_t *prng0) {
+ sk += generate_l1_F12(sk, prng0);
+ generate_l2_F12356(sk, prng0);
+}
+
+static void calculate_t4(unsigned char *t2_to_t4, const unsigned char *t1, const unsigned char *t3) {
+ // t4 = T_sk.t1 * T_sk.t3 - T_sk.t2
+ unsigned char temp[_V1_BYTE + 32];
+ unsigned char *t4 = t2_to_t4;
+ for (unsigned int i = 0; i < _O2; i++) { /// t3 width
+ gfmat_prod(temp, t1, _V1_BYTE, _O1, t3);
+ gf256v_add(t4, temp, _V1_BYTE);
+ t4 += _V1_BYTE;
+ t3 += _O1_BYTE;
+ }
+}
+
+static void obsfucate_l1_polys(unsigned char *l1_polys, const unsigned char *l2_polys, unsigned int n_terms, const unsigned char *s1) {
+ unsigned char temp[_O1_BYTE + 32];
+ while (n_terms--) {
+ gfmat_prod(temp, s1, _O1_BYTE, _O2, l2_polys);
+ gf256v_add(l1_polys, temp, _O1_BYTE);
+ l1_polys += _O1_BYTE;
+ l2_polys += _O2_BYTE;
+ }
+}
+
+/////////////////// Classic //////////////////////////////////
+
+static void _generate_secretkey(sk_t *sk, const unsigned char *sk_seed) {
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // set up prng
+ prng_t prng0;
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_set(&prng0, sk_seed, LEN_SKSEED);
+
+ // generating secret key with prng.
+ generate_S_T(sk->s1, &prng0);
+ generate_B1_B2(sk->l1_F1, &prng0);
+
+ // clean prng
+ memset(&prng0, 0, sizeof(prng_t));
+}
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_generate_keypair(pk_t *rpk, sk_t *sk, const unsigned char *sk_seed) {
+ _generate_secretkey(sk, sk_seed);
+
+ // set up a temporary structure ext_cpk_t for calculating public key.
+ ext_cpk_t pk;
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_calculate_Q_from_F(&pk, sk, sk); // compute the public key in ext_cpk_t format.
+ calculate_t4(sk->t4, sk->t1, sk->t3);
+
+ obsfucate_l1_polys(pk.l1_Q1, pk.l2_Q1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(pk.l1_Q2, pk.l2_Q2, _V1 * _O1, sk->s1);
+ obsfucate_l1_polys(pk.l1_Q3, pk.l2_Q3, _V1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk.l1_Q5, pk.l2_Q5, N_TRIANGLE_TERMS(_O1), sk->s1);
+ obsfucate_l1_polys(pk.l1_Q6, pk.l2_Q6, _O1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk.l1_Q9, pk.l2_Q9, N_TRIANGLE_TERMS(_O2), sk->s1);
+ // so far, the pk contains the full pk but in ext_cpk_t format.
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_extcpk_to_pk(rpk, &pk); // convert the public key from ext_cpk_t to pk_t.
+}
+
+
+
diff --git a/crypto_sign/rainbowIa-classic/clean/rainbow_keypair.h b/crypto_sign/rainbowIa-classic/clean/rainbow_keypair.h
new file mode 100644
index 00000000..f614f064
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/rainbow_keypair.h
@@ -0,0 +1,61 @@
+#ifndef _RAINBOW_KEYPAIR_H_
+#define _RAINBOW_KEYPAIR_H_
+/// @file rainbow_keypair.h
+/// @brief Formats of key pairs and functions for generating key pairs.
+/// Formats of key pairs and functions for generating key pairs.
+///
+
+#include "rainbow_config.h"
+
+#define N_TRIANGLE_TERMS(n_var) ((n_var) * ((n_var) + 1) / 2)
+
+/// @brief public key for classic rainbow
+///
+/// public key for classic rainbow
+///
+typedef struct rainbow_publickey {
+ unsigned char pk[(_PUB_M_BYTE)*N_TRIANGLE_TERMS(_PUB_N)];
+} pk_t;
+
+/// @brief secret key for classic rainbow
+///
+/// secret key for classic rainbow
+///
+typedef struct rainbow_secretkey {
+ ///
+ /// seed for generating secret key.
+ /// Generating S, T, and F for classic rainbow.
+ /// Generating S and T only for cyclic rainbow.
+ unsigned char sk_seed[LEN_SKSEED];
+
+ unsigned char s1[_O1_BYTE * _O2]; ///< part of S map
+ unsigned char t1[_V1_BYTE * _O1]; ///< part of T map
+ unsigned char t4[_V1_BYTE * _O2]; ///< part of T map
+ unsigned char t3[_O1_BYTE * _O2]; ///< part of T map
+
+ unsigned char l1_F1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer1
+ unsigned char l1_F2[_O1_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer1
+
+ unsigned char l2_F1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer2
+ unsigned char l2_F2[_O2_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer2
+
+ unsigned char l2_F3[_O2_BYTE * _V1 * _O2]; ///< part of C-map, F3, Layer2
+ unsigned char l2_F5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< part of C-map, F5, Layer2
+ unsigned char l2_F6[_O2_BYTE * _O1 * _O2]; ///< part of C-map, F6, Layer2
+} sk_t;
+
+
+///
+/// @brief Generate key pairs for classic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the secret key.
+/// @param[in] sk_seed - seed for generating the secret key.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_generate_keypair(pk_t *pk, sk_t *sk, const unsigned char *sk_seed);
+
+
+
+
+
+#endif // _RAINBOW_KEYPAIR_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/rainbow_keypair_computation.c b/crypto_sign/rainbowIa-classic/clean/rainbow_keypair_computation.c
new file mode 100644
index 00000000..88ad49bd
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/rainbow_keypair_computation.c
@@ -0,0 +1,189 @@
+/// @file rainbow_keypair_computation.c
+/// @brief Implementations for functions in rainbow_keypair_computation.h
+///
+
+#include "rainbow_keypair_computation.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair.h"
+#include
+#include
+#include
+
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk) {
+ const unsigned char *idx_l1 = cpk->l1_Q1;
+ const unsigned char *idx_l2 = cpk->l2_Q1;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = i; j < _V1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q2;
+ idx_l2 = cpk->l2_Q2;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q3;
+ idx_l2 = cpk->l2_Q3;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q5;
+ idx_l2 = cpk->l2_Q5;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = i; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q6;
+ idx_l2 = cpk->l2_Q6;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q9;
+ idx_l2 = cpk->l2_Q9;
+ for (unsigned int i = _V1 + _O1; i < _PUB_N; i++) {
+ for (unsigned int j = i; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+}
+
+static void calculate_Q_from_F_ref(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ /*
+ Layer 1
+ Computing :
+ Q_pk.l1_F1s[i] = F_sk.l1_F1s[i]
+
+ Q_pk.l1_F2s[i] = (F1* T1 + F2) + F1tr * t1
+ Q_pk.l1_F5s[i] = UT( T1tr* (F1 * T1 + F2) )
+ */
+ const unsigned char *t2 = Ts->t4;
+
+ memcpy(Qs->l1_Q1, Fs->l1_F1, _O1_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ memcpy(Qs->l1_Q2, Fs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_trimat_madd(Qs->l1_Q2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // F1*T1 + F2
+
+ memset(Qs->l1_Q3, 0, _O1_BYTE * _V1 * _O2);
+ memset(Qs->l1_Q5, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O1));
+ memset(Qs->l1_Q6, 0, _O1_BYTE * _O1 * _O2);
+ memset(Qs->l1_Q9, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ // l1_Q5 : _O1_BYTE * _O1 * _O1
+ // l1_Q9 : _O1_BYTE * _O2 * _O2
+ // l2_Q5 : _O2_BYTE * _V1 * _O1
+ // l2_Q9 : _O2_BYTE * _V1 * _O2
+
+ unsigned char tempQ[_O1_BYTE * _O1 * _O1 + 32];
+
+ memset(tempQ, 0, _O1_BYTE * _O1 * _O1); // l1_Q5
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q2, _O1, _O1_BYTE); // t1_tr*(F1*T1 + F2)
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_UpperTrianglize(Qs->l1_Q5, tempQ, _O1, _O1_BYTE); // UT( ... ) // Q5
+
+ batch_trimatTr_madd(Qs->l1_Q2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // Q2
+ /*
+ Computing:
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+ Q_pk.l1_F3s[i] = F1_F1T_T2 + F2_T3
+ Q_pk.l1_F6s[i] = T1tr* ( F1_F1T_T2 + F2_T3 ) + F2tr * t2
+ Q_pk.l1_F9s[i] = UT( T2tr* ( F1_T2 + F2_T3 ) )
+ */
+ batch_trimat_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1*T2
+ batch_mat_madd(Qs->l1_Q3, Fs->l1_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O1_BYTE); // F1_T2 + F2_T3
+
+ memset(tempQ, 0, _O1_BYTE * _O2 * _O2); // l1_Q9
+ batch_matTr_madd(tempQ, t2, _V1, _V1_BYTE, _O2, Qs->l1_Q3, _O2, _O1_BYTE); // T2tr * ( F1_T2 + F2_T3 )
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_UpperTrianglize(Qs->l1_Q9, tempQ, _O2, _O1_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1_F1T_T2 + F2_T3 // Q3
+
+ batch_bmatTr_madd(Qs->l1_Q6, Fs->l1_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F2tr*T2
+ batch_matTr_madd(Qs->l1_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q3, _O2, _O1_BYTE); // Q6
+
+ /*
+ layer 2
+ Computing:
+ Q1 = F1
+ Q2 = F1_F1T*T1 + F2
+ Q5 = UT( T1tr( F1*T1 + F2 ) + F5 )
+ */
+ memcpy(Qs->l2_Q1, Fs->l2_F1, _O2_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ memcpy(Qs->l2_Q2, Fs->l2_F2, _O2_BYTE * _V1 * _O1);
+ batch_trimat_madd(Qs->l2_Q2, Fs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // F1*T1 + F2
+
+ memcpy(Qs->l2_Q5, Fs->l2_F5, _O2_BYTE * N_TRIANGLE_TERMS(_O1));
+ memset(tempQ, 0, _O2_BYTE * _O1 * _O1); // l2_Q5
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l2_Q2, _O1, _O2_BYTE); // t1_tr*(F1*T1 + F2)
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_UpperTrianglize(Qs->l2_Q5, tempQ, _O1, _O2_BYTE); // UT( ... ) // Q5
+
+ batch_trimatTr_madd(Qs->l2_Q2, Fs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // Q2
+
+ /*
+ Computing:
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+
+ Q3 = F1_F1T*T2 + F2*T3 + F3
+ Q9 = UT( T2tr*( F1*T2 + F2*T3 + F3 ) + T3tr*( F5*T3 + F6 ) )
+ Q6 = T1tr*( F1_F1T*T2 + F2*T3 + F3 ) + F2Tr*T2 + F5_F5T*T3 + F6
+ */
+ memcpy(Qs->l2_Q3, Fs->l2_F3, _O2_BYTE * _V1 * _O2);
+ batch_trimat_madd(Qs->l2_Q3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1*T2 + F3
+ batch_mat_madd(Qs->l2_Q3, Fs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F1_T2 + F2_T3 + F3
+
+ memset(tempQ, 0, _O2_BYTE * _O2 * _O2); // l2_Q9
+ batch_matTr_madd(tempQ, t2, _V1, _V1_BYTE, _O2, Qs->l2_Q3, _O2, _O2_BYTE); // T2tr * ( ..... )
+
+ memcpy(Qs->l2_Q6, Fs->l2_F6, _O2_BYTE * _O1 * _O2);
+
+ batch_trimat_madd(Qs->l2_Q6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6
+ batch_matTr_madd(tempQ, Ts->t3, _O1, _O1_BYTE, _O2, Qs->l2_Q6, _O2, _O2_BYTE); // T2tr*( ..... ) + T3tr*( ..... )
+ memset(Qs->l2_Q9, 0, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_UpperTrianglize(Qs->l2_Q9, tempQ, _O2, _O2_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l2_Q3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1_F1T_T2 + F2_T3 + F3 // Q3
+
+ batch_bmatTr_madd(Qs->l2_Q6, Fs->l2_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6 + F2tr*T2
+ batch_trimatTr_madd(Qs->l2_Q6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F2tr*T2 + F5_F5T*T3 + F6
+ batch_matTr_madd(Qs->l2_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l2_Q3, _O2, _O2_BYTE); // Q6
+}
+#define calculate_Q_from_F_impl calculate_Q_from_F_ref
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ calculate_Q_from_F_impl(Qs, Fs, Ts);
+}
diff --git a/crypto_sign/rainbowIa-classic/clean/rainbow_keypair_computation.h b/crypto_sign/rainbowIa-classic/clean/rainbow_keypair_computation.h
new file mode 100644
index 00000000..7f8b96d2
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/rainbow_keypair_computation.h
@@ -0,0 +1,53 @@
+#ifndef _RAINBOW_KEYPAIR_COMP_H_
+#define _RAINBOW_KEYPAIR_COMP_H_
+/// @file rainbow_keypair_computation.h
+/// @brief Functions for calculating pk/sk while generating keys.
+///
+/// Defining an internal structure of public key.
+/// Functions for calculating pk/sk for key generation.
+///
+
+#include "rainbow_keypair.h"
+
+/// @brief The (internal use) public key for rainbow
+///
+/// The (internal use) public key for rainbow. The public
+/// polynomials are divided into l1_Q1, l1_Q2, ... l1_Q9,
+/// l2_Q1, .... , l2_Q9.
+///
+typedef struct rainbow_extend_publickey {
+ unsigned char l1_Q1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l1_Q2[_O1_BYTE * _V1 * _O1];
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2];
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2];
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)];
+
+ unsigned char l2_Q1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l2_Q2[_O2_BYTE * _V1 * _O1];
+ unsigned char l2_Q3[_O2_BYTE * _V1 * _O2];
+ unsigned char l2_Q5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l2_Q6[_O2_BYTE * _O1 * _O2];
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)];
+} ext_cpk_t;
+
+///
+/// @brief converting formats of public keys : from ext_cpk_t version to pk_t
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the internel public key.
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk);
+/////////////////////////////////////////////////
+
+///
+/// @brief Computing public key from secret key
+///
+/// @param[out] Qs - the public key
+/// @param[in] Fs - parts of the secret key: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the secret key: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIACLASSIC_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+
+#endif // _RAINBOW_KEYPAIR_COMP_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/sign.c b/crypto_sign/rainbowIa-classic/clean/sign.c
new file mode 100644
index 00000000..08405878
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/sign.c
@@ -0,0 +1,74 @@
+/// @file sign.c
+/// @brief the implementations for functions in api.h
+///
+///
+
+#include "api.h"
+#include "rainbow.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
+ unsigned char sk_seed[LEN_SKSEED] = {0};
+ randombytes(sk_seed, LEN_SKSEED);
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_generate_keypair((pk_t *)pk, (sk_t *)sk, sk_seed);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_crypto_sign(unsigned char *sm, size_t *smlen, const unsigned char *m, size_t mlen, const unsigned char *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+
+ memcpy(sm, m, mlen);
+ smlen[0] = mlen + _SIGNATURE_BYTE;
+
+ return PQCLEAN_RAINBOWIACLASSIC_CLEAN_rainbow_sign(sm + mlen, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_crypto_sign_open(unsigned char *m, size_t *mlen, const unsigned char *sm, size_t smlen, const unsigned char *pk) {
+ int rc;
+ if (_SIGNATURE_BYTE > smlen) {
+ rc = -1;
+ } else {
+ *mlen = smlen - _SIGNATURE_BYTE;
+
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, sm, *mlen);
+
+ rc = PQCLEAN_RAINBOWIACLASSIC_CLEAN_rainbow_verify(digest, sm + mlen[0], (const pk_t *)pk);
+ }
+ if (!rc) {
+ memcpy(m, sm, smlen - _SIGNATURE_BYTE);
+ } else { // bad signature
+ *mlen = (size_t) -1;
+ memset(m, 0, smlen);
+ }
+ return rc;
+}
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ *siglen = _SIGNATURE_BYTE;
+ return PQCLEAN_RAINBOWIACLASSIC_CLEAN_rainbow_sign(sig, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ if (siglen != _SIGNATURE_BYTE) {
+ return -1;
+ }
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ return PQCLEAN_RAINBOWIACLASSIC_CLEAN_rainbow_verify(digest, sig, (const pk_t *)pk);
+}
diff --git a/crypto_sign/rainbowIa-classic/clean/utils_hash.c b/crypto_sign/rainbowIa-classic/clean/utils_hash.c
new file mode 100644
index 00000000..052f53c8
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/utils_hash.c
@@ -0,0 +1,50 @@
+/// @file utils_hash.c
+/// @brief the adapter for SHA2 families.
+///
+///
+
+#include "utils_hash.h"
+#include "rainbow_config.h"
+#include "sha2.h"
+
+static inline int _hash(unsigned char *digest, const unsigned char *m, size_t mlen) {
+ sha256(digest, m, mlen);
+ return 0;
+}
+
+static inline int expand_hash(unsigned char *digest, size_t n_digest, const unsigned char *hash) {
+ if (_HASH_LEN >= n_digest) {
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[i] = hash[i];
+ }
+ return 0;
+ }
+ for (size_t i = 0; i < _HASH_LEN; i++) {
+ digest[i] = hash[i];
+ }
+ n_digest -= _HASH_LEN;
+
+ while (_HASH_LEN <= n_digest) {
+ _hash(digest + _HASH_LEN, digest, _HASH_LEN);
+
+ n_digest -= _HASH_LEN;
+ digest += _HASH_LEN;
+ }
+ unsigned char temp[_HASH_LEN];
+ if (n_digest) {
+ _hash(temp, digest, _HASH_LEN);
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[_HASH_LEN + i] = temp[i];
+ }
+ }
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_hash_msg(unsigned char *digest,
+ size_t len_digest,
+ const unsigned char *m,
+ size_t mlen) {
+ unsigned char buf[_HASH_LEN];
+ _hash(buf, m, mlen);
+ return expand_hash(digest, len_digest, buf);
+}
diff --git a/crypto_sign/rainbowIa-classic/clean/utils_hash.h b/crypto_sign/rainbowIa-classic/clean/utils_hash.h
new file mode 100644
index 00000000..da190bac
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/utils_hash.h
@@ -0,0 +1,11 @@
+#ifndef _UTILS_HASH_H_
+#define _UTILS_HASH_H_
+/// @file utils_hash.h
+/// @brief the interface for adapting hash functions.
+///
+
+#include
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_hash_msg(unsigned char *digest, size_t len_digest, const unsigned char *m, size_t mlen);
+
+#endif // _UTILS_HASH_H_
diff --git a/crypto_sign/rainbowIa-classic/clean/utils_prng.c b/crypto_sign/rainbowIa-classic/clean/utils_prng.c
new file mode 100644
index 00000000..36eae4b7
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/utils_prng.c
@@ -0,0 +1,95 @@
+/// @file utils_prng.c
+/// @brief The implementation of PRNG related functions.
+///
+
+#include "utils_prng.h"
+#include "aes.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+static void prng_update(const unsigned char *provided_data,
+ unsigned char *Key,
+ unsigned char *V) {
+ unsigned char temp[48];
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, Key);
+ for (int i = 0; i < 3; i++) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (V[j] == 0xff) {
+ V[j] = 0x00;
+ } else {
+ V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(temp + 16 * i, V, 1, &ctx);
+ }
+ if (provided_data != NULL) {
+ for (int i = 0; i < 48; i++) {
+ temp[i] ^= provided_data[i];
+ }
+ }
+ memcpy(Key, temp, 32);
+ memcpy(V, temp + 32, 16);
+}
+static void randombytes_init_with_state(prng_t *state,
+ unsigned char *entropy_input_48bytes) {
+ memset(state->Key, 0x00, 32);
+ memset(state->V, 0x00, 16);
+ prng_update(entropy_input_48bytes, state->Key, state->V);
+}
+
+static int randombytes_with_state(prng_t *state,
+ unsigned char *x,
+ size_t xlen) {
+
+ unsigned char block[16];
+ int i = 0;
+
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, state->Key);
+
+ while (xlen > 0) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (state->V[j] == 0xff) {
+ state->V[j] = 0x00;
+ } else {
+ state->V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(block, state->V, 1, &ctx);
+ if (xlen > 15) {
+ memcpy(x + i, block, 16);
+ i += 16;
+ xlen -= 16;
+ } else {
+ memcpy(x + i, block, xlen);
+ xlen = 0;
+ }
+ }
+ prng_update(NULL, state->Key, state->V);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen) {
+ unsigned char seed[48];
+ if (prng_seedlen >= 48) {
+ memcpy(seed, prng_seed, 48);
+ } else {
+ memcpy(seed, prng_seed, prng_seedlen);
+ PQCLEAN_RAINBOWIACLASSIC_CLEAN_hash_msg(seed + prng_seedlen, 48 - (unsigned)prng_seedlen, (const unsigned char *)prng_seed, prng_seedlen);
+ }
+
+ randombytes_init_with_state(ctx, seed);
+
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen) {
+ return randombytes_with_state(ctx, out, outlen);
+}
diff --git a/crypto_sign/rainbowIa-classic/clean/utils_prng.h b/crypto_sign/rainbowIa-classic/clean/utils_prng.h
new file mode 100644
index 00000000..0c1a5323
--- /dev/null
+++ b/crypto_sign/rainbowIa-classic/clean/utils_prng.h
@@ -0,0 +1,18 @@
+#ifndef _UTILS_PRNG_H_
+#define _UTILS_PRNG_H_
+/// @file utils_prng.h
+/// @brief the interface for adapting PRNG functions.
+///
+///
+
+#include "randombytes.h"
+
+typedef struct {
+ unsigned char Key[32];
+ unsigned char V[16];
+} prng_t;
+
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen);
+int PQCLEAN_RAINBOWIACLASSIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen);
+
+#endif // _UTILS_PRNG_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/META.yml b/crypto_sign/rainbowIa-cyclic-compressed/META.yml
new file mode 100644
index 00000000..ddf7caea
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/META.yml
@@ -0,0 +1,18 @@
+name: Rainbow-Ia-cyclic-compressed
+type: signature
+claimed-nist-level: 1
+length-public-key: 58144
+length-secret-key: 64
+length-signature: 64
+nistkat-sha256: 65bb9e9b68b3114105e86d1107ede320901e174770ff8474722b4f459c3f2a51
+testvectors-sha256: 79d0bfaee00d058aa39981397016279738925f65bfec1aebb42372030abc4056
+principal-submitters:
+ - Jintai Ding
+auxiliary-submitters:
+ - Ming-Shing Chen
+ - Albrecht Petzoldt
+ - Dieter Schmidt
+ - Bo-Yin Yang
+implementations:
+ - name: clean
+ version: https://github.com/fast-crypto-lab/rainbow-submission-round2/commit/af826fcb78f6af51a02d0352cff28a9690467bfd
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/LICENSE b/crypto_sign/rainbowIa-cyclic-compressed/clean/LICENSE
new file mode 100644
index 00000000..cb00a6e3
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/LICENSE
@@ -0,0 +1,8 @@
+`Software implementation of Rainbow for NIST R2 submission' by Ming-Shing Chen
+
+To the extent possible under law, the person who associated CC0 with
+`Software implementation of Rainbow for NIST R2 submission' has waived all copyright and related or neighboring rights
+to `Software implementation of Rainbow for NIST R2 submission'.
+
+You should have received a copy of the CC0 legalcode along with this
+work. If not, see .
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/Makefile b/crypto_sign/rainbowIa-cyclic-compressed/clean/Makefile
new file mode 100644
index 00000000..a2ea04cf
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=librainbowIa-cyclic-compressed_clean.a
+
+HEADERS = api.h blas_comm.h blas.h blas_u32.h gf.h parallel_matrix_op.h rainbow_blas.h rainbow_config.h rainbow.h rainbow_keypair_computation.h rainbow_keypair.h utils_hash.h utils_prng.h
+OBJECTS = blas_comm.o parallel_matrix_op.o rainbow.o rainbow_keypair.o rainbow_keypair_computation.o sign.o utils_hash.o utils_prng.o blas_u32.o gf.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/Makefile.Microsoft_nmake b/crypto_sign/rainbowIa-cyclic-compressed/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..cb4cedbd
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=librainbowIa-cyclic-compressed_clean.lib
+OBJECTS = blas_comm.obj parallel_matrix_op.obj rainbow.obj rainbow_keypair.obj rainbow_keypair_computation.obj sign.obj utils_hash.obj utils_prng.obj blas_u32.obj gf.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/api.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/api.h
new file mode 100644
index 00000000..6d2f6c21
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/api.h
@@ -0,0 +1,32 @@
+#ifndef PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_API_H
+#define PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_CRYPTO_SECRETKEYBYTES 64
+#define PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_CRYPTO_PUBLICKEYBYTES 58144
+#define PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_CRYPTO_BYTES 64
+#define PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_CRYPTO_ALGNAME "RAINBOW(16,32,32,32) - cyclic compressed"
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
+
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen,
+ const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen,
+ const uint8_t *pk);
+
+
+#endif
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/blas.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/blas.h
new file mode 100644
index 00000000..ff8aee9e
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/blas.h
@@ -0,0 +1,20 @@
+#ifndef _BLAS_H_
+#define _BLAS_H_
+/// @file blas.h
+/// @brief Defining the implementations for linear algebra functions depending on the machine architecture.
+///
+
+#include "blas_comm.h"
+#include "blas_u32.h"
+#include "rainbow_config.h"
+
+#define gf256v_predicated_add PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_predicated_add_u32
+#define gf256v_add PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_add_u32
+
+
+#define gf16v_mul_scalar PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_scalar_u32
+#define gf16v_madd PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_madd_u32
+#define gf16v_dot PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_dot_u32
+
+
+#endif // _BLAS_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_comm.c b/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_comm.c
new file mode 100644
index 00000000..3ab27446
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_comm.c
@@ -0,0 +1,150 @@
+/// @file blas_comm.c
+/// @brief The standard implementations for blas_comm.h
+///
+
+#include "blas_comm.h"
+#include "blas.h"
+#include "gf.h"
+#include "rainbow_config.h"
+
+#include
+#include
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte) {
+ gf256v_add(b, b, _num_byte);
+}
+
+/// @brief get an element from GF(16) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(const uint8_t *a, unsigned int i) {
+ uint8_t r = a[i >> 1];
+ uint8_t r0 = r & 0xf;
+ uint8_t r1 = r >> 4;
+ uint8_t m = (uint8_t)(-((int8_t)i & 1));
+ return (uint8_t)((r1 & m) | ((~m) & r0));
+}
+
+/// @brief set an element for a GF(16) vector .
+///
+/// @param[in,out] a - the vector a.
+/// @param[in] i - the index in the vector a.
+/// @param[in] v - the value for the i-th element in vector a.
+/// @return the value of the element.
+///
+static uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_set_ele(uint8_t *a, unsigned int i, uint8_t v) {
+ uint8_t m = (uint8_t)(0xf ^ (-((int8_t)i & 1))); /// 1--> 0xf0 , 0--> 0x0f
+ uint8_t ai_remaining = (uint8_t)(a[i >> 1] & (~m)); /// erase
+ a[i >> 1] = (uint8_t)(ai_remaining | (m & (v << 4)) | (m & v & 0xf)); /// set
+ return v;
+}
+
+static void gf16mat_prod_ref(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_set_zero(c, n_A_vec_byte);
+ for (unsigned int i = 0; i < n_A_width; i++) {
+ uint8_t bb = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(b, i);
+ gf16v_madd(c, matA, bb, n_A_vec_byte);
+ matA += n_A_vec_byte;
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec) {
+ unsigned int n_vec_byte = (len_vec + 1) / 2;
+ for (unsigned int k = 0; k < len_vec; k++) {
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_set_zero(c, n_vec_byte);
+ const uint8_t *bk = b + n_vec_byte * k;
+ for (unsigned int i = 0; i < len_vec; i++) {
+ uint8_t bb = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(bk, i);
+ gf16v_madd(c, a + n_vec_byte * i, bb, n_vec_byte);
+ }
+ c += n_vec_byte;
+ }
+}
+
+static unsigned int gf16mat_gauss_elim_ref(uint8_t *mat, unsigned int h, unsigned int w) {
+ unsigned int n_w_byte = (w + 1) / 2;
+ unsigned int r8 = 1;
+ for (unsigned int i = 0; i < h; i++) {
+ unsigned int offset_byte = i >> 1;
+ uint8_t *ai = mat + n_w_byte * i;
+ for (unsigned int j = i + 1; j < h; j++) {
+ uint8_t *aj = mat + n_w_byte * j;
+ gf256v_predicated_add(ai + offset_byte, !PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16_is_nonzero(PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(ai, i)), aj + offset_byte, n_w_byte - offset_byte);
+ }
+ uint8_t pivot = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(ai, i);
+ r8 &= PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16_is_nonzero(pivot);
+ pivot = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16_inv(pivot);
+ offset_byte = (i + 1) >> 1;
+ gf16v_mul_scalar(ai + offset_byte, pivot, n_w_byte - offset_byte);
+ for (unsigned int j = 0; j < h; j++) {
+ if (i == j) {
+ continue;
+ }
+ uint8_t *aj = mat + n_w_byte * j;
+ gf16v_madd(aj + offset_byte, ai + offset_byte, PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(aj, i), n_w_byte - offset_byte);
+ }
+ }
+ return r8;
+}
+
+static unsigned int gf16mat_solve_linear_eq_ref(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ uint8_t mat[64 * 33];
+ unsigned int n_byte = (n + 1) >> 1;
+ for (unsigned int i = 0; i < n; i++) {
+ memcpy(mat + i * (n_byte + 1), inp_mat + i * n_byte, n_byte);
+ mat[i * (n_byte + 1) + n_byte] = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(c_terms, i);
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_gauss_elim(mat, n, n + 2);
+ for (unsigned int i = 0; i < n; i++) {
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_set_ele(sol, i, mat[i * (n_byte + 1) + n_byte]);
+ }
+ return r8;
+}
+
+static inline void gf16mat_submat(uint8_t *mat2, unsigned int w2, unsigned int st, const uint8_t *mat, unsigned int w, unsigned int h) {
+ unsigned int n_byte_w1 = (w + 1) / 2;
+ unsigned int n_byte_w2 = (w2 + 1) / 2;
+ unsigned int st_2 = st / 2;
+ for (unsigned int i = 0; i < h; i++) {
+ for (unsigned int j = 0; j < n_byte_w2; j++) {
+ mat2[i * n_byte_w2 + j] = mat[i * n_byte_w1 + st_2 + j];
+ }
+ }
+}
+
+unsigned int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer) {
+ unsigned int n_w_byte = (H + 1) / 2;
+
+ uint8_t *aa = buffer;
+ for (unsigned int i = 0; i < H; i++) {
+ uint8_t *ai = aa + i * 2 * n_w_byte;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_set_zero(ai, 2 * n_w_byte);
+ gf256v_add(ai, a + i * n_w_byte, n_w_byte);
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_set_ele(ai + n_w_byte, i, 1);
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_gauss_elim(aa, H, 2 * H);
+ gf16mat_submat(inv_a, H, H, aa, 2 * H, H);
+ return r8;
+}
+
+// choosing the implementations depends on the macros _BLAS_AVX2_ and _BLAS_SSE
+
+#define gf16mat_prod_impl gf16mat_prod_ref
+#define gf16mat_gauss_elim_impl gf16mat_gauss_elim_ref
+#define gf16mat_solve_linear_eq_impl gf16mat_solve_linear_eq_ref
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ gf16mat_prod_impl(c, matA, n_A_vec_byte, n_A_width, b);
+}
+
+unsigned int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w) {
+ return gf16mat_gauss_elim_impl(mat, h, w);
+}
+
+unsigned int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ return gf16mat_solve_linear_eq_impl(sol, inp_mat, c_terms, n);
+}
+
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_comm.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_comm.h
new file mode 100644
index 00000000..bf0131b7
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_comm.h
@@ -0,0 +1,74 @@
+#ifndef _BLAS_COMM_H_
+#define _BLAS_COMM_H_
+/// @file blas_comm.h
+/// @brief Common functions for linear algebra.
+///
+
+#include "rainbow_config.h"
+#include
+
+/// @brief set a vector to 0.
+///
+/// @param[in,out] b - the vector b.
+/// @param[in] _num_byte - number of bytes for the vector b.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte);
+
+/// @brief get an element from GF(16) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(const uint8_t *a, unsigned int i);
+
+/// @brief matrix-matrix multiplication: c = a * b , in GF(16)
+///
+/// @param[out] c - the output matrix c
+/// @param[in] c - a matrix a.
+/// @param[in] b - a matrix b.
+/// @param[in] len_vec - the length of column vectors.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec);
+
+/// @brief Gauss elimination for a matrix, in GF(16)
+///
+/// @param[in,out] mat - the matrix.
+/// @param[in] h - the height of the matrix.
+/// @param[in] w - the width of the matrix.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w);
+
+/// @brief Solving linear equations, in GF(16)
+///
+/// @param[out] sol - the solutions.
+/// @param[in] inp_mat - the matrix parts of input equations.
+/// @param[in] c_terms - the constant terms of the input equations.
+/// @param[in] n - the number of equations.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n);
+
+/// @brief Computing the inverse matrix, in GF(16)
+///
+/// @param[out] inv_a - the output of matrix a.
+/// @param[in] a - a matrix a.
+/// @param[in] H - height of matrix a, i.e., matrix a is an HxH matrix.
+/// @param[in] buffer - The buffer for computations. it has to be as large as 2 input matrixes.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer);
+
+/// @brief matrix-vector multiplication: c = matA * b , in GF(16)
+///
+/// @param[out] c - the output vector c
+/// @param[in] matA - a column-major matrix A.
+/// @param[in] n_A_vec_byte - the size of column vectors in bytes.
+/// @param[in] n_A_width - the width of matrix A.
+/// @param[in] b - the vector b.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b);
+
+
+#endif // _BLAS_COMM_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_u32.c b/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_u32.c
new file mode 100644
index 00000000..76044e16
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_u32.c
@@ -0,0 +1,115 @@
+#include "blas_u32.h"
+#include "gf.h"
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte) {
+ uint32_t pr_u32 = ((uint32_t)0) - ((uint32_t)predicate);
+ uint8_t pr_u8 = pr_u32 & 0xff;
+
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= (a_u32[i] & pr_u32);
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= (a[i] & pr_u8);
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= a_u32[i];
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= a[i];
+ }
+}
+
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_scalar_u32(uint8_t *a, uint8_t gf16_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *a_u32 = (uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ a_u32[i] = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(a_u32[i], gf16_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(t.u32, gf16_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ a[i] = t.u8[i];
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf16_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *c_u32 = (uint32_t *)accu_c;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ c_u32[i] ^= PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(a_u32[i], gf16_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ accu_c += (n_u32 << 2);
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(t.u32, gf16_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_c[i] ^= t.u8[i];
+ }
+}
+
+uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_dot_u32(const uint8_t *a, const uint8_t *b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ const uint32_t *b_u32 = (const uint32_t *)b;
+ uint32_t r = 0;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ r ^= PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_u32_u32(a_u32[i], b_u32[i]);
+ }
+
+ unsigned int rem = _num_byte & 3;
+ if (rem) {
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } ta, tb;
+ ta.u32 = 0;
+ tb.u32 = 0;
+ for (unsigned int i = 0; i < rem; i++) {
+ ta.u8[i] = a[(n_u32 << 2) + i];
+ }
+ for (unsigned int i = 0; i < rem; i++) {
+ tb.u8[i] = b[(n_u32 << 2) + i];
+ }
+ r ^= PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_u32_u32(ta.u32, tb.u32);
+ }
+ return PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_reduce_u32(r);
+}
+
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_u32.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_u32.h
new file mode 100644
index 00000000..992d447f
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/blas_u32.h
@@ -0,0 +1,19 @@
+#ifndef _BLAS_U32_H_
+#define _BLAS_U32_H_
+/// @file blas_u32.h
+/// @brief Inlined functions for implementing basic linear algebra functions for uint32 arch.
+///
+
+#include "rainbow_config.h"
+#include
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte);
+
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf16_b, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_scalar_u32(uint8_t *a, uint8_t gf16_b, unsigned int _num_byte);
+uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_dot_u32(const uint8_t *a, const uint8_t *b, unsigned int _num_byte);
+
+
+#endif // _BLAS_U32_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/gf.c b/crypto_sign/rainbowIa-cyclic-compressed/clean/gf.c
new file mode 100644
index 00000000..55d9fd6a
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/gf.c
@@ -0,0 +1,124 @@
+#include "gf.h"
+
+//// gf4 := gf2[x]/x^2+x+1
+static inline uint8_t gf4_mul_2(uint8_t a) {
+ uint8_t r = (uint8_t)(a << 1);
+ r ^= (uint8_t)((a >> 1) * 7);
+ return r;
+}
+
+static inline uint8_t gf4_mul(uint8_t a, uint8_t b) {
+ uint8_t r = (uint8_t)(a * (b & 1));
+ return r ^ (uint8_t)(gf4_mul_2(a) * (b >> 1));
+}
+
+static inline uint8_t gf4_squ(uint8_t a) {
+ return a ^ (a >> 1);
+}
+
+static inline uint32_t gf4v_mul_2_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit1 ^ (bit1 >> 1);
+}
+
+static inline uint32_t gf4v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t bit0_b = ((uint32_t)0) - ((uint32_t)(b & 1));
+ uint32_t bit1_b = ((uint32_t)0) - ((uint32_t)((b >> 1) & 1));
+ return (a & bit0_b) ^ (bit1_b & gf4v_mul_2_u32(a));
+}
+
+//// gf16 := gf4[y]/y^2+y+x
+static inline uint8_t gf16_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ uint8_t b0 = b & 3;
+ uint8_t b1 = (b >> 2);
+ uint8_t a0b0 = gf4_mul(a0, b0);
+ uint8_t a1b1 = gf4_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf4_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x2 = gf4_mul_2(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 2 ^ a0b0 ^ a1b1_x2);
+}
+
+static inline uint8_t gf16_squ(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ a1 = gf4_squ(a1);
+ uint8_t a1squ_x2 = gf4_mul_2(a1);
+ return (uint8_t)((a1 << 2) ^ a1squ_x2 ^ gf4_squ(a0));
+}
+
+// gf16 := gf4[y]/y^2+y+x
+uint32_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = gf4v_mul_u32(a, b);
+ uint32_t axb1 = gf4v_mul_u32(a, b >> 2);
+ uint32_t a0b1 = (axb1 << 2) & 0xcccccccc;
+ uint32_t a1b1 = axb1 & 0xcccccccc;
+ uint32_t a1b1_2 = a1b1 >> 2;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf4v_mul_2_u32(a1b1_2);
+}
+
+
+static inline uint32_t _gf4v_mul_u32_u32(uint32_t a0, uint32_t a1, uint32_t b0, uint32_t b1) {
+ uint32_t c0 = a0 & b0;
+ uint32_t c2 = a1 & b1;
+ uint32_t c1_ = (a0 ^ a1) & (b0 ^ b1);
+ return ((c1_ ^ c0) << 1) ^ c0 ^ c2;
+}
+
+uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16_is_nonzero(uint8_t a) {
+ unsigned int a4 = a & 0xf;
+ unsigned int r = ((unsigned int)0) - a4;
+ r >>= 4;
+ return r & 1;
+}
+
+uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16_inv(uint8_t a) {
+ uint8_t a2 = gf16_squ(a);
+ uint8_t a4 = gf16_squ(a2);
+ uint8_t a8 = gf16_squ(a4);
+ uint8_t a6 = gf16_mul(a4, a2);
+ return gf16_mul(a8, a6);
+}
+
+static inline uint32_t _gf16v_mul_u32_u32(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) {
+ uint32_t c0 = _gf4v_mul_u32_u32(a0, a1, b0, b1);
+ uint32_t c1_ = _gf4v_mul_u32_u32(a0 ^ a2, a1 ^ a3, b0 ^ b2, b1 ^ b3);
+
+ uint32_t c2_0 = a2 & b2;
+ uint32_t c2_2 = a3 & b3;
+ uint32_t c2_1_ = (a2 ^ a3) & (b2 ^ b3);
+ uint32_t c2_r0 = c2_0 ^ c2_2;
+ uint32_t c2_r1 = c2_0 ^ c2_1_;
+ // GF(4) x2: (bit0<<1)^bit1^(bit1>>1);
+ return ((c1_ ^ c0) << 2) ^ c0 ^ (c2_r0 << 1) ^ c2_r1 ^ (c2_r1 << 1);
+}
+
+uint32_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_u32_u32(uint32_t a, uint32_t b) {
+ uint32_t a0 = a & 0x11111111;
+ uint32_t a1 = (a >> 1) & 0x11111111;
+ uint32_t a2 = (a >> 2) & 0x11111111;
+ uint32_t a3 = (a >> 3) & 0x11111111;
+ uint32_t b0 = b & 0x11111111;
+ uint32_t b1 = (b >> 1) & 0x11111111;
+ uint32_t b2 = (b >> 2) & 0x11111111;
+ uint32_t b3 = (b >> 3) & 0x11111111;
+
+ return _gf16v_mul_u32_u32(a0, a1, a2, a3, b0, b1, b2, b3);
+}
+
+static inline uint8_t gf256v_reduce_u32(uint32_t a) {
+ // https://godbolt.org/z/7hirMb
+ uint16_t *aa = (uint16_t *)(&a);
+ uint16_t r = aa[0] ^ aa[1];
+ uint8_t *rr = (uint8_t *)(&r);
+ return rr[0] ^ rr[1];
+}
+
+uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_reduce_u32(uint32_t a) {
+ uint8_t r256 = gf256v_reduce_u32(a);
+ return (uint8_t)((r256 & 0xf) ^ (r256 >> 4));
+}
+
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/gf.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/gf.h
new file mode 100644
index 00000000..946db489
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/gf.h
@@ -0,0 +1,20 @@
+#ifndef _GF16_H_
+#define _GF16_H_
+
+#include "rainbow_config.h"
+#include
+
+/// @file gf16.h
+/// @brief Library for arithmetics in GF(16) and GF(256)
+///
+
+uint32_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b);
+
+
+uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16_is_nonzero(uint8_t a);
+uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16_inv(uint8_t a);
+uint32_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_u32_u32(uint32_t a, uint32_t b);
+uint8_t PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_reduce_u32(uint32_t a);
+
+
+#endif // _GF16_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/parallel_matrix_op.c b/crypto_sign/rainbowIa-cyclic-compressed/clean/parallel_matrix_op.c
new file mode 100644
index 00000000..97e3265c
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/parallel_matrix_op.c
@@ -0,0 +1,182 @@
+/// @file parallel_matrix_op.c
+/// @brief the standard implementations for functions in parallel_matrix_op.h
+///
+/// the standard implementations for functions in parallel_matrix_op.h
+///
+
+#include "parallel_matrix_op.h"
+#include "blas.h"
+#include "blas_comm.h"
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim) {
+ return (dim + dim - i_row + 1) * i_row / 2 + j_col - i_row;
+}
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle or lower-triangle matrix.
+///
+/// @param[in] i_row - the i-th row in a triangle matrix.
+/// @param[in] j_col - the j-th column in a triangle matrix.
+/// @param[in] dim - the dimension of the triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+static inline unsigned int idx_of_2trimat(unsigned int i_row, unsigned int j_col, unsigned int n_var) {
+ if (i_row > j_col) {
+ return PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(j_col, i_row, n_var);
+ }
+ return PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(i_row, j_col, n_var);
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch) {
+ unsigned char *runningC = btriC;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < i; j++) {
+ unsigned int idx = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(j, i, Aheight);
+ gf256v_add(btriC + idx * size_batch, bA + size_batch * (i * Awidth + j), size_batch);
+ }
+ gf256v_add(runningC, bA + size_batch * (i * Awidth + i), size_batch * (Aheight - i));
+ runningC += size_batch * (Aheight - i);
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (k < i) {
+ continue;
+ }
+ gf16v_madd(bC, &btriA[(k - i) * size_batch], PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ btriA += (Aheight - i) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i < k) {
+ continue;
+ }
+ gf16v_madd(bC, &btriA[size_batch * (PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(k, i, Aheight))], PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i == k) {
+ continue;
+ }
+ gf16v_madd(bC, &btriA[size_batch * (idx_of_2trimat(i, k, Aheight))], PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf16(unsigned char *bC, const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Atr_height = Awidth;
+ unsigned int Atr_width = Aheight;
+ for (unsigned int i = 0; i < Atr_height; i++) {
+ for (unsigned int j = 0; j < Atr_width; j++) {
+ gf16v_madd(bC, &bB[j * Bwidth * size_batch], PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(&A_to_tr[size_Acolvec * i], j), size_batch * Bwidth);
+ }
+ bC += size_batch * Bwidth;
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ const unsigned char *bA = bA_to_tr;
+ unsigned int Aheight = Awidth_before_tr;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf16v_madd(bC, &bA[size_batch * (i + k * Aheight)], PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf16v_madd(bC, &bA[k * size_batch], PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ bA += (Awidth) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y, const unsigned char *mat,
+ const unsigned char *x, unsigned int dim_x, unsigned int size_batch) {
+ unsigned char tmp[128];
+
+ unsigned char _x[128];
+ for (unsigned int i = 0; i < dim_x; i++) {
+ _x[i] = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(x, i);
+ }
+ unsigned char _y[128];
+ for (unsigned int i = 0; i < dim_y; i++) {
+ _y[i] = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(y, i);
+ }
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_set_zero(z, size_batch);
+ for (unsigned int i = 0; i < dim_y; i++) {
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = 0; j < dim_x; j++) {
+ gf16v_madd(tmp, mat, _x[j], size_batch);
+ mat += size_batch;
+ }
+ gf16v_madd(z, tmp, _y[i], size_batch);
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch) {
+ unsigned char tmp[256];
+
+ unsigned char _x[256];
+ for (unsigned int i = 0; i < dim; i++) {
+ _x[i] = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele(x, i);
+ }
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_set_zero(y, size_batch);
+ for (unsigned int i = 0; i < dim; i++) {
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = i; j < dim; j++) {
+ gf16v_madd(tmp, trimat, _x[j], size_batch);
+ trimat += size_batch;
+ }
+ gf16v_madd(y, tmp, _x[i], size_batch);
+ }
+}
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/parallel_matrix_op.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/parallel_matrix_op.h
new file mode 100644
index 00000000..00c40ed7
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/parallel_matrix_op.h
@@ -0,0 +1,260 @@
+#ifndef _P_MATRIX_OP_H_
+#define _P_MATRIX_OP_H_
+/// @file parallel_matrix_op.h
+/// @brief Librarys for operations of batched matrixes.
+///
+///
+
+//////////////// Section: triangle matrix <-> rectangle matrix ///////////////////////////////////
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim);
+
+///
+/// @brief Upper trianglize a rectangle matrix to the corresponding upper-trangle matrix.
+///
+/// @param[out] btriC - the batched upper-trianglized matrix C.
+/// @param[in] bA - a batched retangle matrix A.
+/// @param[in] bwidth - the width of the batched matrix A, i.e., A is a Awidth x Awidth matrix.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch);
+
+//////////////////// Section: matrix multiplications ///////////////////////////////
+
+///
+/// @brief bC += btriA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. A will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A, which will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf16(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf256(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+//////////////////// Section: "quadratric" matrix evaluation ///////////////////////////////
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(16)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(256)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(16)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(256)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+#endif // _P_MATRIX_OP_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow.c b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow.c
new file mode 100644
index 00000000..949b04bd
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow.c
@@ -0,0 +1,180 @@
+/// @file rainbow.c
+/// @brief The standard implementations for functions in rainbow.h
+///
+
+#include "rainbow.h"
+#include "blas.h"
+#include "rainbow_blas.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "utils_hash.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+#define MAX_ATTEMPT_FRMAT 128
+#define _MAX_O ((_O1 > _O2) ? _O1 : _O2)
+#define _MAX_O_BYTE ((_O1_BYTE > _O2_BYTE) ? _O1_BYTE : _O2_BYTE)
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *_digest) {
+ uint8_t mat_l1[_O1 * _O1_BYTE];
+ uint8_t mat_l2[_O2 * _O2_BYTE];
+ uint8_t mat_buffer[2 * _MAX_O * _MAX_O_BYTE];
+
+ // setup PRNG
+ prng_t prng_sign;
+ uint8_t prng_preseed[LEN_SKSEED + _HASH_LEN];
+ memcpy(prng_preseed, sk->sk_seed, LEN_SKSEED);
+ memcpy(prng_preseed + LEN_SKSEED, _digest, _HASH_LEN); // prng_preseed = sk_seed || digest
+ uint8_t prng_seed[_HASH_LEN];
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_hash_msg(prng_seed, _HASH_LEN, prng_preseed, _HASH_LEN + LEN_SKSEED);
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_set(&prng_sign, prng_seed, _HASH_LEN); // seed = H( sk_seed || digest )
+ for (unsigned int i = 0; i < LEN_SKSEED + _HASH_LEN; i++) {
+ prng_preseed[i] ^= prng_preseed[i]; // clean
+ }
+ for (unsigned int i = 0; i < _HASH_LEN; i++) {
+ prng_seed[i] ^= prng_seed[i]; // clean
+ }
+
+ // roll vinegars.
+ uint8_t vinegar[_V1_BYTE];
+ unsigned int n_attempt = 0;
+ unsigned int l1_succ = 0;
+ while (!l1_succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(&prng_sign, vinegar, _V1_BYTE); // generating vinegars
+ gfmat_prod(mat_l1, sk->l1_F2, _O1 * _O1_BYTE, _V1, vinegar); // generating the linear equations for layer 1
+ l1_succ = gfmat_inv(mat_l1, mat_l1, _O1, mat_buffer); // check if the linear equation solvable
+ n_attempt++;
+ }
+
+ // Given the vinegars, pre-compute variables needed for layer 2
+ uint8_t r_l1_F1[_O1_BYTE] = {0};
+ uint8_t r_l2_F1[_O2_BYTE] = {0};
+ batch_quad_trimat_eval(r_l1_F1, sk->l1_F1, vinegar, _V1, _O1_BYTE);
+ batch_quad_trimat_eval(r_l2_F1, sk->l2_F1, vinegar, _V1, _O2_BYTE);
+ uint8_t mat_l2_F3[_O2 * _O2_BYTE];
+ uint8_t mat_l2_F2[_O1 * _O2_BYTE];
+ gfmat_prod(mat_l2_F3, sk->l2_F3, _O2 * _O2_BYTE, _V1, vinegar);
+ gfmat_prod(mat_l2_F2, sk->l2_F2, _O1 * _O2_BYTE, _V1, vinegar);
+
+ // Some local variables.
+ uint8_t _z[_PUB_M_BYTE];
+ uint8_t y[_PUB_M_BYTE];
+ uint8_t *x_v1 = vinegar;
+ uint8_t x_o1[_O1_BYTE];
+ uint8_t x_o2[_O1_BYTE];
+
+ uint8_t digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, _digest, _HASH_LEN);
+ uint8_t *salt = digest_salt + _HASH_LEN;
+
+ uint8_t temp_o[_MAX_O_BYTE + 32] = {0};
+ unsigned int succ = 0;
+ while (!succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ // The computation: H(digest||salt) --> z --S--> y --C-map--> x --T--> w
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(&prng_sign, salt, _SALT_BYTE); // roll the salt
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_hash_msg(_z, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H(digest||salt)
+
+ // y = S^-1 * z
+ memcpy(y, _z, _PUB_M_BYTE); // identity part of S
+ gfmat_prod(temp_o, sk->s1, _O1_BYTE, _O2, _z + _O1_BYTE);
+ gf256v_add(y, temp_o, _O1_BYTE);
+
+ // Central Map:
+ // layer 1: calculate x_o1
+ memcpy(temp_o, r_l1_F1, _O1_BYTE);
+ gf256v_add(temp_o, y, _O1_BYTE);
+ gfmat_prod(x_o1, mat_l1, _O1_BYTE, _O1, temp_o);
+
+ // layer 2: calculate x_o2
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf256v_set_zero(temp_o, _O2_BYTE);
+ gfmat_prod(temp_o, mat_l2_F2, _O2_BYTE, _O1, x_o1); // F2
+ batch_quad_trimat_eval(mat_l2, sk->l2_F5, x_o1, _O1, _O2_BYTE); // F5
+ gf256v_add(temp_o, mat_l2, _O2_BYTE);
+ gf256v_add(temp_o, r_l2_F1, _O2_BYTE); // F1
+ gf256v_add(temp_o, y + _O1_BYTE, _O2_BYTE);
+
+ // generate the linear equations of the 2nd layer
+ gfmat_prod(mat_l2, sk->l2_F6, _O2 * _O2_BYTE, _O1, x_o1); // F6
+ gf256v_add(mat_l2, mat_l2_F3, _O2 * _O2_BYTE); // F3
+ succ = gfmat_inv(mat_l2, mat_l2, _O2, mat_buffer);
+ gfmat_prod(x_o2, mat_l2, _O2_BYTE, _O2, temp_o); // solve l2 eqs
+
+ n_attempt++;
+ };
+ // w = T^-1 * y
+ uint8_t w[_PUB_N_BYTE];
+ // identity part of T.
+ memcpy(w, x_v1, _V1_BYTE);
+ memcpy(w + _V1_BYTE, x_o1, _O1_BYTE);
+ memcpy(w + _V2_BYTE, x_o2, _O2_BYTE);
+ // Computing the t1 part.
+ gfmat_prod(y, sk->t1, _V1_BYTE, _O1, x_o1);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t4 part.
+ gfmat_prod(y, sk->t4, _V1_BYTE, _O2, x_o2);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t3 part.
+ gfmat_prod(y, sk->t3, _O1_BYTE, _O2, x_o2);
+ gf256v_add(w + _V1_BYTE, y, _O1_BYTE);
+
+ memset(signature, 0, _SIGNATURE_BYTE); // set the output 0
+ // clean
+ memset(&prng_sign, 0, sizeof(prng_t));
+ memset(vinegar, 0, _V1_BYTE);
+ memset(r_l1_F1, 0, _O1_BYTE);
+ memset(r_l2_F1, 0, _O2_BYTE);
+ memset(_z, 0, _PUB_M_BYTE);
+ memset(y, 0, _PUB_M_BYTE);
+ memset(x_o1, 0, _O1_BYTE);
+ memset(x_o2, 0, _O2_BYTE);
+ memset(temp_o, 0, sizeof(temp_o));
+
+ // return: copy w and salt to the signature.
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ return -1;
+ }
+ gf256v_add(signature, w, _PUB_N_BYTE);
+ gf256v_add(signature + _PUB_N_BYTE, salt, _SALT_BYTE);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk) {
+ unsigned char digest_ck[_PUB_M_BYTE];
+ // public_map( digest_ck , pk , signature ); Evaluating the quadratic public polynomials.
+ batch_quad_trimat_eval(digest_ck, pk->pk, signature, _PUB_N, _PUB_M_BYTE);
+
+ unsigned char correct[_PUB_M_BYTE];
+ unsigned char digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, digest, _HASH_LEN);
+ memcpy(digest_salt + _HASH_LEN, signature + _PUB_N_BYTE, _SALT_BYTE);
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_hash_msg(correct, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H( digest || salt )
+
+ // check consistancy.
+ unsigned char cc = 0;
+ for (unsigned int i = 0; i < _PUB_M_BYTE; i++) {
+ cc |= (digest_ck[i] ^ correct[i]);
+ }
+ return (0 == cc) ? 0 : -1;
+}
+
+/////////////// cyclic version ///////////////////////////
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(uint8_t *signature, const csk_t *csk, const uint8_t *digest) {
+ unsigned char sk[sizeof(sk_t) + 32];
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_generate_secretkey_cyclic((sk_t *)sk, csk->pk_seed, csk->sk_seed); // generating classic secret key.
+ return PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_sign(signature, (sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *_pk) {
+ unsigned char pk[sizeof(pk_t) + 32];
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_cpk_to_pk((pk_t *)pk, _pk); // generating classic public key.
+ return PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_verify(digest, signature, (pk_t *)pk);
+}
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow.h
new file mode 100644
index 00000000..69112530
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow.h
@@ -0,0 +1,50 @@
+#ifndef _RAINBOW_H_
+#define _RAINBOW_H_
+/// @file rainbow.h
+/// @brief APIs for rainbow.
+///
+
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+
+#include
+
+///
+/// @brief Signing function for classical secret key.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk);
+
+///
+/// @brief Signing function for compressed secret key of the cyclic rainbow.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the compressed secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(uint8_t *signature, const csk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function for cyclic public keys.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key of cyclic rainbow.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *pk);
+
+#endif // _RAINBOW_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_blas.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_blas.h
new file mode 100644
index 00000000..e1392257
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_blas.h
@@ -0,0 +1,31 @@
+#ifndef _RAINBOW_BLAS_H_
+#define _RAINBOW_BLAS_H_
+/// @file rainbow_blas.h
+/// @brief Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+///
+/// Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+
+#include "blas.h"
+#include "parallel_matrix_op.h"
+#include "rainbow_config.h"
+
+
+#define gfv_get_ele PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_get_ele
+#define gfv_mul_scalar PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_mul_scalar
+#define gfv_madd PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16v_madd
+
+#define gfmat_prod PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_prod
+#define gfmat_inv PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_gf16mat_inv
+
+#define batch_trimat_madd PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf16
+#define batch_trimatTr_madd PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf16
+#define batch_2trimat_madd PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf16
+#define batch_matTr_madd PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf16
+#define batch_bmatTr_madd PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf16
+#define batch_mat_madd PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf16
+
+#define batch_quad_trimat_eval PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf16
+#define batch_quad_recmat_eval PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf16
+
+
+#endif // _RAINBOW_BLAS_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_config.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_config.h
new file mode 100644
index 00000000..2222abe1
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_config.h
@@ -0,0 +1,47 @@
+#ifndef _H_RAINBOW_CONFIG_H_
+#define _H_RAINBOW_CONFIG_H_
+
+/// @file rainbow_config.h
+/// @brief Defining the parameters of the Rainbow and the corresponding constants.
+///
+
+#define _USE_GF16
+#define _GFSIZE 16
+#define _V1 32
+#define _O1 32
+#define _O2 32
+#define _HASH_LEN 32
+
+
+#define _V2 ((_V1) + (_O1))
+
+/// size of N, in # of gf elements.
+#define _PUB_N (_V1 + _O1 + _O2)
+
+/// size of M, in # gf elements.
+#define _PUB_M (_O1 + _O2)
+
+/// size of variables, in # bytes.
+
+// GF16
+#define _V1_BYTE (_V1 / 2)
+#define _V2_BYTE (_V2 / 2)
+#define _O1_BYTE (_O1 / 2)
+#define _O2_BYTE (_O2 / 2)
+#define _PUB_N_BYTE (_PUB_N / 2)
+#define _PUB_M_BYTE (_PUB_M / 2)
+
+
+/// length of seed for public key, in # bytes
+#define LEN_PKSEED 32
+
+/// length of seed for secret key, in # bytes
+#define LEN_SKSEED 32
+
+/// length of salt for a signature, in # bytes
+#define _SALT_BYTE 16
+
+/// length of a signature
+#define _SIGNATURE_BYTE (_PUB_N_BYTE + _SALT_BYTE)
+
+#endif // _H_RAINBOW_CONFIG_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair.c b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair.c
new file mode 100644
index 00000000..d57039c6
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair.c
@@ -0,0 +1,188 @@
+/// @file rainbow_keypair.c
+/// @brief implementations of functions in rainbow_keypair.h
+///
+
+#include "rainbow_keypair.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair_computation.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+static void generate_S_T(unsigned char *s_and_t, prng_t *prng0) {
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // S1
+ s_and_t += _O1_BYTE * _O2;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O1); // T1
+ s_and_t += _V1_BYTE * _O1;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O2); // T2
+ s_and_t += _V1_BYTE * _O2;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // T3
+}
+
+static unsigned int generate_l1_F12(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O1_BYTE * N_TRIANGLE_TERMS(_V1)); // l1_F1
+ sk += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O1_BYTE * _V1 * _O1); // l1_F2
+ n_byte_generated += _O1_BYTE * _V1 * _O1;
+ return n_byte_generated;
+}
+
+static unsigned int generate_l2_F12356(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // l2_F1
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O1); // l2_F2
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O2); // l2_F3
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // l2_F5
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _O1 * _O2); // l2_F6
+ n_byte_generated += _O2_BYTE * _O1 * _O2;
+
+ return n_byte_generated;
+}
+
+static void generate_B1_B2(unsigned char *sk, prng_t *prng0) {
+ sk += generate_l1_F12(sk, prng0);
+ generate_l2_F12356(sk, prng0);
+}
+
+static void calculate_t4(unsigned char *t2_to_t4, const unsigned char *t1, const unsigned char *t3) {
+ // t4 = T_sk.t1 * T_sk.t3 - T_sk.t2
+ unsigned char temp[_V1_BYTE + 32];
+ unsigned char *t4 = t2_to_t4;
+ for (unsigned int i = 0; i < _O2; i++) { /// t3 width
+ gfmat_prod(temp, t1, _V1_BYTE, _O1, t3);
+ gf256v_add(t4, temp, _V1_BYTE);
+ t4 += _V1_BYTE;
+ t3 += _O1_BYTE;
+ }
+}
+
+static void obsfucate_l1_polys(unsigned char *l1_polys, const unsigned char *l2_polys, unsigned int n_terms, const unsigned char *s1) {
+ unsigned char temp[_O1_BYTE + 32];
+ while (n_terms--) {
+ gfmat_prod(temp, s1, _O1_BYTE, _O2, l2_polys);
+ gf256v_add(l1_polys, temp, _O1_BYTE);
+ l1_polys += _O1_BYTE;
+ l2_polys += _O2_BYTE;
+ }
+}
+
+/////////////////// Classic //////////////////////////////////
+
+
+///////////////////// Cyclic //////////////////////////////////
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(pk->pk_seed, pk_seed, LEN_PKSEED);
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // prng for sk
+ prng_t prng;
+ prng_t *prng0 = &prng;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_set(prng0, sk_seed, LEN_SKSEED);
+ generate_S_T(sk->s1, prng0); // S,T: only a part of sk
+
+ unsigned char t2[sizeof(sk->t4)];
+ memcpy(t2, sk->t4, _V1_BYTE * _O2); // temporarily store t2
+ calculate_t4(sk->t4, sk->t1, sk->t3); // t2 <- t4
+
+ // prng for pk
+ sk_t inst_Qs;
+ sk_t *Qs = &inst_Qs;
+ prng_t *prng1 = &prng;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_set(prng1, pk_seed, LEN_PKSEED);
+ generate_B1_B2(Qs->l1_F1, prng1); // generating l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+ obsfucate_l1_polys(Qs->l1_F1, Qs->l2_F1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(Qs->l1_F2, Qs->l2_F2, _V1 * _O1, sk->s1);
+ // so far, the Qs contains l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6.
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk, Qs, sk); // calcuate the rest parts of secret key from Qs and S,T
+
+ unsigned char t4[sizeof(sk->t4)];
+ memcpy(t4, sk->t4, _V1_BYTE * _O2); // temporarily store t4
+ memcpy(sk->t4, t2, _V1_BYTE * _O2); // restore t2
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_calculate_Q_from_F_cyclic(pk, sk, sk); // calculate the rest parts of public key: l1_Q3, l1_Q5, l1_Q6, l1_Q9, l2_Q9
+ memcpy(sk->t4, t4, _V1_BYTE * _O2); // restore t4
+
+ obsfucate_l1_polys(pk->l1_Q3, Qs->l2_F3, _V1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q5, Qs->l2_F5, N_TRIANGLE_TERMS(_O1), sk->s1);
+ obsfucate_l1_polys(pk->l1_Q6, Qs->l2_F6, _O1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q9, pk->l2_Q9, N_TRIANGLE_TERMS(_O2), sk->s1);
+
+ // clean
+ memset(&prng, 0, sizeof(prng_t));
+}
+
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_generate_compact_keypair_cyclic(cpk_t *pk, csk_t *rsk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(rsk->pk_seed, pk_seed, LEN_PKSEED);
+ memcpy(rsk->sk_seed, sk_seed, LEN_SKSEED);
+ sk_t sk;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_generate_keypair_cyclic(pk, &sk, pk_seed, sk_seed);
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_generate_secretkey_cyclic(sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // prng for sk
+ prng_t prng0;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_set(&prng0, sk_seed, LEN_SKSEED);
+ generate_S_T(sk->s1, &prng0);
+ calculate_t4(sk->t4, sk->t1, sk->t3);
+
+ // prng for pk
+ sk_t inst_Qs;
+ sk_t *Qs = &inst_Qs;
+ prng_t prng1;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_set(&prng1, pk_seed, LEN_PKSEED);
+ generate_B1_B2(Qs->l1_F1, &prng1);
+
+ obsfucate_l1_polys(Qs->l1_F1, Qs->l2_F1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(Qs->l1_F2, Qs->l2_F2, _V1 * _O1, sk->s1);
+
+ // calcuate the parts of sk according to pk.
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk, Qs, sk);
+
+ // clean prng for sk
+ memset(&prng0, 0, sizeof(prng_t));
+}
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_cpk_to_pk(pk_t *rpk, const cpk_t *cpk) {
+ // procedure: cpk_t --> extcpk_t --> pk_t
+
+ // convert from cpk_t to extcpk_t
+ ext_cpk_t pk;
+
+ // setup prng
+ prng_t prng0;
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_set(&prng0, cpk->pk_seed, LEN_SKSEED);
+
+ // generating parts of key with prng
+ generate_l1_F12(pk.l1_Q1, &prng0);
+ // copying parts of key from input. l1_Q3, l1_Q5, l1_Q6, l1_Q9
+ memcpy(pk.l1_Q3, cpk->l1_Q3, _O1_BYTE * (_V1 * _O2 + N_TRIANGLE_TERMS(_O1) + _O1 * _O2 + N_TRIANGLE_TERMS(_O2)));
+
+ // generating parts of key with prng
+ generate_l2_F12356(pk.l2_Q1, &prng0);
+ // copying parts of key from input: l2_Q9
+ memcpy(pk.l2_Q9, cpk->l2_Q9, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ // convert from extcpk_t to pk_t
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_extcpk_to_pk(rpk, &pk);
+}
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair.h
new file mode 100644
index 00000000..718b959c
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair.h
@@ -0,0 +1,111 @@
+#ifndef _RAINBOW_KEYPAIR_H_
+#define _RAINBOW_KEYPAIR_H_
+/// @file rainbow_keypair.h
+/// @brief Formats of key pairs and functions for generating key pairs.
+/// Formats of key pairs and functions for generating key pairs.
+///
+
+#include "rainbow_config.h"
+
+#define N_TRIANGLE_TERMS(n_var) ((n_var) * ((n_var) + 1) / 2)
+
+/// @brief public key for classic rainbow
+///
+/// public key for classic rainbow
+///
+typedef struct rainbow_publickey {
+ unsigned char pk[(_PUB_M_BYTE)*N_TRIANGLE_TERMS(_PUB_N)];
+} pk_t;
+
+/// @brief secret key for classic rainbow
+///
+/// secret key for classic rainbow
+///
+typedef struct rainbow_secretkey {
+ ///
+ /// seed for generating secret key.
+ /// Generating S, T, and F for classic rainbow.
+ /// Generating S and T only for cyclic rainbow.
+ unsigned char sk_seed[LEN_SKSEED];
+
+ unsigned char s1[_O1_BYTE * _O2]; ///< part of S map
+ unsigned char t1[_V1_BYTE * _O1]; ///< part of T map
+ unsigned char t4[_V1_BYTE * _O2]; ///< part of T map
+ unsigned char t3[_O1_BYTE * _O2]; ///< part of T map
+
+ unsigned char l1_F1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer1
+ unsigned char l1_F2[_O1_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer1
+
+ unsigned char l2_F1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer2
+ unsigned char l2_F2[_O2_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer2
+
+ unsigned char l2_F3[_O2_BYTE * _V1 * _O2]; ///< part of C-map, F3, Layer2
+ unsigned char l2_F5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< part of C-map, F5, Layer2
+ unsigned char l2_F6[_O2_BYTE * _O1 * _O2]; ///< part of C-map, F6, Layer2
+} sk_t;
+
+/// @brief public key for cyclic rainbow
+///
+/// public key for cyclic rainbow
+///
+typedef struct rainbow_publickey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating l1_Q1,l1_Q2,l2_Q1,l2_Q2,l2_Q3,l2_Q5,l2_Q6
+
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2]; ///< Q3, layer1
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< Q5, layer1
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2]; ///< Q6, layer1
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer1
+
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer2
+} cpk_t;
+
+/// @brief compressed secret key for cyclic rainbow
+///
+/// compressed secret key for cyclic rainbow
+///
+typedef struct rainbow_secretkey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating a part of public key.
+ unsigned char sk_seed[LEN_SKSEED]; ///< seed for generating a part of secret key.
+} csk_t;
+
+
+///
+/// @brief Generate key pairs for cyclic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the secret key.
+/// @param[in] pk_seed - seed for generating parts of public key.
+/// @param[in] sk_seed - seed for generating secret key.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+///
+/// @brief Generate compressed key pairs for cyclic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the compressed secret key.
+/// @param[in] pk_seed - seed for generating parts of the public key.
+/// @param[in] sk_seed - seed for generating the secret key.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_generate_compact_keypair_cyclic(cpk_t *pk, csk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+///
+/// @brief Generate secret key for cyclic rainbow.
+///
+/// @param[out] sk - the secret key.
+/// @param[in] pk_seed - seed for generating parts of the pbulic key.
+/// @param[in] sk_seed - seed for generating the secret key.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_generate_secretkey_cyclic(sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+////////////////////////////////////
+
+///
+/// @brief converting formats of public keys : from cyclic version to classic key
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the cyclic public key.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_cpk_to_pk(pk_t *pk, const cpk_t *cpk);
+
+#endif // _RAINBOW_KEYPAIR_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair_computation.c b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair_computation.c
new file mode 100644
index 00000000..ab7756b3
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair_computation.c
@@ -0,0 +1,213 @@
+/// @file rainbow_keypair_computation.c
+/// @brief Implementations for functions in rainbow_keypair_computation.h
+///
+
+#include "rainbow_keypair_computation.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair.h"
+#include
+#include
+#include
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk) {
+ const unsigned char *idx_l1 = cpk->l1_Q1;
+ const unsigned char *idx_l2 = cpk->l2_Q1;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = i; j < _V1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q2;
+ idx_l2 = cpk->l2_Q2;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q3;
+ idx_l2 = cpk->l2_Q3;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q5;
+ idx_l2 = cpk->l2_Q5;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = i; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q6;
+ idx_l2 = cpk->l2_Q6;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q9;
+ idx_l2 = cpk->l2_Q9;
+ for (unsigned int i = _V1 + _O1; i < _PUB_N; i++) {
+ for (unsigned int j = i; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+}
+
+static void calculate_F_from_Q_ref(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ // Layer 1
+ // F_sk.l1_F1s[i] = Q_pk.l1_F1s[i]
+ memcpy(Fs->l1_F1, Qs->l1_F1, _O1_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ // F_sk.l1_F2s[i] = ( Q_pk.l1_F1s[i] + Q_pk.l1_F1s[i].transpose() ) * T_sk.t1 + Q_pk.l1_F2s[i]
+ memcpy(Fs->l1_F2, Qs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_2trimat_madd(Fs->l1_F2, Qs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE);
+
+ /*
+ Layer 2
+ computations:
+
+ F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ Q1_T1 = Q_pk.l2_F1s[i]*T_sk.t1
+ F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+
+ Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ #Q1_Q1T_T4 = Q1_Q1T * t4
+ Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ + Q_pk.l2_F2s[i].transpose() * t4
+ + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+
+ */
+ memcpy(Fs->l2_F1, Qs->l2_F1, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ // F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ // F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+ memcpy(Fs->l2_F2, Qs->l2_F2, _O2_BYTE * _V1 * _O1);
+ batch_trimat_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // Q1_T1+ Q2
+
+ unsigned char tempQ[_O1 * _O1 * _O2_BYTE + 32];
+ memset(tempQ, 0, _O1 * _O1 * _O2_BYTE);
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F2, _O1, _O2_BYTE); // t1_tr*(Q1_T1+Q2)
+ memcpy(Fs->l2_F5, Qs->l2_F5, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // F5
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_UpperTrianglize(Fs->l2_F5, tempQ, _O1, _O2_BYTE); // UT( ... )
+
+ batch_trimatTr_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // F2 = Q1_T1 + Q2 + Q1^tr*t1
+
+ // Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ // Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ // F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ memcpy(Fs->l2_F3, Qs->l2_F3, _V1 * _O2 * _O2_BYTE);
+ batch_2trimat_madd(Fs->l2_F3, Qs->l2_F1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE); // Q1_Q1T_T4
+ batch_mat_madd(Fs->l2_F3, Qs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // Q2_T3
+
+ // F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ // + Q_pk.l2_F2s[i].transpose() * t4
+ // + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+ memcpy(Fs->l2_F6, Qs->l2_F6, _O1 * _O2 * _O2_BYTE);
+ batch_matTr_madd(Fs->l2_F6, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F3, _O2, _O2_BYTE); // t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ batch_2trimat_madd(Fs->l2_F6, Qs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3
+ batch_bmatTr_madd(Fs->l2_F6, Qs->l2_F2, _O1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE);
+}
+
+static void calculate_Q_from_F_cyclic_ref(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ // Layer 1: Computing Q5, Q3, Q6, Q9
+
+ // Q_pk.l1_F5s[i] = UT( T1tr* (F1 * T1 + F2) )
+ const unsigned char *t2 = Ts->t4;
+ sk_t tempQ;
+ memcpy(tempQ.l1_F2, Fs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_trimat_madd(tempQ.l1_F2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // F1*T1 + F2
+ memset(tempQ.l2_F1, 0, sizeof(tempQ.l2_F1));
+ memset(tempQ.l2_F2, 0, sizeof(tempQ.l2_F2));
+ batch_matTr_madd(tempQ.l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, tempQ.l1_F2, _O1, _O1_BYTE); // T1tr*(F1*T1 + F2)
+ memset(Qs->l1_Q5, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O1));
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_UpperTrianglize(Qs->l1_Q5, tempQ.l2_F1, _O1, _O1_BYTE); // UT( ... ) // Q5
+
+ /*
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+ Q_pk.l1_F3s[i] = F1_F1T_T2 + F2_T3
+ Q_pk.l1_F6s[i] = T1tr* ( F1_F1T_T2 + F2_T3 ) + F2tr * t2
+ Q_pk.l1_F9s[i] = UT( T2tr* ( F1_T2 + F2_T3 ) )
+ */
+ memset(Qs->l1_Q3, 0, _O1_BYTE * _V1 * _O2);
+ memset(Qs->l1_Q6, 0, _O1_BYTE * _O1 * _O2);
+ memset(Qs->l1_Q9, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ batch_trimat_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1*T2
+ batch_mat_madd(Qs->l1_Q3, Fs->l1_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O1_BYTE); // F1_T2 + F2_T3
+
+ memset(tempQ.l1_F2, 0, _O1_BYTE * _V1 * _O2); // should be F3. assuming: _O1 >= _O2
+ batch_matTr_madd(tempQ.l1_F2, t2, _V1, _V1_BYTE, _O2, Qs->l1_Q3, _O2, _O1_BYTE); // T2tr * ( F1_T2 + F2_T3 )
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_UpperTrianglize(Qs->l1_Q9, tempQ.l1_F2, _O2, _O1_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1_F1T_T2 + F2_T3 // Q3
+
+ batch_bmatTr_madd(Qs->l1_Q6, Fs->l1_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F2tr*T2
+ batch_matTr_madd(Qs->l1_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q3, _O2, _O1_BYTE); // Q6
+ /*
+ Layer 2
+ Computing Q9:
+
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ Q9 = UT( T2tr*( F1*T2 + F2*T3 + F3 ) + T3tr*( F5*T3 + F6 ) )
+ */
+ sk_t tempQ2;
+ memcpy(tempQ2.l2_F3, Fs->l2_F3, _O2_BYTE * _V1 * _O2); /// F3 actually.
+ batch_trimat_madd(tempQ2.l2_F3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1*T2 + F3
+ batch_mat_madd(tempQ2.l2_F3, Fs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F1_T2 + F2_T3 + F3
+
+ memset(tempQ.l2_F3, 0, _O2_BYTE * _V1 * _O2);
+ batch_matTr_madd(tempQ.l2_F3, t2, _V1, _V1_BYTE, _O2, tempQ2.l2_F3, _O2, _O2_BYTE); // T2tr * ( ..... )
+
+ memcpy(tempQ.l2_F6, Fs->l2_F6, _O2_BYTE * _O1 * _O2);
+ batch_trimat_madd(tempQ.l2_F6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6
+
+ batch_matTr_madd(tempQ.l2_F3, Ts->t3, _O1, _O1_BYTE, _O2, tempQ.l2_F6, _O2, _O2_BYTE); // T2tr*( ..... ) + T3tr*( ..... )
+ memset(Qs->l2_Q9, 0, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_UpperTrianglize(Qs->l2_Q9, tempQ.l2_F3, _O2, _O2_BYTE); // Q9
+}
+
+// Choosing implementations depends on the macros: _BLAS_SSE_ and _BLAS_AVX2_
+#define calculate_F_from_Q_impl calculate_F_from_Q_ref
+#define calculate_Q_from_F_cyclic_impl calculate_Q_from_F_cyclic_ref
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ calculate_F_from_Q_impl(Fs, Qs, Ts);
+}
+
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ calculate_Q_from_F_cyclic_impl(Qs, Fs, Ts);
+}
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair_computation.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair_computation.h
new file mode 100644
index 00000000..3af7563a
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/rainbow_keypair_computation.h
@@ -0,0 +1,71 @@
+#ifndef _RAINBOW_KEYPAIR_COMP_H_
+#define _RAINBOW_KEYPAIR_COMP_H_
+/// @file rainbow_keypair_computation.h
+/// @brief Functions for calculating pk/sk while generating keys.
+///
+/// Defining an internal structure of public key.
+/// Functions for calculating pk/sk for key generation.
+///
+
+#include "rainbow_keypair.h"
+
+/// @brief The (internal use) public key for rainbow
+///
+/// The (internal use) public key for rainbow. The public
+/// polynomials are divided into l1_Q1, l1_Q2, ... l1_Q9,
+/// l2_Q1, .... , l2_Q9.
+///
+typedef struct rainbow_extend_publickey {
+ unsigned char l1_Q1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l1_Q2[_O1_BYTE * _V1 * _O1];
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2];
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2];
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)];
+
+ unsigned char l2_Q1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l2_Q2[_O2_BYTE * _V1 * _O1];
+ unsigned char l2_Q3[_O2_BYTE * _V1 * _O2];
+ unsigned char l2_Q5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l2_Q6[_O2_BYTE * _O1 * _O2];
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)];
+} ext_cpk_t;
+
+///
+/// @brief converting formats of public keys : from ext_cpk_t version to pk_t
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the internel public key.
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk);
+/////////////////////////////////////////////////
+
+///
+/// @brief Computing public key from secret key
+///
+/// @param[out] Qs - the public key
+/// @param[in] Fs - parts of the secret key: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the secret key: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+
+///
+/// @brief Computing parts of the sk from parts of pk and sk
+///
+/// @param[out] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Qs - parts of the pk: l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts);
+
+///
+/// @brief Computing parts of the pk from the secret key
+///
+/// @param[out] Qs - parts of the pk: l1_Q3, l1_Q5, l2_Q6, l1_Q9, l2_Q9
+/// @param[in] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+#endif // _RAINBOW_KEYPAIR_COMP_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/sign.c b/crypto_sign/rainbowIa-cyclic-compressed/clean/sign.c
new file mode 100644
index 00000000..d0687aa3
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/sign.c
@@ -0,0 +1,76 @@
+/// @file sign.c
+/// @brief the implementations for functions in api.h
+///
+///
+
+#include "api.h"
+#include "rainbow.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
+ unsigned char sk_seed[LEN_SKSEED] = {0};
+ randombytes(sk_seed, LEN_SKSEED);
+
+ unsigned char pk_seed[LEN_PKSEED] = {0};
+ randombytes(pk_seed, LEN_PKSEED);
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_generate_compact_keypair_cyclic((cpk_t *)pk, (csk_t *)sk, pk_seed, sk_seed);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_crypto_sign(unsigned char *sm, size_t *smlen, const unsigned char *m, size_t mlen, const unsigned char *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+
+ memcpy(sm, m, mlen);
+ smlen[0] = mlen + _SIGNATURE_BYTE;
+
+ return PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(sm + mlen, (const csk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_crypto_sign_open(unsigned char *m, size_t *mlen, const unsigned char *sm, size_t smlen, const unsigned char *pk) {
+ int rc;
+ if (_SIGNATURE_BYTE > smlen) {
+ rc = -1;
+ } else {
+ *mlen = smlen - _SIGNATURE_BYTE;
+
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, sm, *mlen);
+
+ rc = PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(digest, sm + mlen[0], (const cpk_t *)pk);
+ }
+ if (!rc) {
+ memcpy(m, sm, smlen - _SIGNATURE_BYTE);
+ } else { // bad signature
+ *mlen = (size_t) -1;
+ memset(m, 0, smlen);
+ }
+ return rc;
+}
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ *siglen = _SIGNATURE_BYTE;
+ return PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(sig, (const csk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ if (siglen != _SIGNATURE_BYTE) {
+ return -1;
+ }
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ return PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(digest, sig, (const cpk_t *)pk);
+}
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_hash.c b/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_hash.c
new file mode 100644
index 00000000..3cec9977
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_hash.c
@@ -0,0 +1,50 @@
+/// @file utils_hash.c
+/// @brief the adapter for SHA2 families.
+///
+///
+
+#include "utils_hash.h"
+#include "rainbow_config.h"
+#include "sha2.h"
+
+static inline int _hash(unsigned char *digest, const unsigned char *m, size_t mlen) {
+ sha256(digest, m, mlen);
+ return 0;
+}
+
+static inline int expand_hash(unsigned char *digest, size_t n_digest, const unsigned char *hash) {
+ if (_HASH_LEN >= n_digest) {
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[i] = hash[i];
+ }
+ return 0;
+ }
+ for (size_t i = 0; i < _HASH_LEN; i++) {
+ digest[i] = hash[i];
+ }
+ n_digest -= _HASH_LEN;
+
+ while (_HASH_LEN <= n_digest) {
+ _hash(digest + _HASH_LEN, digest, _HASH_LEN);
+
+ n_digest -= _HASH_LEN;
+ digest += _HASH_LEN;
+ }
+ unsigned char temp[_HASH_LEN];
+ if (n_digest) {
+ _hash(temp, digest, _HASH_LEN);
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[_HASH_LEN + i] = temp[i];
+ }
+ }
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_hash_msg(unsigned char *digest,
+ size_t len_digest,
+ const unsigned char *m,
+ size_t mlen) {
+ unsigned char buf[_HASH_LEN];
+ _hash(buf, m, mlen);
+ return expand_hash(digest, len_digest, buf);
+}
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_hash.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_hash.h
new file mode 100644
index 00000000..2e7fde28
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_hash.h
@@ -0,0 +1,11 @@
+#ifndef _UTILS_HASH_H_
+#define _UTILS_HASH_H_
+/// @file utils_hash.h
+/// @brief the interface for adapting hash functions.
+///
+
+#include
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_hash_msg(unsigned char *digest, size_t len_digest, const unsigned char *m, size_t mlen);
+
+#endif // _UTILS_HASH_H_
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_prng.c b/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_prng.c
new file mode 100644
index 00000000..7937f31d
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_prng.c
@@ -0,0 +1,95 @@
+/// @file utils_prng.c
+/// @brief The implementation of PRNG related functions.
+///
+
+#include "utils_prng.h"
+#include "aes.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+static void prng_update(const unsigned char *provided_data,
+ unsigned char *Key,
+ unsigned char *V) {
+ unsigned char temp[48];
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, Key);
+ for (int i = 0; i < 3; i++) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (V[j] == 0xff) {
+ V[j] = 0x00;
+ } else {
+ V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(temp + 16 * i, V, 1, &ctx);
+ }
+ if (provided_data != NULL) {
+ for (int i = 0; i < 48; i++) {
+ temp[i] ^= provided_data[i];
+ }
+ }
+ memcpy(Key, temp, 32);
+ memcpy(V, temp + 32, 16);
+}
+static void randombytes_init_with_state(prng_t *state,
+ unsigned char *entropy_input_48bytes) {
+ memset(state->Key, 0x00, 32);
+ memset(state->V, 0x00, 16);
+ prng_update(entropy_input_48bytes, state->Key, state->V);
+}
+
+static int randombytes_with_state(prng_t *state,
+ unsigned char *x,
+ size_t xlen) {
+
+ unsigned char block[16];
+ int i = 0;
+
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, state->Key);
+
+ while (xlen > 0) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (state->V[j] == 0xff) {
+ state->V[j] = 0x00;
+ } else {
+ state->V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(block, state->V, 1, &ctx);
+ if (xlen > 15) {
+ memcpy(x + i, block, 16);
+ i += 16;
+ xlen -= 16;
+ } else {
+ memcpy(x + i, block, xlen);
+ xlen = 0;
+ }
+ }
+ prng_update(NULL, state->Key, state->V);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen) {
+ unsigned char seed[48];
+ if (prng_seedlen >= 48) {
+ memcpy(seed, prng_seed, 48);
+ } else {
+ memcpy(seed, prng_seed, prng_seedlen);
+ PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_hash_msg(seed + prng_seedlen, 48 - (unsigned)prng_seedlen, (const unsigned char *)prng_seed, prng_seedlen);
+ }
+
+ randombytes_init_with_state(ctx, seed);
+
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen) {
+ return randombytes_with_state(ctx, out, outlen);
+}
diff --git a/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_prng.h b/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_prng.h
new file mode 100644
index 00000000..ab9ea9ea
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic-compressed/clean/utils_prng.h
@@ -0,0 +1,18 @@
+#ifndef _UTILS_PRNG_H_
+#define _UTILS_PRNG_H_
+/// @file utils_prng.h
+/// @brief the interface for adapting PRNG functions.
+///
+///
+
+#include "randombytes.h"
+
+typedef struct {
+ unsigned char Key[32];
+ unsigned char V[16];
+} prng_t;
+
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen);
+int PQCLEAN_RAINBOWIACYCLICCOMPRESSED_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen);
+
+#endif // _UTILS_PRNG_H_
diff --git a/crypto_sign/rainbowIa-cyclic/META.yml b/crypto_sign/rainbowIa-cyclic/META.yml
new file mode 100644
index 00000000..69270392
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/META.yml
@@ -0,0 +1,18 @@
+name: Rainbow-Ia-cyclic
+type: signature
+claimed-nist-level: 1
+length-public-key: 58144
+length-secret-key: 92960
+length-signature: 64
+nistkat-sha256: 16f53bf0966b433451ae26e47f09f2dc8ea42db6a5c58fff1a2e7954f94dac0a
+testvectors-sha256: b7341bd862a8f683339e03cf236b885804854d9e0479cb53955761864ecc18bf
+principal-submitters:
+ - Jintai Ding
+auxiliary-submitters:
+ - Ming-Shing Chen
+ - Albrecht Petzoldt
+ - Dieter Schmidt
+ - Bo-Yin Yang
+implementations:
+ - name: clean
+ version: https://github.com/fast-crypto-lab/rainbow-submission-round2/commit/af826fcb78f6af51a02d0352cff28a9690467bfd
diff --git a/crypto_sign/rainbowIa-cyclic/clean/LICENSE b/crypto_sign/rainbowIa-cyclic/clean/LICENSE
new file mode 100644
index 00000000..cb00a6e3
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/LICENSE
@@ -0,0 +1,8 @@
+`Software implementation of Rainbow for NIST R2 submission' by Ming-Shing Chen
+
+To the extent possible under law, the person who associated CC0 with
+`Software implementation of Rainbow for NIST R2 submission' has waived all copyright and related or neighboring rights
+to `Software implementation of Rainbow for NIST R2 submission'.
+
+You should have received a copy of the CC0 legalcode along with this
+work. If not, see .
diff --git a/crypto_sign/rainbowIa-cyclic/clean/Makefile b/crypto_sign/rainbowIa-cyclic/clean/Makefile
new file mode 100644
index 00000000..62ae0619
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=librainbowIa-cyclic_clean.a
+
+HEADERS = api.h blas_comm.h blas.h blas_u32.h gf.h parallel_matrix_op.h rainbow_blas.h rainbow_config.h rainbow.h rainbow_keypair_computation.h rainbow_keypair.h utils_hash.h utils_prng.h
+OBJECTS = blas_comm.o parallel_matrix_op.o rainbow.o rainbow_keypair.o rainbow_keypair_computation.o sign.o utils_hash.o utils_prng.o blas_u32.o gf.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/rainbowIa-cyclic/clean/Makefile.Microsoft_nmake b/crypto_sign/rainbowIa-cyclic/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..8eb7371b
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=librainbowIa-cyclic_clean.lib
+OBJECTS = blas_comm.obj parallel_matrix_op.obj rainbow.obj rainbow_keypair.obj rainbow_keypair_computation.obj sign.obj utils_hash.obj utils_prng.obj blas_u32.obj gf.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/rainbowIa-cyclic/clean/api.h b/crypto_sign/rainbowIa-cyclic/clean/api.h
new file mode 100644
index 00000000..a37bb952
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/api.h
@@ -0,0 +1,32 @@
+#ifndef PQCLEAN_RAINBOWIACYCLIC_CLEAN_API_H
+#define PQCLEAN_RAINBOWIACYCLIC_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_RAINBOWIACYCLIC_CLEAN_CRYPTO_SECRETKEYBYTES 92960
+#define PQCLEAN_RAINBOWIACYCLIC_CLEAN_CRYPTO_PUBLICKEYBYTES 58144
+#define PQCLEAN_RAINBOWIACYCLIC_CLEAN_CRYPTO_BYTES 64
+#define PQCLEAN_RAINBOWIACYCLIC_CLEAN_CRYPTO_ALGNAME "RAINBOW(16,32,32,32) - cyclic"
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
+
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen,
+ const uint8_t *sk);
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen,
+ const uint8_t *pk);
+
+
+#endif
diff --git a/crypto_sign/rainbowIa-cyclic/clean/blas.h b/crypto_sign/rainbowIa-cyclic/clean/blas.h
new file mode 100644
index 00000000..1e71e14b
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/blas.h
@@ -0,0 +1,20 @@
+#ifndef _BLAS_H_
+#define _BLAS_H_
+/// @file blas.h
+/// @brief Defining the implementations for linear algebra functions depending on the machine architecture.
+///
+
+#include "blas_comm.h"
+#include "blas_u32.h"
+#include "rainbow_config.h"
+
+#define gf256v_predicated_add PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_predicated_add_u32
+#define gf256v_add PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_add_u32
+
+
+#define gf16v_mul_scalar PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_scalar_u32
+#define gf16v_madd PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_madd_u32
+#define gf16v_dot PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_dot_u32
+
+
+#endif // _BLAS_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/blas_comm.c b/crypto_sign/rainbowIa-cyclic/clean/blas_comm.c
new file mode 100644
index 00000000..45f062cf
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/blas_comm.c
@@ -0,0 +1,150 @@
+/// @file blas_comm.c
+/// @brief The standard implementations for blas_comm.h
+///
+
+#include "blas_comm.h"
+#include "blas.h"
+#include "gf.h"
+#include "rainbow_config.h"
+
+#include
+#include
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte) {
+ gf256v_add(b, b, _num_byte);
+}
+
+/// @brief get an element from GF(16) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(const uint8_t *a, unsigned int i) {
+ uint8_t r = a[i >> 1];
+ uint8_t r0 = r & 0xf;
+ uint8_t r1 = r >> 4;
+ uint8_t m = (uint8_t)(-((int8_t)i & 1));
+ return (uint8_t)((r1 & m) | ((~m) & r0));
+}
+
+/// @brief set an element for a GF(16) vector .
+///
+/// @param[in,out] a - the vector a.
+/// @param[in] i - the index in the vector a.
+/// @param[in] v - the value for the i-th element in vector a.
+/// @return the value of the element.
+///
+static uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_set_ele(uint8_t *a, unsigned int i, uint8_t v) {
+ uint8_t m = (uint8_t)(0xf ^ (-((int8_t)i & 1))); /// 1--> 0xf0 , 0--> 0x0f
+ uint8_t ai_remaining = (uint8_t)(a[i >> 1] & (~m)); /// erase
+ a[i >> 1] = (uint8_t)(ai_remaining | (m & (v << 4)) | (m & v & 0xf)); /// set
+ return v;
+}
+
+static void gf16mat_prod_ref(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_set_zero(c, n_A_vec_byte);
+ for (unsigned int i = 0; i < n_A_width; i++) {
+ uint8_t bb = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(b, i);
+ gf16v_madd(c, matA, bb, n_A_vec_byte);
+ matA += n_A_vec_byte;
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec) {
+ unsigned int n_vec_byte = (len_vec + 1) / 2;
+ for (unsigned int k = 0; k < len_vec; k++) {
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_set_zero(c, n_vec_byte);
+ const uint8_t *bk = b + n_vec_byte * k;
+ for (unsigned int i = 0; i < len_vec; i++) {
+ uint8_t bb = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(bk, i);
+ gf16v_madd(c, a + n_vec_byte * i, bb, n_vec_byte);
+ }
+ c += n_vec_byte;
+ }
+}
+
+static unsigned int gf16mat_gauss_elim_ref(uint8_t *mat, unsigned int h, unsigned int w) {
+ unsigned int n_w_byte = (w + 1) / 2;
+ unsigned int r8 = 1;
+ for (unsigned int i = 0; i < h; i++) {
+ unsigned int offset_byte = i >> 1;
+ uint8_t *ai = mat + n_w_byte * i;
+ for (unsigned int j = i + 1; j < h; j++) {
+ uint8_t *aj = mat + n_w_byte * j;
+ gf256v_predicated_add(ai + offset_byte, !PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16_is_nonzero(PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(ai, i)), aj + offset_byte, n_w_byte - offset_byte);
+ }
+ uint8_t pivot = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(ai, i);
+ r8 &= PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16_is_nonzero(pivot);
+ pivot = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16_inv(pivot);
+ offset_byte = (i + 1) >> 1;
+ gf16v_mul_scalar(ai + offset_byte, pivot, n_w_byte - offset_byte);
+ for (unsigned int j = 0; j < h; j++) {
+ if (i == j) {
+ continue;
+ }
+ uint8_t *aj = mat + n_w_byte * j;
+ gf16v_madd(aj + offset_byte, ai + offset_byte, PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(aj, i), n_w_byte - offset_byte);
+ }
+ }
+ return r8;
+}
+
+static unsigned int gf16mat_solve_linear_eq_ref(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ uint8_t mat[64 * 33];
+ unsigned int n_byte = (n + 1) >> 1;
+ for (unsigned int i = 0; i < n; i++) {
+ memcpy(mat + i * (n_byte + 1), inp_mat + i * n_byte, n_byte);
+ mat[i * (n_byte + 1) + n_byte] = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(c_terms, i);
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_gauss_elim(mat, n, n + 2);
+ for (unsigned int i = 0; i < n; i++) {
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_set_ele(sol, i, mat[i * (n_byte + 1) + n_byte]);
+ }
+ return r8;
+}
+
+static inline void gf16mat_submat(uint8_t *mat2, unsigned int w2, unsigned int st, const uint8_t *mat, unsigned int w, unsigned int h) {
+ unsigned int n_byte_w1 = (w + 1) / 2;
+ unsigned int n_byte_w2 = (w2 + 1) / 2;
+ unsigned int st_2 = st / 2;
+ for (unsigned int i = 0; i < h; i++) {
+ for (unsigned int j = 0; j < n_byte_w2; j++) {
+ mat2[i * n_byte_w2 + j] = mat[i * n_byte_w1 + st_2 + j];
+ }
+ }
+}
+
+unsigned int PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer) {
+ unsigned int n_w_byte = (H + 1) / 2;
+
+ uint8_t *aa = buffer;
+ for (unsigned int i = 0; i < H; i++) {
+ uint8_t *ai = aa + i * 2 * n_w_byte;
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_set_zero(ai, 2 * n_w_byte);
+ gf256v_add(ai, a + i * n_w_byte, n_w_byte);
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_set_ele(ai + n_w_byte, i, 1);
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_gauss_elim(aa, H, 2 * H);
+ gf16mat_submat(inv_a, H, H, aa, 2 * H, H);
+ return r8;
+}
+
+// choosing the implementations depends on the macros _BLAS_AVX2_ and _BLAS_SSE
+
+#define gf16mat_prod_impl gf16mat_prod_ref
+#define gf16mat_gauss_elim_impl gf16mat_gauss_elim_ref
+#define gf16mat_solve_linear_eq_impl gf16mat_solve_linear_eq_ref
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ gf16mat_prod_impl(c, matA, n_A_vec_byte, n_A_width, b);
+}
+
+unsigned int PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w) {
+ return gf16mat_gauss_elim_impl(mat, h, w);
+}
+
+unsigned int PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ return gf16mat_solve_linear_eq_impl(sol, inp_mat, c_terms, n);
+}
+
diff --git a/crypto_sign/rainbowIa-cyclic/clean/blas_comm.h b/crypto_sign/rainbowIa-cyclic/clean/blas_comm.h
new file mode 100644
index 00000000..570e5ede
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/blas_comm.h
@@ -0,0 +1,74 @@
+#ifndef _BLAS_COMM_H_
+#define _BLAS_COMM_H_
+/// @file blas_comm.h
+/// @brief Common functions for linear algebra.
+///
+
+#include "rainbow_config.h"
+#include
+
+/// @brief set a vector to 0.
+///
+/// @param[in,out] b - the vector b.
+/// @param[in] _num_byte - number of bytes for the vector b.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte);
+
+/// @brief get an element from GF(16) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(const uint8_t *a, unsigned int i);
+
+/// @brief matrix-matrix multiplication: c = a * b , in GF(16)
+///
+/// @param[out] c - the output matrix c
+/// @param[in] c - a matrix a.
+/// @param[in] b - a matrix b.
+/// @param[in] len_vec - the length of column vectors.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec);
+
+/// @brief Gauss elimination for a matrix, in GF(16)
+///
+/// @param[in,out] mat - the matrix.
+/// @param[in] h - the height of the matrix.
+/// @param[in] w - the width of the matrix.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w);
+
+/// @brief Solving linear equations, in GF(16)
+///
+/// @param[out] sol - the solutions.
+/// @param[in] inp_mat - the matrix parts of input equations.
+/// @param[in] c_terms - the constant terms of the input equations.
+/// @param[in] n - the number of equations.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n);
+
+/// @brief Computing the inverse matrix, in GF(16)
+///
+/// @param[out] inv_a - the output of matrix a.
+/// @param[in] a - a matrix a.
+/// @param[in] H - height of matrix a, i.e., matrix a is an HxH matrix.
+/// @param[in] buffer - The buffer for computations. it has to be as large as 2 input matrixes.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer);
+
+/// @brief matrix-vector multiplication: c = matA * b , in GF(16)
+///
+/// @param[out] c - the output vector c
+/// @param[in] matA - a column-major matrix A.
+/// @param[in] n_A_vec_byte - the size of column vectors in bytes.
+/// @param[in] n_A_width - the width of matrix A.
+/// @param[in] b - the vector b.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b);
+
+
+#endif // _BLAS_COMM_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/blas_u32.c b/crypto_sign/rainbowIa-cyclic/clean/blas_u32.c
new file mode 100644
index 00000000..518f6489
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/blas_u32.c
@@ -0,0 +1,115 @@
+#include "blas_u32.h"
+#include "gf.h"
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte) {
+ uint32_t pr_u32 = ((uint32_t)0) - ((uint32_t)predicate);
+ uint8_t pr_u8 = pr_u32 & 0xff;
+
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= (a_u32[i] & pr_u32);
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= (a[i] & pr_u8);
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= a_u32[i];
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= a[i];
+ }
+}
+
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_scalar_u32(uint8_t *a, uint8_t gf16_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *a_u32 = (uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ a_u32[i] = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_u32(a_u32[i], gf16_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_u32(t.u32, gf16_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ a[i] = t.u8[i];
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf16_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *c_u32 = (uint32_t *)accu_c;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ c_u32[i] ^= PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_u32(a_u32[i], gf16_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ accu_c += (n_u32 << 2);
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_u32(t.u32, gf16_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_c[i] ^= t.u8[i];
+ }
+}
+
+uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_dot_u32(const uint8_t *a, const uint8_t *b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ const uint32_t *b_u32 = (const uint32_t *)b;
+ uint32_t r = 0;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ r ^= PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_u32_u32(a_u32[i], b_u32[i]);
+ }
+
+ unsigned int rem = _num_byte & 3;
+ if (rem) {
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } ta, tb;
+ ta.u32 = 0;
+ tb.u32 = 0;
+ for (unsigned int i = 0; i < rem; i++) {
+ ta.u8[i] = a[(n_u32 << 2) + i];
+ }
+ for (unsigned int i = 0; i < rem; i++) {
+ tb.u8[i] = b[(n_u32 << 2) + i];
+ }
+ r ^= PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_u32_u32(ta.u32, tb.u32);
+ }
+ return PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_reduce_u32(r);
+}
+
diff --git a/crypto_sign/rainbowIa-cyclic/clean/blas_u32.h b/crypto_sign/rainbowIa-cyclic/clean/blas_u32.h
new file mode 100644
index 00000000..cd3ea9e4
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/blas_u32.h
@@ -0,0 +1,19 @@
+#ifndef _BLAS_U32_H_
+#define _BLAS_U32_H_
+/// @file blas_u32.h
+/// @brief Inlined functions for implementing basic linear algebra functions for uint32 arch.
+///
+
+#include "rainbow_config.h"
+#include
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte);
+
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf16_b, unsigned int _num_byte);
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_scalar_u32(uint8_t *a, uint8_t gf16_b, unsigned int _num_byte);
+uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_dot_u32(const uint8_t *a, const uint8_t *b, unsigned int _num_byte);
+
+
+#endif // _BLAS_U32_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/gf.c b/crypto_sign/rainbowIa-cyclic/clean/gf.c
new file mode 100644
index 00000000..29c75c68
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/gf.c
@@ -0,0 +1,124 @@
+#include "gf.h"
+
+//// gf4 := gf2[x]/x^2+x+1
+static inline uint8_t gf4_mul_2(uint8_t a) {
+ uint8_t r = (uint8_t)(a << 1);
+ r ^= (uint8_t)((a >> 1) * 7);
+ return r;
+}
+
+static inline uint8_t gf4_mul(uint8_t a, uint8_t b) {
+ uint8_t r = (uint8_t)(a * (b & 1));
+ return r ^ (uint8_t)(gf4_mul_2(a) * (b >> 1));
+}
+
+static inline uint8_t gf4_squ(uint8_t a) {
+ return a ^ (a >> 1);
+}
+
+static inline uint32_t gf4v_mul_2_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit1 ^ (bit1 >> 1);
+}
+
+static inline uint32_t gf4v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t bit0_b = ((uint32_t)0) - ((uint32_t)(b & 1));
+ uint32_t bit1_b = ((uint32_t)0) - ((uint32_t)((b >> 1) & 1));
+ return (a & bit0_b) ^ (bit1_b & gf4v_mul_2_u32(a));
+}
+
+//// gf16 := gf4[y]/y^2+y+x
+static inline uint8_t gf16_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ uint8_t b0 = b & 3;
+ uint8_t b1 = (b >> 2);
+ uint8_t a0b0 = gf4_mul(a0, b0);
+ uint8_t a1b1 = gf4_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf4_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x2 = gf4_mul_2(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 2 ^ a0b0 ^ a1b1_x2);
+}
+
+static inline uint8_t gf16_squ(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ a1 = gf4_squ(a1);
+ uint8_t a1squ_x2 = gf4_mul_2(a1);
+ return (uint8_t)((a1 << 2) ^ a1squ_x2 ^ gf4_squ(a0));
+}
+
+// gf16 := gf4[y]/y^2+y+x
+uint32_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = gf4v_mul_u32(a, b);
+ uint32_t axb1 = gf4v_mul_u32(a, b >> 2);
+ uint32_t a0b1 = (axb1 << 2) & 0xcccccccc;
+ uint32_t a1b1 = axb1 & 0xcccccccc;
+ uint32_t a1b1_2 = a1b1 >> 2;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf4v_mul_2_u32(a1b1_2);
+}
+
+
+static inline uint32_t _gf4v_mul_u32_u32(uint32_t a0, uint32_t a1, uint32_t b0, uint32_t b1) {
+ uint32_t c0 = a0 & b0;
+ uint32_t c2 = a1 & b1;
+ uint32_t c1_ = (a0 ^ a1) & (b0 ^ b1);
+ return ((c1_ ^ c0) << 1) ^ c0 ^ c2;
+}
+
+uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16_is_nonzero(uint8_t a) {
+ unsigned int a4 = a & 0xf;
+ unsigned int r = ((unsigned int)0) - a4;
+ r >>= 4;
+ return r & 1;
+}
+
+uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16_inv(uint8_t a) {
+ uint8_t a2 = gf16_squ(a);
+ uint8_t a4 = gf16_squ(a2);
+ uint8_t a8 = gf16_squ(a4);
+ uint8_t a6 = gf16_mul(a4, a2);
+ return gf16_mul(a8, a6);
+}
+
+static inline uint32_t _gf16v_mul_u32_u32(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) {
+ uint32_t c0 = _gf4v_mul_u32_u32(a0, a1, b0, b1);
+ uint32_t c1_ = _gf4v_mul_u32_u32(a0 ^ a2, a1 ^ a3, b0 ^ b2, b1 ^ b3);
+
+ uint32_t c2_0 = a2 & b2;
+ uint32_t c2_2 = a3 & b3;
+ uint32_t c2_1_ = (a2 ^ a3) & (b2 ^ b3);
+ uint32_t c2_r0 = c2_0 ^ c2_2;
+ uint32_t c2_r1 = c2_0 ^ c2_1_;
+ // GF(4) x2: (bit0<<1)^bit1^(bit1>>1);
+ return ((c1_ ^ c0) << 2) ^ c0 ^ (c2_r0 << 1) ^ c2_r1 ^ (c2_r1 << 1);
+}
+
+uint32_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_u32_u32(uint32_t a, uint32_t b) {
+ uint32_t a0 = a & 0x11111111;
+ uint32_t a1 = (a >> 1) & 0x11111111;
+ uint32_t a2 = (a >> 2) & 0x11111111;
+ uint32_t a3 = (a >> 3) & 0x11111111;
+ uint32_t b0 = b & 0x11111111;
+ uint32_t b1 = (b >> 1) & 0x11111111;
+ uint32_t b2 = (b >> 2) & 0x11111111;
+ uint32_t b3 = (b >> 3) & 0x11111111;
+
+ return _gf16v_mul_u32_u32(a0, a1, a2, a3, b0, b1, b2, b3);
+}
+
+static inline uint8_t gf256v_reduce_u32(uint32_t a) {
+ // https://godbolt.org/z/7hirMb
+ uint16_t *aa = (uint16_t *)(&a);
+ uint16_t r = aa[0] ^ aa[1];
+ uint8_t *rr = (uint8_t *)(&r);
+ return rr[0] ^ rr[1];
+}
+
+uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_reduce_u32(uint32_t a) {
+ uint8_t r256 = gf256v_reduce_u32(a);
+ return (uint8_t)((r256 & 0xf) ^ (r256 >> 4));
+}
+
diff --git a/crypto_sign/rainbowIa-cyclic/clean/gf.h b/crypto_sign/rainbowIa-cyclic/clean/gf.h
new file mode 100644
index 00000000..e45cf934
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/gf.h
@@ -0,0 +1,20 @@
+#ifndef _GF16_H_
+#define _GF16_H_
+
+#include "rainbow_config.h"
+#include
+
+/// @file gf16.h
+/// @brief Library for arithmetics in GF(16) and GF(256)
+///
+
+uint32_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b);
+
+
+uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16_is_nonzero(uint8_t a);
+uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16_inv(uint8_t a);
+uint32_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_u32_u32(uint32_t a, uint32_t b);
+uint8_t PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_reduce_u32(uint32_t a);
+
+
+#endif // _GF16_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/parallel_matrix_op.c b/crypto_sign/rainbowIa-cyclic/clean/parallel_matrix_op.c
new file mode 100644
index 00000000..6fa60381
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/parallel_matrix_op.c
@@ -0,0 +1,182 @@
+/// @file parallel_matrix_op.c
+/// @brief the standard implementations for functions in parallel_matrix_op.h
+///
+/// the standard implementations for functions in parallel_matrix_op.h
+///
+
+#include "parallel_matrix_op.h"
+#include "blas.h"
+#include "blas_comm.h"
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim) {
+ return (dim + dim - i_row + 1) * i_row / 2 + j_col - i_row;
+}
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle or lower-triangle matrix.
+///
+/// @param[in] i_row - the i-th row in a triangle matrix.
+/// @param[in] j_col - the j-th column in a triangle matrix.
+/// @param[in] dim - the dimension of the triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+static inline unsigned int idx_of_2trimat(unsigned int i_row, unsigned int j_col, unsigned int n_var) {
+ if (i_row > j_col) {
+ return PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(j_col, i_row, n_var);
+ }
+ return PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(i_row, j_col, n_var);
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch) {
+ unsigned char *runningC = btriC;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < i; j++) {
+ unsigned int idx = PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(j, i, Aheight);
+ gf256v_add(btriC + idx * size_batch, bA + size_batch * (i * Awidth + j), size_batch);
+ }
+ gf256v_add(runningC, bA + size_batch * (i * Awidth + i), size_batch * (Aheight - i));
+ runningC += size_batch * (Aheight - i);
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (k < i) {
+ continue;
+ }
+ gf16v_madd(bC, &btriA[(k - i) * size_batch], PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ btriA += (Aheight - i) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i < k) {
+ continue;
+ }
+ gf16v_madd(bC, &btriA[size_batch * (PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(k, i, Aheight))], PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i == k) {
+ continue;
+ }
+ gf16v_madd(bC, &btriA[size_batch * (idx_of_2trimat(i, k, Aheight))], PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_matTr_madd_gf16(unsigned char *bC, const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Atr_height = Awidth;
+ unsigned int Atr_width = Aheight;
+ for (unsigned int i = 0; i < Atr_height; i++) {
+ for (unsigned int j = 0; j < Atr_width; j++) {
+ gf16v_madd(bC, &bB[j * Bwidth * size_batch], PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(&A_to_tr[size_Acolvec * i], j), size_batch * Bwidth);
+ }
+ bC += size_batch * Bwidth;
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ const unsigned char *bA = bA_to_tr;
+ unsigned int Aheight = Awidth_before_tr;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf16v_madd(bC, &bA[size_batch * (i + k * Aheight)], PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf16v_madd(bC, &bA[k * size_batch], PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ bA += (Awidth) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y, const unsigned char *mat,
+ const unsigned char *x, unsigned int dim_x, unsigned int size_batch) {
+ unsigned char tmp[128];
+
+ unsigned char _x[128];
+ for (unsigned int i = 0; i < dim_x; i++) {
+ _x[i] = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(x, i);
+ }
+ unsigned char _y[128];
+ for (unsigned int i = 0; i < dim_y; i++) {
+ _y[i] = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(y, i);
+ }
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_set_zero(z, size_batch);
+ for (unsigned int i = 0; i < dim_y; i++) {
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = 0; j < dim_x; j++) {
+ gf16v_madd(tmp, mat, _x[j], size_batch);
+ mat += size_batch;
+ }
+ gf16v_madd(z, tmp, _y[i], size_batch);
+ }
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch) {
+ unsigned char tmp[256];
+
+ unsigned char _x[256];
+ for (unsigned int i = 0; i < dim; i++) {
+ _x[i] = PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele(x, i);
+ }
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_set_zero(y, size_batch);
+ for (unsigned int i = 0; i < dim; i++) {
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = i; j < dim; j++) {
+ gf16v_madd(tmp, trimat, _x[j], size_batch);
+ trimat += size_batch;
+ }
+ gf16v_madd(y, tmp, _x[i], size_batch);
+ }
+}
diff --git a/crypto_sign/rainbowIa-cyclic/clean/parallel_matrix_op.h b/crypto_sign/rainbowIa-cyclic/clean/parallel_matrix_op.h
new file mode 100644
index 00000000..223fbeea
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/parallel_matrix_op.h
@@ -0,0 +1,260 @@
+#ifndef _P_MATRIX_OP_H_
+#define _P_MATRIX_OP_H_
+/// @file parallel_matrix_op.h
+/// @brief Librarys for operations of batched matrixes.
+///
+///
+
+//////////////// Section: triangle matrix <-> rectangle matrix ///////////////////////////////////
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim);
+
+///
+/// @brief Upper trianglize a rectangle matrix to the corresponding upper-trangle matrix.
+///
+/// @param[out] btriC - the batched upper-trianglized matrix C.
+/// @param[in] bA - a batched retangle matrix A.
+/// @param[in] bwidth - the width of the batched matrix A, i.e., A is a Awidth x Awidth matrix.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch);
+
+//////////////////// Section: matrix multiplications ///////////////////////////////
+
+///
+/// @brief bC += btriA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. A will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A, which will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_matTr_madd_gf16(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_matTr_madd_gf256(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+//////////////////// Section: "quadratric" matrix evaluation ///////////////////////////////
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(16)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(256)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(16)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(256)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+#endif // _P_MATRIX_OP_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/rainbow.c b/crypto_sign/rainbowIa-cyclic/clean/rainbow.c
new file mode 100644
index 00000000..7fc7e5b7
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/rainbow.c
@@ -0,0 +1,174 @@
+/// @file rainbow.c
+/// @brief The standard implementations for functions in rainbow.h
+///
+
+#include "rainbow.h"
+#include "blas.h"
+#include "rainbow_blas.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "utils_hash.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+#define MAX_ATTEMPT_FRMAT 128
+#define _MAX_O ((_O1 > _O2) ? _O1 : _O2)
+#define _MAX_O_BYTE ((_O1_BYTE > _O2_BYTE) ? _O1_BYTE : _O2_BYTE)
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *_digest) {
+ uint8_t mat_l1[_O1 * _O1_BYTE];
+ uint8_t mat_l2[_O2 * _O2_BYTE];
+ uint8_t mat_buffer[2 * _MAX_O * _MAX_O_BYTE];
+
+ // setup PRNG
+ prng_t prng_sign;
+ uint8_t prng_preseed[LEN_SKSEED + _HASH_LEN];
+ memcpy(prng_preseed, sk->sk_seed, LEN_SKSEED);
+ memcpy(prng_preseed + LEN_SKSEED, _digest, _HASH_LEN); // prng_preseed = sk_seed || digest
+ uint8_t prng_seed[_HASH_LEN];
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_hash_msg(prng_seed, _HASH_LEN, prng_preseed, _HASH_LEN + LEN_SKSEED);
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_set(&prng_sign, prng_seed, _HASH_LEN); // seed = H( sk_seed || digest )
+ for (unsigned int i = 0; i < LEN_SKSEED + _HASH_LEN; i++) {
+ prng_preseed[i] ^= prng_preseed[i]; // clean
+ }
+ for (unsigned int i = 0; i < _HASH_LEN; i++) {
+ prng_seed[i] ^= prng_seed[i]; // clean
+ }
+
+ // roll vinegars.
+ uint8_t vinegar[_V1_BYTE];
+ unsigned int n_attempt = 0;
+ unsigned int l1_succ = 0;
+ while (!l1_succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(&prng_sign, vinegar, _V1_BYTE); // generating vinegars
+ gfmat_prod(mat_l1, sk->l1_F2, _O1 * _O1_BYTE, _V1, vinegar); // generating the linear equations for layer 1
+ l1_succ = gfmat_inv(mat_l1, mat_l1, _O1, mat_buffer); // check if the linear equation solvable
+ n_attempt++;
+ }
+
+ // Given the vinegars, pre-compute variables needed for layer 2
+ uint8_t r_l1_F1[_O1_BYTE] = {0};
+ uint8_t r_l2_F1[_O2_BYTE] = {0};
+ batch_quad_trimat_eval(r_l1_F1, sk->l1_F1, vinegar, _V1, _O1_BYTE);
+ batch_quad_trimat_eval(r_l2_F1, sk->l2_F1, vinegar, _V1, _O2_BYTE);
+ uint8_t mat_l2_F3[_O2 * _O2_BYTE];
+ uint8_t mat_l2_F2[_O1 * _O2_BYTE];
+ gfmat_prod(mat_l2_F3, sk->l2_F3, _O2 * _O2_BYTE, _V1, vinegar);
+ gfmat_prod(mat_l2_F2, sk->l2_F2, _O1 * _O2_BYTE, _V1, vinegar);
+
+ // Some local variables.
+ uint8_t _z[_PUB_M_BYTE];
+ uint8_t y[_PUB_M_BYTE];
+ uint8_t *x_v1 = vinegar;
+ uint8_t x_o1[_O1_BYTE];
+ uint8_t x_o2[_O1_BYTE];
+
+ uint8_t digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, _digest, _HASH_LEN);
+ uint8_t *salt = digest_salt + _HASH_LEN;
+
+ uint8_t temp_o[_MAX_O_BYTE + 32] = {0};
+ unsigned int succ = 0;
+ while (!succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ // The computation: H(digest||salt) --> z --S--> y --C-map--> x --T--> w
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(&prng_sign, salt, _SALT_BYTE); // roll the salt
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_hash_msg(_z, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H(digest||salt)
+
+ // y = S^-1 * z
+ memcpy(y, _z, _PUB_M_BYTE); // identity part of S
+ gfmat_prod(temp_o, sk->s1, _O1_BYTE, _O2, _z + _O1_BYTE);
+ gf256v_add(y, temp_o, _O1_BYTE);
+
+ // Central Map:
+ // layer 1: calculate x_o1
+ memcpy(temp_o, r_l1_F1, _O1_BYTE);
+ gf256v_add(temp_o, y, _O1_BYTE);
+ gfmat_prod(x_o1, mat_l1, _O1_BYTE, _O1, temp_o);
+
+ // layer 2: calculate x_o2
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf256v_set_zero(temp_o, _O2_BYTE);
+ gfmat_prod(temp_o, mat_l2_F2, _O2_BYTE, _O1, x_o1); // F2
+ batch_quad_trimat_eval(mat_l2, sk->l2_F5, x_o1, _O1, _O2_BYTE); // F5
+ gf256v_add(temp_o, mat_l2, _O2_BYTE);
+ gf256v_add(temp_o, r_l2_F1, _O2_BYTE); // F1
+ gf256v_add(temp_o, y + _O1_BYTE, _O2_BYTE);
+
+ // generate the linear equations of the 2nd layer
+ gfmat_prod(mat_l2, sk->l2_F6, _O2 * _O2_BYTE, _O1, x_o1); // F6
+ gf256v_add(mat_l2, mat_l2_F3, _O2 * _O2_BYTE); // F3
+ succ = gfmat_inv(mat_l2, mat_l2, _O2, mat_buffer);
+ gfmat_prod(x_o2, mat_l2, _O2_BYTE, _O2, temp_o); // solve l2 eqs
+
+ n_attempt++;
+ };
+ // w = T^-1 * y
+ uint8_t w[_PUB_N_BYTE];
+ // identity part of T.
+ memcpy(w, x_v1, _V1_BYTE);
+ memcpy(w + _V1_BYTE, x_o1, _O1_BYTE);
+ memcpy(w + _V2_BYTE, x_o2, _O2_BYTE);
+ // Computing the t1 part.
+ gfmat_prod(y, sk->t1, _V1_BYTE, _O1, x_o1);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t4 part.
+ gfmat_prod(y, sk->t4, _V1_BYTE, _O2, x_o2);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t3 part.
+ gfmat_prod(y, sk->t3, _O1_BYTE, _O2, x_o2);
+ gf256v_add(w + _V1_BYTE, y, _O1_BYTE);
+
+ memset(signature, 0, _SIGNATURE_BYTE); // set the output 0
+ // clean
+ memset(&prng_sign, 0, sizeof(prng_t));
+ memset(vinegar, 0, _V1_BYTE);
+ memset(r_l1_F1, 0, _O1_BYTE);
+ memset(r_l2_F1, 0, _O2_BYTE);
+ memset(_z, 0, _PUB_M_BYTE);
+ memset(y, 0, _PUB_M_BYTE);
+ memset(x_o1, 0, _O1_BYTE);
+ memset(x_o2, 0, _O2_BYTE);
+ memset(temp_o, 0, sizeof(temp_o));
+
+ // return: copy w and salt to the signature.
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ return -1;
+ }
+ gf256v_add(signature, w, _PUB_N_BYTE);
+ gf256v_add(signature + _PUB_N_BYTE, salt, _SALT_BYTE);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk) {
+ unsigned char digest_ck[_PUB_M_BYTE];
+ // public_map( digest_ck , pk , signature ); Evaluating the quadratic public polynomials.
+ batch_quad_trimat_eval(digest_ck, pk->pk, signature, _PUB_N, _PUB_M_BYTE);
+
+ unsigned char correct[_PUB_M_BYTE];
+ unsigned char digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, digest, _HASH_LEN);
+ memcpy(digest_salt + _HASH_LEN, signature + _PUB_N_BYTE, _SALT_BYTE);
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_hash_msg(correct, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H( digest || salt )
+
+ // check consistancy.
+ unsigned char cc = 0;
+ for (unsigned int i = 0; i < _PUB_M_BYTE; i++) {
+ cc |= (digest_ck[i] ^ correct[i]);
+ }
+ return (0 == cc) ? 0 : -1;
+}
+
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *_pk) {
+ unsigned char pk[sizeof(pk_t) + 32];
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_cpk_to_pk((pk_t *)pk, _pk); // generating classic public key.
+ return PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_verify(digest, signature, (pk_t *)pk);
+}
diff --git a/crypto_sign/rainbowIa-cyclic/clean/rainbow.h b/crypto_sign/rainbowIa-cyclic/clean/rainbow.h
new file mode 100644
index 00000000..dca27b11
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/rainbow.h
@@ -0,0 +1,42 @@
+#ifndef _RAINBOW_H_
+#define _RAINBOW_H_
+/// @file rainbow.h
+/// @brief APIs for rainbow.
+///
+
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+
+#include
+
+///
+/// @brief Signing function for classical secret key.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk);
+
+
+///
+/// @brief Verifying function for cyclic public keys.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key of cyclic rainbow.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *pk);
+
+#endif // _RAINBOW_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/rainbow_blas.h b/crypto_sign/rainbowIa-cyclic/clean/rainbow_blas.h
new file mode 100644
index 00000000..b0bd58ae
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/rainbow_blas.h
@@ -0,0 +1,31 @@
+#ifndef _RAINBOW_BLAS_H_
+#define _RAINBOW_BLAS_H_
+/// @file rainbow_blas.h
+/// @brief Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+///
+/// Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+
+#include "blas.h"
+#include "parallel_matrix_op.h"
+#include "rainbow_config.h"
+
+
+#define gfv_get_ele PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_get_ele
+#define gfv_mul_scalar PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_mul_scalar
+#define gfv_madd PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16v_madd
+
+#define gfmat_prod PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_prod
+#define gfmat_inv PQCLEAN_RAINBOWIACYCLIC_CLEAN_gf16mat_inv
+
+#define batch_trimat_madd PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_trimat_madd_gf16
+#define batch_trimatTr_madd PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_trimatTr_madd_gf16
+#define batch_2trimat_madd PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_2trimat_madd_gf16
+#define batch_matTr_madd PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_matTr_madd_gf16
+#define batch_bmatTr_madd PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_bmatTr_madd_gf16
+#define batch_mat_madd PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_mat_madd_gf16
+
+#define batch_quad_trimat_eval PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_quad_trimat_eval_gf16
+#define batch_quad_recmat_eval PQCLEAN_RAINBOWIACYCLIC_CLEAN_batch_quad_recmat_eval_gf16
+
+
+#endif // _RAINBOW_BLAS_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/rainbow_config.h b/crypto_sign/rainbowIa-cyclic/clean/rainbow_config.h
new file mode 100644
index 00000000..2222abe1
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/rainbow_config.h
@@ -0,0 +1,47 @@
+#ifndef _H_RAINBOW_CONFIG_H_
+#define _H_RAINBOW_CONFIG_H_
+
+/// @file rainbow_config.h
+/// @brief Defining the parameters of the Rainbow and the corresponding constants.
+///
+
+#define _USE_GF16
+#define _GFSIZE 16
+#define _V1 32
+#define _O1 32
+#define _O2 32
+#define _HASH_LEN 32
+
+
+#define _V2 ((_V1) + (_O1))
+
+/// size of N, in # of gf elements.
+#define _PUB_N (_V1 + _O1 + _O2)
+
+/// size of M, in # gf elements.
+#define _PUB_M (_O1 + _O2)
+
+/// size of variables, in # bytes.
+
+// GF16
+#define _V1_BYTE (_V1 / 2)
+#define _V2_BYTE (_V2 / 2)
+#define _O1_BYTE (_O1 / 2)
+#define _O2_BYTE (_O2 / 2)
+#define _PUB_N_BYTE (_PUB_N / 2)
+#define _PUB_M_BYTE (_PUB_M / 2)
+
+
+/// length of seed for public key, in # bytes
+#define LEN_PKSEED 32
+
+/// length of seed for secret key, in # bytes
+#define LEN_SKSEED 32
+
+/// length of salt for a signature, in # bytes
+#define _SALT_BYTE 16
+
+/// length of a signature
+#define _SIGNATURE_BYTE (_PUB_N_BYTE + _SALT_BYTE)
+
+#endif // _H_RAINBOW_CONFIG_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair.c b/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair.c
new file mode 100644
index 00000000..92d08634
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair.c
@@ -0,0 +1,157 @@
+/// @file rainbow_keypair.c
+/// @brief implementations of functions in rainbow_keypair.h
+///
+
+#include "rainbow_keypair.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair_computation.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+static void generate_S_T(unsigned char *s_and_t, prng_t *prng0) {
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // S1
+ s_and_t += _O1_BYTE * _O2;
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O1); // T1
+ s_and_t += _V1_BYTE * _O1;
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O2); // T2
+ s_and_t += _V1_BYTE * _O2;
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // T3
+}
+
+static unsigned int generate_l1_F12(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * N_TRIANGLE_TERMS(_V1)); // l1_F1
+ sk += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * _V1 * _O1); // l1_F2
+ n_byte_generated += _O1_BYTE * _V1 * _O1;
+ return n_byte_generated;
+}
+
+static unsigned int generate_l2_F12356(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // l2_F1
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O1); // l2_F2
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O2); // l2_F3
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // l2_F5
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _O1 * _O2); // l2_F6
+ n_byte_generated += _O2_BYTE * _O1 * _O2;
+
+ return n_byte_generated;
+}
+
+static void generate_B1_B2(unsigned char *sk, prng_t *prng0) {
+ sk += generate_l1_F12(sk, prng0);
+ generate_l2_F12356(sk, prng0);
+}
+
+static void calculate_t4(unsigned char *t2_to_t4, const unsigned char *t1, const unsigned char *t3) {
+ // t4 = T_sk.t1 * T_sk.t3 - T_sk.t2
+ unsigned char temp[_V1_BYTE + 32];
+ unsigned char *t4 = t2_to_t4;
+ for (unsigned int i = 0; i < _O2; i++) { /// t3 width
+ gfmat_prod(temp, t1, _V1_BYTE, _O1, t3);
+ gf256v_add(t4, temp, _V1_BYTE);
+ t4 += _V1_BYTE;
+ t3 += _O1_BYTE;
+ }
+}
+
+static void obsfucate_l1_polys(unsigned char *l1_polys, const unsigned char *l2_polys, unsigned int n_terms, const unsigned char *s1) {
+ unsigned char temp[_O1_BYTE + 32];
+ while (n_terms--) {
+ gfmat_prod(temp, s1, _O1_BYTE, _O2, l2_polys);
+ gf256v_add(l1_polys, temp, _O1_BYTE);
+ l1_polys += _O1_BYTE;
+ l2_polys += _O2_BYTE;
+ }
+}
+
+/////////////////// Classic //////////////////////////////////
+
+
+///////////////////// Cyclic //////////////////////////////////
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(pk->pk_seed, pk_seed, LEN_PKSEED);
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // prng for sk
+ prng_t prng;
+ prng_t *prng0 = &prng;
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_set(prng0, sk_seed, LEN_SKSEED);
+ generate_S_T(sk->s1, prng0); // S,T: only a part of sk
+
+ unsigned char t2[sizeof(sk->t4)];
+ memcpy(t2, sk->t4, _V1_BYTE * _O2); // temporarily store t2
+ calculate_t4(sk->t4, sk->t1, sk->t3); // t2 <- t4
+
+ // prng for pk
+ sk_t inst_Qs;
+ sk_t *Qs = &inst_Qs;
+ prng_t *prng1 = &prng;
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_set(prng1, pk_seed, LEN_PKSEED);
+ generate_B1_B2(Qs->l1_F1, prng1); // generating l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+ obsfucate_l1_polys(Qs->l1_F1, Qs->l2_F1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(Qs->l1_F2, Qs->l2_F2, _V1 * _O1, sk->s1);
+ // so far, the Qs contains l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6.
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_calculate_F_from_Q(sk, Qs, sk); // calcuate the rest parts of secret key from Qs and S,T
+
+ unsigned char t4[sizeof(sk->t4)];
+ memcpy(t4, sk->t4, _V1_BYTE * _O2); // temporarily store t4
+ memcpy(sk->t4, t2, _V1_BYTE * _O2); // restore t2
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_calculate_Q_from_F_cyclic(pk, sk, sk); // calculate the rest parts of public key: l1_Q3, l1_Q5, l1_Q6, l1_Q9, l2_Q9
+ memcpy(sk->t4, t4, _V1_BYTE * _O2); // restore t4
+
+ obsfucate_l1_polys(pk->l1_Q3, Qs->l2_F3, _V1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q5, Qs->l2_F5, N_TRIANGLE_TERMS(_O1), sk->s1);
+ obsfucate_l1_polys(pk->l1_Q6, Qs->l2_F6, _O1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q9, pk->l2_Q9, N_TRIANGLE_TERMS(_O2), sk->s1);
+
+ // clean
+ memset(&prng, 0, sizeof(prng_t));
+}
+
+
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_cpk_to_pk(pk_t *rpk, const cpk_t *cpk) {
+ // procedure: cpk_t --> extcpk_t --> pk_t
+
+ // convert from cpk_t to extcpk_t
+ ext_cpk_t pk;
+
+ // setup prng
+ prng_t prng0;
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_set(&prng0, cpk->pk_seed, LEN_SKSEED);
+
+ // generating parts of key with prng
+ generate_l1_F12(pk.l1_Q1, &prng0);
+ // copying parts of key from input. l1_Q3, l1_Q5, l1_Q6, l1_Q9
+ memcpy(pk.l1_Q3, cpk->l1_Q3, _O1_BYTE * (_V1 * _O2 + N_TRIANGLE_TERMS(_O1) + _O1 * _O2 + N_TRIANGLE_TERMS(_O2)));
+
+ // generating parts of key with prng
+ generate_l2_F12356(pk.l2_Q1, &prng0);
+ // copying parts of key from input: l2_Q9
+ memcpy(pk.l2_Q9, cpk->l2_Q9, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ // convert from extcpk_t to pk_t
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_extcpk_to_pk(rpk, &pk);
+}
diff --git a/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair.h b/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair.h
new file mode 100644
index 00000000..3490ea05
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair.h
@@ -0,0 +1,94 @@
+#ifndef _RAINBOW_KEYPAIR_H_
+#define _RAINBOW_KEYPAIR_H_
+/// @file rainbow_keypair.h
+/// @brief Formats of key pairs and functions for generating key pairs.
+/// Formats of key pairs and functions for generating key pairs.
+///
+
+#include "rainbow_config.h"
+
+#define N_TRIANGLE_TERMS(n_var) ((n_var) * ((n_var) + 1) / 2)
+
+/// @brief public key for classic rainbow
+///
+/// public key for classic rainbow
+///
+typedef struct rainbow_publickey {
+ unsigned char pk[(_PUB_M_BYTE)*N_TRIANGLE_TERMS(_PUB_N)];
+} pk_t;
+
+/// @brief secret key for classic rainbow
+///
+/// secret key for classic rainbow
+///
+typedef struct rainbow_secretkey {
+ ///
+ /// seed for generating secret key.
+ /// Generating S, T, and F for classic rainbow.
+ /// Generating S and T only for cyclic rainbow.
+ unsigned char sk_seed[LEN_SKSEED];
+
+ unsigned char s1[_O1_BYTE * _O2]; ///< part of S map
+ unsigned char t1[_V1_BYTE * _O1]; ///< part of T map
+ unsigned char t4[_V1_BYTE * _O2]; ///< part of T map
+ unsigned char t3[_O1_BYTE * _O2]; ///< part of T map
+
+ unsigned char l1_F1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer1
+ unsigned char l1_F2[_O1_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer1
+
+ unsigned char l2_F1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer2
+ unsigned char l2_F2[_O2_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer2
+
+ unsigned char l2_F3[_O2_BYTE * _V1 * _O2]; ///< part of C-map, F3, Layer2
+ unsigned char l2_F5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< part of C-map, F5, Layer2
+ unsigned char l2_F6[_O2_BYTE * _O1 * _O2]; ///< part of C-map, F6, Layer2
+} sk_t;
+
+/// @brief public key for cyclic rainbow
+///
+/// public key for cyclic rainbow
+///
+typedef struct rainbow_publickey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating l1_Q1,l1_Q2,l2_Q1,l2_Q2,l2_Q3,l2_Q5,l2_Q6
+
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2]; ///< Q3, layer1
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< Q5, layer1
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2]; ///< Q6, layer1
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer1
+
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer2
+} cpk_t;
+
+/// @brief compressed secret key for cyclic rainbow
+///
+/// compressed secret key for cyclic rainbow
+///
+typedef struct rainbow_secretkey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating a part of public key.
+ unsigned char sk_seed[LEN_SKSEED]; ///< seed for generating a part of secret key.
+} csk_t;
+
+
+///
+/// @brief Generate key pairs for cyclic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the secret key.
+/// @param[in] pk_seed - seed for generating parts of public key.
+/// @param[in] sk_seed - seed for generating secret key.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+
+
+////////////////////////////////////
+
+///
+/// @brief converting formats of public keys : from cyclic version to classic key
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the cyclic public key.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_cpk_to_pk(pk_t *pk, const cpk_t *cpk);
+
+#endif // _RAINBOW_KEYPAIR_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair_computation.c b/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair_computation.c
new file mode 100644
index 00000000..982d13b1
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair_computation.c
@@ -0,0 +1,213 @@
+/// @file rainbow_keypair_computation.c
+/// @brief Implementations for functions in rainbow_keypair_computation.h
+///
+
+#include "rainbow_keypair_computation.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair.h"
+#include
+#include
+#include
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk) {
+ const unsigned char *idx_l1 = cpk->l1_Q1;
+ const unsigned char *idx_l2 = cpk->l2_Q1;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = i; j < _V1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q2;
+ idx_l2 = cpk->l2_Q2;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q3;
+ idx_l2 = cpk->l2_Q3;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q5;
+ idx_l2 = cpk->l2_Q5;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = i; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q6;
+ idx_l2 = cpk->l2_Q6;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q9;
+ idx_l2 = cpk->l2_Q9;
+ for (unsigned int i = _V1 + _O1; i < _PUB_N; i++) {
+ for (unsigned int j = i; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWIACYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+}
+
+static void calculate_F_from_Q_ref(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ // Layer 1
+ // F_sk.l1_F1s[i] = Q_pk.l1_F1s[i]
+ memcpy(Fs->l1_F1, Qs->l1_F1, _O1_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ // F_sk.l1_F2s[i] = ( Q_pk.l1_F1s[i] + Q_pk.l1_F1s[i].transpose() ) * T_sk.t1 + Q_pk.l1_F2s[i]
+ memcpy(Fs->l1_F2, Qs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_2trimat_madd(Fs->l1_F2, Qs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE);
+
+ /*
+ Layer 2
+ computations:
+
+ F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ Q1_T1 = Q_pk.l2_F1s[i]*T_sk.t1
+ F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+
+ Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ #Q1_Q1T_T4 = Q1_Q1T * t4
+ Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ + Q_pk.l2_F2s[i].transpose() * t4
+ + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+
+ */
+ memcpy(Fs->l2_F1, Qs->l2_F1, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ // F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ // F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+ memcpy(Fs->l2_F2, Qs->l2_F2, _O2_BYTE * _V1 * _O1);
+ batch_trimat_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // Q1_T1+ Q2
+
+ unsigned char tempQ[_O1 * _O1 * _O2_BYTE + 32];
+ memset(tempQ, 0, _O1 * _O1 * _O2_BYTE);
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F2, _O1, _O2_BYTE); // t1_tr*(Q1_T1+Q2)
+ memcpy(Fs->l2_F5, Qs->l2_F5, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // F5
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_UpperTrianglize(Fs->l2_F5, tempQ, _O1, _O2_BYTE); // UT( ... )
+
+ batch_trimatTr_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // F2 = Q1_T1 + Q2 + Q1^tr*t1
+
+ // Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ // Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ // F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ memcpy(Fs->l2_F3, Qs->l2_F3, _V1 * _O2 * _O2_BYTE);
+ batch_2trimat_madd(Fs->l2_F3, Qs->l2_F1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE); // Q1_Q1T_T4
+ batch_mat_madd(Fs->l2_F3, Qs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // Q2_T3
+
+ // F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ // + Q_pk.l2_F2s[i].transpose() * t4
+ // + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+ memcpy(Fs->l2_F6, Qs->l2_F6, _O1 * _O2 * _O2_BYTE);
+ batch_matTr_madd(Fs->l2_F6, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F3, _O2, _O2_BYTE); // t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ batch_2trimat_madd(Fs->l2_F6, Qs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3
+ batch_bmatTr_madd(Fs->l2_F6, Qs->l2_F2, _O1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE);
+}
+
+static void calculate_Q_from_F_cyclic_ref(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ // Layer 1: Computing Q5, Q3, Q6, Q9
+
+ // Q_pk.l1_F5s[i] = UT( T1tr* (F1 * T1 + F2) )
+ const unsigned char *t2 = Ts->t4;
+ sk_t tempQ;
+ memcpy(tempQ.l1_F2, Fs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_trimat_madd(tempQ.l1_F2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // F1*T1 + F2
+ memset(tempQ.l2_F1, 0, sizeof(tempQ.l2_F1));
+ memset(tempQ.l2_F2, 0, sizeof(tempQ.l2_F2));
+ batch_matTr_madd(tempQ.l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, tempQ.l1_F2, _O1, _O1_BYTE); // T1tr*(F1*T1 + F2)
+ memset(Qs->l1_Q5, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O1));
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_UpperTrianglize(Qs->l1_Q5, tempQ.l2_F1, _O1, _O1_BYTE); // UT( ... ) // Q5
+
+ /*
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+ Q_pk.l1_F3s[i] = F1_F1T_T2 + F2_T3
+ Q_pk.l1_F6s[i] = T1tr* ( F1_F1T_T2 + F2_T3 ) + F2tr * t2
+ Q_pk.l1_F9s[i] = UT( T2tr* ( F1_T2 + F2_T3 ) )
+ */
+ memset(Qs->l1_Q3, 0, _O1_BYTE * _V1 * _O2);
+ memset(Qs->l1_Q6, 0, _O1_BYTE * _O1 * _O2);
+ memset(Qs->l1_Q9, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ batch_trimat_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1*T2
+ batch_mat_madd(Qs->l1_Q3, Fs->l1_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O1_BYTE); // F1_T2 + F2_T3
+
+ memset(tempQ.l1_F2, 0, _O1_BYTE * _V1 * _O2); // should be F3. assuming: _O1 >= _O2
+ batch_matTr_madd(tempQ.l1_F2, t2, _V1, _V1_BYTE, _O2, Qs->l1_Q3, _O2, _O1_BYTE); // T2tr * ( F1_T2 + F2_T3 )
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_UpperTrianglize(Qs->l1_Q9, tempQ.l1_F2, _O2, _O1_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1_F1T_T2 + F2_T3 // Q3
+
+ batch_bmatTr_madd(Qs->l1_Q6, Fs->l1_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F2tr*T2
+ batch_matTr_madd(Qs->l1_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q3, _O2, _O1_BYTE); // Q6
+ /*
+ Layer 2
+ Computing Q9:
+
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ Q9 = UT( T2tr*( F1*T2 + F2*T3 + F3 ) + T3tr*( F5*T3 + F6 ) )
+ */
+ sk_t tempQ2;
+ memcpy(tempQ2.l2_F3, Fs->l2_F3, _O2_BYTE * _V1 * _O2); /// F3 actually.
+ batch_trimat_madd(tempQ2.l2_F3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1*T2 + F3
+ batch_mat_madd(tempQ2.l2_F3, Fs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F1_T2 + F2_T3 + F3
+
+ memset(tempQ.l2_F3, 0, _O2_BYTE * _V1 * _O2);
+ batch_matTr_madd(tempQ.l2_F3, t2, _V1, _V1_BYTE, _O2, tempQ2.l2_F3, _O2, _O2_BYTE); // T2tr * ( ..... )
+
+ memcpy(tempQ.l2_F6, Fs->l2_F6, _O2_BYTE * _O1 * _O2);
+ batch_trimat_madd(tempQ.l2_F6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6
+
+ batch_matTr_madd(tempQ.l2_F3, Ts->t3, _O1, _O1_BYTE, _O2, tempQ.l2_F6, _O2, _O2_BYTE); // T2tr*( ..... ) + T3tr*( ..... )
+ memset(Qs->l2_Q9, 0, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_UpperTrianglize(Qs->l2_Q9, tempQ.l2_F3, _O2, _O2_BYTE); // Q9
+}
+
+// Choosing implementations depends on the macros: _BLAS_SSE_ and _BLAS_AVX2_
+#define calculate_F_from_Q_impl calculate_F_from_Q_ref
+#define calculate_Q_from_F_cyclic_impl calculate_Q_from_F_cyclic_ref
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ calculate_F_from_Q_impl(Fs, Qs, Ts);
+}
+
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ calculate_Q_from_F_cyclic_impl(Qs, Fs, Ts);
+}
diff --git a/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair_computation.h b/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair_computation.h
new file mode 100644
index 00000000..9416abb4
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/rainbow_keypair_computation.h
@@ -0,0 +1,71 @@
+#ifndef _RAINBOW_KEYPAIR_COMP_H_
+#define _RAINBOW_KEYPAIR_COMP_H_
+/// @file rainbow_keypair_computation.h
+/// @brief Functions for calculating pk/sk while generating keys.
+///
+/// Defining an internal structure of public key.
+/// Functions for calculating pk/sk for key generation.
+///
+
+#include "rainbow_keypair.h"
+
+/// @brief The (internal use) public key for rainbow
+///
+/// The (internal use) public key for rainbow. The public
+/// polynomials are divided into l1_Q1, l1_Q2, ... l1_Q9,
+/// l2_Q1, .... , l2_Q9.
+///
+typedef struct rainbow_extend_publickey {
+ unsigned char l1_Q1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l1_Q2[_O1_BYTE * _V1 * _O1];
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2];
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2];
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)];
+
+ unsigned char l2_Q1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l2_Q2[_O2_BYTE * _V1 * _O1];
+ unsigned char l2_Q3[_O2_BYTE * _V1 * _O2];
+ unsigned char l2_Q5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l2_Q6[_O2_BYTE * _O1 * _O2];
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)];
+} ext_cpk_t;
+
+///
+/// @brief converting formats of public keys : from ext_cpk_t version to pk_t
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the internel public key.
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk);
+/////////////////////////////////////////////////
+
+///
+/// @brief Computing public key from secret key
+///
+/// @param[out] Qs - the public key
+/// @param[in] Fs - parts of the secret key: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the secret key: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+
+///
+/// @brief Computing parts of the sk from parts of pk and sk
+///
+/// @param[out] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Qs - parts of the pk: l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts);
+
+///
+/// @brief Computing parts of the pk from the secret key
+///
+/// @param[out] Qs - parts of the pk: l1_Q3, l1_Q5, l2_Q6, l1_Q9, l2_Q9
+/// @param[in] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWIACYCLIC_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+#endif // _RAINBOW_KEYPAIR_COMP_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/sign.c b/crypto_sign/rainbowIa-cyclic/clean/sign.c
new file mode 100644
index 00000000..cd5c2809
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/sign.c
@@ -0,0 +1,76 @@
+/// @file sign.c
+/// @brief the implementations for functions in api.h
+///
+///
+
+#include "api.h"
+#include "rainbow.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
+ unsigned char sk_seed[LEN_SKSEED] = {0};
+ randombytes(sk_seed, LEN_SKSEED);
+
+ unsigned char pk_seed[LEN_PKSEED] = {0};
+ randombytes(pk_seed, LEN_PKSEED);
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_generate_keypair_cyclic((cpk_t *)pk, (sk_t *)sk, pk_seed, sk_seed);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_crypto_sign(unsigned char *sm, size_t *smlen, const unsigned char *m, size_t mlen, const unsigned char *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+
+ memcpy(sm, m, mlen);
+ smlen[0] = mlen + _SIGNATURE_BYTE;
+
+ return PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_sign(sm + mlen, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_crypto_sign_open(unsigned char *m, size_t *mlen, const unsigned char *sm, size_t smlen, const unsigned char *pk) {
+ int rc;
+ if (_SIGNATURE_BYTE > smlen) {
+ rc = -1;
+ } else {
+ *mlen = smlen - _SIGNATURE_BYTE;
+
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, sm, *mlen);
+
+ rc = PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_verify_cyclic(digest, sm + mlen[0], (const cpk_t *)pk);
+ }
+ if (!rc) {
+ memcpy(m, sm, smlen - _SIGNATURE_BYTE);
+ } else { // bad signature
+ *mlen = (size_t) -1;
+ memset(m, 0, smlen);
+ }
+ return rc;
+}
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ *siglen = _SIGNATURE_BYTE;
+ return PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_sign(sig, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ if (siglen != _SIGNATURE_BYTE) {
+ return -1;
+ }
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ return PQCLEAN_RAINBOWIACYCLIC_CLEAN_rainbow_verify_cyclic(digest, sig, (const cpk_t *)pk);
+}
diff --git a/crypto_sign/rainbowIa-cyclic/clean/utils_hash.c b/crypto_sign/rainbowIa-cyclic/clean/utils_hash.c
new file mode 100644
index 00000000..dba6a633
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/utils_hash.c
@@ -0,0 +1,50 @@
+/// @file utils_hash.c
+/// @brief the adapter for SHA2 families.
+///
+///
+
+#include "utils_hash.h"
+#include "rainbow_config.h"
+#include "sha2.h"
+
+static inline int _hash(unsigned char *digest, const unsigned char *m, size_t mlen) {
+ sha256(digest, m, mlen);
+ return 0;
+}
+
+static inline int expand_hash(unsigned char *digest, size_t n_digest, const unsigned char *hash) {
+ if (_HASH_LEN >= n_digest) {
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[i] = hash[i];
+ }
+ return 0;
+ }
+ for (size_t i = 0; i < _HASH_LEN; i++) {
+ digest[i] = hash[i];
+ }
+ n_digest -= _HASH_LEN;
+
+ while (_HASH_LEN <= n_digest) {
+ _hash(digest + _HASH_LEN, digest, _HASH_LEN);
+
+ n_digest -= _HASH_LEN;
+ digest += _HASH_LEN;
+ }
+ unsigned char temp[_HASH_LEN];
+ if (n_digest) {
+ _hash(temp, digest, _HASH_LEN);
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[_HASH_LEN + i] = temp[i];
+ }
+ }
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_hash_msg(unsigned char *digest,
+ size_t len_digest,
+ const unsigned char *m,
+ size_t mlen) {
+ unsigned char buf[_HASH_LEN];
+ _hash(buf, m, mlen);
+ return expand_hash(digest, len_digest, buf);
+}
diff --git a/crypto_sign/rainbowIa-cyclic/clean/utils_hash.h b/crypto_sign/rainbowIa-cyclic/clean/utils_hash.h
new file mode 100644
index 00000000..da601579
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/utils_hash.h
@@ -0,0 +1,11 @@
+#ifndef _UTILS_HASH_H_
+#define _UTILS_HASH_H_
+/// @file utils_hash.h
+/// @brief the interface for adapting hash functions.
+///
+
+#include
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_hash_msg(unsigned char *digest, size_t len_digest, const unsigned char *m, size_t mlen);
+
+#endif // _UTILS_HASH_H_
diff --git a/crypto_sign/rainbowIa-cyclic/clean/utils_prng.c b/crypto_sign/rainbowIa-cyclic/clean/utils_prng.c
new file mode 100644
index 00000000..849994cb
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/utils_prng.c
@@ -0,0 +1,95 @@
+/// @file utils_prng.c
+/// @brief The implementation of PRNG related functions.
+///
+
+#include "utils_prng.h"
+#include "aes.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+static void prng_update(const unsigned char *provided_data,
+ unsigned char *Key,
+ unsigned char *V) {
+ unsigned char temp[48];
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, Key);
+ for (int i = 0; i < 3; i++) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (V[j] == 0xff) {
+ V[j] = 0x00;
+ } else {
+ V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(temp + 16 * i, V, 1, &ctx);
+ }
+ if (provided_data != NULL) {
+ for (int i = 0; i < 48; i++) {
+ temp[i] ^= provided_data[i];
+ }
+ }
+ memcpy(Key, temp, 32);
+ memcpy(V, temp + 32, 16);
+}
+static void randombytes_init_with_state(prng_t *state,
+ unsigned char *entropy_input_48bytes) {
+ memset(state->Key, 0x00, 32);
+ memset(state->V, 0x00, 16);
+ prng_update(entropy_input_48bytes, state->Key, state->V);
+}
+
+static int randombytes_with_state(prng_t *state,
+ unsigned char *x,
+ size_t xlen) {
+
+ unsigned char block[16];
+ int i = 0;
+
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, state->Key);
+
+ while (xlen > 0) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (state->V[j] == 0xff) {
+ state->V[j] = 0x00;
+ } else {
+ state->V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(block, state->V, 1, &ctx);
+ if (xlen > 15) {
+ memcpy(x + i, block, 16);
+ i += 16;
+ xlen -= 16;
+ } else {
+ memcpy(x + i, block, xlen);
+ xlen = 0;
+ }
+ }
+ prng_update(NULL, state->Key, state->V);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen) {
+ unsigned char seed[48];
+ if (prng_seedlen >= 48) {
+ memcpy(seed, prng_seed, 48);
+ } else {
+ memcpy(seed, prng_seed, prng_seedlen);
+ PQCLEAN_RAINBOWIACYCLIC_CLEAN_hash_msg(seed + prng_seedlen, 48 - (unsigned)prng_seedlen, (const unsigned char *)prng_seed, prng_seedlen);
+ }
+
+ randombytes_init_with_state(ctx, seed);
+
+ return 0;
+}
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen) {
+ return randombytes_with_state(ctx, out, outlen);
+}
diff --git a/crypto_sign/rainbowIa-cyclic/clean/utils_prng.h b/crypto_sign/rainbowIa-cyclic/clean/utils_prng.h
new file mode 100644
index 00000000..4465547e
--- /dev/null
+++ b/crypto_sign/rainbowIa-cyclic/clean/utils_prng.h
@@ -0,0 +1,18 @@
+#ifndef _UTILS_PRNG_H_
+#define _UTILS_PRNG_H_
+/// @file utils_prng.h
+/// @brief the interface for adapting PRNG functions.
+///
+///
+
+#include "randombytes.h"
+
+typedef struct {
+ unsigned char Key[32];
+ unsigned char V[16];
+} prng_t;
+
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen);
+int PQCLEAN_RAINBOWIACYCLIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen);
+
+#endif // _UTILS_PRNG_H_
diff --git a/crypto_sign/rainbowVc-classic/META.yml b/crypto_sign/rainbowVc-classic/META.yml
new file mode 100644
index 00000000..0d6c769f
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/META.yml
@@ -0,0 +1,18 @@
+name: Rainbow-Vc-classic
+type: signature
+claimed-nist-level: 5
+length-public-key: 1705536
+length-secret-key: 1227104
+length-signature: 204
+nistkat-sha256: e9d065cbdd5736f4ad2bf5c910fcdf163c3e93828a2e59cd4d1dbebb8c1de202
+testvectors-sha256: 729d88ca4b5a64508c15c86f986ab81489275ee84d371b5ec0792f89b9ca5ac3
+principal-submitters:
+ - Jintai Ding
+auxiliary-submitters:
+ - Ming-Shing Chen
+ - Albrecht Petzoldt
+ - Dieter Schmidt
+ - Bo-Yin Yang
+implementations:
+ - name: clean
+ version: https://github.com/fast-crypto-lab/rainbow-submission-round2/commit/af826fcb78f6af51a02d0352cff28a9690467bfd
diff --git a/crypto_sign/rainbowVc-classic/clean/LICENSE b/crypto_sign/rainbowVc-classic/clean/LICENSE
new file mode 100644
index 00000000..cb00a6e3
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/LICENSE
@@ -0,0 +1,8 @@
+`Software implementation of Rainbow for NIST R2 submission' by Ming-Shing Chen
+
+To the extent possible under law, the person who associated CC0 with
+`Software implementation of Rainbow for NIST R2 submission' has waived all copyright and related or neighboring rights
+to `Software implementation of Rainbow for NIST R2 submission'.
+
+You should have received a copy of the CC0 legalcode along with this
+work. If not, see .
diff --git a/crypto_sign/rainbowVc-classic/clean/Makefile b/crypto_sign/rainbowVc-classic/clean/Makefile
new file mode 100644
index 00000000..5aa2d89b
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=librainbowVc-classic_clean.a
+
+HEADERS = api.h blas_comm.h blas.h blas_u32.h gf.h parallel_matrix_op.h rainbow_blas.h rainbow_config.h rainbow.h rainbow_keypair_computation.h rainbow_keypair.h utils_hash.h utils_prng.h
+OBJECTS = blas_comm.o parallel_matrix_op.o rainbow.o rainbow_keypair.o rainbow_keypair_computation.o sign.o utils_hash.o utils_prng.o blas_u32.o gf.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/rainbowVc-classic/clean/Makefile.Microsoft_nmake b/crypto_sign/rainbowVc-classic/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..1c09a88e
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=librainbowVc-classic_clean.lib
+OBJECTS = blas_comm.obj parallel_matrix_op.obj rainbow.obj rainbow_keypair.obj rainbow_keypair_computation.obj sign.obj utils_hash.obj utils_prng.obj blas_u32.obj gf.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/rainbowVc-classic/clean/api.h b/crypto_sign/rainbowVc-classic/clean/api.h
new file mode 100644
index 00000000..11edfb14
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/api.h
@@ -0,0 +1,32 @@
+#ifndef PQCLEAN_RAINBOWVCCLASSIC_CLEAN_API_H
+#define PQCLEAN_RAINBOWVCCLASSIC_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_RAINBOWVCCLASSIC_CLEAN_CRYPTO_SECRETKEYBYTES 1227104
+#define PQCLEAN_RAINBOWVCCLASSIC_CLEAN_CRYPTO_PUBLICKEYBYTES 1705536
+#define PQCLEAN_RAINBOWVCCLASSIC_CLEAN_CRYPTO_BYTES 204
+#define PQCLEAN_RAINBOWVCCLASSIC_CLEAN_CRYPTO_ALGNAME "RAINBOW(256,92,48,48) - classic"
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
+
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen,
+ const uint8_t *sk);
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen,
+ const uint8_t *pk);
+
+
+#endif
diff --git a/crypto_sign/rainbowVc-classic/clean/blas.h b/crypto_sign/rainbowVc-classic/clean/blas.h
new file mode 100644
index 00000000..40c71d56
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/blas.h
@@ -0,0 +1,19 @@
+#ifndef _BLAS_H_
+#define _BLAS_H_
+/// @file blas.h
+/// @brief Defining the implementations for linear algebra functions depending on the machine architecture.
+///
+
+#include "blas_comm.h"
+#include "blas_u32.h"
+#include "rainbow_config.h"
+
+#define gf256v_predicated_add PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_predicated_add_u32
+#define gf256v_add PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_add_u32
+
+
+#define gf256v_mul_scalar PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_mul_scalar_u32
+#define gf256v_madd PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_madd_u32
+
+
+#endif // _BLAS_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/blas_comm.c b/crypto_sign/rainbowVc-classic/clean/blas_comm.c
new file mode 100644
index 00000000..594f5f30
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/blas_comm.c
@@ -0,0 +1,142 @@
+/// @file blas_comm.c
+/// @brief The standard implementations for blas_comm.h
+///
+
+#include "blas_comm.h"
+#include "blas.h"
+#include "gf.h"
+#include "rainbow_config.h"
+
+#include
+#include
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte) {
+ gf256v_add(b, b, _num_byte);
+}
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i) {
+ return a[i];
+}
+
+unsigned int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte) {
+ uint8_t r = 0;
+ while (_num_byte--) {
+ r |= a[0];
+ a++;
+ }
+ return (0 == r);
+}
+
+/// polynomial multplication
+/// School boook
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num) {
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(c, _num * 2 - 1);
+ for (unsigned int i = 0; i < _num; i++) {
+ gf256v_madd(c + i, a, b[i], _num);
+ }
+}
+
+static void gf256mat_prod_ref(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(c, n_A_vec_byte);
+ for (unsigned int i = 0; i < n_A_width; i++) {
+ gf256v_madd(c, matA, b[i], n_A_vec_byte);
+ matA += n_A_vec_byte;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec) {
+ unsigned int n_vec_byte = len_vec;
+ for (unsigned int k = 0; k < len_vec; k++) {
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(c, n_vec_byte);
+ const uint8_t *bk = b + n_vec_byte * k;
+ for (unsigned int i = 0; i < len_vec; i++) {
+ gf256v_madd(c, a + n_vec_byte * i, bk[i], n_vec_byte);
+ }
+ c += n_vec_byte;
+ }
+}
+
+static unsigned int gf256mat_gauss_elim_ref(uint8_t *mat, unsigned int h, unsigned int w) {
+ unsigned int r8 = 1;
+
+ for (unsigned int i = 0; i < h; i++) {
+ uint8_t *ai = mat + w * i;
+ unsigned int skip_len_align4 = i & ((unsigned int)~0x3);
+
+ for (unsigned int j = i + 1; j < h; j++) {
+ uint8_t *aj = mat + w * j;
+ gf256v_predicated_add(ai + skip_len_align4, !PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256_is_nonzero(ai[i]), aj + skip_len_align4, w - skip_len_align4);
+ }
+ r8 &= PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256_is_nonzero(ai[i]);
+ uint8_t pivot = ai[i];
+ pivot = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256_inv(pivot);
+ gf256v_mul_scalar(ai + skip_len_align4, pivot, w - skip_len_align4);
+ for (unsigned int j = 0; j < h; j++) {
+ if (i == j) {
+ continue;
+ }
+ uint8_t *aj = mat + w * j;
+ gf256v_madd(aj + skip_len_align4, ai + skip_len_align4, aj[i], w - skip_len_align4);
+ }
+ }
+
+ return r8;
+}
+
+static unsigned int gf256mat_solve_linear_eq_ref(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ uint8_t mat[64 * 64];
+ for (unsigned int i = 0; i < n; i++) {
+ memcpy(mat + i * (n + 1), inp_mat + i * n, n);
+ mat[i * (n + 1) + n] = c_terms[i];
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_gauss_elim(mat, n, n + 1);
+ for (unsigned int i = 0; i < n; i++) {
+ sol[i] = mat[i * (n + 1) + n];
+ }
+ return r8;
+}
+
+static inline void gf256mat_submat(uint8_t *mat2, unsigned int w2, unsigned int st, const uint8_t *mat, unsigned int w, unsigned int h) {
+ for (unsigned int i = 0; i < h; i++) {
+ for (unsigned int j = 0; j < w2; j++) {
+ mat2[i * w2 + j] = mat[i * w + st + j];
+ }
+ }
+}
+
+unsigned int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer) {
+ uint8_t *aa = buffer;
+ for (unsigned int i = 0; i < H; i++) {
+ uint8_t *ai = aa + i * 2 * H;
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(ai, 2 * H);
+ gf256v_add(ai, a + i * H, H);
+ ai[H + i] = 1;
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_gauss_elim(aa, H, 2 * H);
+ gf256mat_submat(inv_a, H, H, aa, 2 * H, H);
+ return r8;
+}
+
+
+// choosing the implementations depends on the macros _BLAS_AVX2_ and _BLAS_SSE
+
+#define gf256mat_prod_impl gf256mat_prod_ref
+#define gf256mat_gauss_elim_impl gf256mat_gauss_elim_ref
+#define gf256mat_solve_linear_eq_impl gf256mat_solve_linear_eq_ref
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ gf256mat_prod_impl(c, matA, n_A_vec_byte, n_A_width, b);
+}
+
+unsigned int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w) {
+ return gf256mat_gauss_elim_impl(mat, h, w);
+}
+
+unsigned int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ return gf256mat_solve_linear_eq_impl(sol, inp_mat, c_terms, n);
+}
+
diff --git a/crypto_sign/rainbowVc-classic/clean/blas_comm.h b/crypto_sign/rainbowVc-classic/clean/blas_comm.h
new file mode 100644
index 00000000..55be9b5e
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/blas_comm.h
@@ -0,0 +1,90 @@
+#ifndef _BLAS_COMM_H_
+#define _BLAS_COMM_H_
+/// @file blas_comm.h
+/// @brief Common functions for linear algebra.
+///
+
+#include "rainbow_config.h"
+#include
+
+/// @brief set a vector to 0.
+///
+/// @param[in,out] b - the vector b.
+/// @param[in] _num_byte - number of bytes for the vector b.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte);
+
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i);
+
+/// @brief check if a vector is 0.
+///
+/// @param[in] a - the vector a.
+/// @param[in] _num_byte - number of bytes for the vector a.
+/// @return 1(true) if a is 0. 0(false) else.
+///
+unsigned int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte);
+
+/// @brief polynomial multiplication: c = a*b
+///
+/// @param[out] c - the output polynomial c
+/// @param[in] a - the vector a.
+/// @param[in] b - the vector b.
+/// @param[in] _num - number of elements for the polynomials a and b.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num);
+
+/// @brief matrix-vector multiplication: c = matA * b , in GF(256)
+///
+/// @param[out] c - the output vector c
+/// @param[in] matA - a column-major matrix A.
+/// @param[in] n_A_vec_byte - the size of column vectors in bytes.
+/// @param[in] n_A_width - the width of matrix A.
+/// @param[in] b - the vector b.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b);
+
+/// @brief matrix-matrix multiplication: c = a * b , in GF(256)
+///
+/// @param[out] c - the output matrix c
+/// @param[in] c - a matrix a.
+/// @param[in] b - a matrix b.
+/// @param[in] len_vec - the length of column vectors.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec);
+
+/// @brief Gauss elimination for a matrix, in GF(256)
+///
+/// @param[in,out] mat - the matrix.
+/// @param[in] h - the height of the matrix.
+/// @param[in] w - the width of the matrix.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w);
+
+/// @brief Solving linear equations, in GF(256)
+///
+/// @param[out] sol - the solutions.
+/// @param[in] inp_mat - the matrix parts of input equations.
+/// @param[in] c_terms - the constant terms of the input equations.
+/// @param[in] n - the number of equations.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n);
+
+/// @brief Computing the inverse matrix, in GF(256)
+///
+/// @param[out] inv_a - the output of matrix a.
+/// @param[in] a - a matrix a.
+/// @param[in] H - height of matrix a, i.e., matrix a is an HxH matrix.
+/// @param[in] buffer - The buffer for computations. it has to be as large as 2 input matrixes.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer);
+
+#endif // _BLAS_COMM_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/blas_u32.c b/crypto_sign/rainbowVc-classic/clean/blas_u32.c
new file mode 100644
index 00000000..65be162d
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/blas_u32.c
@@ -0,0 +1,87 @@
+#include "blas_u32.h"
+#include "gf.h"
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte) {
+ uint32_t pr_u32 = ((uint32_t)0) - ((uint32_t)predicate);
+ uint8_t pr_u8 = pr_u32 & 0xff;
+
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= (a_u32[i] & pr_u32);
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= (a[i] & pr_u8);
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= a_u32[i];
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= a[i];
+ }
+}
+
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *a_u32 = (uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ a_u32[i] = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_mul_u32(a_u32[i], b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_mul_u32(t.u32, b);
+ for (unsigned int i = 0; i < rem; i++) {
+ a[i] = t.u8[i];
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *c_u32 = (uint32_t *)accu_c;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ c_u32[i] ^= PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_mul_u32(a_u32[i], gf256_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ accu_c += (n_u32 << 2);
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_mul_u32(t.u32, gf256_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_c[i] ^= t.u8[i];
+ }
+}
+
diff --git a/crypto_sign/rainbowVc-classic/clean/blas_u32.h b/crypto_sign/rainbowVc-classic/clean/blas_u32.h
new file mode 100644
index 00000000..eba39b9c
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/blas_u32.h
@@ -0,0 +1,18 @@
+#ifndef _BLAS_U32_H_
+#define _BLAS_U32_H_
+/// @file blas_u32.h
+/// @brief Inlined functions for implementing basic linear algebra functions for uint32 arch.
+///
+
+#include "rainbow_config.h"
+#include
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte);
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte);
+
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte);
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte);
+
+
+#endif // _BLAS_U32_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/gf.c b/crypto_sign/rainbowVc-classic/clean/gf.c
new file mode 100644
index 00000000..81437d26
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/gf.c
@@ -0,0 +1,134 @@
+#include "gf.h"
+
+//// gf4 := gf2[x]/x^2+x+1
+static inline uint8_t gf4_mul_2(uint8_t a) {
+ uint8_t r = (uint8_t)(a << 1);
+ r ^= (uint8_t)((a >> 1) * 7);
+ return r;
+}
+
+static inline uint8_t gf4_mul(uint8_t a, uint8_t b) {
+ uint8_t r = (uint8_t)(a * (b & 1));
+ return r ^ (uint8_t)(gf4_mul_2(a) * (b >> 1));
+}
+
+static inline uint8_t gf4_squ(uint8_t a) {
+ return a ^ (a >> 1);
+}
+
+static inline uint32_t gf4v_mul_2_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit1 ^ (bit1 >> 1);
+}
+
+static inline uint32_t gf4v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t bit0_b = ((uint32_t)0) - ((uint32_t)(b & 1));
+ uint32_t bit1_b = ((uint32_t)0) - ((uint32_t)((b >> 1) & 1));
+ return (a & bit0_b) ^ (bit1_b & gf4v_mul_2_u32(a));
+}
+
+//// gf16 := gf4[y]/y^2+y+x
+static inline uint8_t gf16_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ uint8_t b0 = b & 3;
+ uint8_t b1 = (b >> 2);
+ uint8_t a0b0 = gf4_mul(a0, b0);
+ uint8_t a1b1 = gf4_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf4_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x2 = gf4_mul_2(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 2 ^ a0b0 ^ a1b1_x2);
+}
+
+static inline uint8_t gf16_squ(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ a1 = gf4_squ(a1);
+ uint8_t a1squ_x2 = gf4_mul_2(a1);
+ return (uint8_t)((a1 << 2) ^ a1squ_x2 ^ gf4_squ(a0));
+}
+
+// gf16 := gf4[y]/y^2+y+x
+uint32_t PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = gf4v_mul_u32(a, b);
+ uint32_t axb1 = gf4v_mul_u32(a, b >> 2);
+ uint32_t a0b1 = (axb1 << 2) & 0xcccccccc;
+ uint32_t a1b1 = axb1 & 0xcccccccc;
+ uint32_t a1b1_2 = a1b1 >> 2;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf4v_mul_2_u32(a1b1_2);
+}
+
+uint8_t PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256_is_nonzero(uint8_t a) {
+ unsigned int a8 = a;
+ unsigned int r = ((unsigned int)0) - a8;
+ r >>= 8;
+ return r & 1;
+}
+
+static inline uint8_t gf4_mul_3(uint8_t a) {
+ uint8_t msk = (uint8_t)((a - 2) >> 1);
+ return (uint8_t)((msk & ((int)a * 3)) | ((~msk) & ((int)a - 1)));
+}
+static inline uint8_t gf16_mul_8(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = a >> 2;
+ return (uint8_t)((gf4_mul_2(a0 ^ a1) << 2) | gf4_mul_3(a1));
+}
+
+// gf256 := gf16[X]/X^2+X+xy
+static inline uint8_t gf256_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ uint8_t b0 = b & 15;
+ uint8_t b1 = (b >> 4);
+ uint8_t a0b0 = gf16_mul(a0, b0);
+ uint8_t a1b1 = gf16_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf16_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x8 = gf16_mul_8(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 4 ^ a0b0 ^ a1b1_x8);
+}
+
+static inline uint8_t gf256_squ(uint8_t a) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ a1 = gf16_squ(a1);
+ uint8_t a1squ_x8 = gf16_mul_8(a1);
+ return (uint8_t)((a1 << 4) ^ a1squ_x8 ^ gf16_squ(a0));
+}
+
+uint8_t PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256_inv(uint8_t a) {
+ // 128+64+32+16+8+4+2 = 254
+ uint8_t a2 = gf256_squ(a);
+ uint8_t a4 = gf256_squ(a2);
+ uint8_t a8 = gf256_squ(a4);
+ uint8_t a4_2 = gf256_mul(a4, a2);
+ uint8_t a8_4_2 = gf256_mul(a4_2, a8);
+ uint8_t a64_ = gf256_squ(a8_4_2);
+ a64_ = gf256_squ(a64_);
+ a64_ = gf256_squ(a64_);
+ uint8_t a64_2 = gf256_mul(a64_, a8_4_2);
+ uint8_t a128_ = gf256_squ(a64_2);
+ return gf256_mul(a2, a128_);
+}
+
+static inline uint32_t gf4v_mul_3_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit0 ^ (bit1 >> 1);
+}
+static inline uint32_t gf16v_mul_8_u32(uint32_t a) {
+ uint32_t a1 = a & 0xcccccccc;
+ uint32_t a0 = (a << 2) & 0xcccccccc;
+ return gf4v_mul_2_u32(a0 ^ a1) | gf4v_mul_3_u32(a1 >> 2);
+}
+uint32_t PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf16v_mul_u32(a, b);
+ uint32_t axb1 = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf16v_mul_u32(a, b >> 4);
+ uint32_t a0b1 = (axb1 << 4) & 0xf0f0f0f0;
+ uint32_t a1b1 = axb1 & 0xf0f0f0f0;
+ uint32_t a1b1_4 = a1b1 >> 4;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf16v_mul_8_u32(a1b1_4);
+}
diff --git a/crypto_sign/rainbowVc-classic/clean/gf.h b/crypto_sign/rainbowVc-classic/clean/gf.h
new file mode 100644
index 00000000..7137179e
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/gf.h
@@ -0,0 +1,19 @@
+#ifndef _GF16_H_
+#define _GF16_H_
+
+#include "rainbow_config.h"
+#include
+
+/// @file gf16.h
+/// @brief Library for arithmetics in GF(16) and GF(256)
+///
+
+uint32_t PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b);
+
+
+uint8_t PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256_is_nonzero(uint8_t a);
+uint8_t PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256_inv(uint8_t a);
+uint32_t PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b);
+
+
+#endif // _GF16_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/parallel_matrix_op.c b/crypto_sign/rainbowVc-classic/clean/parallel_matrix_op.c
new file mode 100644
index 00000000..764b3a48
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/parallel_matrix_op.c
@@ -0,0 +1,183 @@
+/// @file parallel_matrix_op.c
+/// @brief the standard implementations for functions in parallel_matrix_op.h
+///
+/// the standard implementations for functions in parallel_matrix_op.h
+///
+
+#include "parallel_matrix_op.h"
+#include "blas.h"
+#include "blas_comm.h"
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim) {
+ return (dim + dim - i_row + 1) * i_row / 2 + j_col - i_row;
+}
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle or lower-triangle matrix.
+///
+/// @param[in] i_row - the i-th row in a triangle matrix.
+/// @param[in] j_col - the j-th column in a triangle matrix.
+/// @param[in] dim - the dimension of the triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+static inline unsigned int idx_of_2trimat(unsigned int i_row, unsigned int j_col, unsigned int n_var) {
+ if (i_row > j_col) {
+ return PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(j_col, i_row, n_var);
+ }
+ return PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(i_row, j_col, n_var);
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch) {
+ unsigned char *runningC = btriC;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < i; j++) {
+ unsigned int idx = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(j, i, Aheight);
+ gf256v_add(btriC + idx * size_batch, bA + size_batch * (i * Awidth + j), size_batch);
+ }
+ gf256v_add(runningC, bA + size_batch * (i * Awidth + i), size_batch * (Aheight - i));
+ runningC += size_batch * (Aheight - i);
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (k < i) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[(k - i) * size_batch], PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ btriA += (Aheight - i) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i < k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(k, i, Aheight))], PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i == k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (idx_of_2trimat(i, k, Aheight))], PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_matTr_madd_gf256(unsigned char *bC, const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Atr_height = Awidth;
+ unsigned int Atr_width = Aheight;
+ for (unsigned int i = 0; i < Atr_height; i++) {
+ for (unsigned int j = 0; j < Atr_width; j++) {
+ gf256v_madd(bC, &bB[j * Bwidth * size_batch], PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(&A_to_tr[size_Acolvec * i], j), size_batch * Bwidth);
+ }
+ bC += size_batch * Bwidth;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ const unsigned char *bA = bA_to_tr;
+ unsigned int Aheight = Awidth_before_tr;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[size_batch * (i + k * Aheight)], PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[k * size_batch], PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ bA += (Awidth) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch) {
+ unsigned char tmp[256];
+
+ unsigned char _x[256];
+ for (unsigned int i = 0; i < dim; i++) {
+ _x[i] = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(x, i);
+ }
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(y, size_batch);
+ for (unsigned int i = 0; i < dim; i++) {
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = i; j < dim; j++) {
+ gf256v_madd(tmp, trimat, _x[j], size_batch);
+ trimat += size_batch;
+ }
+ gf256v_madd(y, tmp, _x[i], size_batch);
+ }
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y, const unsigned char *mat,
+ const unsigned char *x, unsigned dim_x, unsigned size_batch) {
+ unsigned char tmp[128];
+
+ unsigned char _x[128];
+ for (unsigned int i = 0; i < dim_x; i++) {
+ _x[i] = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(x, i);
+ }
+ unsigned char _y[128];
+ for (unsigned int i = 0; i < dim_y; i++) {
+ _y[i] = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele(y, i);
+ }
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(z, size_batch);
+ for (unsigned int i = 0; i < dim_y; i++) {
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = 0; j < dim_x; j++) {
+ gf256v_madd(tmp, mat, _x[j], size_batch);
+ mat += size_batch;
+ }
+ gf256v_madd(z, tmp, _y[i], size_batch);
+ }
+}
+
diff --git a/crypto_sign/rainbowVc-classic/clean/parallel_matrix_op.h b/crypto_sign/rainbowVc-classic/clean/parallel_matrix_op.h
new file mode 100644
index 00000000..2af16a7e
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/parallel_matrix_op.h
@@ -0,0 +1,260 @@
+#ifndef _P_MATRIX_OP_H_
+#define _P_MATRIX_OP_H_
+/// @file parallel_matrix_op.h
+/// @brief Librarys for operations of batched matrixes.
+///
+///
+
+//////////////// Section: triangle matrix <-> rectangle matrix ///////////////////////////////////
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim);
+
+///
+/// @brief Upper trianglize a rectangle matrix to the corresponding upper-trangle matrix.
+///
+/// @param[out] btriC - the batched upper-trianglized matrix C.
+/// @param[in] bA - a batched retangle matrix A.
+/// @param[in] bwidth - the width of the batched matrix A, i.e., A is a Awidth x Awidth matrix.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch);
+
+//////////////////// Section: matrix multiplications ///////////////////////////////
+
+///
+/// @brief bC += btriA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. A will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A, which will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_matTr_madd_gf16(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_matTr_madd_gf256(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+//////////////////// Section: "quadratric" matrix evaluation ///////////////////////////////
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(16)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(256)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(16)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(256)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+#endif // _P_MATRIX_OP_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/rainbow.c b/crypto_sign/rainbowVc-classic/clean/rainbow.c
new file mode 100644
index 00000000..e1527f60
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/rainbow.c
@@ -0,0 +1,169 @@
+/// @file rainbow.c
+/// @brief The standard implementations for functions in rainbow.h
+///
+
+#include "rainbow.h"
+#include "blas.h"
+#include "rainbow_blas.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "utils_hash.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+#define MAX_ATTEMPT_FRMAT 128
+#define _MAX_O ((_O1 > _O2) ? _O1 : _O2)
+#define _MAX_O_BYTE ((_O1_BYTE > _O2_BYTE) ? _O1_BYTE : _O2_BYTE)
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *_digest) {
+ uint8_t mat_l1[_O1 * _O1_BYTE];
+ uint8_t mat_l2[_O2 * _O2_BYTE];
+ uint8_t mat_buffer[2 * _MAX_O * _MAX_O_BYTE];
+
+ // setup PRNG
+ prng_t prng_sign;
+ uint8_t prng_preseed[LEN_SKSEED + _HASH_LEN];
+ memcpy(prng_preseed, sk->sk_seed, LEN_SKSEED);
+ memcpy(prng_preseed + LEN_SKSEED, _digest, _HASH_LEN); // prng_preseed = sk_seed || digest
+ uint8_t prng_seed[_HASH_LEN];
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_hash_msg(prng_seed, _HASH_LEN, prng_preseed, _HASH_LEN + LEN_SKSEED);
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_set(&prng_sign, prng_seed, _HASH_LEN); // seed = H( sk_seed || digest )
+ for (unsigned int i = 0; i < LEN_SKSEED + _HASH_LEN; i++) {
+ prng_preseed[i] ^= prng_preseed[i]; // clean
+ }
+ for (unsigned int i = 0; i < _HASH_LEN; i++) {
+ prng_seed[i] ^= prng_seed[i]; // clean
+ }
+
+ // roll vinegars.
+ uint8_t vinegar[_V1_BYTE];
+ unsigned int n_attempt = 0;
+ unsigned int l1_succ = 0;
+ while (!l1_succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(&prng_sign, vinegar, _V1_BYTE); // generating vinegars
+ gfmat_prod(mat_l1, sk->l1_F2, _O1 * _O1_BYTE, _V1, vinegar); // generating the linear equations for layer 1
+ l1_succ = gfmat_inv(mat_l1, mat_l1, _O1, mat_buffer); // check if the linear equation solvable
+ n_attempt++;
+ }
+
+ // Given the vinegars, pre-compute variables needed for layer 2
+ uint8_t r_l1_F1[_O1_BYTE] = {0};
+ uint8_t r_l2_F1[_O2_BYTE] = {0};
+ batch_quad_trimat_eval(r_l1_F1, sk->l1_F1, vinegar, _V1, _O1_BYTE);
+ batch_quad_trimat_eval(r_l2_F1, sk->l2_F1, vinegar, _V1, _O2_BYTE);
+ uint8_t mat_l2_F3[_O2 * _O2_BYTE];
+ uint8_t mat_l2_F2[_O1 * _O2_BYTE];
+ gfmat_prod(mat_l2_F3, sk->l2_F3, _O2 * _O2_BYTE, _V1, vinegar);
+ gfmat_prod(mat_l2_F2, sk->l2_F2, _O1 * _O2_BYTE, _V1, vinegar);
+
+ // Some local variables.
+ uint8_t _z[_PUB_M_BYTE];
+ uint8_t y[_PUB_M_BYTE];
+ uint8_t *x_v1 = vinegar;
+ uint8_t x_o1[_O1_BYTE];
+ uint8_t x_o2[_O1_BYTE];
+
+ uint8_t digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, _digest, _HASH_LEN);
+ uint8_t *salt = digest_salt + _HASH_LEN;
+
+ uint8_t temp_o[_MAX_O_BYTE + 32] = {0};
+ unsigned int succ = 0;
+ while (!succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ // The computation: H(digest||salt) --> z --S--> y --C-map--> x --T--> w
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(&prng_sign, salt, _SALT_BYTE); // roll the salt
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_hash_msg(_z, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H(digest||salt)
+
+ // y = S^-1 * z
+ memcpy(y, _z, _PUB_M_BYTE); // identity part of S
+ gfmat_prod(temp_o, sk->s1, _O1_BYTE, _O2, _z + _O1_BYTE);
+ gf256v_add(y, temp_o, _O1_BYTE);
+
+ // Central Map:
+ // layer 1: calculate x_o1
+ memcpy(temp_o, r_l1_F1, _O1_BYTE);
+ gf256v_add(temp_o, y, _O1_BYTE);
+ gfmat_prod(x_o1, mat_l1, _O1_BYTE, _O1, temp_o);
+
+ // layer 2: calculate x_o2
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_set_zero(temp_o, _O2_BYTE);
+ gfmat_prod(temp_o, mat_l2_F2, _O2_BYTE, _O1, x_o1); // F2
+ batch_quad_trimat_eval(mat_l2, sk->l2_F5, x_o1, _O1, _O2_BYTE); // F5
+ gf256v_add(temp_o, mat_l2, _O2_BYTE);
+ gf256v_add(temp_o, r_l2_F1, _O2_BYTE); // F1
+ gf256v_add(temp_o, y + _O1_BYTE, _O2_BYTE);
+
+ // generate the linear equations of the 2nd layer
+ gfmat_prod(mat_l2, sk->l2_F6, _O2 * _O2_BYTE, _O1, x_o1); // F6
+ gf256v_add(mat_l2, mat_l2_F3, _O2 * _O2_BYTE); // F3
+ succ = gfmat_inv(mat_l2, mat_l2, _O2, mat_buffer);
+ gfmat_prod(x_o2, mat_l2, _O2_BYTE, _O2, temp_o); // solve l2 eqs
+
+ n_attempt++;
+ };
+ // w = T^-1 * y
+ uint8_t w[_PUB_N_BYTE];
+ // identity part of T.
+ memcpy(w, x_v1, _V1_BYTE);
+ memcpy(w + _V1_BYTE, x_o1, _O1_BYTE);
+ memcpy(w + _V2_BYTE, x_o2, _O2_BYTE);
+ // Computing the t1 part.
+ gfmat_prod(y, sk->t1, _V1_BYTE, _O1, x_o1);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t4 part.
+ gfmat_prod(y, sk->t4, _V1_BYTE, _O2, x_o2);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t3 part.
+ gfmat_prod(y, sk->t3, _O1_BYTE, _O2, x_o2);
+ gf256v_add(w + _V1_BYTE, y, _O1_BYTE);
+
+ memset(signature, 0, _SIGNATURE_BYTE); // set the output 0
+ // clean
+ memset(&prng_sign, 0, sizeof(prng_t));
+ memset(vinegar, 0, _V1_BYTE);
+ memset(r_l1_F1, 0, _O1_BYTE);
+ memset(r_l2_F1, 0, _O2_BYTE);
+ memset(_z, 0, _PUB_M_BYTE);
+ memset(y, 0, _PUB_M_BYTE);
+ memset(x_o1, 0, _O1_BYTE);
+ memset(x_o2, 0, _O2_BYTE);
+ memset(temp_o, 0, sizeof(temp_o));
+
+ // return: copy w and salt to the signature.
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ return -1;
+ }
+ gf256v_add(signature, w, _PUB_N_BYTE);
+ gf256v_add(signature + _PUB_N_BYTE, salt, _SALT_BYTE);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk) {
+ unsigned char digest_ck[_PUB_M_BYTE];
+ // public_map( digest_ck , pk , signature ); Evaluating the quadratic public polynomials.
+ batch_quad_trimat_eval(digest_ck, pk->pk, signature, _PUB_N, _PUB_M_BYTE);
+
+ unsigned char correct[_PUB_M_BYTE];
+ unsigned char digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, digest, _HASH_LEN);
+ memcpy(digest_salt + _HASH_LEN, signature + _PUB_N_BYTE, _SALT_BYTE);
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_hash_msg(correct, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H( digest || salt )
+
+ // check consistancy.
+ unsigned char cc = 0;
+ for (unsigned int i = 0; i < _PUB_M_BYTE; i++) {
+ cc |= (digest_ck[i] ^ correct[i]);
+ }
+ return (0 == cc) ? 0 : -1;
+}
+
+
diff --git a/crypto_sign/rainbowVc-classic/clean/rainbow.h b/crypto_sign/rainbowVc-classic/clean/rainbow.h
new file mode 100644
index 00000000..e455fe47
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/rainbow.h
@@ -0,0 +1,33 @@
+#ifndef _RAINBOW_H_
+#define _RAINBOW_H_
+/// @file rainbow.h
+/// @brief APIs for rainbow.
+///
+
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+
+#include
+
+///
+/// @brief Signing function for classical secret key.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk);
+
+
+
+#endif // _RAINBOW_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/rainbow_blas.h b/crypto_sign/rainbowVc-classic/clean/rainbow_blas.h
new file mode 100644
index 00000000..a2500d98
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/rainbow_blas.h
@@ -0,0 +1,31 @@
+#ifndef _RAINBOW_BLAS_H_
+#define _RAINBOW_BLAS_H_
+/// @file rainbow_blas.h
+/// @brief Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+///
+/// Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+
+#include "blas.h"
+#include "parallel_matrix_op.h"
+#include "rainbow_config.h"
+
+
+#define gfv_get_ele PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_get_ele
+#define gfv_mul_scalar PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_mul_scalar
+#define gfv_madd PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256v_madd
+
+#define gfmat_prod PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_prod
+#define gfmat_inv PQCLEAN_RAINBOWVCCLASSIC_CLEAN_gf256mat_inv
+
+#define batch_trimat_madd PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_trimat_madd_gf256
+#define batch_trimatTr_madd PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_trimatTr_madd_gf256
+#define batch_2trimat_madd PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_2trimat_madd_gf256
+#define batch_matTr_madd PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_matTr_madd_gf256
+#define batch_bmatTr_madd PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_bmatTr_madd_gf256
+#define batch_mat_madd PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_mat_madd_gf256
+
+#define batch_quad_trimat_eval PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_quad_trimat_eval_gf256
+#define batch_quad_recmat_eval PQCLEAN_RAINBOWVCCLASSIC_CLEAN_batch_quad_recmat_eval_gf256
+
+
+#endif // _RAINBOW_BLAS_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/rainbow_config.h b/crypto_sign/rainbowVc-classic/clean/rainbow_config.h
new file mode 100644
index 00000000..979aa244
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/rainbow_config.h
@@ -0,0 +1,46 @@
+#ifndef _H_RAINBOW_CONFIG_H_
+#define _H_RAINBOW_CONFIG_H_
+
+/// @file rainbow_config.h
+/// @brief Defining the parameters of the Rainbow and the corresponding constants.
+///
+
+#define _GFSIZE 256
+#define _V1 92
+#define _O1 48
+#define _O2 48
+#define _HASH_LEN 64
+
+
+#define _V2 ((_V1) + (_O1))
+
+/// size of N, in # of gf elements.
+#define _PUB_N (_V1 + _O1 + _O2)
+
+/// size of M, in # gf elements.
+#define _PUB_M (_O1 + _O2)
+
+/// size of variables, in # bytes.
+
+// GF256
+#define _V1_BYTE (_V1)
+#define _V2_BYTE (_V2)
+#define _O1_BYTE (_O1)
+#define _O2_BYTE (_O2)
+#define _PUB_N_BYTE (_PUB_N)
+#define _PUB_M_BYTE (_PUB_M)
+
+
+/// length of seed for public key, in # bytes
+#define LEN_PKSEED 32
+
+/// length of seed for secret key, in # bytes
+#define LEN_SKSEED 32
+
+/// length of salt for a signature, in # bytes
+#define _SALT_BYTE 16
+
+/// length of a signature
+#define _SIGNATURE_BYTE (_PUB_N_BYTE + _SALT_BYTE)
+
+#endif // _H_RAINBOW_CONFIG_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/rainbow_keypair.c b/crypto_sign/rainbowVc-classic/clean/rainbow_keypair.c
new file mode 100644
index 00000000..14632136
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/rainbow_keypair.c
@@ -0,0 +1,126 @@
+/// @file rainbow_keypair.c
+/// @brief implementations of functions in rainbow_keypair.h
+///
+
+#include "rainbow_keypair.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair_computation.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+static void generate_S_T(unsigned char *s_and_t, prng_t *prng0) {
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // S1
+ s_and_t += _O1_BYTE * _O2;
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O1); // T1
+ s_and_t += _V1_BYTE * _O1;
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O2); // T2
+ s_and_t += _V1_BYTE * _O2;
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // T3
+}
+
+static unsigned int generate_l1_F12(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * N_TRIANGLE_TERMS(_V1)); // l1_F1
+ sk += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * _V1 * _O1); // l1_F2
+ n_byte_generated += _O1_BYTE * _V1 * _O1;
+ return n_byte_generated;
+}
+
+static unsigned int generate_l2_F12356(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // l2_F1
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O1); // l2_F2
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O2); // l2_F3
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // l2_F5
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _O1 * _O2); // l2_F6
+ n_byte_generated += _O2_BYTE * _O1 * _O2;
+
+ return n_byte_generated;
+}
+
+static void generate_B1_B2(unsigned char *sk, prng_t *prng0) {
+ sk += generate_l1_F12(sk, prng0);
+ generate_l2_F12356(sk, prng0);
+}
+
+static void calculate_t4(unsigned char *t2_to_t4, const unsigned char *t1, const unsigned char *t3) {
+ // t4 = T_sk.t1 * T_sk.t3 - T_sk.t2
+ unsigned char temp[_V1_BYTE + 32];
+ unsigned char *t4 = t2_to_t4;
+ for (unsigned int i = 0; i < _O2; i++) { /// t3 width
+ gfmat_prod(temp, t1, _V1_BYTE, _O1, t3);
+ gf256v_add(t4, temp, _V1_BYTE);
+ t4 += _V1_BYTE;
+ t3 += _O1_BYTE;
+ }
+}
+
+static void obsfucate_l1_polys(unsigned char *l1_polys, const unsigned char *l2_polys, unsigned int n_terms, const unsigned char *s1) {
+ unsigned char temp[_O1_BYTE + 32];
+ while (n_terms--) {
+ gfmat_prod(temp, s1, _O1_BYTE, _O2, l2_polys);
+ gf256v_add(l1_polys, temp, _O1_BYTE);
+ l1_polys += _O1_BYTE;
+ l2_polys += _O2_BYTE;
+ }
+}
+
+/////////////////// Classic //////////////////////////////////
+
+static void _generate_secretkey(sk_t *sk, const unsigned char *sk_seed) {
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // set up prng
+ prng_t prng0;
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_set(&prng0, sk_seed, LEN_SKSEED);
+
+ // generating secret key with prng.
+ generate_S_T(sk->s1, &prng0);
+ generate_B1_B2(sk->l1_F1, &prng0);
+
+ // clean prng
+ memset(&prng0, 0, sizeof(prng_t));
+}
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_generate_keypair(pk_t *rpk, sk_t *sk, const unsigned char *sk_seed) {
+ _generate_secretkey(sk, sk_seed);
+
+ // set up a temporary structure ext_cpk_t for calculating public key.
+ ext_cpk_t pk;
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_calculate_Q_from_F(&pk, sk, sk); // compute the public key in ext_cpk_t format.
+ calculate_t4(sk->t4, sk->t1, sk->t3);
+
+ obsfucate_l1_polys(pk.l1_Q1, pk.l2_Q1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(pk.l1_Q2, pk.l2_Q2, _V1 * _O1, sk->s1);
+ obsfucate_l1_polys(pk.l1_Q3, pk.l2_Q3, _V1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk.l1_Q5, pk.l2_Q5, N_TRIANGLE_TERMS(_O1), sk->s1);
+ obsfucate_l1_polys(pk.l1_Q6, pk.l2_Q6, _O1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk.l1_Q9, pk.l2_Q9, N_TRIANGLE_TERMS(_O2), sk->s1);
+ // so far, the pk contains the full pk but in ext_cpk_t format.
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_extcpk_to_pk(rpk, &pk); // convert the public key from ext_cpk_t to pk_t.
+}
+
+
+
diff --git a/crypto_sign/rainbowVc-classic/clean/rainbow_keypair.h b/crypto_sign/rainbowVc-classic/clean/rainbow_keypair.h
new file mode 100644
index 00000000..2092aa86
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/rainbow_keypair.h
@@ -0,0 +1,61 @@
+#ifndef _RAINBOW_KEYPAIR_H_
+#define _RAINBOW_KEYPAIR_H_
+/// @file rainbow_keypair.h
+/// @brief Formats of key pairs and functions for generating key pairs.
+/// Formats of key pairs and functions for generating key pairs.
+///
+
+#include "rainbow_config.h"
+
+#define N_TRIANGLE_TERMS(n_var) ((n_var) * ((n_var) + 1) / 2)
+
+/// @brief public key for classic rainbow
+///
+/// public key for classic rainbow
+///
+typedef struct rainbow_publickey {
+ unsigned char pk[(_PUB_M_BYTE)*N_TRIANGLE_TERMS(_PUB_N)];
+} pk_t;
+
+/// @brief secret key for classic rainbow
+///
+/// secret key for classic rainbow
+///
+typedef struct rainbow_secretkey {
+ ///
+ /// seed for generating secret key.
+ /// Generating S, T, and F for classic rainbow.
+ /// Generating S and T only for cyclic rainbow.
+ unsigned char sk_seed[LEN_SKSEED];
+
+ unsigned char s1[_O1_BYTE * _O2]; ///< part of S map
+ unsigned char t1[_V1_BYTE * _O1]; ///< part of T map
+ unsigned char t4[_V1_BYTE * _O2]; ///< part of T map
+ unsigned char t3[_O1_BYTE * _O2]; ///< part of T map
+
+ unsigned char l1_F1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer1
+ unsigned char l1_F2[_O1_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer1
+
+ unsigned char l2_F1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer2
+ unsigned char l2_F2[_O2_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer2
+
+ unsigned char l2_F3[_O2_BYTE * _V1 * _O2]; ///< part of C-map, F3, Layer2
+ unsigned char l2_F5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< part of C-map, F5, Layer2
+ unsigned char l2_F6[_O2_BYTE * _O1 * _O2]; ///< part of C-map, F6, Layer2
+} sk_t;
+
+
+///
+/// @brief Generate key pairs for classic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the secret key.
+/// @param[in] sk_seed - seed for generating the secret key.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_generate_keypair(pk_t *pk, sk_t *sk, const unsigned char *sk_seed);
+
+
+
+
+
+#endif // _RAINBOW_KEYPAIR_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/rainbow_keypair_computation.c b/crypto_sign/rainbowVc-classic/clean/rainbow_keypair_computation.c
new file mode 100644
index 00000000..da7851f4
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/rainbow_keypair_computation.c
@@ -0,0 +1,189 @@
+/// @file rainbow_keypair_computation.c
+/// @brief Implementations for functions in rainbow_keypair_computation.h
+///
+
+#include "rainbow_keypair_computation.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair.h"
+#include
+#include
+#include
+
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk) {
+ const unsigned char *idx_l1 = cpk->l1_Q1;
+ const unsigned char *idx_l2 = cpk->l2_Q1;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = i; j < _V1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q2;
+ idx_l2 = cpk->l2_Q2;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q3;
+ idx_l2 = cpk->l2_Q3;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q5;
+ idx_l2 = cpk->l2_Q5;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = i; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q6;
+ idx_l2 = cpk->l2_Q6;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q9;
+ idx_l2 = cpk->l2_Q9;
+ for (unsigned int i = _V1 + _O1; i < _PUB_N; i++) {
+ for (unsigned int j = i; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+}
+
+static void calculate_Q_from_F_ref(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ /*
+ Layer 1
+ Computing :
+ Q_pk.l1_F1s[i] = F_sk.l1_F1s[i]
+
+ Q_pk.l1_F2s[i] = (F1* T1 + F2) + F1tr * t1
+ Q_pk.l1_F5s[i] = UT( T1tr* (F1 * T1 + F2) )
+ */
+ const unsigned char *t2 = Ts->t4;
+
+ memcpy(Qs->l1_Q1, Fs->l1_F1, _O1_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ memcpy(Qs->l1_Q2, Fs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_trimat_madd(Qs->l1_Q2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // F1*T1 + F2
+
+ memset(Qs->l1_Q3, 0, _O1_BYTE * _V1 * _O2);
+ memset(Qs->l1_Q5, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O1));
+ memset(Qs->l1_Q6, 0, _O1_BYTE * _O1 * _O2);
+ memset(Qs->l1_Q9, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ // l1_Q5 : _O1_BYTE * _O1 * _O1
+ // l1_Q9 : _O1_BYTE * _O2 * _O2
+ // l2_Q5 : _O2_BYTE * _V1 * _O1
+ // l2_Q9 : _O2_BYTE * _V1 * _O2
+
+ unsigned char tempQ[_O1_BYTE * _O1 * _O1 + 32];
+
+ memset(tempQ, 0, _O1_BYTE * _O1 * _O1); // l1_Q5
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q2, _O1, _O1_BYTE); // t1_tr*(F1*T1 + F2)
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_UpperTrianglize(Qs->l1_Q5, tempQ, _O1, _O1_BYTE); // UT( ... ) // Q5
+
+ batch_trimatTr_madd(Qs->l1_Q2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // Q2
+ /*
+ Computing:
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+ Q_pk.l1_F3s[i] = F1_F1T_T2 + F2_T3
+ Q_pk.l1_F6s[i] = T1tr* ( F1_F1T_T2 + F2_T3 ) + F2tr * t2
+ Q_pk.l1_F9s[i] = UT( T2tr* ( F1_T2 + F2_T3 ) )
+ */
+ batch_trimat_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1*T2
+ batch_mat_madd(Qs->l1_Q3, Fs->l1_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O1_BYTE); // F1_T2 + F2_T3
+
+ memset(tempQ, 0, _O1_BYTE * _O2 * _O2); // l1_Q9
+ batch_matTr_madd(tempQ, t2, _V1, _V1_BYTE, _O2, Qs->l1_Q3, _O2, _O1_BYTE); // T2tr * ( F1_T2 + F2_T3 )
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_UpperTrianglize(Qs->l1_Q9, tempQ, _O2, _O1_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1_F1T_T2 + F2_T3 // Q3
+
+ batch_bmatTr_madd(Qs->l1_Q6, Fs->l1_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F2tr*T2
+ batch_matTr_madd(Qs->l1_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q3, _O2, _O1_BYTE); // Q6
+
+ /*
+ layer 2
+ Computing:
+ Q1 = F1
+ Q2 = F1_F1T*T1 + F2
+ Q5 = UT( T1tr( F1*T1 + F2 ) + F5 )
+ */
+ memcpy(Qs->l2_Q1, Fs->l2_F1, _O2_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ memcpy(Qs->l2_Q2, Fs->l2_F2, _O2_BYTE * _V1 * _O1);
+ batch_trimat_madd(Qs->l2_Q2, Fs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // F1*T1 + F2
+
+ memcpy(Qs->l2_Q5, Fs->l2_F5, _O2_BYTE * N_TRIANGLE_TERMS(_O1));
+ memset(tempQ, 0, _O2_BYTE * _O1 * _O1); // l2_Q5
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l2_Q2, _O1, _O2_BYTE); // t1_tr*(F1*T1 + F2)
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_UpperTrianglize(Qs->l2_Q5, tempQ, _O1, _O2_BYTE); // UT( ... ) // Q5
+
+ batch_trimatTr_madd(Qs->l2_Q2, Fs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // Q2
+
+ /*
+ Computing:
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+
+ Q3 = F1_F1T*T2 + F2*T3 + F3
+ Q9 = UT( T2tr*( F1*T2 + F2*T3 + F3 ) + T3tr*( F5*T3 + F6 ) )
+ Q6 = T1tr*( F1_F1T*T2 + F2*T3 + F3 ) + F2Tr*T2 + F5_F5T*T3 + F6
+ */
+ memcpy(Qs->l2_Q3, Fs->l2_F3, _O2_BYTE * _V1 * _O2);
+ batch_trimat_madd(Qs->l2_Q3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1*T2 + F3
+ batch_mat_madd(Qs->l2_Q3, Fs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F1_T2 + F2_T3 + F3
+
+ memset(tempQ, 0, _O2_BYTE * _O2 * _O2); // l2_Q9
+ batch_matTr_madd(tempQ, t2, _V1, _V1_BYTE, _O2, Qs->l2_Q3, _O2, _O2_BYTE); // T2tr * ( ..... )
+
+ memcpy(Qs->l2_Q6, Fs->l2_F6, _O2_BYTE * _O1 * _O2);
+
+ batch_trimat_madd(Qs->l2_Q6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6
+ batch_matTr_madd(tempQ, Ts->t3, _O1, _O1_BYTE, _O2, Qs->l2_Q6, _O2, _O2_BYTE); // T2tr*( ..... ) + T3tr*( ..... )
+ memset(Qs->l2_Q9, 0, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_UpperTrianglize(Qs->l2_Q9, tempQ, _O2, _O2_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l2_Q3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1_F1T_T2 + F2_T3 + F3 // Q3
+
+ batch_bmatTr_madd(Qs->l2_Q6, Fs->l2_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6 + F2tr*T2
+ batch_trimatTr_madd(Qs->l2_Q6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F2tr*T2 + F5_F5T*T3 + F6
+ batch_matTr_madd(Qs->l2_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l2_Q3, _O2, _O2_BYTE); // Q6
+}
+#define calculate_Q_from_F_impl calculate_Q_from_F_ref
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ calculate_Q_from_F_impl(Qs, Fs, Ts);
+}
diff --git a/crypto_sign/rainbowVc-classic/clean/rainbow_keypair_computation.h b/crypto_sign/rainbowVc-classic/clean/rainbow_keypair_computation.h
new file mode 100644
index 00000000..c9ea1499
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/rainbow_keypair_computation.h
@@ -0,0 +1,53 @@
+#ifndef _RAINBOW_KEYPAIR_COMP_H_
+#define _RAINBOW_KEYPAIR_COMP_H_
+/// @file rainbow_keypair_computation.h
+/// @brief Functions for calculating pk/sk while generating keys.
+///
+/// Defining an internal structure of public key.
+/// Functions for calculating pk/sk for key generation.
+///
+
+#include "rainbow_keypair.h"
+
+/// @brief The (internal use) public key for rainbow
+///
+/// The (internal use) public key for rainbow. The public
+/// polynomials are divided into l1_Q1, l1_Q2, ... l1_Q9,
+/// l2_Q1, .... , l2_Q9.
+///
+typedef struct rainbow_extend_publickey {
+ unsigned char l1_Q1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l1_Q2[_O1_BYTE * _V1 * _O1];
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2];
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2];
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)];
+
+ unsigned char l2_Q1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l2_Q2[_O2_BYTE * _V1 * _O1];
+ unsigned char l2_Q3[_O2_BYTE * _V1 * _O2];
+ unsigned char l2_Q5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l2_Q6[_O2_BYTE * _O1 * _O2];
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)];
+} ext_cpk_t;
+
+///
+/// @brief converting formats of public keys : from ext_cpk_t version to pk_t
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the internel public key.
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk);
+/////////////////////////////////////////////////
+
+///
+/// @brief Computing public key from secret key
+///
+/// @param[out] Qs - the public key
+/// @param[in] Fs - parts of the secret key: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the secret key: T1, T4, T3
+///
+void PQCLEAN_RAINBOWVCCLASSIC_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+
+#endif // _RAINBOW_KEYPAIR_COMP_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/sign.c b/crypto_sign/rainbowVc-classic/clean/sign.c
new file mode 100644
index 00000000..3422f1b9
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/sign.c
@@ -0,0 +1,74 @@
+/// @file sign.c
+/// @brief the implementations for functions in api.h
+///
+///
+
+#include "api.h"
+#include "rainbow.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
+ unsigned char sk_seed[LEN_SKSEED] = {0};
+ randombytes(sk_seed, LEN_SKSEED);
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_generate_keypair((pk_t *)pk, (sk_t *)sk, sk_seed);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_crypto_sign(unsigned char *sm, size_t *smlen, const unsigned char *m, size_t mlen, const unsigned char *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+
+ memcpy(sm, m, mlen);
+ smlen[0] = mlen + _SIGNATURE_BYTE;
+
+ return PQCLEAN_RAINBOWVCCLASSIC_CLEAN_rainbow_sign(sm + mlen, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_crypto_sign_open(unsigned char *m, size_t *mlen, const unsigned char *sm, size_t smlen, const unsigned char *pk) {
+ int rc;
+ if (_SIGNATURE_BYTE > smlen) {
+ rc = -1;
+ } else {
+ *mlen = smlen - _SIGNATURE_BYTE;
+
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, sm, *mlen);
+
+ rc = PQCLEAN_RAINBOWVCCLASSIC_CLEAN_rainbow_verify(digest, sm + mlen[0], (const pk_t *)pk);
+ }
+ if (!rc) {
+ memcpy(m, sm, smlen - _SIGNATURE_BYTE);
+ } else { // bad signature
+ *mlen = (size_t) -1;
+ memset(m, 0, smlen);
+ }
+ return rc;
+}
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ *siglen = _SIGNATURE_BYTE;
+ return PQCLEAN_RAINBOWVCCLASSIC_CLEAN_rainbow_sign(sig, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ if (siglen != _SIGNATURE_BYTE) {
+ return -1;
+ }
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ return PQCLEAN_RAINBOWVCCLASSIC_CLEAN_rainbow_verify(digest, sig, (const pk_t *)pk);
+}
diff --git a/crypto_sign/rainbowVc-classic/clean/utils_hash.c b/crypto_sign/rainbowVc-classic/clean/utils_hash.c
new file mode 100644
index 00000000..b7bb5f3b
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/utils_hash.c
@@ -0,0 +1,50 @@
+/// @file utils_hash.c
+/// @brief the adapter for SHA2 families.
+///
+///
+
+#include "utils_hash.h"
+#include "rainbow_config.h"
+#include "sha2.h"
+
+static inline int _hash(unsigned char *digest, const unsigned char *m, size_t mlen) {
+ sha512(digest, m, mlen);
+ return 0;
+}
+
+static inline int expand_hash(unsigned char *digest, size_t n_digest, const unsigned char *hash) {
+ if (_HASH_LEN >= n_digest) {
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[i] = hash[i];
+ }
+ return 0;
+ }
+ for (size_t i = 0; i < _HASH_LEN; i++) {
+ digest[i] = hash[i];
+ }
+ n_digest -= _HASH_LEN;
+
+ while (_HASH_LEN <= n_digest) {
+ _hash(digest + _HASH_LEN, digest, _HASH_LEN);
+
+ n_digest -= _HASH_LEN;
+ digest += _HASH_LEN;
+ }
+ unsigned char temp[_HASH_LEN];
+ if (n_digest) {
+ _hash(temp, digest, _HASH_LEN);
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[_HASH_LEN + i] = temp[i];
+ }
+ }
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_hash_msg(unsigned char *digest,
+ size_t len_digest,
+ const unsigned char *m,
+ size_t mlen) {
+ unsigned char buf[_HASH_LEN];
+ _hash(buf, m, mlen);
+ return expand_hash(digest, len_digest, buf);
+}
diff --git a/crypto_sign/rainbowVc-classic/clean/utils_hash.h b/crypto_sign/rainbowVc-classic/clean/utils_hash.h
new file mode 100644
index 00000000..bab03631
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/utils_hash.h
@@ -0,0 +1,11 @@
+#ifndef _UTILS_HASH_H_
+#define _UTILS_HASH_H_
+/// @file utils_hash.h
+/// @brief the interface for adapting hash functions.
+///
+
+#include
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_hash_msg(unsigned char *digest, size_t len_digest, const unsigned char *m, size_t mlen);
+
+#endif // _UTILS_HASH_H_
diff --git a/crypto_sign/rainbowVc-classic/clean/utils_prng.c b/crypto_sign/rainbowVc-classic/clean/utils_prng.c
new file mode 100644
index 00000000..dd081dfb
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/utils_prng.c
@@ -0,0 +1,95 @@
+/// @file utils_prng.c
+/// @brief The implementation of PRNG related functions.
+///
+
+#include "utils_prng.h"
+#include "aes.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+static void prng_update(const unsigned char *provided_data,
+ unsigned char *Key,
+ unsigned char *V) {
+ unsigned char temp[48];
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, Key);
+ for (int i = 0; i < 3; i++) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (V[j] == 0xff) {
+ V[j] = 0x00;
+ } else {
+ V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(temp + 16 * i, V, 1, &ctx);
+ }
+ if (provided_data != NULL) {
+ for (int i = 0; i < 48; i++) {
+ temp[i] ^= provided_data[i];
+ }
+ }
+ memcpy(Key, temp, 32);
+ memcpy(V, temp + 32, 16);
+}
+static void randombytes_init_with_state(prng_t *state,
+ unsigned char *entropy_input_48bytes) {
+ memset(state->Key, 0x00, 32);
+ memset(state->V, 0x00, 16);
+ prng_update(entropy_input_48bytes, state->Key, state->V);
+}
+
+static int randombytes_with_state(prng_t *state,
+ unsigned char *x,
+ size_t xlen) {
+
+ unsigned char block[16];
+ int i = 0;
+
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, state->Key);
+
+ while (xlen > 0) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (state->V[j] == 0xff) {
+ state->V[j] = 0x00;
+ } else {
+ state->V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(block, state->V, 1, &ctx);
+ if (xlen > 15) {
+ memcpy(x + i, block, 16);
+ i += 16;
+ xlen -= 16;
+ } else {
+ memcpy(x + i, block, xlen);
+ xlen = 0;
+ }
+ }
+ prng_update(NULL, state->Key, state->V);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen) {
+ unsigned char seed[48];
+ if (prng_seedlen >= 48) {
+ memcpy(seed, prng_seed, 48);
+ } else {
+ memcpy(seed, prng_seed, prng_seedlen);
+ PQCLEAN_RAINBOWVCCLASSIC_CLEAN_hash_msg(seed + prng_seedlen, 48 - (unsigned)prng_seedlen, (const unsigned char *)prng_seed, prng_seedlen);
+ }
+
+ randombytes_init_with_state(ctx, seed);
+
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen) {
+ return randombytes_with_state(ctx, out, outlen);
+}
diff --git a/crypto_sign/rainbowVc-classic/clean/utils_prng.h b/crypto_sign/rainbowVc-classic/clean/utils_prng.h
new file mode 100644
index 00000000..ea9457b4
--- /dev/null
+++ b/crypto_sign/rainbowVc-classic/clean/utils_prng.h
@@ -0,0 +1,18 @@
+#ifndef _UTILS_PRNG_H_
+#define _UTILS_PRNG_H_
+/// @file utils_prng.h
+/// @brief the interface for adapting PRNG functions.
+///
+///
+
+#include "randombytes.h"
+
+typedef struct {
+ unsigned char Key[32];
+ unsigned char V[16];
+} prng_t;
+
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen);
+int PQCLEAN_RAINBOWVCCLASSIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen);
+
+#endif // _UTILS_PRNG_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/META.yml b/crypto_sign/rainbowVc-cyclic-compressed/META.yml
new file mode 100644
index 00000000..0d5f2908
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/META.yml
@@ -0,0 +1,18 @@
+name: Rainbow-Vc-cyclic-compressed
+type: signature
+claimed-nist-level: 5
+length-public-key: 491936
+length-secret-key: 64
+length-signature: 204
+nistkat-sha256: 7bc9f57b718843d525d893fc361d97417de0b06e954f2687f808bebaaf2c762c
+testvectors-sha256: acd054aed76af99bf0b31438226bdcca8ac34efde180cf80732c30bc00a63a9c
+principal-submitters:
+ - Jintai Ding
+auxiliary-submitters:
+ - Ming-Shing Chen
+ - Albrecht Petzoldt
+ - Dieter Schmidt
+ - Bo-Yin Yang
+implementations:
+ - name: clean
+ version: https://github.com/fast-crypto-lab/rainbow-submission-round2/commit/af826fcb78f6af51a02d0352cff28a9690467bfd
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/LICENSE b/crypto_sign/rainbowVc-cyclic-compressed/clean/LICENSE
new file mode 100644
index 00000000..cb00a6e3
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/LICENSE
@@ -0,0 +1,8 @@
+`Software implementation of Rainbow for NIST R2 submission' by Ming-Shing Chen
+
+To the extent possible under law, the person who associated CC0 with
+`Software implementation of Rainbow for NIST R2 submission' has waived all copyright and related or neighboring rights
+to `Software implementation of Rainbow for NIST R2 submission'.
+
+You should have received a copy of the CC0 legalcode along with this
+work. If not, see .
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/Makefile b/crypto_sign/rainbowVc-cyclic-compressed/clean/Makefile
new file mode 100644
index 00000000..e4387a30
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=librainbowVc-cyclic-compressed_clean.a
+
+HEADERS = api.h blas_comm.h blas.h blas_u32.h gf.h parallel_matrix_op.h rainbow_blas.h rainbow_config.h rainbow.h rainbow_keypair_computation.h rainbow_keypair.h utils_hash.h utils_prng.h
+OBJECTS = blas_comm.o parallel_matrix_op.o rainbow.o rainbow_keypair.o rainbow_keypair_computation.o sign.o utils_hash.o utils_prng.o blas_u32.o gf.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/Makefile.Microsoft_nmake b/crypto_sign/rainbowVc-cyclic-compressed/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..e2aa7250
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=librainbowVc-cyclic-compressed_clean.lib
+OBJECTS = blas_comm.obj parallel_matrix_op.obj rainbow.obj rainbow_keypair.obj rainbow_keypair_computation.obj sign.obj utils_hash.obj utils_prng.obj blas_u32.obj gf.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/api.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/api.h
new file mode 100644
index 00000000..7f4a866c
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/api.h
@@ -0,0 +1,32 @@
+#ifndef PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_API_H
+#define PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_CRYPTO_SECRETKEYBYTES 64
+#define PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_CRYPTO_PUBLICKEYBYTES 491936
+#define PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_CRYPTO_BYTES 204
+#define PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_CRYPTO_ALGNAME "RAINBOW(256,92,48,48) - cyclic compressed"
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
+
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen,
+ const uint8_t *sk);
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen,
+ const uint8_t *pk);
+
+
+#endif
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/blas.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/blas.h
new file mode 100644
index 00000000..5dd02866
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/blas.h
@@ -0,0 +1,19 @@
+#ifndef _BLAS_H_
+#define _BLAS_H_
+/// @file blas.h
+/// @brief Defining the implementations for linear algebra functions depending on the machine architecture.
+///
+
+#include "blas_comm.h"
+#include "blas_u32.h"
+#include "rainbow_config.h"
+
+#define gf256v_predicated_add PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_predicated_add_u32
+#define gf256v_add PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_add_u32
+
+
+#define gf256v_mul_scalar PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_mul_scalar_u32
+#define gf256v_madd PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_madd_u32
+
+
+#endif // _BLAS_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_comm.c b/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_comm.c
new file mode 100644
index 00000000..1a59ae7c
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_comm.c
@@ -0,0 +1,142 @@
+/// @file blas_comm.c
+/// @brief The standard implementations for blas_comm.h
+///
+
+#include "blas_comm.h"
+#include "blas.h"
+#include "gf.h"
+#include "rainbow_config.h"
+
+#include
+#include
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte) {
+ gf256v_add(b, b, _num_byte);
+}
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i) {
+ return a[i];
+}
+
+unsigned int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte) {
+ uint8_t r = 0;
+ while (_num_byte--) {
+ r |= a[0];
+ a++;
+ }
+ return (0 == r);
+}
+
+/// polynomial multplication
+/// School boook
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num) {
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(c, _num * 2 - 1);
+ for (unsigned int i = 0; i < _num; i++) {
+ gf256v_madd(c + i, a, b[i], _num);
+ }
+}
+
+static void gf256mat_prod_ref(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(c, n_A_vec_byte);
+ for (unsigned int i = 0; i < n_A_width; i++) {
+ gf256v_madd(c, matA, b[i], n_A_vec_byte);
+ matA += n_A_vec_byte;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec) {
+ unsigned int n_vec_byte = len_vec;
+ for (unsigned int k = 0; k < len_vec; k++) {
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(c, n_vec_byte);
+ const uint8_t *bk = b + n_vec_byte * k;
+ for (unsigned int i = 0; i < len_vec; i++) {
+ gf256v_madd(c, a + n_vec_byte * i, bk[i], n_vec_byte);
+ }
+ c += n_vec_byte;
+ }
+}
+
+static unsigned int gf256mat_gauss_elim_ref(uint8_t *mat, unsigned int h, unsigned int w) {
+ unsigned int r8 = 1;
+
+ for (unsigned int i = 0; i < h; i++) {
+ uint8_t *ai = mat + w * i;
+ unsigned int skip_len_align4 = i & ((unsigned int)~0x3);
+
+ for (unsigned int j = i + 1; j < h; j++) {
+ uint8_t *aj = mat + w * j;
+ gf256v_predicated_add(ai + skip_len_align4, !PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256_is_nonzero(ai[i]), aj + skip_len_align4, w - skip_len_align4);
+ }
+ r8 &= PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256_is_nonzero(ai[i]);
+ uint8_t pivot = ai[i];
+ pivot = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256_inv(pivot);
+ gf256v_mul_scalar(ai + skip_len_align4, pivot, w - skip_len_align4);
+ for (unsigned int j = 0; j < h; j++) {
+ if (i == j) {
+ continue;
+ }
+ uint8_t *aj = mat + w * j;
+ gf256v_madd(aj + skip_len_align4, ai + skip_len_align4, aj[i], w - skip_len_align4);
+ }
+ }
+
+ return r8;
+}
+
+static unsigned int gf256mat_solve_linear_eq_ref(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ uint8_t mat[64 * 64];
+ for (unsigned int i = 0; i < n; i++) {
+ memcpy(mat + i * (n + 1), inp_mat + i * n, n);
+ mat[i * (n + 1) + n] = c_terms[i];
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_gauss_elim(mat, n, n + 1);
+ for (unsigned int i = 0; i < n; i++) {
+ sol[i] = mat[i * (n + 1) + n];
+ }
+ return r8;
+}
+
+static inline void gf256mat_submat(uint8_t *mat2, unsigned int w2, unsigned int st, const uint8_t *mat, unsigned int w, unsigned int h) {
+ for (unsigned int i = 0; i < h; i++) {
+ for (unsigned int j = 0; j < w2; j++) {
+ mat2[i * w2 + j] = mat[i * w + st + j];
+ }
+ }
+}
+
+unsigned int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer) {
+ uint8_t *aa = buffer;
+ for (unsigned int i = 0; i < H; i++) {
+ uint8_t *ai = aa + i * 2 * H;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(ai, 2 * H);
+ gf256v_add(ai, a + i * H, H);
+ ai[H + i] = 1;
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_gauss_elim(aa, H, 2 * H);
+ gf256mat_submat(inv_a, H, H, aa, 2 * H, H);
+ return r8;
+}
+
+
+// choosing the implementations depends on the macros _BLAS_AVX2_ and _BLAS_SSE
+
+#define gf256mat_prod_impl gf256mat_prod_ref
+#define gf256mat_gauss_elim_impl gf256mat_gauss_elim_ref
+#define gf256mat_solve_linear_eq_impl gf256mat_solve_linear_eq_ref
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ gf256mat_prod_impl(c, matA, n_A_vec_byte, n_A_width, b);
+}
+
+unsigned int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w) {
+ return gf256mat_gauss_elim_impl(mat, h, w);
+}
+
+unsigned int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ return gf256mat_solve_linear_eq_impl(sol, inp_mat, c_terms, n);
+}
+
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_comm.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_comm.h
new file mode 100644
index 00000000..af5715c6
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_comm.h
@@ -0,0 +1,90 @@
+#ifndef _BLAS_COMM_H_
+#define _BLAS_COMM_H_
+/// @file blas_comm.h
+/// @brief Common functions for linear algebra.
+///
+
+#include "rainbow_config.h"
+#include
+
+/// @brief set a vector to 0.
+///
+/// @param[in,out] b - the vector b.
+/// @param[in] _num_byte - number of bytes for the vector b.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte);
+
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i);
+
+/// @brief check if a vector is 0.
+///
+/// @param[in] a - the vector a.
+/// @param[in] _num_byte - number of bytes for the vector a.
+/// @return 1(true) if a is 0. 0(false) else.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte);
+
+/// @brief polynomial multiplication: c = a*b
+///
+/// @param[out] c - the output polynomial c
+/// @param[in] a - the vector a.
+/// @param[in] b - the vector b.
+/// @param[in] _num - number of elements for the polynomials a and b.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num);
+
+/// @brief matrix-vector multiplication: c = matA * b , in GF(256)
+///
+/// @param[out] c - the output vector c
+/// @param[in] matA - a column-major matrix A.
+/// @param[in] n_A_vec_byte - the size of column vectors in bytes.
+/// @param[in] n_A_width - the width of matrix A.
+/// @param[in] b - the vector b.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b);
+
+/// @brief matrix-matrix multiplication: c = a * b , in GF(256)
+///
+/// @param[out] c - the output matrix c
+/// @param[in] c - a matrix a.
+/// @param[in] b - a matrix b.
+/// @param[in] len_vec - the length of column vectors.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec);
+
+/// @brief Gauss elimination for a matrix, in GF(256)
+///
+/// @param[in,out] mat - the matrix.
+/// @param[in] h - the height of the matrix.
+/// @param[in] w - the width of the matrix.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w);
+
+/// @brief Solving linear equations, in GF(256)
+///
+/// @param[out] sol - the solutions.
+/// @param[in] inp_mat - the matrix parts of input equations.
+/// @param[in] c_terms - the constant terms of the input equations.
+/// @param[in] n - the number of equations.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n);
+
+/// @brief Computing the inverse matrix, in GF(256)
+///
+/// @param[out] inv_a - the output of matrix a.
+/// @param[in] a - a matrix a.
+/// @param[in] H - height of matrix a, i.e., matrix a is an HxH matrix.
+/// @param[in] buffer - The buffer for computations. it has to be as large as 2 input matrixes.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer);
+
+#endif // _BLAS_COMM_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_u32.c b/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_u32.c
new file mode 100644
index 00000000..c37d4687
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_u32.c
@@ -0,0 +1,87 @@
+#include "blas_u32.h"
+#include "gf.h"
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte) {
+ uint32_t pr_u32 = ((uint32_t)0) - ((uint32_t)predicate);
+ uint8_t pr_u8 = pr_u32 & 0xff;
+
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= (a_u32[i] & pr_u32);
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= (a[i] & pr_u8);
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= a_u32[i];
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= a[i];
+ }
+}
+
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *a_u32 = (uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ a_u32[i] = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(a_u32[i], b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(t.u32, b);
+ for (unsigned int i = 0; i < rem; i++) {
+ a[i] = t.u8[i];
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *c_u32 = (uint32_t *)accu_c;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ c_u32[i] ^= PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(a_u32[i], gf256_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ accu_c += (n_u32 << 2);
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(t.u32, gf256_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_c[i] ^= t.u8[i];
+ }
+}
+
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_u32.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_u32.h
new file mode 100644
index 00000000..6777dafc
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/blas_u32.h
@@ -0,0 +1,18 @@
+#ifndef _BLAS_U32_H_
+#define _BLAS_U32_H_
+/// @file blas_u32.h
+/// @brief Inlined functions for implementing basic linear algebra functions for uint32 arch.
+///
+
+#include "rainbow_config.h"
+#include
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte);
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte);
+
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte);
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte);
+
+
+#endif // _BLAS_U32_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/gf.c b/crypto_sign/rainbowVc-cyclic-compressed/clean/gf.c
new file mode 100644
index 00000000..b5a4d604
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/gf.c
@@ -0,0 +1,134 @@
+#include "gf.h"
+
+//// gf4 := gf2[x]/x^2+x+1
+static inline uint8_t gf4_mul_2(uint8_t a) {
+ uint8_t r = (uint8_t)(a << 1);
+ r ^= (uint8_t)((a >> 1) * 7);
+ return r;
+}
+
+static inline uint8_t gf4_mul(uint8_t a, uint8_t b) {
+ uint8_t r = (uint8_t)(a * (b & 1));
+ return r ^ (uint8_t)(gf4_mul_2(a) * (b >> 1));
+}
+
+static inline uint8_t gf4_squ(uint8_t a) {
+ return a ^ (a >> 1);
+}
+
+static inline uint32_t gf4v_mul_2_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit1 ^ (bit1 >> 1);
+}
+
+static inline uint32_t gf4v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t bit0_b = ((uint32_t)0) - ((uint32_t)(b & 1));
+ uint32_t bit1_b = ((uint32_t)0) - ((uint32_t)((b >> 1) & 1));
+ return (a & bit0_b) ^ (bit1_b & gf4v_mul_2_u32(a));
+}
+
+//// gf16 := gf4[y]/y^2+y+x
+static inline uint8_t gf16_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ uint8_t b0 = b & 3;
+ uint8_t b1 = (b >> 2);
+ uint8_t a0b0 = gf4_mul(a0, b0);
+ uint8_t a1b1 = gf4_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf4_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x2 = gf4_mul_2(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 2 ^ a0b0 ^ a1b1_x2);
+}
+
+static inline uint8_t gf16_squ(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ a1 = gf4_squ(a1);
+ uint8_t a1squ_x2 = gf4_mul_2(a1);
+ return (uint8_t)((a1 << 2) ^ a1squ_x2 ^ gf4_squ(a0));
+}
+
+// gf16 := gf4[y]/y^2+y+x
+uint32_t PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = gf4v_mul_u32(a, b);
+ uint32_t axb1 = gf4v_mul_u32(a, b >> 2);
+ uint32_t a0b1 = (axb1 << 2) & 0xcccccccc;
+ uint32_t a1b1 = axb1 & 0xcccccccc;
+ uint32_t a1b1_2 = a1b1 >> 2;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf4v_mul_2_u32(a1b1_2);
+}
+
+uint8_t PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256_is_nonzero(uint8_t a) {
+ unsigned int a8 = a;
+ unsigned int r = ((unsigned int)0) - a8;
+ r >>= 8;
+ return r & 1;
+}
+
+static inline uint8_t gf4_mul_3(uint8_t a) {
+ uint8_t msk = (uint8_t)((a - 2) >> 1);
+ return (uint8_t)((msk & ((int)a * 3)) | ((~msk) & ((int)a - 1)));
+}
+static inline uint8_t gf16_mul_8(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = a >> 2;
+ return (uint8_t)((gf4_mul_2(a0 ^ a1) << 2) | gf4_mul_3(a1));
+}
+
+// gf256 := gf16[X]/X^2+X+xy
+static inline uint8_t gf256_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ uint8_t b0 = b & 15;
+ uint8_t b1 = (b >> 4);
+ uint8_t a0b0 = gf16_mul(a0, b0);
+ uint8_t a1b1 = gf16_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf16_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x8 = gf16_mul_8(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 4 ^ a0b0 ^ a1b1_x8);
+}
+
+static inline uint8_t gf256_squ(uint8_t a) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ a1 = gf16_squ(a1);
+ uint8_t a1squ_x8 = gf16_mul_8(a1);
+ return (uint8_t)((a1 << 4) ^ a1squ_x8 ^ gf16_squ(a0));
+}
+
+uint8_t PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256_inv(uint8_t a) {
+ // 128+64+32+16+8+4+2 = 254
+ uint8_t a2 = gf256_squ(a);
+ uint8_t a4 = gf256_squ(a2);
+ uint8_t a8 = gf256_squ(a4);
+ uint8_t a4_2 = gf256_mul(a4, a2);
+ uint8_t a8_4_2 = gf256_mul(a4_2, a8);
+ uint8_t a64_ = gf256_squ(a8_4_2);
+ a64_ = gf256_squ(a64_);
+ a64_ = gf256_squ(a64_);
+ uint8_t a64_2 = gf256_mul(a64_, a8_4_2);
+ uint8_t a128_ = gf256_squ(a64_2);
+ return gf256_mul(a2, a128_);
+}
+
+static inline uint32_t gf4v_mul_3_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit0 ^ (bit1 >> 1);
+}
+static inline uint32_t gf16v_mul_8_u32(uint32_t a) {
+ uint32_t a1 = a & 0xcccccccc;
+ uint32_t a0 = (a << 2) & 0xcccccccc;
+ return gf4v_mul_2_u32(a0 ^ a1) | gf4v_mul_3_u32(a1 >> 2);
+}
+uint32_t PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(a, b);
+ uint32_t axb1 = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(a, b >> 4);
+ uint32_t a0b1 = (axb1 << 4) & 0xf0f0f0f0;
+ uint32_t a1b1 = axb1 & 0xf0f0f0f0;
+ uint32_t a1b1_4 = a1b1 >> 4;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf16v_mul_8_u32(a1b1_4);
+}
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/gf.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/gf.h
new file mode 100644
index 00000000..57031de2
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/gf.h
@@ -0,0 +1,19 @@
+#ifndef _GF16_H_
+#define _GF16_H_
+
+#include "rainbow_config.h"
+#include
+
+/// @file gf16.h
+/// @brief Library for arithmetics in GF(16) and GF(256)
+///
+
+uint32_t PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b);
+
+
+uint8_t PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256_is_nonzero(uint8_t a);
+uint8_t PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256_inv(uint8_t a);
+uint32_t PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b);
+
+
+#endif // _GF16_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/parallel_matrix_op.c b/crypto_sign/rainbowVc-cyclic-compressed/clean/parallel_matrix_op.c
new file mode 100644
index 00000000..8e04fabe
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/parallel_matrix_op.c
@@ -0,0 +1,183 @@
+/// @file parallel_matrix_op.c
+/// @brief the standard implementations for functions in parallel_matrix_op.h
+///
+/// the standard implementations for functions in parallel_matrix_op.h
+///
+
+#include "parallel_matrix_op.h"
+#include "blas.h"
+#include "blas_comm.h"
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim) {
+ return (dim + dim - i_row + 1) * i_row / 2 + j_col - i_row;
+}
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle or lower-triangle matrix.
+///
+/// @param[in] i_row - the i-th row in a triangle matrix.
+/// @param[in] j_col - the j-th column in a triangle matrix.
+/// @param[in] dim - the dimension of the triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+static inline unsigned int idx_of_2trimat(unsigned int i_row, unsigned int j_col, unsigned int n_var) {
+ if (i_row > j_col) {
+ return PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(j_col, i_row, n_var);
+ }
+ return PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i_row, j_col, n_var);
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch) {
+ unsigned char *runningC = btriC;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < i; j++) {
+ unsigned int idx = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(j, i, Aheight);
+ gf256v_add(btriC + idx * size_batch, bA + size_batch * (i * Awidth + j), size_batch);
+ }
+ gf256v_add(runningC, bA + size_batch * (i * Awidth + i), size_batch * (Aheight - i));
+ runningC += size_batch * (Aheight - i);
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (k < i) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[(k - i) * size_batch], PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ btriA += (Aheight - i) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i < k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(k, i, Aheight))], PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i == k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (idx_of_2trimat(i, k, Aheight))], PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf256(unsigned char *bC, const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Atr_height = Awidth;
+ unsigned int Atr_width = Aheight;
+ for (unsigned int i = 0; i < Atr_height; i++) {
+ for (unsigned int j = 0; j < Atr_width; j++) {
+ gf256v_madd(bC, &bB[j * Bwidth * size_batch], PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&A_to_tr[size_Acolvec * i], j), size_batch * Bwidth);
+ }
+ bC += size_batch * Bwidth;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ const unsigned char *bA = bA_to_tr;
+ unsigned int Aheight = Awidth_before_tr;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[size_batch * (i + k * Aheight)], PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[k * size_batch], PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ bA += (Awidth) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch) {
+ unsigned char tmp[256];
+
+ unsigned char _x[256];
+ for (unsigned int i = 0; i < dim; i++) {
+ _x[i] = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(x, i);
+ }
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(y, size_batch);
+ for (unsigned int i = 0; i < dim; i++) {
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = i; j < dim; j++) {
+ gf256v_madd(tmp, trimat, _x[j], size_batch);
+ trimat += size_batch;
+ }
+ gf256v_madd(y, tmp, _x[i], size_batch);
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y, const unsigned char *mat,
+ const unsigned char *x, unsigned dim_x, unsigned size_batch) {
+ unsigned char tmp[128];
+
+ unsigned char _x[128];
+ for (unsigned int i = 0; i < dim_x; i++) {
+ _x[i] = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(x, i);
+ }
+ unsigned char _y[128];
+ for (unsigned int i = 0; i < dim_y; i++) {
+ _y[i] = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele(y, i);
+ }
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(z, size_batch);
+ for (unsigned int i = 0; i < dim_y; i++) {
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = 0; j < dim_x; j++) {
+ gf256v_madd(tmp, mat, _x[j], size_batch);
+ mat += size_batch;
+ }
+ gf256v_madd(z, tmp, _y[i], size_batch);
+ }
+}
+
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/parallel_matrix_op.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/parallel_matrix_op.h
new file mode 100644
index 00000000..6ce3d8c6
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/parallel_matrix_op.h
@@ -0,0 +1,260 @@
+#ifndef _P_MATRIX_OP_H_
+#define _P_MATRIX_OP_H_
+/// @file parallel_matrix_op.h
+/// @brief Librarys for operations of batched matrixes.
+///
+///
+
+//////////////// Section: triangle matrix <-> rectangle matrix ///////////////////////////////////
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim);
+
+///
+/// @brief Upper trianglize a rectangle matrix to the corresponding upper-trangle matrix.
+///
+/// @param[out] btriC - the batched upper-trianglized matrix C.
+/// @param[in] bA - a batched retangle matrix A.
+/// @param[in] bwidth - the width of the batched matrix A, i.e., A is a Awidth x Awidth matrix.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch);
+
+//////////////////// Section: matrix multiplications ///////////////////////////////
+
+///
+/// @brief bC += btriA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. A will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A, which will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf16(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf256(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+//////////////////// Section: "quadratric" matrix evaluation ///////////////////////////////
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(16)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(256)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(16)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(256)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+#endif // _P_MATRIX_OP_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow.c b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow.c
new file mode 100644
index 00000000..e78bc524
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow.c
@@ -0,0 +1,180 @@
+/// @file rainbow.c
+/// @brief The standard implementations for functions in rainbow.h
+///
+
+#include "rainbow.h"
+#include "blas.h"
+#include "rainbow_blas.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "utils_hash.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+#define MAX_ATTEMPT_FRMAT 128
+#define _MAX_O ((_O1 > _O2) ? _O1 : _O2)
+#define _MAX_O_BYTE ((_O1_BYTE > _O2_BYTE) ? _O1_BYTE : _O2_BYTE)
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *_digest) {
+ uint8_t mat_l1[_O1 * _O1_BYTE];
+ uint8_t mat_l2[_O2 * _O2_BYTE];
+ uint8_t mat_buffer[2 * _MAX_O * _MAX_O_BYTE];
+
+ // setup PRNG
+ prng_t prng_sign;
+ uint8_t prng_preseed[LEN_SKSEED + _HASH_LEN];
+ memcpy(prng_preseed, sk->sk_seed, LEN_SKSEED);
+ memcpy(prng_preseed + LEN_SKSEED, _digest, _HASH_LEN); // prng_preseed = sk_seed || digest
+ uint8_t prng_seed[_HASH_LEN];
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_hash_msg(prng_seed, _HASH_LEN, prng_preseed, _HASH_LEN + LEN_SKSEED);
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_set(&prng_sign, prng_seed, _HASH_LEN); // seed = H( sk_seed || digest )
+ for (unsigned int i = 0; i < LEN_SKSEED + _HASH_LEN; i++) {
+ prng_preseed[i] ^= prng_preseed[i]; // clean
+ }
+ for (unsigned int i = 0; i < _HASH_LEN; i++) {
+ prng_seed[i] ^= prng_seed[i]; // clean
+ }
+
+ // roll vinegars.
+ uint8_t vinegar[_V1_BYTE];
+ unsigned int n_attempt = 0;
+ unsigned int l1_succ = 0;
+ while (!l1_succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(&prng_sign, vinegar, _V1_BYTE); // generating vinegars
+ gfmat_prod(mat_l1, sk->l1_F2, _O1 * _O1_BYTE, _V1, vinegar); // generating the linear equations for layer 1
+ l1_succ = gfmat_inv(mat_l1, mat_l1, _O1, mat_buffer); // check if the linear equation solvable
+ n_attempt++;
+ }
+
+ // Given the vinegars, pre-compute variables needed for layer 2
+ uint8_t r_l1_F1[_O1_BYTE] = {0};
+ uint8_t r_l2_F1[_O2_BYTE] = {0};
+ batch_quad_trimat_eval(r_l1_F1, sk->l1_F1, vinegar, _V1, _O1_BYTE);
+ batch_quad_trimat_eval(r_l2_F1, sk->l2_F1, vinegar, _V1, _O2_BYTE);
+ uint8_t mat_l2_F3[_O2 * _O2_BYTE];
+ uint8_t mat_l2_F2[_O1 * _O2_BYTE];
+ gfmat_prod(mat_l2_F3, sk->l2_F3, _O2 * _O2_BYTE, _V1, vinegar);
+ gfmat_prod(mat_l2_F2, sk->l2_F2, _O1 * _O2_BYTE, _V1, vinegar);
+
+ // Some local variables.
+ uint8_t _z[_PUB_M_BYTE];
+ uint8_t y[_PUB_M_BYTE];
+ uint8_t *x_v1 = vinegar;
+ uint8_t x_o1[_O1_BYTE];
+ uint8_t x_o2[_O1_BYTE];
+
+ uint8_t digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, _digest, _HASH_LEN);
+ uint8_t *salt = digest_salt + _HASH_LEN;
+
+ uint8_t temp_o[_MAX_O_BYTE + 32] = {0};
+ unsigned int succ = 0;
+ while (!succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ // The computation: H(digest||salt) --> z --S--> y --C-map--> x --T--> w
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(&prng_sign, salt, _SALT_BYTE); // roll the salt
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_hash_msg(_z, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H(digest||salt)
+
+ // y = S^-1 * z
+ memcpy(y, _z, _PUB_M_BYTE); // identity part of S
+ gfmat_prod(temp_o, sk->s1, _O1_BYTE, _O2, _z + _O1_BYTE);
+ gf256v_add(y, temp_o, _O1_BYTE);
+
+ // Central Map:
+ // layer 1: calculate x_o1
+ memcpy(temp_o, r_l1_F1, _O1_BYTE);
+ gf256v_add(temp_o, y, _O1_BYTE);
+ gfmat_prod(x_o1, mat_l1, _O1_BYTE, _O1, temp_o);
+
+ // layer 2: calculate x_o2
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_set_zero(temp_o, _O2_BYTE);
+ gfmat_prod(temp_o, mat_l2_F2, _O2_BYTE, _O1, x_o1); // F2
+ batch_quad_trimat_eval(mat_l2, sk->l2_F5, x_o1, _O1, _O2_BYTE); // F5
+ gf256v_add(temp_o, mat_l2, _O2_BYTE);
+ gf256v_add(temp_o, r_l2_F1, _O2_BYTE); // F1
+ gf256v_add(temp_o, y + _O1_BYTE, _O2_BYTE);
+
+ // generate the linear equations of the 2nd layer
+ gfmat_prod(mat_l2, sk->l2_F6, _O2 * _O2_BYTE, _O1, x_o1); // F6
+ gf256v_add(mat_l2, mat_l2_F3, _O2 * _O2_BYTE); // F3
+ succ = gfmat_inv(mat_l2, mat_l2, _O2, mat_buffer);
+ gfmat_prod(x_o2, mat_l2, _O2_BYTE, _O2, temp_o); // solve l2 eqs
+
+ n_attempt++;
+ };
+ // w = T^-1 * y
+ uint8_t w[_PUB_N_BYTE];
+ // identity part of T.
+ memcpy(w, x_v1, _V1_BYTE);
+ memcpy(w + _V1_BYTE, x_o1, _O1_BYTE);
+ memcpy(w + _V2_BYTE, x_o2, _O2_BYTE);
+ // Computing the t1 part.
+ gfmat_prod(y, sk->t1, _V1_BYTE, _O1, x_o1);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t4 part.
+ gfmat_prod(y, sk->t4, _V1_BYTE, _O2, x_o2);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t3 part.
+ gfmat_prod(y, sk->t3, _O1_BYTE, _O2, x_o2);
+ gf256v_add(w + _V1_BYTE, y, _O1_BYTE);
+
+ memset(signature, 0, _SIGNATURE_BYTE); // set the output 0
+ // clean
+ memset(&prng_sign, 0, sizeof(prng_t));
+ memset(vinegar, 0, _V1_BYTE);
+ memset(r_l1_F1, 0, _O1_BYTE);
+ memset(r_l2_F1, 0, _O2_BYTE);
+ memset(_z, 0, _PUB_M_BYTE);
+ memset(y, 0, _PUB_M_BYTE);
+ memset(x_o1, 0, _O1_BYTE);
+ memset(x_o2, 0, _O2_BYTE);
+ memset(temp_o, 0, sizeof(temp_o));
+
+ // return: copy w and salt to the signature.
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ return -1;
+ }
+ gf256v_add(signature, w, _PUB_N_BYTE);
+ gf256v_add(signature + _PUB_N_BYTE, salt, _SALT_BYTE);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk) {
+ unsigned char digest_ck[_PUB_M_BYTE];
+ // public_map( digest_ck , pk , signature ); Evaluating the quadratic public polynomials.
+ batch_quad_trimat_eval(digest_ck, pk->pk, signature, _PUB_N, _PUB_M_BYTE);
+
+ unsigned char correct[_PUB_M_BYTE];
+ unsigned char digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, digest, _HASH_LEN);
+ memcpy(digest_salt + _HASH_LEN, signature + _PUB_N_BYTE, _SALT_BYTE);
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_hash_msg(correct, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H( digest || salt )
+
+ // check consistancy.
+ unsigned char cc = 0;
+ for (unsigned int i = 0; i < _PUB_M_BYTE; i++) {
+ cc |= (digest_ck[i] ^ correct[i]);
+ }
+ return (0 == cc) ? 0 : -1;
+}
+
+/////////////// cyclic version ///////////////////////////
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(uint8_t *signature, const csk_t *csk, const uint8_t *digest) {
+ unsigned char sk[sizeof(sk_t) + 32];
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_generate_secretkey_cyclic((sk_t *)sk, csk->pk_seed, csk->sk_seed); // generating classic secret key.
+ return PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_sign(signature, (sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *_pk) {
+ unsigned char pk[sizeof(pk_t) + 32];
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_cpk_to_pk((pk_t *)pk, _pk); // generating classic public key.
+ return PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_verify(digest, signature, (pk_t *)pk);
+}
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow.h
new file mode 100644
index 00000000..116735d6
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow.h
@@ -0,0 +1,50 @@
+#ifndef _RAINBOW_H_
+#define _RAINBOW_H_
+/// @file rainbow.h
+/// @brief APIs for rainbow.
+///
+
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+
+#include
+
+///
+/// @brief Signing function for classical secret key.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk);
+
+///
+/// @brief Signing function for compressed secret key of the cyclic rainbow.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the compressed secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(uint8_t *signature, const csk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function for cyclic public keys.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key of cyclic rainbow.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *pk);
+
+#endif // _RAINBOW_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_blas.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_blas.h
new file mode 100644
index 00000000..1b4db7e6
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_blas.h
@@ -0,0 +1,31 @@
+#ifndef _RAINBOW_BLAS_H_
+#define _RAINBOW_BLAS_H_
+/// @file rainbow_blas.h
+/// @brief Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+///
+/// Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+
+#include "blas.h"
+#include "parallel_matrix_op.h"
+#include "rainbow_config.h"
+
+
+#define gfv_get_ele PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_get_ele
+#define gfv_mul_scalar PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_mul_scalar
+#define gfv_madd PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256v_madd
+
+#define gfmat_prod PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_prod
+#define gfmat_inv PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_gf256mat_inv
+
+#define batch_trimat_madd PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_trimat_madd_gf256
+#define batch_trimatTr_madd PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_trimatTr_madd_gf256
+#define batch_2trimat_madd PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_2trimat_madd_gf256
+#define batch_matTr_madd PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_matTr_madd_gf256
+#define batch_bmatTr_madd PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_bmatTr_madd_gf256
+#define batch_mat_madd PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_mat_madd_gf256
+
+#define batch_quad_trimat_eval PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_quad_trimat_eval_gf256
+#define batch_quad_recmat_eval PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_batch_quad_recmat_eval_gf256
+
+
+#endif // _RAINBOW_BLAS_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_config.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_config.h
new file mode 100644
index 00000000..979aa244
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_config.h
@@ -0,0 +1,46 @@
+#ifndef _H_RAINBOW_CONFIG_H_
+#define _H_RAINBOW_CONFIG_H_
+
+/// @file rainbow_config.h
+/// @brief Defining the parameters of the Rainbow and the corresponding constants.
+///
+
+#define _GFSIZE 256
+#define _V1 92
+#define _O1 48
+#define _O2 48
+#define _HASH_LEN 64
+
+
+#define _V2 ((_V1) + (_O1))
+
+/// size of N, in # of gf elements.
+#define _PUB_N (_V1 + _O1 + _O2)
+
+/// size of M, in # gf elements.
+#define _PUB_M (_O1 + _O2)
+
+/// size of variables, in # bytes.
+
+// GF256
+#define _V1_BYTE (_V1)
+#define _V2_BYTE (_V2)
+#define _O1_BYTE (_O1)
+#define _O2_BYTE (_O2)
+#define _PUB_N_BYTE (_PUB_N)
+#define _PUB_M_BYTE (_PUB_M)
+
+
+/// length of seed for public key, in # bytes
+#define LEN_PKSEED 32
+
+/// length of seed for secret key, in # bytes
+#define LEN_SKSEED 32
+
+/// length of salt for a signature, in # bytes
+#define _SALT_BYTE 16
+
+/// length of a signature
+#define _SIGNATURE_BYTE (_PUB_N_BYTE + _SALT_BYTE)
+
+#endif // _H_RAINBOW_CONFIG_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair.c b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair.c
new file mode 100644
index 00000000..d90a2ecb
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair.c
@@ -0,0 +1,188 @@
+/// @file rainbow_keypair.c
+/// @brief implementations of functions in rainbow_keypair.h
+///
+
+#include "rainbow_keypair.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair_computation.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+static void generate_S_T(unsigned char *s_and_t, prng_t *prng0) {
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // S1
+ s_and_t += _O1_BYTE * _O2;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O1); // T1
+ s_and_t += _V1_BYTE * _O1;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O2); // T2
+ s_and_t += _V1_BYTE * _O2;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // T3
+}
+
+static unsigned int generate_l1_F12(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O1_BYTE * N_TRIANGLE_TERMS(_V1)); // l1_F1
+ sk += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O1_BYTE * _V1 * _O1); // l1_F2
+ n_byte_generated += _O1_BYTE * _V1 * _O1;
+ return n_byte_generated;
+}
+
+static unsigned int generate_l2_F12356(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // l2_F1
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O1); // l2_F2
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O2); // l2_F3
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // l2_F5
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _O1 * _O2); // l2_F6
+ n_byte_generated += _O2_BYTE * _O1 * _O2;
+
+ return n_byte_generated;
+}
+
+static void generate_B1_B2(unsigned char *sk, prng_t *prng0) {
+ sk += generate_l1_F12(sk, prng0);
+ generate_l2_F12356(sk, prng0);
+}
+
+static void calculate_t4(unsigned char *t2_to_t4, const unsigned char *t1, const unsigned char *t3) {
+ // t4 = T_sk.t1 * T_sk.t3 - T_sk.t2
+ unsigned char temp[_V1_BYTE + 32];
+ unsigned char *t4 = t2_to_t4;
+ for (unsigned int i = 0; i < _O2; i++) { /// t3 width
+ gfmat_prod(temp, t1, _V1_BYTE, _O1, t3);
+ gf256v_add(t4, temp, _V1_BYTE);
+ t4 += _V1_BYTE;
+ t3 += _O1_BYTE;
+ }
+}
+
+static void obsfucate_l1_polys(unsigned char *l1_polys, const unsigned char *l2_polys, unsigned int n_terms, const unsigned char *s1) {
+ unsigned char temp[_O1_BYTE + 32];
+ while (n_terms--) {
+ gfmat_prod(temp, s1, _O1_BYTE, _O2, l2_polys);
+ gf256v_add(l1_polys, temp, _O1_BYTE);
+ l1_polys += _O1_BYTE;
+ l2_polys += _O2_BYTE;
+ }
+}
+
+/////////////////// Classic //////////////////////////////////
+
+
+///////////////////// Cyclic //////////////////////////////////
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(pk->pk_seed, pk_seed, LEN_PKSEED);
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // prng for sk
+ prng_t prng;
+ prng_t *prng0 = &prng;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_set(prng0, sk_seed, LEN_SKSEED);
+ generate_S_T(sk->s1, prng0); // S,T: only a part of sk
+
+ unsigned char t2[sizeof(sk->t4)];
+ memcpy(t2, sk->t4, _V1_BYTE * _O2); // temporarily store t2
+ calculate_t4(sk->t4, sk->t1, sk->t3); // t2 <- t4
+
+ // prng for pk
+ sk_t inst_Qs;
+ sk_t *Qs = &inst_Qs;
+ prng_t *prng1 = &prng;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_set(prng1, pk_seed, LEN_PKSEED);
+ generate_B1_B2(Qs->l1_F1, prng1); // generating l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+ obsfucate_l1_polys(Qs->l1_F1, Qs->l2_F1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(Qs->l1_F2, Qs->l2_F2, _V1 * _O1, sk->s1);
+ // so far, the Qs contains l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6.
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk, Qs, sk); // calcuate the rest parts of secret key from Qs and S,T
+
+ unsigned char t4[sizeof(sk->t4)];
+ memcpy(t4, sk->t4, _V1_BYTE * _O2); // temporarily store t4
+ memcpy(sk->t4, t2, _V1_BYTE * _O2); // restore t2
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_calculate_Q_from_F_cyclic(pk, sk, sk); // calculate the rest parts of public key: l1_Q3, l1_Q5, l1_Q6, l1_Q9, l2_Q9
+ memcpy(sk->t4, t4, _V1_BYTE * _O2); // restore t4
+
+ obsfucate_l1_polys(pk->l1_Q3, Qs->l2_F3, _V1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q5, Qs->l2_F5, N_TRIANGLE_TERMS(_O1), sk->s1);
+ obsfucate_l1_polys(pk->l1_Q6, Qs->l2_F6, _O1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q9, pk->l2_Q9, N_TRIANGLE_TERMS(_O2), sk->s1);
+
+ // clean
+ memset(&prng, 0, sizeof(prng_t));
+}
+
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_generate_compact_keypair_cyclic(cpk_t *pk, csk_t *rsk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(rsk->pk_seed, pk_seed, LEN_PKSEED);
+ memcpy(rsk->sk_seed, sk_seed, LEN_SKSEED);
+ sk_t sk;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_generate_keypair_cyclic(pk, &sk, pk_seed, sk_seed);
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_generate_secretkey_cyclic(sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // prng for sk
+ prng_t prng0;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_set(&prng0, sk_seed, LEN_SKSEED);
+ generate_S_T(sk->s1, &prng0);
+ calculate_t4(sk->t4, sk->t1, sk->t3);
+
+ // prng for pk
+ sk_t inst_Qs;
+ sk_t *Qs = &inst_Qs;
+ prng_t prng1;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_set(&prng1, pk_seed, LEN_PKSEED);
+ generate_B1_B2(Qs->l1_F1, &prng1);
+
+ obsfucate_l1_polys(Qs->l1_F1, Qs->l2_F1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(Qs->l1_F2, Qs->l2_F2, _V1 * _O1, sk->s1);
+
+ // calcuate the parts of sk according to pk.
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk, Qs, sk);
+
+ // clean prng for sk
+ memset(&prng0, 0, sizeof(prng_t));
+}
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_cpk_to_pk(pk_t *rpk, const cpk_t *cpk) {
+ // procedure: cpk_t --> extcpk_t --> pk_t
+
+ // convert from cpk_t to extcpk_t
+ ext_cpk_t pk;
+
+ // setup prng
+ prng_t prng0;
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_set(&prng0, cpk->pk_seed, LEN_SKSEED);
+
+ // generating parts of key with prng
+ generate_l1_F12(pk.l1_Q1, &prng0);
+ // copying parts of key from input. l1_Q3, l1_Q5, l1_Q6, l1_Q9
+ memcpy(pk.l1_Q3, cpk->l1_Q3, _O1_BYTE * (_V1 * _O2 + N_TRIANGLE_TERMS(_O1) + _O1 * _O2 + N_TRIANGLE_TERMS(_O2)));
+
+ // generating parts of key with prng
+ generate_l2_F12356(pk.l2_Q1, &prng0);
+ // copying parts of key from input: l2_Q9
+ memcpy(pk.l2_Q9, cpk->l2_Q9, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ // convert from extcpk_t to pk_t
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_extcpk_to_pk(rpk, &pk);
+}
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair.h
new file mode 100644
index 00000000..f0ccb746
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair.h
@@ -0,0 +1,111 @@
+#ifndef _RAINBOW_KEYPAIR_H_
+#define _RAINBOW_KEYPAIR_H_
+/// @file rainbow_keypair.h
+/// @brief Formats of key pairs and functions for generating key pairs.
+/// Formats of key pairs and functions for generating key pairs.
+///
+
+#include "rainbow_config.h"
+
+#define N_TRIANGLE_TERMS(n_var) ((n_var) * ((n_var) + 1) / 2)
+
+/// @brief public key for classic rainbow
+///
+/// public key for classic rainbow
+///
+typedef struct rainbow_publickey {
+ unsigned char pk[(_PUB_M_BYTE)*N_TRIANGLE_TERMS(_PUB_N)];
+} pk_t;
+
+/// @brief secret key for classic rainbow
+///
+/// secret key for classic rainbow
+///
+typedef struct rainbow_secretkey {
+ ///
+ /// seed for generating secret key.
+ /// Generating S, T, and F for classic rainbow.
+ /// Generating S and T only for cyclic rainbow.
+ unsigned char sk_seed[LEN_SKSEED];
+
+ unsigned char s1[_O1_BYTE * _O2]; ///< part of S map
+ unsigned char t1[_V1_BYTE * _O1]; ///< part of T map
+ unsigned char t4[_V1_BYTE * _O2]; ///< part of T map
+ unsigned char t3[_O1_BYTE * _O2]; ///< part of T map
+
+ unsigned char l1_F1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer1
+ unsigned char l1_F2[_O1_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer1
+
+ unsigned char l2_F1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer2
+ unsigned char l2_F2[_O2_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer2
+
+ unsigned char l2_F3[_O2_BYTE * _V1 * _O2]; ///< part of C-map, F3, Layer2
+ unsigned char l2_F5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< part of C-map, F5, Layer2
+ unsigned char l2_F6[_O2_BYTE * _O1 * _O2]; ///< part of C-map, F6, Layer2
+} sk_t;
+
+/// @brief public key for cyclic rainbow
+///
+/// public key for cyclic rainbow
+///
+typedef struct rainbow_publickey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating l1_Q1,l1_Q2,l2_Q1,l2_Q2,l2_Q3,l2_Q5,l2_Q6
+
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2]; ///< Q3, layer1
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< Q5, layer1
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2]; ///< Q6, layer1
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer1
+
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer2
+} cpk_t;
+
+/// @brief compressed secret key for cyclic rainbow
+///
+/// compressed secret key for cyclic rainbow
+///
+typedef struct rainbow_secretkey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating a part of public key.
+ unsigned char sk_seed[LEN_SKSEED]; ///< seed for generating a part of secret key.
+} csk_t;
+
+
+///
+/// @brief Generate key pairs for cyclic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the secret key.
+/// @param[in] pk_seed - seed for generating parts of public key.
+/// @param[in] sk_seed - seed for generating secret key.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+///
+/// @brief Generate compressed key pairs for cyclic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the compressed secret key.
+/// @param[in] pk_seed - seed for generating parts of the public key.
+/// @param[in] sk_seed - seed for generating the secret key.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_generate_compact_keypair_cyclic(cpk_t *pk, csk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+///
+/// @brief Generate secret key for cyclic rainbow.
+///
+/// @param[out] sk - the secret key.
+/// @param[in] pk_seed - seed for generating parts of the pbulic key.
+/// @param[in] sk_seed - seed for generating the secret key.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_generate_secretkey_cyclic(sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+////////////////////////////////////
+
+///
+/// @brief converting formats of public keys : from cyclic version to classic key
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the cyclic public key.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_cpk_to_pk(pk_t *pk, const cpk_t *cpk);
+
+#endif // _RAINBOW_KEYPAIR_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair_computation.c b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair_computation.c
new file mode 100644
index 00000000..3661f6c8
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair_computation.c
@@ -0,0 +1,213 @@
+/// @file rainbow_keypair_computation.c
+/// @brief Implementations for functions in rainbow_keypair_computation.h
+///
+
+#include "rainbow_keypair_computation.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair.h"
+#include
+#include
+#include
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk) {
+ const unsigned char *idx_l1 = cpk->l1_Q1;
+ const unsigned char *idx_l2 = cpk->l2_Q1;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = i; j < _V1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q2;
+ idx_l2 = cpk->l2_Q2;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q3;
+ idx_l2 = cpk->l2_Q3;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q5;
+ idx_l2 = cpk->l2_Q5;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = i; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q6;
+ idx_l2 = cpk->l2_Q6;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q9;
+ idx_l2 = cpk->l2_Q9;
+ for (unsigned int i = _V1 + _O1; i < _PUB_N; i++) {
+ for (unsigned int j = i; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+}
+
+static void calculate_F_from_Q_ref(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ // Layer 1
+ // F_sk.l1_F1s[i] = Q_pk.l1_F1s[i]
+ memcpy(Fs->l1_F1, Qs->l1_F1, _O1_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ // F_sk.l1_F2s[i] = ( Q_pk.l1_F1s[i] + Q_pk.l1_F1s[i].transpose() ) * T_sk.t1 + Q_pk.l1_F2s[i]
+ memcpy(Fs->l1_F2, Qs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_2trimat_madd(Fs->l1_F2, Qs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE);
+
+ /*
+ Layer 2
+ computations:
+
+ F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ Q1_T1 = Q_pk.l2_F1s[i]*T_sk.t1
+ F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+
+ Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ #Q1_Q1T_T4 = Q1_Q1T * t4
+ Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ + Q_pk.l2_F2s[i].transpose() * t4
+ + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+
+ */
+ memcpy(Fs->l2_F1, Qs->l2_F1, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ // F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ // F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+ memcpy(Fs->l2_F2, Qs->l2_F2, _O2_BYTE * _V1 * _O1);
+ batch_trimat_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // Q1_T1+ Q2
+
+ unsigned char tempQ[_O1 * _O1 * _O2_BYTE + 32];
+ memset(tempQ, 0, _O1 * _O1 * _O2_BYTE);
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F2, _O1, _O2_BYTE); // t1_tr*(Q1_T1+Q2)
+ memcpy(Fs->l2_F5, Qs->l2_F5, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // F5
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_UpperTrianglize(Fs->l2_F5, tempQ, _O1, _O2_BYTE); // UT( ... )
+
+ batch_trimatTr_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // F2 = Q1_T1 + Q2 + Q1^tr*t1
+
+ // Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ // Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ // F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ memcpy(Fs->l2_F3, Qs->l2_F3, _V1 * _O2 * _O2_BYTE);
+ batch_2trimat_madd(Fs->l2_F3, Qs->l2_F1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE); // Q1_Q1T_T4
+ batch_mat_madd(Fs->l2_F3, Qs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // Q2_T3
+
+ // F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ // + Q_pk.l2_F2s[i].transpose() * t4
+ // + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+ memcpy(Fs->l2_F6, Qs->l2_F6, _O1 * _O2 * _O2_BYTE);
+ batch_matTr_madd(Fs->l2_F6, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F3, _O2, _O2_BYTE); // t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ batch_2trimat_madd(Fs->l2_F6, Qs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3
+ batch_bmatTr_madd(Fs->l2_F6, Qs->l2_F2, _O1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE);
+}
+
+static void calculate_Q_from_F_cyclic_ref(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ // Layer 1: Computing Q5, Q3, Q6, Q9
+
+ // Q_pk.l1_F5s[i] = UT( T1tr* (F1 * T1 + F2) )
+ const unsigned char *t2 = Ts->t4;
+ sk_t tempQ;
+ memcpy(tempQ.l1_F2, Fs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_trimat_madd(tempQ.l1_F2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // F1*T1 + F2
+ memset(tempQ.l2_F1, 0, sizeof(tempQ.l2_F1));
+ memset(tempQ.l2_F2, 0, sizeof(tempQ.l2_F2));
+ batch_matTr_madd(tempQ.l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, tempQ.l1_F2, _O1, _O1_BYTE); // T1tr*(F1*T1 + F2)
+ memset(Qs->l1_Q5, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O1));
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_UpperTrianglize(Qs->l1_Q5, tempQ.l2_F1, _O1, _O1_BYTE); // UT( ... ) // Q5
+
+ /*
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+ Q_pk.l1_F3s[i] = F1_F1T_T2 + F2_T3
+ Q_pk.l1_F6s[i] = T1tr* ( F1_F1T_T2 + F2_T3 ) + F2tr * t2
+ Q_pk.l1_F9s[i] = UT( T2tr* ( F1_T2 + F2_T3 ) )
+ */
+ memset(Qs->l1_Q3, 0, _O1_BYTE * _V1 * _O2);
+ memset(Qs->l1_Q6, 0, _O1_BYTE * _O1 * _O2);
+ memset(Qs->l1_Q9, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ batch_trimat_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1*T2
+ batch_mat_madd(Qs->l1_Q3, Fs->l1_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O1_BYTE); // F1_T2 + F2_T3
+
+ memset(tempQ.l1_F2, 0, _O1_BYTE * _V1 * _O2); // should be F3. assuming: _O1 >= _O2
+ batch_matTr_madd(tempQ.l1_F2, t2, _V1, _V1_BYTE, _O2, Qs->l1_Q3, _O2, _O1_BYTE); // T2tr * ( F1_T2 + F2_T3 )
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_UpperTrianglize(Qs->l1_Q9, tempQ.l1_F2, _O2, _O1_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1_F1T_T2 + F2_T3 // Q3
+
+ batch_bmatTr_madd(Qs->l1_Q6, Fs->l1_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F2tr*T2
+ batch_matTr_madd(Qs->l1_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q3, _O2, _O1_BYTE); // Q6
+ /*
+ Layer 2
+ Computing Q9:
+
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ Q9 = UT( T2tr*( F1*T2 + F2*T3 + F3 ) + T3tr*( F5*T3 + F6 ) )
+ */
+ sk_t tempQ2;
+ memcpy(tempQ2.l2_F3, Fs->l2_F3, _O2_BYTE * _V1 * _O2); /// F3 actually.
+ batch_trimat_madd(tempQ2.l2_F3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1*T2 + F3
+ batch_mat_madd(tempQ2.l2_F3, Fs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F1_T2 + F2_T3 + F3
+
+ memset(tempQ.l2_F3, 0, _O2_BYTE * _V1 * _O2);
+ batch_matTr_madd(tempQ.l2_F3, t2, _V1, _V1_BYTE, _O2, tempQ2.l2_F3, _O2, _O2_BYTE); // T2tr * ( ..... )
+
+ memcpy(tempQ.l2_F6, Fs->l2_F6, _O2_BYTE * _O1 * _O2);
+ batch_trimat_madd(tempQ.l2_F6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6
+
+ batch_matTr_madd(tempQ.l2_F3, Ts->t3, _O1, _O1_BYTE, _O2, tempQ.l2_F6, _O2, _O2_BYTE); // T2tr*( ..... ) + T3tr*( ..... )
+ memset(Qs->l2_Q9, 0, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_UpperTrianglize(Qs->l2_Q9, tempQ.l2_F3, _O2, _O2_BYTE); // Q9
+}
+
+// Choosing implementations depends on the macros: _BLAS_SSE_ and _BLAS_AVX2_
+#define calculate_F_from_Q_impl calculate_F_from_Q_ref
+#define calculate_Q_from_F_cyclic_impl calculate_Q_from_F_cyclic_ref
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ calculate_F_from_Q_impl(Fs, Qs, Ts);
+}
+
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ calculate_Q_from_F_cyclic_impl(Qs, Fs, Ts);
+}
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair_computation.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair_computation.h
new file mode 100644
index 00000000..ea3a279d
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/rainbow_keypair_computation.h
@@ -0,0 +1,71 @@
+#ifndef _RAINBOW_KEYPAIR_COMP_H_
+#define _RAINBOW_KEYPAIR_COMP_H_
+/// @file rainbow_keypair_computation.h
+/// @brief Functions for calculating pk/sk while generating keys.
+///
+/// Defining an internal structure of public key.
+/// Functions for calculating pk/sk for key generation.
+///
+
+#include "rainbow_keypair.h"
+
+/// @brief The (internal use) public key for rainbow
+///
+/// The (internal use) public key for rainbow. The public
+/// polynomials are divided into l1_Q1, l1_Q2, ... l1_Q9,
+/// l2_Q1, .... , l2_Q9.
+///
+typedef struct rainbow_extend_publickey {
+ unsigned char l1_Q1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l1_Q2[_O1_BYTE * _V1 * _O1];
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2];
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2];
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)];
+
+ unsigned char l2_Q1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l2_Q2[_O2_BYTE * _V1 * _O1];
+ unsigned char l2_Q3[_O2_BYTE * _V1 * _O2];
+ unsigned char l2_Q5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l2_Q6[_O2_BYTE * _O1 * _O2];
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)];
+} ext_cpk_t;
+
+///
+/// @brief converting formats of public keys : from ext_cpk_t version to pk_t
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the internel public key.
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk);
+/////////////////////////////////////////////////
+
+///
+/// @brief Computing public key from secret key
+///
+/// @param[out] Qs - the public key
+/// @param[in] Fs - parts of the secret key: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the secret key: T1, T4, T3
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+
+///
+/// @brief Computing parts of the sk from parts of pk and sk
+///
+/// @param[out] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Qs - parts of the pk: l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts);
+
+///
+/// @brief Computing parts of the pk from the secret key
+///
+/// @param[out] Qs - parts of the pk: l1_Q3, l1_Q5, l2_Q6, l1_Q9, l2_Q9
+/// @param[in] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+#endif // _RAINBOW_KEYPAIR_COMP_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/sign.c b/crypto_sign/rainbowVc-cyclic-compressed/clean/sign.c
new file mode 100644
index 00000000..99f483cb
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/sign.c
@@ -0,0 +1,76 @@
+/// @file sign.c
+/// @brief the implementations for functions in api.h
+///
+///
+
+#include "api.h"
+#include "rainbow.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
+ unsigned char sk_seed[LEN_SKSEED] = {0};
+ randombytes(sk_seed, LEN_SKSEED);
+
+ unsigned char pk_seed[LEN_PKSEED] = {0};
+ randombytes(pk_seed, LEN_PKSEED);
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_generate_compact_keypair_cyclic((cpk_t *)pk, (csk_t *)sk, pk_seed, sk_seed);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_crypto_sign(unsigned char *sm, size_t *smlen, const unsigned char *m, size_t mlen, const unsigned char *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+
+ memcpy(sm, m, mlen);
+ smlen[0] = mlen + _SIGNATURE_BYTE;
+
+ return PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(sm + mlen, (const csk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_crypto_sign_open(unsigned char *m, size_t *mlen, const unsigned char *sm, size_t smlen, const unsigned char *pk) {
+ int rc;
+ if (_SIGNATURE_BYTE > smlen) {
+ rc = -1;
+ } else {
+ *mlen = smlen - _SIGNATURE_BYTE;
+
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, sm, *mlen);
+
+ rc = PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(digest, sm + mlen[0], (const cpk_t *)pk);
+ }
+ if (!rc) {
+ memcpy(m, sm, smlen - _SIGNATURE_BYTE);
+ } else { // bad signature
+ *mlen = (size_t) -1;
+ memset(m, 0, smlen);
+ }
+ return rc;
+}
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ *siglen = _SIGNATURE_BYTE;
+ return PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_sign_cyclic(sig, (const csk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ if (siglen != _SIGNATURE_BYTE) {
+ return -1;
+ }
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ return PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_rainbow_verify_cyclic(digest, sig, (const cpk_t *)pk);
+}
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_hash.c b/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_hash.c
new file mode 100644
index 00000000..f3bffff1
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_hash.c
@@ -0,0 +1,50 @@
+/// @file utils_hash.c
+/// @brief the adapter for SHA2 families.
+///
+///
+
+#include "utils_hash.h"
+#include "rainbow_config.h"
+#include "sha2.h"
+
+static inline int _hash(unsigned char *digest, const unsigned char *m, size_t mlen) {
+ sha512(digest, m, mlen);
+ return 0;
+}
+
+static inline int expand_hash(unsigned char *digest, size_t n_digest, const unsigned char *hash) {
+ if (_HASH_LEN >= n_digest) {
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[i] = hash[i];
+ }
+ return 0;
+ }
+ for (size_t i = 0; i < _HASH_LEN; i++) {
+ digest[i] = hash[i];
+ }
+ n_digest -= _HASH_LEN;
+
+ while (_HASH_LEN <= n_digest) {
+ _hash(digest + _HASH_LEN, digest, _HASH_LEN);
+
+ n_digest -= _HASH_LEN;
+ digest += _HASH_LEN;
+ }
+ unsigned char temp[_HASH_LEN];
+ if (n_digest) {
+ _hash(temp, digest, _HASH_LEN);
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[_HASH_LEN + i] = temp[i];
+ }
+ }
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_hash_msg(unsigned char *digest,
+ size_t len_digest,
+ const unsigned char *m,
+ size_t mlen) {
+ unsigned char buf[_HASH_LEN];
+ _hash(buf, m, mlen);
+ return expand_hash(digest, len_digest, buf);
+}
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_hash.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_hash.h
new file mode 100644
index 00000000..651fd686
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_hash.h
@@ -0,0 +1,11 @@
+#ifndef _UTILS_HASH_H_
+#define _UTILS_HASH_H_
+/// @file utils_hash.h
+/// @brief the interface for adapting hash functions.
+///
+
+#include
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_hash_msg(unsigned char *digest, size_t len_digest, const unsigned char *m, size_t mlen);
+
+#endif // _UTILS_HASH_H_
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_prng.c b/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_prng.c
new file mode 100644
index 00000000..53f4111c
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_prng.c
@@ -0,0 +1,95 @@
+/// @file utils_prng.c
+/// @brief The implementation of PRNG related functions.
+///
+
+#include "utils_prng.h"
+#include "aes.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+static void prng_update(const unsigned char *provided_data,
+ unsigned char *Key,
+ unsigned char *V) {
+ unsigned char temp[48];
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, Key);
+ for (int i = 0; i < 3; i++) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (V[j] == 0xff) {
+ V[j] = 0x00;
+ } else {
+ V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(temp + 16 * i, V, 1, &ctx);
+ }
+ if (provided_data != NULL) {
+ for (int i = 0; i < 48; i++) {
+ temp[i] ^= provided_data[i];
+ }
+ }
+ memcpy(Key, temp, 32);
+ memcpy(V, temp + 32, 16);
+}
+static void randombytes_init_with_state(prng_t *state,
+ unsigned char *entropy_input_48bytes) {
+ memset(state->Key, 0x00, 32);
+ memset(state->V, 0x00, 16);
+ prng_update(entropy_input_48bytes, state->Key, state->V);
+}
+
+static int randombytes_with_state(prng_t *state,
+ unsigned char *x,
+ size_t xlen) {
+
+ unsigned char block[16];
+ int i = 0;
+
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, state->Key);
+
+ while (xlen > 0) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (state->V[j] == 0xff) {
+ state->V[j] = 0x00;
+ } else {
+ state->V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(block, state->V, 1, &ctx);
+ if (xlen > 15) {
+ memcpy(x + i, block, 16);
+ i += 16;
+ xlen -= 16;
+ } else {
+ memcpy(x + i, block, xlen);
+ xlen = 0;
+ }
+ }
+ prng_update(NULL, state->Key, state->V);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen) {
+ unsigned char seed[48];
+ if (prng_seedlen >= 48) {
+ memcpy(seed, prng_seed, 48);
+ } else {
+ memcpy(seed, prng_seed, prng_seedlen);
+ PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_hash_msg(seed + prng_seedlen, 48 - (unsigned)prng_seedlen, (const unsigned char *)prng_seed, prng_seedlen);
+ }
+
+ randombytes_init_with_state(ctx, seed);
+
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen) {
+ return randombytes_with_state(ctx, out, outlen);
+}
diff --git a/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_prng.h b/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_prng.h
new file mode 100644
index 00000000..a4e331ee
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic-compressed/clean/utils_prng.h
@@ -0,0 +1,18 @@
+#ifndef _UTILS_PRNG_H_
+#define _UTILS_PRNG_H_
+/// @file utils_prng.h
+/// @brief the interface for adapting PRNG functions.
+///
+///
+
+#include "randombytes.h"
+
+typedef struct {
+ unsigned char Key[32];
+ unsigned char V[16];
+} prng_t;
+
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen);
+int PQCLEAN_RAINBOWVCCYCLICCOMPRESSED_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen);
+
+#endif // _UTILS_PRNG_H_
diff --git a/crypto_sign/rainbowVc-cyclic/META.yml b/crypto_sign/rainbowVc-cyclic/META.yml
new file mode 100644
index 00000000..d91962b6
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/META.yml
@@ -0,0 +1,18 @@
+name: Rainbow-Vc-cyclic
+type: signature
+claimed-nist-level: 5
+length-public-key: 491936
+length-secret-key: 1227104
+length-signature: 204
+nistkat-sha256: f33608a7f2db6ea71394f38a9e1ee06b96330759ccd4fc1719ac2286dac43650
+testvectors-sha256: d760ae98b24bdc3f8d22e8324ba73e0dd759a99a58b9e8860a168182de02b669
+principal-submitters:
+ - Jintai Ding
+auxiliary-submitters:
+ - Ming-Shing Chen
+ - Albrecht Petzoldt
+ - Dieter Schmidt
+ - Bo-Yin Yang
+implementations:
+ - name: clean
+ version: https://github.com/fast-crypto-lab/rainbow-submission-round2/commit/af826fcb78f6af51a02d0352cff28a9690467bfd
diff --git a/crypto_sign/rainbowVc-cyclic/clean/LICENSE b/crypto_sign/rainbowVc-cyclic/clean/LICENSE
new file mode 100644
index 00000000..cb00a6e3
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/LICENSE
@@ -0,0 +1,8 @@
+`Software implementation of Rainbow for NIST R2 submission' by Ming-Shing Chen
+
+To the extent possible under law, the person who associated CC0 with
+`Software implementation of Rainbow for NIST R2 submission' has waived all copyright and related or neighboring rights
+to `Software implementation of Rainbow for NIST R2 submission'.
+
+You should have received a copy of the CC0 legalcode along with this
+work. If not, see .
diff --git a/crypto_sign/rainbowVc-cyclic/clean/Makefile b/crypto_sign/rainbowVc-cyclic/clean/Makefile
new file mode 100644
index 00000000..de6d19fd
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=librainbowVc-cyclic_clean.a
+
+HEADERS = api.h blas_comm.h blas.h blas_u32.h gf.h parallel_matrix_op.h rainbow_blas.h rainbow_config.h rainbow.h rainbow_keypair_computation.h rainbow_keypair.h utils_hash.h utils_prng.h
+OBJECTS = blas_comm.o parallel_matrix_op.o rainbow.o rainbow_keypair.o rainbow_keypair_computation.o sign.o utils_hash.o utils_prng.o blas_u32.o gf.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/rainbowVc-cyclic/clean/Makefile.Microsoft_nmake b/crypto_sign/rainbowVc-cyclic/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..5b554a44
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=librainbowVc-cyclic_clean.lib
+OBJECTS = blas_comm.obj parallel_matrix_op.obj rainbow.obj rainbow_keypair.obj rainbow_keypair_computation.obj sign.obj utils_hash.obj utils_prng.obj blas_u32.obj gf.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/rainbowVc-cyclic/clean/api.h b/crypto_sign/rainbowVc-cyclic/clean/api.h
new file mode 100644
index 00000000..e7106779
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/api.h
@@ -0,0 +1,32 @@
+#ifndef PQCLEAN_RAINBOWVCCYCLIC_CLEAN_API_H
+#define PQCLEAN_RAINBOWVCCYCLIC_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_RAINBOWVCCYCLIC_CLEAN_CRYPTO_SECRETKEYBYTES 1227104
+#define PQCLEAN_RAINBOWVCCYCLIC_CLEAN_CRYPTO_PUBLICKEYBYTES 491936
+#define PQCLEAN_RAINBOWVCCYCLIC_CLEAN_CRYPTO_BYTES 204
+#define PQCLEAN_RAINBOWVCCYCLIC_CLEAN_CRYPTO_ALGNAME "RAINBOW(256,92,48,48) - cyclic"
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
+
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen,
+ const uint8_t *sk);
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen,
+ const uint8_t *pk);
+
+
+#endif
diff --git a/crypto_sign/rainbowVc-cyclic/clean/blas.h b/crypto_sign/rainbowVc-cyclic/clean/blas.h
new file mode 100644
index 00000000..0469ec1f
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/blas.h
@@ -0,0 +1,19 @@
+#ifndef _BLAS_H_
+#define _BLAS_H_
+/// @file blas.h
+/// @brief Defining the implementations for linear algebra functions depending on the machine architecture.
+///
+
+#include "blas_comm.h"
+#include "blas_u32.h"
+#include "rainbow_config.h"
+
+#define gf256v_predicated_add PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_predicated_add_u32
+#define gf256v_add PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_add_u32
+
+
+#define gf256v_mul_scalar PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_mul_scalar_u32
+#define gf256v_madd PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_madd_u32
+
+
+#endif // _BLAS_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/blas_comm.c b/crypto_sign/rainbowVc-cyclic/clean/blas_comm.c
new file mode 100644
index 00000000..0ff48c2a
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/blas_comm.c
@@ -0,0 +1,142 @@
+/// @file blas_comm.c
+/// @brief The standard implementations for blas_comm.h
+///
+
+#include "blas_comm.h"
+#include "blas.h"
+#include "gf.h"
+#include "rainbow_config.h"
+
+#include
+#include
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte) {
+ gf256v_add(b, b, _num_byte);
+}
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i) {
+ return a[i];
+}
+
+unsigned int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte) {
+ uint8_t r = 0;
+ while (_num_byte--) {
+ r |= a[0];
+ a++;
+ }
+ return (0 == r);
+}
+
+/// polynomial multplication
+/// School boook
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num) {
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(c, _num * 2 - 1);
+ for (unsigned int i = 0; i < _num; i++) {
+ gf256v_madd(c + i, a, b[i], _num);
+ }
+}
+
+static void gf256mat_prod_ref(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(c, n_A_vec_byte);
+ for (unsigned int i = 0; i < n_A_width; i++) {
+ gf256v_madd(c, matA, b[i], n_A_vec_byte);
+ matA += n_A_vec_byte;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec) {
+ unsigned int n_vec_byte = len_vec;
+ for (unsigned int k = 0; k < len_vec; k++) {
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(c, n_vec_byte);
+ const uint8_t *bk = b + n_vec_byte * k;
+ for (unsigned int i = 0; i < len_vec; i++) {
+ gf256v_madd(c, a + n_vec_byte * i, bk[i], n_vec_byte);
+ }
+ c += n_vec_byte;
+ }
+}
+
+static unsigned int gf256mat_gauss_elim_ref(uint8_t *mat, unsigned int h, unsigned int w) {
+ unsigned int r8 = 1;
+
+ for (unsigned int i = 0; i < h; i++) {
+ uint8_t *ai = mat + w * i;
+ unsigned int skip_len_align4 = i & ((unsigned int)~0x3);
+
+ for (unsigned int j = i + 1; j < h; j++) {
+ uint8_t *aj = mat + w * j;
+ gf256v_predicated_add(ai + skip_len_align4, !PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256_is_nonzero(ai[i]), aj + skip_len_align4, w - skip_len_align4);
+ }
+ r8 &= PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256_is_nonzero(ai[i]);
+ uint8_t pivot = ai[i];
+ pivot = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256_inv(pivot);
+ gf256v_mul_scalar(ai + skip_len_align4, pivot, w - skip_len_align4);
+ for (unsigned int j = 0; j < h; j++) {
+ if (i == j) {
+ continue;
+ }
+ uint8_t *aj = mat + w * j;
+ gf256v_madd(aj + skip_len_align4, ai + skip_len_align4, aj[i], w - skip_len_align4);
+ }
+ }
+
+ return r8;
+}
+
+static unsigned int gf256mat_solve_linear_eq_ref(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ uint8_t mat[64 * 64];
+ for (unsigned int i = 0; i < n; i++) {
+ memcpy(mat + i * (n + 1), inp_mat + i * n, n);
+ mat[i * (n + 1) + n] = c_terms[i];
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_gauss_elim(mat, n, n + 1);
+ for (unsigned int i = 0; i < n; i++) {
+ sol[i] = mat[i * (n + 1) + n];
+ }
+ return r8;
+}
+
+static inline void gf256mat_submat(uint8_t *mat2, unsigned int w2, unsigned int st, const uint8_t *mat, unsigned int w, unsigned int h) {
+ for (unsigned int i = 0; i < h; i++) {
+ for (unsigned int j = 0; j < w2; j++) {
+ mat2[i * w2 + j] = mat[i * w + st + j];
+ }
+ }
+}
+
+unsigned int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer) {
+ uint8_t *aa = buffer;
+ for (unsigned int i = 0; i < H; i++) {
+ uint8_t *ai = aa + i * 2 * H;
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(ai, 2 * H);
+ gf256v_add(ai, a + i * H, H);
+ ai[H + i] = 1;
+ }
+ unsigned int r8 = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_gauss_elim(aa, H, 2 * H);
+ gf256mat_submat(inv_a, H, H, aa, 2 * H, H);
+ return r8;
+}
+
+
+// choosing the implementations depends on the macros _BLAS_AVX2_ and _BLAS_SSE
+
+#define gf256mat_prod_impl gf256mat_prod_ref
+#define gf256mat_gauss_elim_impl gf256mat_gauss_elim_ref
+#define gf256mat_solve_linear_eq_impl gf256mat_solve_linear_eq_ref
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b) {
+ gf256mat_prod_impl(c, matA, n_A_vec_byte, n_A_width, b);
+}
+
+unsigned int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w) {
+ return gf256mat_gauss_elim_impl(mat, h, w);
+}
+
+unsigned int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n) {
+ return gf256mat_solve_linear_eq_impl(sol, inp_mat, c_terms, n);
+}
+
diff --git a/crypto_sign/rainbowVc-cyclic/clean/blas_comm.h b/crypto_sign/rainbowVc-cyclic/clean/blas_comm.h
new file mode 100644
index 00000000..08ae23c0
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/blas_comm.h
@@ -0,0 +1,90 @@
+#ifndef _BLAS_COMM_H_
+#define _BLAS_COMM_H_
+/// @file blas_comm.h
+/// @brief Common functions for linear algebra.
+///
+
+#include "rainbow_config.h"
+#include
+
+/// @brief set a vector to 0.
+///
+/// @param[in,out] b - the vector b.
+/// @param[in] _num_byte - number of bytes for the vector b.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(uint8_t *b, unsigned int _num_byte);
+
+/// @brief get an element from GF(256) vector .
+///
+/// @param[in] a - the input vector a.
+/// @param[in] i - the index in the vector a.
+/// @return the value of the element.
+///
+uint8_t PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(const uint8_t *a, unsigned int i);
+
+/// @brief check if a vector is 0.
+///
+/// @param[in] a - the vector a.
+/// @param[in] _num_byte - number of bytes for the vector a.
+/// @return 1(true) if a is 0. 0(false) else.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_is_zero(const uint8_t *a, unsigned int _num_byte);
+
+/// @brief polynomial multiplication: c = a*b
+///
+/// @param[out] c - the output polynomial c
+/// @param[in] a - the vector a.
+/// @param[in] b - the vector b.
+/// @param[in] _num - number of elements for the polynomials a and b.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_polymul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int _num);
+
+/// @brief matrix-vector multiplication: c = matA * b , in GF(256)
+///
+/// @param[out] c - the output vector c
+/// @param[in] matA - a column-major matrix A.
+/// @param[in] n_A_vec_byte - the size of column vectors in bytes.
+/// @param[in] n_A_width - the width of matrix A.
+/// @param[in] b - the vector b.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_prod(uint8_t *c, const uint8_t *matA, unsigned int n_A_vec_byte, unsigned int n_A_width, const uint8_t *b);
+
+/// @brief matrix-matrix multiplication: c = a * b , in GF(256)
+///
+/// @param[out] c - the output matrix c
+/// @param[in] c - a matrix a.
+/// @param[in] b - a matrix b.
+/// @param[in] len_vec - the length of column vectors.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_mul(uint8_t *c, const uint8_t *a, const uint8_t *b, unsigned int len_vec);
+
+/// @brief Gauss elimination for a matrix, in GF(256)
+///
+/// @param[in,out] mat - the matrix.
+/// @param[in] h - the height of the matrix.
+/// @param[in] w - the width of the matrix.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_gauss_elim(uint8_t *mat, unsigned int h, unsigned int w);
+
+/// @brief Solving linear equations, in GF(256)
+///
+/// @param[out] sol - the solutions.
+/// @param[in] inp_mat - the matrix parts of input equations.
+/// @param[in] c_terms - the constant terms of the input equations.
+/// @param[in] n - the number of equations.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_solve_linear_eq(uint8_t *sol, const uint8_t *inp_mat, const uint8_t *c_terms, unsigned int n);
+
+/// @brief Computing the inverse matrix, in GF(256)
+///
+/// @param[out] inv_a - the output of matrix a.
+/// @param[in] a - a matrix a.
+/// @param[in] H - height of matrix a, i.e., matrix a is an HxH matrix.
+/// @param[in] buffer - The buffer for computations. it has to be as large as 2 input matrixes.
+/// @return 1(true) if success. 0(false) if the matrix is singular.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_inv(uint8_t *inv_a, const uint8_t *a, unsigned int H, uint8_t *buffer);
+
+#endif // _BLAS_COMM_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/blas_u32.c b/crypto_sign/rainbowVc-cyclic/clean/blas_u32.c
new file mode 100644
index 00000000..d8d5b65d
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/blas_u32.c
@@ -0,0 +1,87 @@
+#include "blas_u32.h"
+#include "gf.h"
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte) {
+ uint32_t pr_u32 = ((uint32_t)0) - ((uint32_t)predicate);
+ uint8_t pr_u8 = pr_u32 & 0xff;
+
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= (a_u32[i] & pr_u32);
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= (a[i] & pr_u8);
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *b_u32 = (uint32_t *)accu_b;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ b_u32[i] ^= a_u32[i];
+ }
+
+ a += (n_u32 << 2);
+ accu_b += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_b[i] ^= a[i];
+ }
+}
+
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *a_u32 = (uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ a_u32[i] = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_mul_u32(a_u32[i], b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_mul_u32(t.u32, b);
+ for (unsigned int i = 0; i < rem; i++) {
+ a[i] = t.u8[i];
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte) {
+ unsigned int n_u32 = _num_byte >> 2;
+ uint32_t *c_u32 = (uint32_t *)accu_c;
+ const uint32_t *a_u32 = (const uint32_t *)a;
+ for (unsigned int i = 0; i < n_u32; i++) {
+ c_u32[i] ^= PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_mul_u32(a_u32[i], gf256_b);
+ }
+
+ union tmp_32 {
+ uint8_t u8[4];
+ uint32_t u32;
+ } t;
+ t.u32 = 0;
+ accu_c += (n_u32 << 2);
+ a += (n_u32 << 2);
+ unsigned int rem = _num_byte & 3;
+ for (unsigned int i = 0; i < rem; i++) {
+ t.u8[i] = a[i];
+ }
+ t.u32 = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_mul_u32(t.u32, gf256_b);
+ for (unsigned int i = 0; i < rem; i++) {
+ accu_c[i] ^= t.u8[i];
+ }
+}
+
diff --git a/crypto_sign/rainbowVc-cyclic/clean/blas_u32.h b/crypto_sign/rainbowVc-cyclic/clean/blas_u32.h
new file mode 100644
index 00000000..4ca03d6b
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/blas_u32.h
@@ -0,0 +1,18 @@
+#ifndef _BLAS_U32_H_
+#define _BLAS_U32_H_
+/// @file blas_u32.h
+/// @brief Inlined functions for implementing basic linear algebra functions for uint32 arch.
+///
+
+#include "rainbow_config.h"
+#include
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_predicated_add_u32(uint8_t *accu_b, uint8_t predicate, const uint8_t *a, unsigned int _num_byte);
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_add_u32(uint8_t *accu_b, const uint8_t *a, unsigned int _num_byte);
+
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_mul_scalar_u32(uint8_t *a, uint8_t b, unsigned int _num_byte);
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_madd_u32(uint8_t *accu_c, const uint8_t *a, uint8_t gf256_b, unsigned int _num_byte);
+
+
+#endif // _BLAS_U32_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/gf.c b/crypto_sign/rainbowVc-cyclic/clean/gf.c
new file mode 100644
index 00000000..17074555
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/gf.c
@@ -0,0 +1,134 @@
+#include "gf.h"
+
+//// gf4 := gf2[x]/x^2+x+1
+static inline uint8_t gf4_mul_2(uint8_t a) {
+ uint8_t r = (uint8_t)(a << 1);
+ r ^= (uint8_t)((a >> 1) * 7);
+ return r;
+}
+
+static inline uint8_t gf4_mul(uint8_t a, uint8_t b) {
+ uint8_t r = (uint8_t)(a * (b & 1));
+ return r ^ (uint8_t)(gf4_mul_2(a) * (b >> 1));
+}
+
+static inline uint8_t gf4_squ(uint8_t a) {
+ return a ^ (a >> 1);
+}
+
+static inline uint32_t gf4v_mul_2_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit1 ^ (bit1 >> 1);
+}
+
+static inline uint32_t gf4v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t bit0_b = ((uint32_t)0) - ((uint32_t)(b & 1));
+ uint32_t bit1_b = ((uint32_t)0) - ((uint32_t)((b >> 1) & 1));
+ return (a & bit0_b) ^ (bit1_b & gf4v_mul_2_u32(a));
+}
+
+//// gf16 := gf4[y]/y^2+y+x
+static inline uint8_t gf16_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ uint8_t b0 = b & 3;
+ uint8_t b1 = (b >> 2);
+ uint8_t a0b0 = gf4_mul(a0, b0);
+ uint8_t a1b1 = gf4_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf4_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x2 = gf4_mul_2(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 2 ^ a0b0 ^ a1b1_x2);
+}
+
+static inline uint8_t gf16_squ(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = (a >> 2);
+ a1 = gf4_squ(a1);
+ uint8_t a1squ_x2 = gf4_mul_2(a1);
+ return (uint8_t)((a1 << 2) ^ a1squ_x2 ^ gf4_squ(a0));
+}
+
+// gf16 := gf4[y]/y^2+y+x
+uint32_t PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = gf4v_mul_u32(a, b);
+ uint32_t axb1 = gf4v_mul_u32(a, b >> 2);
+ uint32_t a0b1 = (axb1 << 2) & 0xcccccccc;
+ uint32_t a1b1 = axb1 & 0xcccccccc;
+ uint32_t a1b1_2 = a1b1 >> 2;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf4v_mul_2_u32(a1b1_2);
+}
+
+uint8_t PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256_is_nonzero(uint8_t a) {
+ unsigned int a8 = a;
+ unsigned int r = ((unsigned int)0) - a8;
+ r >>= 8;
+ return r & 1;
+}
+
+static inline uint8_t gf4_mul_3(uint8_t a) {
+ uint8_t msk = (uint8_t)((a - 2) >> 1);
+ return (uint8_t)((msk & ((int)a * 3)) | ((~msk) & ((int)a - 1)));
+}
+static inline uint8_t gf16_mul_8(uint8_t a) {
+ uint8_t a0 = a & 3;
+ uint8_t a1 = a >> 2;
+ return (uint8_t)((gf4_mul_2(a0 ^ a1) << 2) | gf4_mul_3(a1));
+}
+
+// gf256 := gf16[X]/X^2+X+xy
+static inline uint8_t gf256_mul(uint8_t a, uint8_t b) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ uint8_t b0 = b & 15;
+ uint8_t b1 = (b >> 4);
+ uint8_t a0b0 = gf16_mul(a0, b0);
+ uint8_t a1b1 = gf16_mul(a1, b1);
+ uint8_t a0b1_a1b0 = gf16_mul(a0 ^ a1, b0 ^ b1) ^ a0b0 ^ a1b1;
+ uint8_t a1b1_x8 = gf16_mul_8(a1b1);
+ return (uint8_t)((a0b1_a1b0 ^ a1b1) << 4 ^ a0b0 ^ a1b1_x8);
+}
+
+static inline uint8_t gf256_squ(uint8_t a) {
+ uint8_t a0 = a & 15;
+ uint8_t a1 = (a >> 4);
+ a1 = gf16_squ(a1);
+ uint8_t a1squ_x8 = gf16_mul_8(a1);
+ return (uint8_t)((a1 << 4) ^ a1squ_x8 ^ gf16_squ(a0));
+}
+
+uint8_t PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256_inv(uint8_t a) {
+ // 128+64+32+16+8+4+2 = 254
+ uint8_t a2 = gf256_squ(a);
+ uint8_t a4 = gf256_squ(a2);
+ uint8_t a8 = gf256_squ(a4);
+ uint8_t a4_2 = gf256_mul(a4, a2);
+ uint8_t a8_4_2 = gf256_mul(a4_2, a8);
+ uint8_t a64_ = gf256_squ(a8_4_2);
+ a64_ = gf256_squ(a64_);
+ a64_ = gf256_squ(a64_);
+ uint8_t a64_2 = gf256_mul(a64_, a8_4_2);
+ uint8_t a128_ = gf256_squ(a64_2);
+ return gf256_mul(a2, a128_);
+}
+
+static inline uint32_t gf4v_mul_3_u32(uint32_t a) {
+ uint32_t bit0 = a & 0x55555555;
+ uint32_t bit1 = a & 0xaaaaaaaa;
+ return (bit0 << 1) ^ bit0 ^ (bit1 >> 1);
+}
+static inline uint32_t gf16v_mul_8_u32(uint32_t a) {
+ uint32_t a1 = a & 0xcccccccc;
+ uint32_t a0 = (a << 2) & 0xcccccccc;
+ return gf4v_mul_2_u32(a0 ^ a1) | gf4v_mul_3_u32(a1 >> 2);
+}
+uint32_t PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b) {
+ uint32_t axb0 = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf16v_mul_u32(a, b);
+ uint32_t axb1 = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf16v_mul_u32(a, b >> 4);
+ uint32_t a0b1 = (axb1 << 4) & 0xf0f0f0f0;
+ uint32_t a1b1 = axb1 & 0xf0f0f0f0;
+ uint32_t a1b1_4 = a1b1 >> 4;
+
+ return axb0 ^ a0b1 ^ a1b1 ^ gf16v_mul_8_u32(a1b1_4);
+}
diff --git a/crypto_sign/rainbowVc-cyclic/clean/gf.h b/crypto_sign/rainbowVc-cyclic/clean/gf.h
new file mode 100644
index 00000000..8d9cc260
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/gf.h
@@ -0,0 +1,19 @@
+#ifndef _GF16_H_
+#define _GF16_H_
+
+#include "rainbow_config.h"
+#include
+
+/// @file gf16.h
+/// @brief Library for arithmetics in GF(16) and GF(256)
+///
+
+uint32_t PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf16v_mul_u32(uint32_t a, uint8_t b);
+
+
+uint8_t PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256_is_nonzero(uint8_t a);
+uint8_t PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256_inv(uint8_t a);
+uint32_t PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_mul_u32(uint32_t a, uint8_t b);
+
+
+#endif // _GF16_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/parallel_matrix_op.c b/crypto_sign/rainbowVc-cyclic/clean/parallel_matrix_op.c
new file mode 100644
index 00000000..22a68c6c
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/parallel_matrix_op.c
@@ -0,0 +1,183 @@
+/// @file parallel_matrix_op.c
+/// @brief the standard implementations for functions in parallel_matrix_op.h
+///
+/// the standard implementations for functions in parallel_matrix_op.h
+///
+
+#include "parallel_matrix_op.h"
+#include "blas.h"
+#include "blas_comm.h"
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim) {
+ return (dim + dim - i_row + 1) * i_row / 2 + j_col - i_row;
+}
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle or lower-triangle matrix.
+///
+/// @param[in] i_row - the i-th row in a triangle matrix.
+/// @param[in] j_col - the j-th column in a triangle matrix.
+/// @param[in] dim - the dimension of the triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+static inline unsigned int idx_of_2trimat(unsigned int i_row, unsigned int j_col, unsigned int n_var) {
+ if (i_row > j_col) {
+ return PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(j_col, i_row, n_var);
+ }
+ return PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(i_row, j_col, n_var);
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch) {
+ unsigned char *runningC = btriC;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < i; j++) {
+ unsigned int idx = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(j, i, Aheight);
+ gf256v_add(btriC + idx * size_batch, bA + size_batch * (i * Awidth + j), size_batch);
+ }
+ gf256v_add(runningC, bA + size_batch * (i * Awidth + i), size_batch * (Aheight - i));
+ runningC += size_batch * (Aheight - i);
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ unsigned int Aheight = Awidth;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (k < i) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[(k - i) * size_batch], PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ btriA += (Aheight - i) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i < k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(k, i, Aheight))], PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Aheight = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ if (i == k) {
+ continue;
+ }
+ gf256v_madd(bC, &btriA[size_batch * (idx_of_2trimat(i, k, Aheight))], PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_matTr_madd_gf256(unsigned char *bC, const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Atr_height = Awidth;
+ unsigned int Atr_width = Aheight;
+ for (unsigned int i = 0; i < Atr_height; i++) {
+ for (unsigned int j = 0; j < Atr_width; j++) {
+ gf256v_madd(bC, &bB[j * Bwidth * size_batch], PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(&A_to_tr[size_Acolvec * i], j), size_batch * Bwidth);
+ }
+ bC += size_batch * Bwidth;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ const unsigned char *bA = bA_to_tr;
+ unsigned int Aheight = Awidth_before_tr;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[size_batch * (i + k * Aheight)], PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch) {
+ unsigned int Awidth = Bheight;
+ for (unsigned int i = 0; i < Aheight; i++) {
+ for (unsigned int j = 0; j < Bwidth; j++) {
+ for (unsigned int k = 0; k < Bheight; k++) {
+ gf256v_madd(bC, &bA[k * size_batch], PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(&B[j * size_Bcolvec], k), size_batch);
+ }
+ bC += size_batch;
+ }
+ bA += (Awidth) * size_batch;
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch) {
+ unsigned char tmp[256];
+
+ unsigned char _x[256];
+ for (unsigned int i = 0; i < dim; i++) {
+ _x[i] = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(x, i);
+ }
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(y, size_batch);
+ for (unsigned int i = 0; i < dim; i++) {
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = i; j < dim; j++) {
+ gf256v_madd(tmp, trimat, _x[j], size_batch);
+ trimat += size_batch;
+ }
+ gf256v_madd(y, tmp, _x[i], size_batch);
+ }
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y, const unsigned char *mat,
+ const unsigned char *x, unsigned dim_x, unsigned size_batch) {
+ unsigned char tmp[128];
+
+ unsigned char _x[128];
+ for (unsigned int i = 0; i < dim_x; i++) {
+ _x[i] = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(x, i);
+ }
+ unsigned char _y[128];
+ for (unsigned int i = 0; i < dim_y; i++) {
+ _y[i] = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele(y, i);
+ }
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(z, size_batch);
+ for (unsigned int i = 0; i < dim_y; i++) {
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(tmp, size_batch);
+ for (unsigned int j = 0; j < dim_x; j++) {
+ gf256v_madd(tmp, mat, _x[j], size_batch);
+ mat += size_batch;
+ }
+ gf256v_madd(z, tmp, _y[i], size_batch);
+ }
+}
+
diff --git a/crypto_sign/rainbowVc-cyclic/clean/parallel_matrix_op.h b/crypto_sign/rainbowVc-cyclic/clean/parallel_matrix_op.h
new file mode 100644
index 00000000..2a3308de
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/parallel_matrix_op.h
@@ -0,0 +1,260 @@
+#ifndef _P_MATRIX_OP_H_
+#define _P_MATRIX_OP_H_
+/// @file parallel_matrix_op.h
+/// @brief Librarys for operations of batched matrixes.
+///
+///
+
+//////////////// Section: triangle matrix <-> rectangle matrix ///////////////////////////////////
+
+///
+/// @brief Calculate the corresponding index in an array for an upper-triangle(UT) matrix.
+///
+/// @param[in] i_row - the i-th row in an upper-triangle matrix.
+/// @param[in] j_col - the j-th column in an upper-triangle matrix.
+/// @param[in] dim - the dimension of the upper-triangle matrix, i.e., an dim x dim matrix.
+/// @return the corresponding index in an array storage.
+///
+unsigned int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(unsigned int i_row, unsigned int j_col, unsigned int dim);
+
+///
+/// @brief Upper trianglize a rectangle matrix to the corresponding upper-trangle matrix.
+///
+/// @param[out] btriC - the batched upper-trianglized matrix C.
+/// @param[in] bA - a batched retangle matrix A.
+/// @param[in] bwidth - the width of the batched matrix A, i.e., A is a Awidth x Awidth matrix.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_UpperTrianglize(unsigned char *btriC, const unsigned char *bA, unsigned int Awidth, unsigned int size_batch);
+
+//////////////////// Section: matrix multiplications ///////////////////////////////
+
+///
+/// @brief bC += btriA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. A will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_trimatTr_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += btriA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A, which will be transposed while multiplying.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_trimatTr_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_2trimat_madd_gf16(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += (btriA + btriA^Tr) *B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] btriA - a batched UT matrix A. The operand for multiplication is (btriA + btriA^Tr).
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_2trimat_madd_gf256(unsigned char *bC, const unsigned char *btriA,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_matTr_madd_gf16(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += A^Tr * bB , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] A_to_tr - a column-major matrix A. The operand for multiplication is A^Tr.
+/// @param[in] Aheight - the height of A.
+/// @param[in] size_Acolvec - the size of a column vector in A.
+/// @param[in] Awidth - the width of A.
+/// @param[in] bB - a batched matrix B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_matTr_madd_gf256(unsigned char *bC,
+ const unsigned char *A_to_tr, unsigned int Aheight, unsigned int size_Acolvec, unsigned int Awidth,
+ const unsigned char *bB, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_bmatTr_madd_gf16(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA^Tr * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA_to_tr - a batched matrix A. The operand for multiplication is (bA^Tr).
+/// @param[in] Awidth_befor_tr - the width of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_bmatTr_madd_gf256(unsigned char *bC, const unsigned char *bA_to_tr, unsigned int Awidth_before_tr,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(16)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_mat_madd_gf16(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+///
+/// @brief bC += bA * B , in GF(256)
+///
+/// @param[out] bC - the batched matrix C.
+/// @param[in] bA - a batched matrix A.
+/// @param[in] Aheigh - the height of A.
+/// @param[in] B - a column-major matrix B.
+/// @param[in] Bheight - the height of B.
+/// @param[in] size_Bcolvec - the size of the column vector in B.
+/// @param[in] Bwidth - the width of B.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_mat_madd_gf256(unsigned char *bC, const unsigned char *bA, unsigned int Aheight,
+ const unsigned char *B, unsigned int Bheight, unsigned int size_Bcolvec, unsigned int Bwidth, unsigned int size_batch);
+
+//////////////////// Section: "quadratric" matrix evaluation ///////////////////////////////
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(16)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_quad_trimat_eval_gf16(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief y = x^Tr * trimat * x , in GF(256)
+///
+/// @param[out] y - the returned batched element y.
+/// @param[in] trimat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim - the dimension of matrix trimat (and x).
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_quad_trimat_eval_gf256(unsigned char *y, const unsigned char *trimat, const unsigned char *x, unsigned int dim, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(16)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_quad_recmat_eval_gf16(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+///
+/// @brief z = y^Tr * mat * x , in GF(256)
+///
+/// @param[out] z - the returned batched element z.
+/// @param[in] y - an input vector y.
+/// @param[in] dim_y - the length of y.
+/// @param[in] mat - a batched matrix.
+/// @param[in] x - an input vector x.
+/// @param[in] dim_x - the length of x.
+/// @param[in] size_batch - number of the batched elements in the corresponding position of the matrix.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_quad_recmat_eval_gf256(unsigned char *z, const unsigned char *y, unsigned int dim_y,
+ const unsigned char *mat, const unsigned char *x, unsigned int dim_x, unsigned int size_batch);
+
+#endif // _P_MATRIX_OP_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/rainbow.c b/crypto_sign/rainbowVc-cyclic/clean/rainbow.c
new file mode 100644
index 00000000..ee75d39a
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/rainbow.c
@@ -0,0 +1,174 @@
+/// @file rainbow.c
+/// @brief The standard implementations for functions in rainbow.h
+///
+
+#include "rainbow.h"
+#include "blas.h"
+#include "rainbow_blas.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "utils_hash.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+#define MAX_ATTEMPT_FRMAT 128
+#define _MAX_O ((_O1 > _O2) ? _O1 : _O2)
+#define _MAX_O_BYTE ((_O1_BYTE > _O2_BYTE) ? _O1_BYTE : _O2_BYTE)
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *_digest) {
+ uint8_t mat_l1[_O1 * _O1_BYTE];
+ uint8_t mat_l2[_O2 * _O2_BYTE];
+ uint8_t mat_buffer[2 * _MAX_O * _MAX_O_BYTE];
+
+ // setup PRNG
+ prng_t prng_sign;
+ uint8_t prng_preseed[LEN_SKSEED + _HASH_LEN];
+ memcpy(prng_preseed, sk->sk_seed, LEN_SKSEED);
+ memcpy(prng_preseed + LEN_SKSEED, _digest, _HASH_LEN); // prng_preseed = sk_seed || digest
+ uint8_t prng_seed[_HASH_LEN];
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_hash_msg(prng_seed, _HASH_LEN, prng_preseed, _HASH_LEN + LEN_SKSEED);
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_set(&prng_sign, prng_seed, _HASH_LEN); // seed = H( sk_seed || digest )
+ for (unsigned int i = 0; i < LEN_SKSEED + _HASH_LEN; i++) {
+ prng_preseed[i] ^= prng_preseed[i]; // clean
+ }
+ for (unsigned int i = 0; i < _HASH_LEN; i++) {
+ prng_seed[i] ^= prng_seed[i]; // clean
+ }
+
+ // roll vinegars.
+ uint8_t vinegar[_V1_BYTE];
+ unsigned int n_attempt = 0;
+ unsigned int l1_succ = 0;
+ while (!l1_succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(&prng_sign, vinegar, _V1_BYTE); // generating vinegars
+ gfmat_prod(mat_l1, sk->l1_F2, _O1 * _O1_BYTE, _V1, vinegar); // generating the linear equations for layer 1
+ l1_succ = gfmat_inv(mat_l1, mat_l1, _O1, mat_buffer); // check if the linear equation solvable
+ n_attempt++;
+ }
+
+ // Given the vinegars, pre-compute variables needed for layer 2
+ uint8_t r_l1_F1[_O1_BYTE] = {0};
+ uint8_t r_l2_F1[_O2_BYTE] = {0};
+ batch_quad_trimat_eval(r_l1_F1, sk->l1_F1, vinegar, _V1, _O1_BYTE);
+ batch_quad_trimat_eval(r_l2_F1, sk->l2_F1, vinegar, _V1, _O2_BYTE);
+ uint8_t mat_l2_F3[_O2 * _O2_BYTE];
+ uint8_t mat_l2_F2[_O1 * _O2_BYTE];
+ gfmat_prod(mat_l2_F3, sk->l2_F3, _O2 * _O2_BYTE, _V1, vinegar);
+ gfmat_prod(mat_l2_F2, sk->l2_F2, _O1 * _O2_BYTE, _V1, vinegar);
+
+ // Some local variables.
+ uint8_t _z[_PUB_M_BYTE];
+ uint8_t y[_PUB_M_BYTE];
+ uint8_t *x_v1 = vinegar;
+ uint8_t x_o1[_O1_BYTE];
+ uint8_t x_o2[_O1_BYTE];
+
+ uint8_t digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, _digest, _HASH_LEN);
+ uint8_t *salt = digest_salt + _HASH_LEN;
+
+ uint8_t temp_o[_MAX_O_BYTE + 32] = {0};
+ unsigned int succ = 0;
+ while (!succ) {
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ break;
+ }
+ // The computation: H(digest||salt) --> z --S--> y --C-map--> x --T--> w
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(&prng_sign, salt, _SALT_BYTE); // roll the salt
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_hash_msg(_z, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H(digest||salt)
+
+ // y = S^-1 * z
+ memcpy(y, _z, _PUB_M_BYTE); // identity part of S
+ gfmat_prod(temp_o, sk->s1, _O1_BYTE, _O2, _z + _O1_BYTE);
+ gf256v_add(y, temp_o, _O1_BYTE);
+
+ // Central Map:
+ // layer 1: calculate x_o1
+ memcpy(temp_o, r_l1_F1, _O1_BYTE);
+ gf256v_add(temp_o, y, _O1_BYTE);
+ gfmat_prod(x_o1, mat_l1, _O1_BYTE, _O1, temp_o);
+
+ // layer 2: calculate x_o2
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_set_zero(temp_o, _O2_BYTE);
+ gfmat_prod(temp_o, mat_l2_F2, _O2_BYTE, _O1, x_o1); // F2
+ batch_quad_trimat_eval(mat_l2, sk->l2_F5, x_o1, _O1, _O2_BYTE); // F5
+ gf256v_add(temp_o, mat_l2, _O2_BYTE);
+ gf256v_add(temp_o, r_l2_F1, _O2_BYTE); // F1
+ gf256v_add(temp_o, y + _O1_BYTE, _O2_BYTE);
+
+ // generate the linear equations of the 2nd layer
+ gfmat_prod(mat_l2, sk->l2_F6, _O2 * _O2_BYTE, _O1, x_o1); // F6
+ gf256v_add(mat_l2, mat_l2_F3, _O2 * _O2_BYTE); // F3
+ succ = gfmat_inv(mat_l2, mat_l2, _O2, mat_buffer);
+ gfmat_prod(x_o2, mat_l2, _O2_BYTE, _O2, temp_o); // solve l2 eqs
+
+ n_attempt++;
+ };
+ // w = T^-1 * y
+ uint8_t w[_PUB_N_BYTE];
+ // identity part of T.
+ memcpy(w, x_v1, _V1_BYTE);
+ memcpy(w + _V1_BYTE, x_o1, _O1_BYTE);
+ memcpy(w + _V2_BYTE, x_o2, _O2_BYTE);
+ // Computing the t1 part.
+ gfmat_prod(y, sk->t1, _V1_BYTE, _O1, x_o1);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t4 part.
+ gfmat_prod(y, sk->t4, _V1_BYTE, _O2, x_o2);
+ gf256v_add(w, y, _V1_BYTE);
+ // Computing the t3 part.
+ gfmat_prod(y, sk->t3, _O1_BYTE, _O2, x_o2);
+ gf256v_add(w + _V1_BYTE, y, _O1_BYTE);
+
+ memset(signature, 0, _SIGNATURE_BYTE); // set the output 0
+ // clean
+ memset(&prng_sign, 0, sizeof(prng_t));
+ memset(vinegar, 0, _V1_BYTE);
+ memset(r_l1_F1, 0, _O1_BYTE);
+ memset(r_l2_F1, 0, _O2_BYTE);
+ memset(_z, 0, _PUB_M_BYTE);
+ memset(y, 0, _PUB_M_BYTE);
+ memset(x_o1, 0, _O1_BYTE);
+ memset(x_o2, 0, _O2_BYTE);
+ memset(temp_o, 0, sizeof(temp_o));
+
+ // return: copy w and salt to the signature.
+ if (MAX_ATTEMPT_FRMAT <= n_attempt) {
+ return -1;
+ }
+ gf256v_add(signature, w, _PUB_N_BYTE);
+ gf256v_add(signature + _PUB_N_BYTE, salt, _SALT_BYTE);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk) {
+ unsigned char digest_ck[_PUB_M_BYTE];
+ // public_map( digest_ck , pk , signature ); Evaluating the quadratic public polynomials.
+ batch_quad_trimat_eval(digest_ck, pk->pk, signature, _PUB_N, _PUB_M_BYTE);
+
+ unsigned char correct[_PUB_M_BYTE];
+ unsigned char digest_salt[_HASH_LEN + _SALT_BYTE];
+ memcpy(digest_salt, digest, _HASH_LEN);
+ memcpy(digest_salt + _HASH_LEN, signature + _PUB_N_BYTE, _SALT_BYTE);
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_hash_msg(correct, _PUB_M_BYTE, digest_salt, _HASH_LEN + _SALT_BYTE); // H( digest || salt )
+
+ // check consistancy.
+ unsigned char cc = 0;
+ for (unsigned int i = 0; i < _PUB_M_BYTE; i++) {
+ cc |= (digest_ck[i] ^ correct[i]);
+ }
+ return (0 == cc) ? 0 : -1;
+}
+
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *_pk) {
+ unsigned char pk[sizeof(pk_t) + 32];
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_cpk_to_pk((pk_t *)pk, _pk); // generating classic public key.
+ return PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_verify(digest, signature, (pk_t *)pk);
+}
diff --git a/crypto_sign/rainbowVc-cyclic/clean/rainbow.h b/crypto_sign/rainbowVc-cyclic/clean/rainbow.h
new file mode 100644
index 00000000..25925507
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/rainbow.h
@@ -0,0 +1,42 @@
+#ifndef _RAINBOW_H_
+#define _RAINBOW_H_
+/// @file rainbow.h
+/// @brief APIs for rainbow.
+///
+
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+
+#include
+
+///
+/// @brief Signing function for classical secret key.
+///
+/// @param[out] signature - the signature.
+/// @param[in] sk - the secret key.
+/// @param[in] digest - the digest.
+///
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_sign(uint8_t *signature, const sk_t *sk, const uint8_t *digest);
+
+///
+/// @brief Verifying function.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_verify(const uint8_t *digest, const uint8_t *signature, const pk_t *pk);
+
+
+///
+/// @brief Verifying function for cyclic public keys.
+///
+/// @param[in] digest - the digest.
+/// @param[in] signature - the signature.
+/// @param[in] pk - the public key of cyclic rainbow.
+/// @return 0 for successful verified. -1 for failed verification.
+///
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_verify_cyclic(const uint8_t *digest, const uint8_t *signature, const cpk_t *pk);
+
+#endif // _RAINBOW_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/rainbow_blas.h b/crypto_sign/rainbowVc-cyclic/clean/rainbow_blas.h
new file mode 100644
index 00000000..a3c8c885
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/rainbow_blas.h
@@ -0,0 +1,31 @@
+#ifndef _RAINBOW_BLAS_H_
+#define _RAINBOW_BLAS_H_
+/// @file rainbow_blas.h
+/// @brief Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+///
+/// Defining the functions used in rainbow.c acconding to the definitions in rainbow_config.h
+
+#include "blas.h"
+#include "parallel_matrix_op.h"
+#include "rainbow_config.h"
+
+
+#define gfv_get_ele PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_get_ele
+#define gfv_mul_scalar PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_mul_scalar
+#define gfv_madd PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256v_madd
+
+#define gfmat_prod PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_prod
+#define gfmat_inv PQCLEAN_RAINBOWVCCYCLIC_CLEAN_gf256mat_inv
+
+#define batch_trimat_madd PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_trimat_madd_gf256
+#define batch_trimatTr_madd PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_trimatTr_madd_gf256
+#define batch_2trimat_madd PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_2trimat_madd_gf256
+#define batch_matTr_madd PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_matTr_madd_gf256
+#define batch_bmatTr_madd PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_bmatTr_madd_gf256
+#define batch_mat_madd PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_mat_madd_gf256
+
+#define batch_quad_trimat_eval PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_quad_trimat_eval_gf256
+#define batch_quad_recmat_eval PQCLEAN_RAINBOWVCCYCLIC_CLEAN_batch_quad_recmat_eval_gf256
+
+
+#endif // _RAINBOW_BLAS_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/rainbow_config.h b/crypto_sign/rainbowVc-cyclic/clean/rainbow_config.h
new file mode 100644
index 00000000..979aa244
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/rainbow_config.h
@@ -0,0 +1,46 @@
+#ifndef _H_RAINBOW_CONFIG_H_
+#define _H_RAINBOW_CONFIG_H_
+
+/// @file rainbow_config.h
+/// @brief Defining the parameters of the Rainbow and the corresponding constants.
+///
+
+#define _GFSIZE 256
+#define _V1 92
+#define _O1 48
+#define _O2 48
+#define _HASH_LEN 64
+
+
+#define _V2 ((_V1) + (_O1))
+
+/// size of N, in # of gf elements.
+#define _PUB_N (_V1 + _O1 + _O2)
+
+/// size of M, in # gf elements.
+#define _PUB_M (_O1 + _O2)
+
+/// size of variables, in # bytes.
+
+// GF256
+#define _V1_BYTE (_V1)
+#define _V2_BYTE (_V2)
+#define _O1_BYTE (_O1)
+#define _O2_BYTE (_O2)
+#define _PUB_N_BYTE (_PUB_N)
+#define _PUB_M_BYTE (_PUB_M)
+
+
+/// length of seed for public key, in # bytes
+#define LEN_PKSEED 32
+
+/// length of seed for secret key, in # bytes
+#define LEN_SKSEED 32
+
+/// length of salt for a signature, in # bytes
+#define _SALT_BYTE 16
+
+/// length of a signature
+#define _SIGNATURE_BYTE (_PUB_N_BYTE + _SALT_BYTE)
+
+#endif // _H_RAINBOW_CONFIG_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair.c b/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair.c
new file mode 100644
index 00000000..3480d2f0
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair.c
@@ -0,0 +1,157 @@
+/// @file rainbow_keypair.c
+/// @brief implementations of functions in rainbow_keypair.h
+///
+
+#include "rainbow_keypair.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair_computation.h"
+#include "utils_prng.h"
+#include
+#include
+#include
+
+static void generate_S_T(unsigned char *s_and_t, prng_t *prng0) {
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // S1
+ s_and_t += _O1_BYTE * _O2;
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O1); // T1
+ s_and_t += _V1_BYTE * _O1;
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, s_and_t, _V1_BYTE * _O2); // T2
+ s_and_t += _V1_BYTE * _O2;
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, s_and_t, _O1_BYTE * _O2); // T3
+}
+
+static unsigned int generate_l1_F12(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * N_TRIANGLE_TERMS(_V1)); // l1_F1
+ sk += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O1_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, sk, _O1_BYTE * _V1 * _O1); // l1_F2
+ n_byte_generated += _O1_BYTE * _V1 * _O1;
+ return n_byte_generated;
+}
+
+static unsigned int generate_l2_F12356(unsigned char *sk, prng_t *prng0) {
+ unsigned int n_byte_generated = 0;
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // l2_F1
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_V1);
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O1); // l2_F2
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _V1 * _O2); // l2_F3
+ sk += _O2_BYTE * _V1 * _O1;
+ n_byte_generated += _O2_BYTE * _V1 * _O1;
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // l2_F5
+ sk += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+ n_byte_generated += _O2_BYTE * N_TRIANGLE_TERMS(_O1);
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng0, sk, _O2_BYTE * _O1 * _O2); // l2_F6
+ n_byte_generated += _O2_BYTE * _O1 * _O2;
+
+ return n_byte_generated;
+}
+
+static void generate_B1_B2(unsigned char *sk, prng_t *prng0) {
+ sk += generate_l1_F12(sk, prng0);
+ generate_l2_F12356(sk, prng0);
+}
+
+static void calculate_t4(unsigned char *t2_to_t4, const unsigned char *t1, const unsigned char *t3) {
+ // t4 = T_sk.t1 * T_sk.t3 - T_sk.t2
+ unsigned char temp[_V1_BYTE + 32];
+ unsigned char *t4 = t2_to_t4;
+ for (unsigned int i = 0; i < _O2; i++) { /// t3 width
+ gfmat_prod(temp, t1, _V1_BYTE, _O1, t3);
+ gf256v_add(t4, temp, _V1_BYTE);
+ t4 += _V1_BYTE;
+ t3 += _O1_BYTE;
+ }
+}
+
+static void obsfucate_l1_polys(unsigned char *l1_polys, const unsigned char *l2_polys, unsigned int n_terms, const unsigned char *s1) {
+ unsigned char temp[_O1_BYTE + 32];
+ while (n_terms--) {
+ gfmat_prod(temp, s1, _O1_BYTE, _O2, l2_polys);
+ gf256v_add(l1_polys, temp, _O1_BYTE);
+ l1_polys += _O1_BYTE;
+ l2_polys += _O2_BYTE;
+ }
+}
+
+/////////////////// Classic //////////////////////////////////
+
+
+///////////////////// Cyclic //////////////////////////////////
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed) {
+ memcpy(pk->pk_seed, pk_seed, LEN_PKSEED);
+ memcpy(sk->sk_seed, sk_seed, LEN_SKSEED);
+
+ // prng for sk
+ prng_t prng;
+ prng_t *prng0 = &prng;
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_set(prng0, sk_seed, LEN_SKSEED);
+ generate_S_T(sk->s1, prng0); // S,T: only a part of sk
+
+ unsigned char t2[sizeof(sk->t4)];
+ memcpy(t2, sk->t4, _V1_BYTE * _O2); // temporarily store t2
+ calculate_t4(sk->t4, sk->t1, sk->t3); // t2 <- t4
+
+ // prng for pk
+ sk_t inst_Qs;
+ sk_t *Qs = &inst_Qs;
+ prng_t *prng1 = &prng;
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_set(prng1, pk_seed, LEN_PKSEED);
+ generate_B1_B2(Qs->l1_F1, prng1); // generating l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+ obsfucate_l1_polys(Qs->l1_F1, Qs->l2_F1, N_TRIANGLE_TERMS(_V1), sk->s1);
+ obsfucate_l1_polys(Qs->l1_F2, Qs->l2_F2, _V1 * _O1, sk->s1);
+ // so far, the Qs contains l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6.
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_calculate_F_from_Q(sk, Qs, sk); // calcuate the rest parts of secret key from Qs and S,T
+
+ unsigned char t4[sizeof(sk->t4)];
+ memcpy(t4, sk->t4, _V1_BYTE * _O2); // temporarily store t4
+ memcpy(sk->t4, t2, _V1_BYTE * _O2); // restore t2
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_calculate_Q_from_F_cyclic(pk, sk, sk); // calculate the rest parts of public key: l1_Q3, l1_Q5, l1_Q6, l1_Q9, l2_Q9
+ memcpy(sk->t4, t4, _V1_BYTE * _O2); // restore t4
+
+ obsfucate_l1_polys(pk->l1_Q3, Qs->l2_F3, _V1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q5, Qs->l2_F5, N_TRIANGLE_TERMS(_O1), sk->s1);
+ obsfucate_l1_polys(pk->l1_Q6, Qs->l2_F6, _O1 * _O2, sk->s1);
+ obsfucate_l1_polys(pk->l1_Q9, pk->l2_Q9, N_TRIANGLE_TERMS(_O2), sk->s1);
+
+ // clean
+ memset(&prng, 0, sizeof(prng_t));
+}
+
+
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_cpk_to_pk(pk_t *rpk, const cpk_t *cpk) {
+ // procedure: cpk_t --> extcpk_t --> pk_t
+
+ // convert from cpk_t to extcpk_t
+ ext_cpk_t pk;
+
+ // setup prng
+ prng_t prng0;
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_set(&prng0, cpk->pk_seed, LEN_SKSEED);
+
+ // generating parts of key with prng
+ generate_l1_F12(pk.l1_Q1, &prng0);
+ // copying parts of key from input. l1_Q3, l1_Q5, l1_Q6, l1_Q9
+ memcpy(pk.l1_Q3, cpk->l1_Q3, _O1_BYTE * (_V1 * _O2 + N_TRIANGLE_TERMS(_O1) + _O1 * _O2 + N_TRIANGLE_TERMS(_O2)));
+
+ // generating parts of key with prng
+ generate_l2_F12356(pk.l2_Q1, &prng0);
+ // copying parts of key from input: l2_Q9
+ memcpy(pk.l2_Q9, cpk->l2_Q9, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ // convert from extcpk_t to pk_t
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_extcpk_to_pk(rpk, &pk);
+}
diff --git a/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair.h b/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair.h
new file mode 100644
index 00000000..67ac998e
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair.h
@@ -0,0 +1,94 @@
+#ifndef _RAINBOW_KEYPAIR_H_
+#define _RAINBOW_KEYPAIR_H_
+/// @file rainbow_keypair.h
+/// @brief Formats of key pairs and functions for generating key pairs.
+/// Formats of key pairs and functions for generating key pairs.
+///
+
+#include "rainbow_config.h"
+
+#define N_TRIANGLE_TERMS(n_var) ((n_var) * ((n_var) + 1) / 2)
+
+/// @brief public key for classic rainbow
+///
+/// public key for classic rainbow
+///
+typedef struct rainbow_publickey {
+ unsigned char pk[(_PUB_M_BYTE)*N_TRIANGLE_TERMS(_PUB_N)];
+} pk_t;
+
+/// @brief secret key for classic rainbow
+///
+/// secret key for classic rainbow
+///
+typedef struct rainbow_secretkey {
+ ///
+ /// seed for generating secret key.
+ /// Generating S, T, and F for classic rainbow.
+ /// Generating S and T only for cyclic rainbow.
+ unsigned char sk_seed[LEN_SKSEED];
+
+ unsigned char s1[_O1_BYTE * _O2]; ///< part of S map
+ unsigned char t1[_V1_BYTE * _O1]; ///< part of T map
+ unsigned char t4[_V1_BYTE * _O2]; ///< part of T map
+ unsigned char t3[_O1_BYTE * _O2]; ///< part of T map
+
+ unsigned char l1_F1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer1
+ unsigned char l1_F2[_O1_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer1
+
+ unsigned char l2_F1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)]; ///< part of C-map, F1, Layer2
+ unsigned char l2_F2[_O2_BYTE * _V1 * _O1]; ///< part of C-map, F2, Layer2
+
+ unsigned char l2_F3[_O2_BYTE * _V1 * _O2]; ///< part of C-map, F3, Layer2
+ unsigned char l2_F5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< part of C-map, F5, Layer2
+ unsigned char l2_F6[_O2_BYTE * _O1 * _O2]; ///< part of C-map, F6, Layer2
+} sk_t;
+
+/// @brief public key for cyclic rainbow
+///
+/// public key for cyclic rainbow
+///
+typedef struct rainbow_publickey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating l1_Q1,l1_Q2,l2_Q1,l2_Q2,l2_Q3,l2_Q5,l2_Q6
+
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2]; ///< Q3, layer1
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)]; ///< Q5, layer1
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2]; ///< Q6, layer1
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer1
+
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)]; ///< Q9, layer2
+} cpk_t;
+
+/// @brief compressed secret key for cyclic rainbow
+///
+/// compressed secret key for cyclic rainbow
+///
+typedef struct rainbow_secretkey_cyclic {
+ unsigned char pk_seed[LEN_PKSEED]; ///< seed for generating a part of public key.
+ unsigned char sk_seed[LEN_SKSEED]; ///< seed for generating a part of secret key.
+} csk_t;
+
+
+///
+/// @brief Generate key pairs for cyclic rainbow.
+///
+/// @param[out] pk - the public key.
+/// @param[out] sk - the secret key.
+/// @param[in] pk_seed - seed for generating parts of public key.
+/// @param[in] sk_seed - seed for generating secret key.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_generate_keypair_cyclic(cpk_t *pk, sk_t *sk, const unsigned char *pk_seed, const unsigned char *sk_seed);
+
+
+
+////////////////////////////////////
+
+///
+/// @brief converting formats of public keys : from cyclic version to classic key
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the cyclic public key.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_cpk_to_pk(pk_t *pk, const cpk_t *cpk);
+
+#endif // _RAINBOW_KEYPAIR_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair_computation.c b/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair_computation.c
new file mode 100644
index 00000000..db23a907
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair_computation.c
@@ -0,0 +1,213 @@
+/// @file rainbow_keypair_computation.c
+/// @brief Implementations for functions in rainbow_keypair_computation.h
+///
+
+#include "rainbow_keypair_computation.h"
+#include "blas.h"
+#include "blas_comm.h"
+#include "rainbow_blas.h"
+#include "rainbow_keypair.h"
+#include
+#include
+#include
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk) {
+ const unsigned char *idx_l1 = cpk->l1_Q1;
+ const unsigned char *idx_l2 = cpk->l2_Q1;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = i; j < _V1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q2;
+ idx_l2 = cpk->l2_Q2;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q3;
+ idx_l2 = cpk->l2_Q3;
+ for (unsigned int i = 0; i < _V1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q5;
+ idx_l2 = cpk->l2_Q5;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = i; j < _V1 + _O1; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q6;
+ idx_l2 = cpk->l2_Q6;
+ for (unsigned int i = _V1; i < _V1 + _O1; i++) {
+ for (unsigned int j = _V1 + _O1; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+ idx_l1 = cpk->l1_Q9;
+ idx_l2 = cpk->l2_Q9;
+ for (unsigned int i = _V1 + _O1; i < _PUB_N; i++) {
+ for (unsigned int j = i; j < _PUB_N; j++) {
+ unsigned int pub_idx = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_idx_of_trimat(i, j, _PUB_N);
+ memcpy(&pk->pk[_PUB_M_BYTE * pub_idx], idx_l1, _O1_BYTE);
+ memcpy((&pk->pk[_PUB_M_BYTE * pub_idx]) + _O1_BYTE, idx_l2, _O2_BYTE);
+ idx_l1 += _O1_BYTE;
+ idx_l2 += _O2_BYTE;
+ }
+ }
+}
+
+static void calculate_F_from_Q_ref(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ // Layer 1
+ // F_sk.l1_F1s[i] = Q_pk.l1_F1s[i]
+ memcpy(Fs->l1_F1, Qs->l1_F1, _O1_BYTE * N_TRIANGLE_TERMS(_V1));
+
+ // F_sk.l1_F2s[i] = ( Q_pk.l1_F1s[i] + Q_pk.l1_F1s[i].transpose() ) * T_sk.t1 + Q_pk.l1_F2s[i]
+ memcpy(Fs->l1_F2, Qs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_2trimat_madd(Fs->l1_F2, Qs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE);
+
+ /*
+ Layer 2
+ computations:
+
+ F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ Q1_T1 = Q_pk.l2_F1s[i]*T_sk.t1
+ F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+
+ Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ #Q1_Q1T_T4 = Q1_Q1T * t4
+ Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ + Q_pk.l2_F2s[i].transpose() * t4
+ + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+
+ */
+ memcpy(Fs->l2_F1, Qs->l2_F1, _O2_BYTE * N_TRIANGLE_TERMS(_V1)); // F_sk.l2_F1s[i] = Q_pk.l2_F1s[i]
+
+ // F_sk.l2_F2s[i] = Q1_T1 + Q_pk.l2_F2s[i] + Q_pk.l2_F1s[i].transpose() * T_sk.t1
+ // F_sk.l2_F5s[i] = UT( t1_tr* ( Q1_T1 + Q_pk.l2_F2s[i] ) ) + Q_pk.l2_F5s[i]
+ memcpy(Fs->l2_F2, Qs->l2_F2, _O2_BYTE * _V1 * _O1);
+ batch_trimat_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // Q1_T1+ Q2
+
+ unsigned char tempQ[_O1 * _O1 * _O2_BYTE + 32];
+ memset(tempQ, 0, _O1 * _O1 * _O2_BYTE);
+ batch_matTr_madd(tempQ, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F2, _O1, _O2_BYTE); // t1_tr*(Q1_T1+Q2)
+ memcpy(Fs->l2_F5, Qs->l2_F5, _O2_BYTE * N_TRIANGLE_TERMS(_O1)); // F5
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_UpperTrianglize(Fs->l2_F5, tempQ, _O1, _O2_BYTE); // UT( ... )
+
+ batch_trimatTr_madd(Fs->l2_F2, Qs->l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O2_BYTE); // F2 = Q1_T1 + Q2 + Q1^tr*t1
+
+ // Q1_Q1T_T4 = (Q_pk.l2_F1s[i] + Q_pk.l2_F1s[i].transpose()) * t4
+ // Q2_T3 = Q_pk.l2_F2s[i]*T_sk.t3
+ // F_sk.l2_F3s[i] = Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i]
+ memcpy(Fs->l2_F3, Qs->l2_F3, _V1 * _O2 * _O2_BYTE);
+ batch_2trimat_madd(Fs->l2_F3, Qs->l2_F1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE); // Q1_Q1T_T4
+ batch_mat_madd(Fs->l2_F3, Qs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // Q2_T3
+
+ // F_sk.l2_F6s[i] = t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ // + Q_pk.l2_F2s[i].transpose() * t4
+ // + (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3 + Q_pk.l2_F6s[i]
+ memcpy(Fs->l2_F6, Qs->l2_F6, _O1 * _O2 * _O2_BYTE);
+ batch_matTr_madd(Fs->l2_F6, Ts->t1, _V1, _V1_BYTE, _O1, Fs->l2_F3, _O2, _O2_BYTE); // t1_tr * ( Q1_Q1T_T4 + Q2_T3 + Q_pk.l2_F3s[i] )
+ batch_2trimat_madd(Fs->l2_F6, Qs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // (Q_pk.l2_F5s[i] + Q_pk.l2_F5s[i].transpose())*T_sk.t3
+ batch_bmatTr_madd(Fs->l2_F6, Qs->l2_F2, _O1, Ts->t4, _V1, _V1_BYTE, _O2, _O2_BYTE);
+}
+
+static void calculate_Q_from_F_cyclic_ref(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ // Layer 1: Computing Q5, Q3, Q6, Q9
+
+ // Q_pk.l1_F5s[i] = UT( T1tr* (F1 * T1 + F2) )
+ const unsigned char *t2 = Ts->t4;
+ sk_t tempQ;
+ memcpy(tempQ.l1_F2, Fs->l1_F2, _O1_BYTE * _V1 * _O1);
+ batch_trimat_madd(tempQ.l1_F2, Fs->l1_F1, Ts->t1, _V1, _V1_BYTE, _O1, _O1_BYTE); // F1*T1 + F2
+ memset(tempQ.l2_F1, 0, sizeof(tempQ.l2_F1));
+ memset(tempQ.l2_F2, 0, sizeof(tempQ.l2_F2));
+ batch_matTr_madd(tempQ.l2_F1, Ts->t1, _V1, _V1_BYTE, _O1, tempQ.l1_F2, _O1, _O1_BYTE); // T1tr*(F1*T1 + F2)
+ memset(Qs->l1_Q5, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O1));
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_UpperTrianglize(Qs->l1_Q5, tempQ.l2_F1, _O1, _O1_BYTE); // UT( ... ) // Q5
+
+ /*
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ F1_F1T_T2 + F2_T3 = F1_T2 + F2_T3 + F1tr * t2
+ Q_pk.l1_F3s[i] = F1_F1T_T2 + F2_T3
+ Q_pk.l1_F6s[i] = T1tr* ( F1_F1T_T2 + F2_T3 ) + F2tr * t2
+ Q_pk.l1_F9s[i] = UT( T2tr* ( F1_T2 + F2_T3 ) )
+ */
+ memset(Qs->l1_Q3, 0, _O1_BYTE * _V1 * _O2);
+ memset(Qs->l1_Q6, 0, _O1_BYTE * _O1 * _O2);
+ memset(Qs->l1_Q9, 0, _O1_BYTE * N_TRIANGLE_TERMS(_O2));
+
+ batch_trimat_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1*T2
+ batch_mat_madd(Qs->l1_Q3, Fs->l1_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O1_BYTE); // F1_T2 + F2_T3
+
+ memset(tempQ.l1_F2, 0, _O1_BYTE * _V1 * _O2); // should be F3. assuming: _O1 >= _O2
+ batch_matTr_madd(tempQ.l1_F2, t2, _V1, _V1_BYTE, _O2, Qs->l1_Q3, _O2, _O1_BYTE); // T2tr * ( F1_T2 + F2_T3 )
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_UpperTrianglize(Qs->l1_Q9, tempQ.l1_F2, _O2, _O1_BYTE); // Q9
+
+ batch_trimatTr_madd(Qs->l1_Q3, Fs->l1_F1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F1_F1T_T2 + F2_T3 // Q3
+
+ batch_bmatTr_madd(Qs->l1_Q6, Fs->l1_F2, _O1, t2, _V1, _V1_BYTE, _O2, _O1_BYTE); // F2tr*T2
+ batch_matTr_madd(Qs->l1_Q6, Ts->t1, _V1, _V1_BYTE, _O1, Qs->l1_Q3, _O2, _O1_BYTE); // Q6
+ /*
+ Layer 2
+ Computing Q9:
+
+ F1_T2 = F1 * t2
+ F2_T3 = F2 * t3
+ Q9 = UT( T2tr*( F1*T2 + F2*T3 + F3 ) + T3tr*( F5*T3 + F6 ) )
+ */
+ sk_t tempQ2;
+ memcpy(tempQ2.l2_F3, Fs->l2_F3, _O2_BYTE * _V1 * _O2); /// F3 actually.
+ batch_trimat_madd(tempQ2.l2_F3, Fs->l2_F1, t2, _V1, _V1_BYTE, _O2, _O2_BYTE); // F1*T2 + F3
+ batch_mat_madd(tempQ2.l2_F3, Fs->l2_F2, _V1, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F1_T2 + F2_T3 + F3
+
+ memset(tempQ.l2_F3, 0, _O2_BYTE * _V1 * _O2);
+ batch_matTr_madd(tempQ.l2_F3, t2, _V1, _V1_BYTE, _O2, tempQ2.l2_F3, _O2, _O2_BYTE); // T2tr * ( ..... )
+
+ memcpy(tempQ.l2_F6, Fs->l2_F6, _O2_BYTE * _O1 * _O2);
+ batch_trimat_madd(tempQ.l2_F6, Fs->l2_F5, Ts->t3, _O1, _O1_BYTE, _O2, _O2_BYTE); // F5*T3 + F6
+
+ batch_matTr_madd(tempQ.l2_F3, Ts->t3, _O1, _O1_BYTE, _O2, tempQ.l2_F6, _O2, _O2_BYTE); // T2tr*( ..... ) + T3tr*( ..... )
+ memset(Qs->l2_Q9, 0, _O2_BYTE * N_TRIANGLE_TERMS(_O2));
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_UpperTrianglize(Qs->l2_Q9, tempQ.l2_F3, _O2, _O2_BYTE); // Q9
+}
+
+// Choosing implementations depends on the macros: _BLAS_SSE_ and _BLAS_AVX2_
+#define calculate_F_from_Q_impl calculate_F_from_Q_ref
+#define calculate_Q_from_F_cyclic_impl calculate_Q_from_F_cyclic_ref
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts) {
+ calculate_F_from_Q_impl(Fs, Qs, Ts);
+}
+
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts) {
+ calculate_Q_from_F_cyclic_impl(Qs, Fs, Ts);
+}
diff --git a/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair_computation.h b/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair_computation.h
new file mode 100644
index 00000000..053e4700
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/rainbow_keypair_computation.h
@@ -0,0 +1,71 @@
+#ifndef _RAINBOW_KEYPAIR_COMP_H_
+#define _RAINBOW_KEYPAIR_COMP_H_
+/// @file rainbow_keypair_computation.h
+/// @brief Functions for calculating pk/sk while generating keys.
+///
+/// Defining an internal structure of public key.
+/// Functions for calculating pk/sk for key generation.
+///
+
+#include "rainbow_keypair.h"
+
+/// @brief The (internal use) public key for rainbow
+///
+/// The (internal use) public key for rainbow. The public
+/// polynomials are divided into l1_Q1, l1_Q2, ... l1_Q9,
+/// l2_Q1, .... , l2_Q9.
+///
+typedef struct rainbow_extend_publickey {
+ unsigned char l1_Q1[_O1_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l1_Q2[_O1_BYTE * _V1 * _O1];
+ unsigned char l1_Q3[_O1_BYTE * _V1 * _O2];
+ unsigned char l1_Q5[_O1_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l1_Q6[_O1_BYTE * _O1 * _O2];
+ unsigned char l1_Q9[_O1_BYTE * N_TRIANGLE_TERMS(_O2)];
+
+ unsigned char l2_Q1[_O2_BYTE * N_TRIANGLE_TERMS(_V1)];
+ unsigned char l2_Q2[_O2_BYTE * _V1 * _O1];
+ unsigned char l2_Q3[_O2_BYTE * _V1 * _O2];
+ unsigned char l2_Q5[_O2_BYTE * N_TRIANGLE_TERMS(_O1)];
+ unsigned char l2_Q6[_O2_BYTE * _O1 * _O2];
+ unsigned char l2_Q9[_O2_BYTE * N_TRIANGLE_TERMS(_O2)];
+} ext_cpk_t;
+
+///
+/// @brief converting formats of public keys : from ext_cpk_t version to pk_t
+///
+/// @param[out] pk - the classic public key.
+/// @param[in] cpk - the internel public key.
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_extcpk_to_pk(pk_t *pk, const ext_cpk_t *cpk);
+/////////////////////////////////////////////////
+
+///
+/// @brief Computing public key from secret key
+///
+/// @param[out] Qs - the public key
+/// @param[in] Fs - parts of the secret key: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the secret key: T1, T4, T3
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_calculate_Q_from_F(ext_cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+
+///
+/// @brief Computing parts of the sk from parts of pk and sk
+///
+/// @param[out] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Qs - parts of the pk: l1_Q1, l1_Q2, l2_Q1, l2_Q2, l2_Q3, l2_Q5, l2_Q6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_calculate_F_from_Q(sk_t *Fs, const sk_t *Qs, sk_t *Ts);
+
+///
+/// @brief Computing parts of the pk from the secret key
+///
+/// @param[out] Qs - parts of the pk: l1_Q3, l1_Q5, l2_Q6, l1_Q9, l2_Q9
+/// @param[in] Fs - parts of the sk: l1_F1, l1_F2, l2_F1, l2_F2, l2_F3, l2_F5, l2_F6
+/// @param[in] Ts - parts of the sk: T1, T4, T3
+///
+void PQCLEAN_RAINBOWVCCYCLIC_CLEAN_calculate_Q_from_F_cyclic(cpk_t *Qs, const sk_t *Fs, const sk_t *Ts);
+
+#endif // _RAINBOW_KEYPAIR_COMP_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/sign.c b/crypto_sign/rainbowVc-cyclic/clean/sign.c
new file mode 100644
index 00000000..9b9924d7
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/sign.c
@@ -0,0 +1,76 @@
+/// @file sign.c
+/// @brief the implementations for functions in api.h
+///
+///
+
+#include "api.h"
+#include "rainbow.h"
+#include "rainbow_config.h"
+#include "rainbow_keypair.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
+ unsigned char sk_seed[LEN_SKSEED] = {0};
+ randombytes(sk_seed, LEN_SKSEED);
+
+ unsigned char pk_seed[LEN_PKSEED] = {0};
+ randombytes(pk_seed, LEN_PKSEED);
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_generate_keypair_cyclic((cpk_t *)pk, (sk_t *)sk, pk_seed, sk_seed);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_crypto_sign(unsigned char *sm, size_t *smlen, const unsigned char *m, size_t mlen, const unsigned char *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+
+ memcpy(sm, m, mlen);
+ smlen[0] = mlen + _SIGNATURE_BYTE;
+
+ return PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_sign(sm + mlen, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_crypto_sign_open(unsigned char *m, size_t *mlen, const unsigned char *sm, size_t smlen, const unsigned char *pk) {
+ int rc;
+ if (_SIGNATURE_BYTE > smlen) {
+ rc = -1;
+ } else {
+ *mlen = smlen - _SIGNATURE_BYTE;
+
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, sm, *mlen);
+
+ rc = PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_verify_cyclic(digest, sm + mlen[0], (const cpk_t *)pk);
+ }
+ if (!rc) {
+ memcpy(m, sm, smlen - _SIGNATURE_BYTE);
+ } else { // bad signature
+ *mlen = (size_t) -1;
+ memset(m, 0, smlen);
+ }
+ return rc;
+}
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ unsigned char digest[_HASH_LEN];
+
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ *siglen = _SIGNATURE_BYTE;
+ return PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_sign(sig, (const sk_t *)sk, digest);
+}
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ if (siglen != _SIGNATURE_BYTE) {
+ return -1;
+ }
+ unsigned char digest[_HASH_LEN];
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_hash_msg(digest, _HASH_LEN, m, mlen);
+ return PQCLEAN_RAINBOWVCCYCLIC_CLEAN_rainbow_verify_cyclic(digest, sig, (const cpk_t *)pk);
+}
diff --git a/crypto_sign/rainbowVc-cyclic/clean/utils_hash.c b/crypto_sign/rainbowVc-cyclic/clean/utils_hash.c
new file mode 100644
index 00000000..37ee1064
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/utils_hash.c
@@ -0,0 +1,50 @@
+/// @file utils_hash.c
+/// @brief the adapter for SHA2 families.
+///
+///
+
+#include "utils_hash.h"
+#include "rainbow_config.h"
+#include "sha2.h"
+
+static inline int _hash(unsigned char *digest, const unsigned char *m, size_t mlen) {
+ sha512(digest, m, mlen);
+ return 0;
+}
+
+static inline int expand_hash(unsigned char *digest, size_t n_digest, const unsigned char *hash) {
+ if (_HASH_LEN >= n_digest) {
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[i] = hash[i];
+ }
+ return 0;
+ }
+ for (size_t i = 0; i < _HASH_LEN; i++) {
+ digest[i] = hash[i];
+ }
+ n_digest -= _HASH_LEN;
+
+ while (_HASH_LEN <= n_digest) {
+ _hash(digest + _HASH_LEN, digest, _HASH_LEN);
+
+ n_digest -= _HASH_LEN;
+ digest += _HASH_LEN;
+ }
+ unsigned char temp[_HASH_LEN];
+ if (n_digest) {
+ _hash(temp, digest, _HASH_LEN);
+ for (size_t i = 0; i < n_digest; i++) {
+ digest[_HASH_LEN + i] = temp[i];
+ }
+ }
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_hash_msg(unsigned char *digest,
+ size_t len_digest,
+ const unsigned char *m,
+ size_t mlen) {
+ unsigned char buf[_HASH_LEN];
+ _hash(buf, m, mlen);
+ return expand_hash(digest, len_digest, buf);
+}
diff --git a/crypto_sign/rainbowVc-cyclic/clean/utils_hash.h b/crypto_sign/rainbowVc-cyclic/clean/utils_hash.h
new file mode 100644
index 00000000..6c38bbd5
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/utils_hash.h
@@ -0,0 +1,11 @@
+#ifndef _UTILS_HASH_H_
+#define _UTILS_HASH_H_
+/// @file utils_hash.h
+/// @brief the interface for adapting hash functions.
+///
+
+#include
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_hash_msg(unsigned char *digest, size_t len_digest, const unsigned char *m, size_t mlen);
+
+#endif // _UTILS_HASH_H_
diff --git a/crypto_sign/rainbowVc-cyclic/clean/utils_prng.c b/crypto_sign/rainbowVc-cyclic/clean/utils_prng.c
new file mode 100644
index 00000000..81fa0412
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/utils_prng.c
@@ -0,0 +1,95 @@
+/// @file utils_prng.c
+/// @brief The implementation of PRNG related functions.
+///
+
+#include "utils_prng.h"
+#include "aes.h"
+#include "randombytes.h"
+#include "utils_hash.h"
+#include
+#include
+
+static void prng_update(const unsigned char *provided_data,
+ unsigned char *Key,
+ unsigned char *V) {
+ unsigned char temp[48];
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, Key);
+ for (int i = 0; i < 3; i++) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (V[j] == 0xff) {
+ V[j] = 0x00;
+ } else {
+ V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(temp + 16 * i, V, 1, &ctx);
+ }
+ if (provided_data != NULL) {
+ for (int i = 0; i < 48; i++) {
+ temp[i] ^= provided_data[i];
+ }
+ }
+ memcpy(Key, temp, 32);
+ memcpy(V, temp + 32, 16);
+}
+static void randombytes_init_with_state(prng_t *state,
+ unsigned char *entropy_input_48bytes) {
+ memset(state->Key, 0x00, 32);
+ memset(state->V, 0x00, 16);
+ prng_update(entropy_input_48bytes, state->Key, state->V);
+}
+
+static int randombytes_with_state(prng_t *state,
+ unsigned char *x,
+ size_t xlen) {
+
+ unsigned char block[16];
+ int i = 0;
+
+ aes256ctx ctx;
+ aes256_keyexp(&ctx, state->Key);
+
+ while (xlen > 0) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (state->V[j] == 0xff) {
+ state->V[j] = 0x00;
+ } else {
+ state->V[j]++;
+ break;
+ }
+ }
+ aes256_ecb(block, state->V, 1, &ctx);
+ if (xlen > 15) {
+ memcpy(x + i, block, 16);
+ i += 16;
+ xlen -= 16;
+ } else {
+ memcpy(x + i, block, xlen);
+ xlen = 0;
+ }
+ }
+ prng_update(NULL, state->Key, state->V);
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen) {
+ unsigned char seed[48];
+ if (prng_seedlen >= 48) {
+ memcpy(seed, prng_seed, 48);
+ } else {
+ memcpy(seed, prng_seed, prng_seedlen);
+ PQCLEAN_RAINBOWVCCYCLIC_CLEAN_hash_msg(seed + prng_seedlen, 48 - (unsigned)prng_seedlen, (const unsigned char *)prng_seed, prng_seedlen);
+ }
+
+ randombytes_init_with_state(ctx, seed);
+
+ return 0;
+}
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen) {
+ return randombytes_with_state(ctx, out, outlen);
+}
diff --git a/crypto_sign/rainbowVc-cyclic/clean/utils_prng.h b/crypto_sign/rainbowVc-cyclic/clean/utils_prng.h
new file mode 100644
index 00000000..35c4f0a7
--- /dev/null
+++ b/crypto_sign/rainbowVc-cyclic/clean/utils_prng.h
@@ -0,0 +1,18 @@
+#ifndef _UTILS_PRNG_H_
+#define _UTILS_PRNG_H_
+/// @file utils_prng.h
+/// @brief the interface for adapting PRNG functions.
+///
+///
+
+#include "randombytes.h"
+
+typedef struct {
+ unsigned char Key[32];
+ unsigned char V[16];
+} prng_t;
+
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_set(prng_t *ctx, const void *prng_seed, unsigned long prng_seedlen);
+int PQCLEAN_RAINBOWVCCYCLIC_CLEAN_prng_gen(prng_t *ctx, unsigned char *out, unsigned long outlen);
+
+#endif // _UTILS_PRNG_H_
diff --git a/test/duplicate_consistency/rainbowIIIc-classic_clean.yml b/test/duplicate_consistency/rainbowIIIc-classic_clean.yml
new file mode 100644
index 00000000..17761fcb
--- /dev/null
+++ b/test/duplicate_consistency/rainbowIIIc-classic_clean.yml
@@ -0,0 +1,73 @@
+consistency_checks:
+- source:
+ scheme: rainbowIIIc-cyclic
+ implementation: clean
+ files:
+ - blas_comm.c
+ - blas_comm.h
+ - blas.h
+ - blas_u32.c
+ - blas_u32.h
+ - gf.c
+ - gf.h
+ - parallel_matrix_op.c
+ - parallel_matrix_op.h
+ - rainbow_blas.h
+ - utils_hash.c
+- source:
+ scheme: rainbowIIIc-cyclic-compressed
+ implementation: clean
+ files:
+ - blas_comm.c
+ - blas_comm.h
+ - blas.h
+ - blas_u32.c
+ - blas_u32.h
+ - gf.c
+ - gf.h
+ - parallel_matrix_op.c
+ - parallel_matrix_op.h
+ - rainbow_blas.h
+ - utils_hash.c
+- source:
+ scheme: rainbowVc-classic
+ implementation: clean
+ files:
+ - blas_comm.c
+ - blas_comm.h
+ - blas.h
+ - blas_u32.c
+ - blas_u32.h
+ - gf.c
+ - gf.h
+ - parallel_matrix_op.c
+ - parallel_matrix_op.h
+ - rainbow_blas.h
+- source:
+ scheme: rainbowVc-cyclic
+ implementation: clean
+ files:
+ - blas_comm.c
+ - blas_comm.h
+ - blas.h
+ - blas_u32.c
+ - blas_u32.h
+ - gf.c
+ - gf.h
+ - parallel_matrix_op.c
+ - parallel_matrix_op.h
+ - rainbow_blas.h
+- source:
+ scheme: rainbowVc-cyclic-compressed
+ implementation: clean
+ files:
+ - blas_comm.c
+ - blas_comm.h
+ - blas.h
+ - blas_u32.c
+ - blas_u32.h
+ - gf.c
+ - gf.h
+ - parallel_matrix_op.c
+ - parallel_matrix_op.h
+ - rainbow_blas.h
diff --git a/test/duplicate_consistency/rainbowIa-classic_clean.yml b/test/duplicate_consistency/rainbowIa-classic_clean.yml
new file mode 100644
index 00000000..6ef12c29
--- /dev/null
+++ b/test/duplicate_consistency/rainbowIa-classic_clean.yml
@@ -0,0 +1,101 @@
+consistency_checks:
+- source:
+ scheme: rainbowIa-cyclic
+ implementation: clean
+ files:
+ - blas_comm.c
+ - blas_comm.h
+ - blas.h
+ - blas_u32.c
+ - blas_u32.h
+ - gf.c
+ - gf.h
+ - parallel_matrix_op.c
+ - parallel_matrix_op.h
+ - rainbow_blas.h
+ - rainbow_config.h
+ - utils_hash.c
+ - utils_hash.h
+ - utils_prng.c
+ - utils_prng.h
+- source:
+ scheme: rainbowIa-cyclic-compressed
+ implementation: clean
+ files:
+ - blas_comm.c
+ - blas_comm.h
+ - blas.h
+ - blas_u32.c
+ - blas_u32.h
+ - gf.c
+ - gf.h
+ - parallel_matrix_op.c
+ - parallel_matrix_op.h
+ - rainbow_blas.h
+ - rainbow_config.h
+ - utils_hash.c
+ - utils_hash.h
+ - utils_prng.c
+ - utils_prng.h
+- source:
+ scheme: rainbowIIIc-classic
+ implementation: clean
+ files:
+ - parallel_matrix_op.h
+ - rainbow.c
+ - rainbow.h
+ - rainbow_keypair.c
+ - rainbow_keypair_computation.c
+ - rainbow_keypair_computation.h
+ - rainbow_keypair.h
+ - sign.c
+ - utils_hash.h
+ - utils_prng.c
+ - utils_prng.h
+- source:
+ scheme: rainbowIIIc-cyclic
+ implementation: clean
+ files:
+ - parallel_matrix_op.h
+ - utils_hash.h
+ - utils_prng.c
+ - utils_prng.h
+- source:
+ scheme: rainbowIIIc-cyclic-compressed
+ implementation: clean
+ files:
+ - parallel_matrix_op.h
+ - utils_hash.h
+ - utils_prng.c
+ - utils_prng.h
+- source:
+ scheme: rainbowVc-classic
+ implementation: clean
+ files:
+ - parallel_matrix_op.h
+ - rainbow.c
+ - rainbow.h
+ - rainbow_keypair.c
+ - rainbow_keypair_computation.c
+ - rainbow_keypair_computation.h
+ - rainbow_keypair.h
+ - sign.c
+ - utils_hash.h
+ - utils_prng.c
+ - utils_prng.h
+- source:
+ scheme: rainbowVc-cyclic
+ implementation: clean
+ files:
+ - parallel_matrix_op.h
+ - utils_hash.h
+ - utils_prng.c
+ - utils_prng.h
+- source:
+ scheme: rainbowVc-cyclic-compressed
+ implementation: clean
+ files:
+ - parallel_matrix_op.h
+ - utils_hash.h
+ - utils_prng.c
+ - utils_prng.h
diff --git a/test/duplicate_consistency/rainbowIa-cyclic-compressed_clean.yml b/test/duplicate_consistency/rainbowIa-cyclic-compressed_clean.yml
new file mode 100644
index 00000000..b4a89d49
--- /dev/null
+++ b/test/duplicate_consistency/rainbowIa-cyclic-compressed_clean.yml
@@ -0,0 +1,21 @@
+consistency_checks:
+- source:
+ scheme: rainbowIIIc-cyclic-compressed
+ implementation: clean
+ files:
+ - rainbow.c
+ - rainbow.h
+ - rainbow_keypair.c
+ - rainbow_keypair_computation.c
+ - rainbow_keypair_computation.h
+ - rainbow_keypair.h
+- source:
+ scheme: rainbowVc-cyclic-compressed
+ implementation: clean
+ files:
+ - rainbow.c
+ - rainbow.h
+ - rainbow_keypair.c
+ - rainbow_keypair_computation.c
+ - rainbow_keypair_computation.h
+ - rainbow_keypair.h
diff --git a/test/duplicate_consistency/rainbowIa-cyclic_clean.yml b/test/duplicate_consistency/rainbowIa-cyclic_clean.yml
new file mode 100644
index 00000000..662b32dd
--- /dev/null
+++ b/test/duplicate_consistency/rainbowIa-cyclic_clean.yml
@@ -0,0 +1,21 @@
+consistency_checks:
+- source:
+ scheme: rainbowIIIc-cyclic
+ implementation: clean
+ files:
+ - rainbow.c
+ - rainbow.h
+ - rainbow_keypair.c
+ - rainbow_keypair_computation.c
+ - rainbow_keypair_computation.h
+ - rainbow_keypair.h
+- source:
+ scheme: rainbowVc-cyclic
+ implementation: clean
+ files:
+ - rainbow.c
+ - rainbow.h
+ - rainbow_keypair.c
+ - rainbow_keypair_computation.c
+ - rainbow_keypair_computation.h
+ - rainbow_keypair.h
diff --git a/test/duplicate_consistency/rainbowVc-classic_clean.yml b/test/duplicate_consistency/rainbowVc-classic_clean.yml
new file mode 100644
index 00000000..bec4bc2a
--- /dev/null
+++ b/test/duplicate_consistency/rainbowVc-classic_clean.yml
@@ -0,0 +1,11 @@
+consistency_checks:
+- source:
+ scheme: rainbowVc-cyclic
+ implementation: clean
+ files:
+ - utils_hash.c
+- source:
+ scheme: rainbowVc-cyclic-compressed
+ implementation: clean
+ files:
+ - utils_hash.c