13status_t hardened_memcpy(uint32_t *restrict dest,
const uint32_t *restrict src,
16 random_order_init(&order, word_len);
23 uintptr_t src_addr = (uintptr_t)src;
24 uintptr_t dest_addr = (uintptr_t)dest;
28 for (; launderw(count) < word_len; count = launderw(count) + 1) {
34 size_t byte_idx = launderw(random_order_advance(&order)) *
sizeof(uint32_t);
41 void *src_word = (
void *)launderw(src_addr + byte_idx);
42 void *dest_word = (
void *)launderw(dest_addr + byte_idx);
45 write_32(read_32(src_word), dest_word);
50 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
53status_t hardened_memshred(uint32_t *dest,
size_t word_len) {
55 random_order_init(&order, word_len);
59 uintptr_t data_addr = (uintptr_t)dest;
61 for (; count < word_len; count = launderw(count) + 1) {
62 size_t byte_idx = launderw(random_order_advance(&order)) *
sizeof(uint32_t);
66 void *data = (
void *)launderw(data_addr + byte_idx);
75 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
81 random_order_init(&order, word_len);
85 uintptr_t lhs_addr = (uintptr_t)lhs;
86 uintptr_t rhs_addr = (uintptr_t)rhs;
89 uint32_t ones = UINT32_MAX;
93 for (; count < word_len; count = launderw(count) + 1) {
94 size_t byte_idx = launderw(random_order_advance(&order)) *
sizeof(uint32_t);
98 void *av = (
void *)launderw(lhs_addr + byte_idx);
99 void *bv = (
void *)launderw(rhs_addr + byte_idx);
101 uint32_t a = read_32(av);
102 uint32_t b = read_32(bv);
109 zeros = launder32(zeros) | (launder32(a) ^ b);
113 ones = launder32(ones) & (launder32(a) ^ ~b);
118 HARDENED_CHECK_NE(lhs_addr, rhs_addr);
119 if (launder32(zeros) == 0) {
124 HARDENED_CHECK_NE(ones, UINT32_MAX);
131 uint32_t ones = UINT32_MAX;
134 random_order_init(&order, len);
138 uintptr_t lhs_addr = (uintptr_t)lhs;
139 uintptr_t rhs_addr = (uintptr_t)rhs;
141 for (; launderw(count) < len; count = launderw(count) + 1) {
142 size_t byte_idx = launderw(random_order_advance(&order));
145 uint8_t *a = (uint8_t *)launderw(lhs_addr + byte_idx);
146 uint8_t *b = (uint8_t *)launderw(rhs_addr + byte_idx);
153 zeros = launder32(zeros) | (launder32((uint32_t)*a) ^ *b);
157 ones = launder32(ones) & (launder32((uint32_t)*a) ^ ~(uint32_t)*b);
162 if (launder32(zeros) == 0) {
167 HARDENED_CHECK_NE(ones, UINT32_MAX);
171status_t hardened_xor(
const uint32_t *restrict x,
const uint32_t *restrict y,
172 size_t word_len, uint32_t *restrict dest) {
174 hardened_memshred(dest, word_len);
177 uint32_t rand[word_len];
178 hardened_memshred(rand, word_len);
181 uintptr_t x_addr = (uintptr_t)x;
182 uintptr_t y_addr = (uintptr_t)y;
183 uintptr_t dest_addr = (uintptr_t)dest;
184 uintptr_t rand_addr = (uintptr_t)&rand;
188 random_order_init(&order, word_len);
193 for (; launderw(count) < word_len; count = launderw(count) + 1) {
194 size_t byte_idx = launderw(random_order_advance(&order)) *
sizeof(uint32_t);
200 uintptr_t xp = x_addr + byte_idx;
201 uintptr_t yp = y_addr + byte_idx;
202 uintptr_t destp = dest_addr + byte_idx;
203 uintptr_t randp = rand_addr + byte_idx;
206 void *xv = (
void *)launderw(xp);
207 void *yv = (
void *)launderw(yp);
208 void *destv = (
void *)launderw(destp);
209 void *randv = (
void *)launderw(randp);
212 write_32(read_32(xv) ^ read_32(randv), destv);
213 write_32(read_32(destv) ^ read_32(yv), destv);
214 write_32(read_32(destv) ^ read_32(randv), destv);
219 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
222status_t hardened_xor_in_place(uint32_t *restrict x,
const uint32_t *restrict y,
226 random_order_init(&order, word_len);
230 uintptr_t x_addr = (uintptr_t)x;
231 uintptr_t y_addr = (uintptr_t)y;
235 for (; launderw(count) < word_len; count = launderw(count) + 1) {
236 size_t byte_idx = launderw(random_order_advance(&order)) *
sizeof(uint32_t);
242 void *xv = (
void *)launderw(x_addr + byte_idx);
243 void *yv = (
void *)launderw(y_addr + byte_idx);
246 write_32(read_32(xv) ^ read_32(yv), xv);
251 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
254status_t randomized_bytecopy(
void *restrict dest,
const void *restrict src,
257 random_order_init(&order, byte_len);
261 uintptr_t src_addr = (uintptr_t)src;
262 uintptr_t dest_addr = (uintptr_t)dest;
264 for (; launderw(count) < byte_len; count = launderw(count) + 1) {
265 size_t byte_idx = launderw(random_order_advance(&order));
268 uint8_t *src_byte_idx = (uint8_t *)launderw(src_addr + byte_idx);
269 uint8_t *dest_byte_idx = (uint8_t *)launderw(dest_addr + byte_idx);
271 *(dest_byte_idx) = *(src_byte_idx);
276 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
279status_t randomized_bytexor_in_place(
void *restrict x,
const void *restrict y,
282 random_order_init(&order, byte_len);
286 uintptr_t x_addr = (uintptr_t)x;
287 uintptr_t y_addr = (uintptr_t)y;
289 for (; launderw(count) < byte_len; count = launderw(count) + 1) {
290 size_t byte_idx = launderw(random_order_advance(&order));
294 uint8_t *x_byte_idx = (uint8_t *)launderw(x_addr + byte_idx);
295 uint8_t *y_byte_idx = (uint8_t *)launderw(y_addr + byte_idx);
297 *(x_byte_idx) = *(x_byte_idx) ^ *(y_byte_idx);
302 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
305#ifdef OT_PLATFORM_RV32
314static inline uint32_t rv32_addc(uint32_t x, uint32_t y, uint32_t *carry) {
315 uint32_t res, next_carry, c1, c2;
316 __asm__ __volatile__(
317 "add %[res], %[x], %[c_in]\n\t"
318 "sltu %[c1], %[res], %[c_in]\n\t"
319 "add %[res], %[res], %[y]\n\t"
320 "sltu %[c2], %[res], %[y]\n\t"
321 "or %[next_c], %[c1], %[c2]"
322 : [res]
"=&r"(res), [next_c]
"=&r"(next_carry), [c1]
"=&r"(c1),
324 : [x]
"r"(x), [y]
"r"(y), [c_in]
"r"(*carry));
337static inline uint32_t rv32_subc(uint32_t x, uint32_t y, uint32_t *borrow) {
338 uint32_t res, next_borrow, b1, b2;
339 __asm__ __volatile__(
340 "sltu %[b1], %[x], %[b_in]\n\t"
341 "sub %[res], %[x], %[b_in]\n\t"
342 "sltu %[b2], %[res], %[y]\n\t"
343 "sub %[res], %[res], %[y]\n\t"
344 "or %[next_b], %[b1], %[b2]"
345 : [res]
"=&r"(res), [next_b]
"=&r"(next_borrow), [b1]
"=&r"(b1),
347 : [x]
"r"(x), [y]
"r"(y), [b_in]
"r"(*borrow));
348 *borrow = next_borrow;
361static inline uint32_t rv32_sel(uint32_t cond, uint32_t a, uint32_t b) {
362 uint32_t res, mask, tmp;
363 __asm__ __volatile__(
364 "neg %[mask], %[cond]\n\t"
366 "xor %[tmp], %[a], %[b]\n\t"
367 "and %[tmp], %[tmp], %[mask]\n\t"
368 "xor %[res], %[b], %[tmp]"
369 : [res]
"=r"(res), [mask]
"=&r"(mask), [tmp]
"=&r"(tmp)
370 : [cond]
"r"(cond), [a]
"r"(a), [b]
"r"(b));
375status_t hardened_add(
const uint32_t *restrict x,
const uint32_t *restrict y,
376 size_t word_len, uint32_t *restrict dest) {
378 hardened_memshred(dest, word_len);
383 for (; launderw(count) < word_len; count = launderw(count) + 1) {
384#ifdef OT_PLATFORM_RV32
385 dest[count] = rv32_addc(x[count], y[count], &carry);
387 uint32_t x_val = x[count];
388 uint32_t y_val = y[count];
390 uint32_t res = x_val + carry;
391 uint32_t next_carry = (res < carry);
394 next_carry += (res < y_val);
402 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
405status_t hardened_sub(
const uint32_t *restrict x,
const uint32_t *restrict y,
406 size_t word_len, uint32_t *restrict dest) {
408 hardened_memshred(dest, word_len);
413 for (; launderw(count) < word_len; count = launderw(count) + 1) {
414#ifdef OT_PLATFORM_RV32
415 dest[count] = rv32_subc(x[count], y[count], &borrow);
417 uint32_t x_val = x[count];
418 uint32_t y_val = y[count];
420 uint32_t res = x_val - borrow;
422 uint32_t next_borrow = (x_val < borrow);
424 next_borrow += (res < y_val);
428 borrow = next_borrow;
433 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
436status_t hardened_sub_mod(
const uint32_t *restrict x,
437 const uint32_t *restrict y,
438 const uint32_t *restrict n,
size_t word_len,
439 uint32_t *restrict dest) {
441 hardened_memshred(dest, word_len);
444 uint32_t temp_sub[word_len];
447 for (; launderw(count) < word_len; count = launderw(count) + 1) {
448#ifdef OT_PLATFORM_RV32
449 temp_sub[count] = rv32_subc(x[count], y[count], &borrow);
451 uint32_t x_val = x[count];
452 uint32_t y_val = y[count];
453 uint32_t res = x_val - borrow;
454 uint32_t next_borrow = (x_val < borrow);
455 next_borrow += (res < y_val);
457 temp_sub[count] = res;
458 borrow = next_borrow;
464 uint32_t temp_add[word_len];
467 for (; launderw(count) < word_len; count = launderw(count) + 1) {
468#ifdef OT_PLATFORM_RV32
469 temp_add[count] = rv32_addc(temp_sub[count], n[count], &carry);
471 uint32_t x_val = temp_sub[count];
472 uint32_t y_val = n[count];
473 uint32_t res = x_val + carry;
474 uint32_t next_carry = (res < carry);
476 next_carry += (res < y_val);
477 temp_add[count] = res;
484 uint32_t is_borrow = launder32(borrow);
487 for (; launderw(count) < word_len; count = launderw(count) + 1) {
488#ifdef OT_PLATFORM_RV32
489 dest[count] = rv32_sel(is_borrow, temp_add[count], temp_sub[count]);
492 uint32_t mask = ~(is_borrow - 1);
494 mask = launder32(mask);
495 dest[count] = (temp_add[count] & launder32(mask)) |
496 (temp_sub[count] & launder32(~mask));
501 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
504status_t hardened_add_mod(
const uint32_t *restrict x,
505 const uint32_t *restrict y,
506 const uint32_t *restrict n,
size_t word_len,
507 uint32_t *restrict dest) {
509 hardened_memshred(dest, word_len);
512 uint32_t temp_add[word_len];
515 for (; launderw(count) < word_len; count = launderw(count) + 1) {
516#ifdef OT_PLATFORM_RV32
517 temp_add[count] = rv32_addc(x[count], y[count], &carry);
519 uint32_t x_val = x[count];
520 uint32_t y_val = y[count];
521 uint32_t res = x_val + carry;
522 uint32_t next_carry = (res < carry);
524 next_carry += (res < y_val);
525 temp_add[count] = res;
532 uint32_t temp_sub[word_len];
535 for (; launderw(count) < word_len; count = launderw(count) + 1) {
536#ifdef OT_PLATFORM_RV32
537 temp_sub[count] = rv32_subc(temp_add[count], n[count], &borrow);
539 uint32_t x_val = temp_add[count];
540 uint32_t y_val = n[count];
541 uint32_t res = x_val - borrow;
542 uint32_t next_borrow = (x_val < borrow);
543 next_borrow += (res < y_val);
545 temp_sub[count] = res;
546 borrow = next_borrow;
551 uint32_t is_ge = launder32(carry) | (1 - launder32(borrow));
554 for (; launderw(count) < word_len; count = launderw(count) + 1) {
555#ifdef OT_PLATFORM_RV32
556 dest[count] = rv32_sel(is_ge, temp_sub[count], temp_add[count]);
558 uint32_t mask = ~(is_ge - 1);
560 mask = launder32(mask);
561 dest[count] = (temp_sub[count] & launder32(mask)) |
562 (temp_add[count] & launder32(~mask));
567 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
570status_t hardened_range_check(
const uint32_t *value,
const uint32_t *N,
573 uint32_t is_zero_acc = 0;
576 for (; launderw(count) < word_len; count = launderw(count) + 1) {
577 uint32_t val_word = value[count];
578 uint32_t n_word = N[count];
581 is_zero_acc = launder32(is_zero_acc) | launder32(val_word);
583#ifdef OT_PLATFORM_RV32
584 (void)rv32_subc(val_word, n_word, &borrow);
587 uint32_t res = val_word - borrow;
588 uint32_t next_borrow = (val_word < borrow);
589 next_borrow += (res < n_word);
591 borrow = next_borrow;
596 uint32_t is_zero = (launder32(is_zero_acc) == 0);
597 uint32_t is_greater_or_eq = (launder32(borrow) == 0);
598 uint32_t is_bad = launder32(is_zero) | launder32(is_greater_or_eq);
600 if (launder32(is_bad) != 0) {
602 .value = (int32_t)launder32((uint32_t)OTCRYPTO_BAD_ARGS.value)};
606 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};
609status_t hardened_mod_reduce(
const uint32_t *value,
const uint32_t *n,
610 size_t word_len, uint32_t *result) {
617 uint32_t r[2 * word_len];
619 uint32_t r_sub[2 * word_len];
624 for (; launderw(i) < 2 * word_len; i = launderw(i) + 1) {
632 for (; launderw(i) > 0; i = launderw(i) - 1) {
633 size_t bit_idx = i - 1;
634 size_t word_idx = bit_idx >> 5;
635 size_t bit_in_word = bit_idx % 32;
640 for (; launderw(j) < 2 * word_len; j = launderw(j) + 1) {
641 uint32_t next_carry = (r[j] >> 31);
642 r[j] = (r[j] << 1) | carry;
648 uint32_t bit = (value[word_idx] >> bit_in_word) & 1;
649 r[0] = r[0] ^ ((r[0] ^ bit) & 1);
654 for (; launderw(j) < word_len; j = launderw(j) + 1) {
655#ifdef OT_PLATFORM_RV32
656 r_sub[j] = rv32_subc(r[j], n[j], &borrow);
658 uint32_t r_word = r[j];
659 uint32_t n_word = n[j];
660 uint32_t res = r_word - borrow;
661 uint32_t next_borrow = (r_word < borrow);
662 next_borrow |= (res < n_word);
665 borrow = next_borrow;
672 for (; launderw(j) < 2 * word_len; j = launderw(j) + 1) {
673#ifdef OT_PLATFORM_RV32
674 r_sub[j] = rv32_subc(r[j], 0, &borrow);
676 uint32_t res = r[j] - borrow;
677 borrow = (r[j] < borrow);
685#ifdef OT_PLATFORM_RV32
686 uint32_t cond = launder32(1 - launder32(borrow));
688 uint32_t mask = borrow - 1;
690 mask = launder32(mask);
694 for (; launderw(j) < 2 * word_len; j = launderw(j) + 1) {
695#ifdef OT_PLATFORM_RV32
696 r[j] = rv32_sel(cond, r_sub[j], r[j]);
698 r[j] = (r_sub[j] & launder32(mask)) | (r[j] & launder32(~mask));
707 TRY(hardened_memcpy(result, r, word_len));
709 return (status_t){.value = (int32_t)launder32((uint32_t)OTCRYPTO_OK.value)};