poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/q120/q120_arithmetic_simple.c
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/q120/q120_arithmetic_simple.cRaw
1#include <assert.h>
2#include <math.h>
3#include <stdint.h>
4
5#include "q120_arithmetic.h"
6#include "q120_common.h"
7
8EXPORT void q120_add_bbb_simple(uint64_t nn, q120b* const res, const q120b* const x, const q120b* const y) {
9 const uint64_t* x_u64 = (uint64_t*)x;
10 const uint64_t* y_u64 = (uint64_t*)y;
11 uint64_t* res_u64 = (uint64_t*)res;
12 for (uint64_t i = 0; i < 4 * nn; i += 4) {
13 res_u64[i + 0] = x_u64[i + 0] % ((uint64_t)Q1 << 33) + y_u64[i + 0] % ((uint64_t)Q1 << 33);
14 res_u64[i + 1] = x_u64[i + 1] % ((uint64_t)Q2 << 33) + y_u64[i + 1] % ((uint64_t)Q2 << 33);
15 res_u64[i + 2] = x_u64[i + 2] % ((uint64_t)Q3 << 33) + y_u64[i + 2] % ((uint64_t)Q3 << 33);
16 res_u64[i + 3] = x_u64[i + 3] % ((uint64_t)Q4 << 33) + y_u64[i + 3] % ((uint64_t)Q4 << 33);
17 }
18}
19
20EXPORT void q120_add_ccc_simple(uint64_t nn, q120c* const res, const q120c* const x, const q120c* const y) {
21 const uint32_t* x_u32 = (uint32_t*)x;
22 const uint32_t* y_u32 = (uint32_t*)y;
23 uint32_t* res_u32 = (uint32_t*)res;
24 for (uint64_t i = 0; i < 8 * nn; i += 8) {
25 res_u32[i + 0] = (uint32_t)(((uint64_t)x_u32[i + 0] + (uint64_t)y_u32[i + 0]) % Q1);
26 res_u32[i + 1] = (uint32_t)(((uint64_t)x_u32[i + 1] + (uint64_t)y_u32[i + 1]) % Q1);
27 res_u32[i + 2] = (uint32_t)(((uint64_t)x_u32[i + 2] + (uint64_t)y_u32[i + 2]) % Q2);
28 res_u32[i + 3] = (uint32_t)(((uint64_t)x_u32[i + 3] + (uint64_t)y_u32[i + 3]) % Q2);
29 res_u32[i + 4] = (uint32_t)(((uint64_t)x_u32[i + 4] + (uint64_t)y_u32[i + 4]) % Q3);
30 res_u32[i + 5] = (uint32_t)(((uint64_t)x_u32[i + 5] + (uint64_t)y_u32[i + 5]) % Q3);
31 res_u32[i + 6] = (uint32_t)(((uint64_t)x_u32[i + 6] + (uint64_t)y_u32[i + 6]) % Q4);
32 res_u32[i + 7] = (uint32_t)(((uint64_t)x_u32[i + 7] + (uint64_t)y_u32[i + 7]) % Q4);
33 }
34}
35
36EXPORT void q120_c_from_b_simple(uint64_t nn, q120c* const res, const q120b* const x) {
37 const uint64_t* x_u64 = (uint64_t*)x;
38 uint32_t* res_u32 = (uint32_t*)res;
39 for (uint64_t i = 0, j = 0; i < 4 * nn; i += 4, j += 8) {
40 res_u32[j + 0] = x_u64[i + 0] % Q1;
41 res_u32[j + 1] = ((uint64_t)res_u32[j + 0] << 32) % Q1;
42 res_u32[j + 2] = x_u64[i + 1] % Q2;
43 res_u32[j + 3] = ((uint64_t)res_u32[j + 2] << 32) % Q2;
44 res_u32[j + 4] = x_u64[i + 2] % Q3;
45 res_u32[j + 5] = ((uint64_t)res_u32[j + 4] << 32) % Q3;
46 res_u32[j + 6] = x_u64[i + 3] % Q4;
47 res_u32[j + 7] = ((uint64_t)res_u32[j + 6] << 32) % Q4;
48 }
49}
50
51EXPORT void q120_b_from_znx64_simple(uint64_t nn, q120b* const res, const int64_t* const x) {
52 static const int64_t MASK_HI = INT64_C(0x8000000000000000);
53 static const int64_t MASK_LO = ~MASK_HI;
54 static const uint64_t OQ[4] = {
55 (Q1 - (UINT64_C(0x8000000000000000) % Q1)),
56 (Q2 - (UINT64_C(0x8000000000000000) % Q2)),
57 (Q3 - (UINT64_C(0x8000000000000000) % Q3)),
58 (Q4 - (UINT64_C(0x8000000000000000) % Q4)),
59 };
60 uint64_t* res_u64 = (uint64_t*)res;
61 for (uint64_t i = 0, j = 0; j < nn; i += 4, ++j) {
62 uint64_t xj_lo = x[j] & MASK_LO;
63 uint64_t xj_hi = x[j] & MASK_HI;
64 res_u64[i + 0] = xj_lo + (xj_hi ? OQ[0] : 0);
65 res_u64[i + 1] = xj_lo + (xj_hi ? OQ[1] : 0);
66 res_u64[i + 2] = xj_lo + (xj_hi ? OQ[2] : 0);
67 res_u64[i + 3] = xj_lo + (xj_hi ? OQ[3] : 0);
68 }
69}
70
71static int64_t posmod(int64_t x, int64_t q) {
72 int64_t t = x % q;
73 if (t < 0)
74 return t + q;
75 else
76 return t;
77}
78
79EXPORT void q120_c_from_znx64_simple(uint64_t nn, q120c* const res, const int64_t* const x) {
80 uint32_t* res_u32 = (uint32_t*)res;
81 for (uint64_t i = 0, j = 0; j < nn; i += 8, ++j) {
82 res_u32[i + 0] = posmod(x[j], Q1);
83 res_u32[i + 1] = ((uint64_t)res_u32[i + 0] << 32) % Q1;
84 res_u32[i + 2] = posmod(x[j], Q2);
85 res_u32[i + 3] = ((uint64_t)res_u32[i + 2] << 32) % Q2;
86 res_u32[i + 4] = posmod(x[j], Q3);
87 res_u32[i + 5] = ((uint64_t)res_u32[i + 4] << 32) % Q3;
88 res_u32[i + 6] = posmod(x[j], Q4);
89 res_u32[i + 7] = ((uint64_t)res_u32[i + 6] << 32) % Q4;
90 ;
91 }
92}
93
94EXPORT void q120_b_to_znx128_simple(uint64_t nn, __int128_t* const res, const q120b* const x) {
95 static const __int128_t Q = (__int128_t)Q1 * Q2 * Q3 * Q4;
96 static const __int128_t Qm1 = (__int128_t)Q2 * Q3 * Q4;
97 static const __int128_t Qm2 = (__int128_t)Q1 * Q3 * Q4;
98 static const __int128_t Qm3 = (__int128_t)Q1 * Q2 * Q4;
99 static const __int128_t Qm4 = (__int128_t)Q1 * Q2 * Q3;
100
101 const uint64_t* x_u64 = (uint64_t*)x;
102 for (uint64_t i = 0, j = 0; j < nn; i += 4, ++j) {
103 __int128_t tmp = 0;
104 tmp += (((x_u64[i + 0] % Q1) * Q1_CRT_CST) % Q1) * Qm1;
105 tmp += (((x_u64[i + 1] % Q2) * Q2_CRT_CST) % Q2) * Qm2;
106 tmp += (((x_u64[i + 2] % Q3) * Q3_CRT_CST) % Q3) * Qm3;
107 tmp += (((x_u64[i + 3] % Q4) * Q4_CRT_CST) % Q4) * Qm4;
108 tmp %= Q;
109 res[j] = (tmp >= (Q + 1) / 2) ? tmp - Q : tmp;
110 }
111}