arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/arch/arm64-sve/rpo/rpo_hash_256bit.h
arch/arm64-sve/rpo/rpo_hash_256bit.hRaw
  1#ifndef RPO_SVE_RPO_HASH_256_H
  2#define RPO_SVE_RPO_HASH_256_H
  3
  4#include <arm_sve.h>
  5#include <stddef.h>
  6#include <stdint.h>
  7#include <string.h>
  8
  9#define STATE_WIDTH 12
 10
 11#define COPY_256(NAME, VIN1, VIN2, SIN3)                \
 12    svuint64_t NAME ## _1 = VIN1;                   \
 13    svuint64_t NAME ## _2 = VIN2;                   \
 14    uint64_t NAME ## _3[4];                         \
 15    memcpy(NAME ## _3, SIN3, 4 * sizeof(uint64_t))
 16
 17#define MULTIPLY_256(PRED, DEST, OP)                    \
 18    mul_256(PRED, &DEST ## _1, &OP ## _1, &DEST ## _2, &OP ## _2, DEST ## _3, OP ## _3)
 19
 20#define SQUARE_256(PRED, NAME)                          \
 21    sq_256(PRED, &NAME ## _1, &NAME ## _2, NAME ## _3)
 22
 23#define SQUARE_DEST_256(PRED, DEST, SRC)                \
 24    COPY_256(DEST, SRC ## _1, SRC ## _2, SRC ## _3);    \
 25    SQUARE_256(PRED, DEST);
 26
 27#define POW_ACC(PRED, NAME, CNT, TAIL)              \
 28    for (size_t i = 0; i < CNT; i++) {              \
 29        SQUARE_256(PRED, NAME);                         \
 30    }                                               \
 31    MULTIPLY_256(PRED, NAME, TAIL);
 32
 33#define POW_ACC_DEST_256(PRED, DEST, CNT, HEAD, TAIL)   \
 34    COPY_256(DEST, HEAD ## _1, HEAD ## _2, HEAD ## _3); \
 35    POW_ACC(PRED, DEST, CNT, TAIL)
 36
 37extern inline void add_constants_256(
 38    svbool_t pg,
 39    svuint64_t *state1,
 40    svuint64_t *const1,
 41    svuint64_t *state2,
 42    svuint64_t *const2,
 43    uint64_t *state3,
 44    uint64_t *const3
 45) {
 46    uint64_t Ms = 0xFFFFFFFF00000001ull;
 47    svuint64_t Mv = svindex_u64(Ms, 0);
 48
 49    uint64_t p_1 = Ms - const3[0];
 50    uint64_t p_2 = Ms - const3[1];
 51    uint64_t p_3 = Ms - const3[2];
 52    uint64_t p_4 = Ms - const3[3];
 53
 54    uint64_t x_1, x_2, x_3, x_4;
 55    uint32_t adj_1 = -__builtin_sub_overflow(state3[0], p_1, &x_1);
 56    uint32_t adj_2 = -__builtin_sub_overflow(state3[1], p_2, &x_2);
 57    uint32_t adj_3 = -__builtin_sub_overflow(state3[2], p_3, &x_3);
 58    uint32_t adj_4 = -__builtin_sub_overflow(state3[3], p_4, &x_4);
 59
 60    state3[0] = x_1 - (uint64_t)adj_1;
 61    state3[1] = x_2 - (uint64_t)adj_2;
 62    state3[2] = x_3 - (uint64_t)adj_3;
 63    state3[3] = x_4 - (uint64_t)adj_4;
 64
 65    svuint64_t p1 = svsub_x(pg, Mv, *const1);
 66    svuint64_t p2 = svsub_x(pg, Mv, *const2);
 67
 68    svuint64_t x1 = svsub_x(pg, *state1, p1);
 69    svuint64_t x2 = svsub_x(pg, *state2, p2);
 70
 71    svbool_t pt1 = svcmplt_u64(pg, *state1, p1);
 72    svbool_t pt2 = svcmplt_u64(pg, *state2, p2);
 73
 74    *state1 = svsub_m(pt1, x1, (uint32_t)-1);
 75    *state2 = svsub_m(pt2, x2, (uint32_t)-1);
 76}
 77
 78extern inline void mul_256(
 79    svbool_t pg,
 80    svuint64_t *r1,
 81    const svuint64_t *op1,
 82    svuint64_t *r2,
 83    const svuint64_t *op2,
 84    uint64_t *r3,
 85    const uint64_t *op3
 86) {
 87    __uint128_t x_1 = r3[0];
 88    __uint128_t x_2 = r3[1];
 89    __uint128_t x_3 = r3[2];
 90    __uint128_t x_4 = r3[3];
 91
 92    x_1 *= (__uint128_t) op3[0];
 93    x_2 *= (__uint128_t) op3[1];
 94    x_3 *= (__uint128_t) op3[2];
 95    x_4 *= (__uint128_t) op3[3];
 96
 97    uint64_t x0_1 = x_1;
 98    uint64_t x0_2 = x_2;
 99    uint64_t x0_3 = x_3;
100    uint64_t x0_4 = x_4;
101
102    svuint64_t l1 = svmul_x(pg, *r1, *op1);
103    svuint64_t l2 = svmul_x(pg, *r2, *op2);
104
105    uint64_t x1_1 = (x_1 >> 64);
106    uint64_t x1_2 = (x_2 >> 64);
107    uint64_t x1_3 = (x_3 >> 64);
108    uint64_t x1_4 = (x_4 >> 64);
109
110    uint64_t a_1, a_2, a_3, a_4;
111    uint64_t e_1 = __builtin_add_overflow(x0_1, (x0_1 << 32), &a_1);
112    uint64_t e_2 = __builtin_add_overflow(x0_2, (x0_2 << 32), &a_2);
113    uint64_t e_3 = __builtin_add_overflow(x0_3, (x0_3 << 32), &a_3);
114    uint64_t e_4 = __builtin_add_overflow(x0_4, (x0_4 << 32), &a_4);
115
116    svuint64_t ls1 = svlsl_x(pg, l1, 32);
117    svuint64_t ls2 = svlsl_x(pg, l2, 32);
118
119    svuint64_t a1 = svadd_x(pg, l1, ls1);
120    svuint64_t a2 = svadd_x(pg, l2, ls2);
121
122    svbool_t e1 = svcmplt(pg, a1, l1);
123    svbool_t e2 = svcmplt(pg, a2, l2);
124
125    svuint64_t as1 = svlsr_x(pg, a1, 32);
126    svuint64_t as2 = svlsr_x(pg, a2, 32);
127
128    svuint64_t b1 = svsub_x(pg, a1, as1);
129    svuint64_t b2 = svsub_x(pg, a2, as2);
130
131    b1 = svsub_m(e1, b1, 1);
132    b2 = svsub_m(e2, b2, 1);
133
134    uint64_t b_1 = a_1 - (a_1 >> 32) - e_1;
135    uint64_t b_2 = a_2 - (a_2 >> 32) - e_2;
136    uint64_t b_3 = a_3 - (a_3 >> 32) - e_3;
137    uint64_t b_4 = a_4 - (a_4 >> 32) - e_4;
138
139    uint64_t r_1, r_2, r_3, r_4;
140    uint32_t c_1 = __builtin_sub_overflow(x1_1, b_1, &r_1);
141    uint32_t c_2 = __builtin_sub_overflow(x1_2, b_2, &r_2);
142    uint32_t c_3 = __builtin_sub_overflow(x1_3, b_3, &r_3);
143    uint32_t c_4 = __builtin_sub_overflow(x1_4, b_4, &r_4);
144
145    svuint64_t h1 = svmulh_x(pg, *r1, *op1);
146    svuint64_t h2 = svmulh_x(pg, *r2, *op2);
147
148    svuint64_t tr1 = svsub_x(pg, h1, b1);
149    svuint64_t tr2 = svsub_x(pg, h2, b2);
150
151    svbool_t c1 = svcmplt_u64(pg, h1, b1);
152    svbool_t c2 = svcmplt_u64(pg, h2, b2);
153
154    *r1 = svsub_m(c1, tr1, (uint32_t) -1);
155    *r2 = svsub_m(c2, tr2, (uint32_t) -1);
156
157    uint32_t minus1_1 = 0 - c_1;
158    uint32_t minus1_2 = 0 - c_2;
159    uint32_t minus1_3 = 0 - c_3;
160    uint32_t minus1_4 = 0 - c_4;
161
162    r3[0] = r_1 - (uint64_t)minus1_1;
163    r3[1] = r_2 - (uint64_t)minus1_2;
164    r3[2] = r_3 - (uint64_t)minus1_3;
165    r3[3] = r_4 - (uint64_t)minus1_4;
166}
167
168extern inline void sq_256(svbool_t pg, svuint64_t *a, svuint64_t *b, uint64_t *c) {
169    mul_256(pg, a, a, b, b, c, c);
170}
171
172extern inline void apply_sbox_256(
173    svbool_t pg,
174    svuint64_t *state1,
175    svuint64_t *state2,
176    uint64_t *state3
177) {
178    COPY_256(x, *state1, *state2, state3);                // copy input to x
179    SQUARE_256(pg, x);                                    // x contains input^2
180    mul_256(pg, state1, &x_1, state2, &x_2, state3, x_3); // state contains input^3
181    SQUARE_256(pg, x);                                    // x contains input^4
182    mul_256(pg, state1, &x_1, state2, &x_2, state3, x_3); // state contains input^7
183}
184
185extern inline void apply_inv_sbox_256(
186    svbool_t pg,
187    svuint64_t *state_1,
188    svuint64_t *state_2,
189    uint64_t *state_3
190) {
191    // base^10
192    COPY_256(t1, *state_1, *state_2, state_3);
193    SQUARE_256(pg, t1);
194
195    // base^100
196    SQUARE_DEST_256(pg, t2, t1);
197
198    // base^100100
199    POW_ACC_DEST_256(pg, t3, 3, t2, t2);
200
201    // base^100100100100
202    POW_ACC_DEST_256(pg, t4, 6, t3, t3);
203
204    // compute base^100100100100100100100100
205    POW_ACC_DEST_256(pg, t5, 12, t4, t4);
206
207    // compute base^100100100100100100100100100100
208    POW_ACC_DEST_256(pg, t6, 6, t5, t3);
209
210    // compute base^1001001001001001001001001001000100100100100100100100100100100
211    POW_ACC_DEST_256(pg, t7, 31, t6, t6);
212
213    // compute base^1001001001001001001001001001000110110110110110110110110110110111
214    SQUARE_256(pg, t7);
215    MULTIPLY_256(pg, t7, t6);
216    SQUARE_256(pg, t7);
217    SQUARE_256(pg, t7);
218    MULTIPLY_256(pg, t7, t1);
219    MULTIPLY_256(pg, t7, t2);
220    mul_256(pg, state_1, &t7_1, state_2, &t7_2, state_3, t7_3);
221}
222
223bool add_constants_and_apply_sbox_256(uint64_t state[STATE_WIDTH], uint64_t constants[STATE_WIDTH]) {
224    const uint64_t vl = 4;   // number of u64 numbers in one 128 bit SVE vector
225    svbool_t ptrue = svptrue_b64();
226
227    svuint64_t state1 = svld1(ptrue, state + 0 * vl);
228    svuint64_t state2 = svld1(ptrue, state + 1 * vl);
229
230    svuint64_t const1 = svld1(ptrue, constants + 0 * vl);
231    svuint64_t const2 = svld1(ptrue, constants + 1 * vl);
232
233    add_constants_256(ptrue, &state1, &const1, &state2, &const2, state + 8, constants + 8);
234    apply_sbox_256(ptrue, &state1, &state2, state + 8);
235
236    svst1(ptrue, state + 0 * vl, state1);
237    svst1(ptrue, state + 1 * vl, state2);
238
239    return true;
240}
241
242bool add_constants_and_apply_inv_sbox_256(uint64_t state[STATE_WIDTH], uint64_t constants[STATE_WIDTH]) {
243    const uint64_t vl = 4;   // number of u64 numbers in one 128 bit SVE vector
244    svbool_t ptrue = svptrue_b64();
245
246    svuint64_t state1 = svld1(ptrue, state + 0 * vl);
247    svuint64_t state2 = svld1(ptrue, state + 1 * vl);
248
249    svuint64_t const1 = svld1(ptrue, constants + 0 * vl);
250    svuint64_t const2 = svld1(ptrue, constants + 1 * vl);
251
252    add_constants_256(ptrue, &state1, &const1, &state2, &const2, state + 8, constants + 8);
253    apply_inv_sbox_256(ptrue, &state1, &state2, state + 8);
254
255    svst1(ptrue, state + 0 * vl, state1);
256    svst1(ptrue, state + 1 * vl, state2);
257
258    return true;
259}
260
261#endif //RPO_SVE_RPO_HASH_256_H