1 /* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2  * SPDX-License-Identifier: Apache-2.0"
3  *
4  * Written by Nir Drucker and Shay Gueron
5  * AWS Cryptographic Algorithms Group.
6  * (ndrucker@amazon.com, gueron@amazon.com)
7  */
8 
9 #include "sampling.h"
10 #include <assert.h>
11 #include <string.h>
12 
13 _INLINE_ ret_t
get_rand_mod_len(OUT uint32_t * rand_pos,IN const uint32_t len,IN OUT aes_ctr_prf_state_t * prf_state)14 get_rand_mod_len(OUT uint32_t *    rand_pos,
15                  IN const uint32_t len,
16                  IN OUT aes_ctr_prf_state_t *prf_state)
17 {
18   const uint64_t mask = MASK(bit_scan_reverse(len));
19 
20   do
21   {
22     // Generate 128bit of random numbers
23     POSIX_GUARD(aes_ctr_prf((uint8_t *)rand_pos, prf_state, sizeof(*rand_pos)));
24 
25     // Mask only relevant bits
26     (*rand_pos) &= mask;
27 
28     // Break if a number smaller than len is found
29     if((*rand_pos) < len)
30     {
31       break;
32     }
33 
34   } while(1);
35 
36   return SUCCESS;
37 }
38 
39 _INLINE_ void
make_odd_weight(IN OUT r_t * r)40 make_odd_weight(IN OUT r_t *r)
41 {
42   if(((r_bits_vector_weight(r) % 2) == 1))
43   {
44     // Already odd
45     return;
46   }
47 
48   r->raw[0] ^= 1;
49 }
50 
51 // IN: must_be_odd - 1 true, 0 not
52 ret_t
sample_uniform_r_bits_with_fixed_prf_context(OUT r_t * r,IN OUT aes_ctr_prf_state_t * prf_state,IN const must_be_odd_t must_be_odd)53 sample_uniform_r_bits_with_fixed_prf_context(OUT r_t *r,
54                                              IN OUT
55                                                  aes_ctr_prf_state_t *prf_state,
56                                              IN const must_be_odd_t   must_be_odd)
57 {
58   // Generate random data
59   POSIX_GUARD(aes_ctr_prf(r->raw, prf_state, R_SIZE));
60 
61   // Mask upper bits of the MSByte
62   r->raw[R_SIZE - 1] &= MASK(R_BITS + 8 - (R_SIZE * 8));
63 
64   if(must_be_odd == MUST_BE_ODD)
65   {
66     make_odd_weight(r);
67   }
68 
69   return SUCCESS;
70 }
71 
72 _INLINE_ int
is_new(IN const idx_t wlist[],IN const uint32_t ctr)73 is_new(IN const idx_t wlist[], IN const uint32_t ctr)
74 {
75   for(uint32_t i = 0; i < ctr; i++)
76   {
77     if(wlist[i] == wlist[ctr])
78     {
79       return 0;
80     }
81   }
82 
83   return 1;
84 }
85 
86 // Assumption 1) paddded_len % 64 = 0!
87 // Assumption 2) a is a len bits array. It is padded to be a padded_len
88 //               bytes array. The padded area may be modified and should
89 //               be ignored outside the function scope.
90 ret_t
generate_sparse_rep(OUT uint64_t * a,OUT idx_t wlist[],IN const uint32_t weight,IN const uint32_t len,IN const uint32_t padded_len,IN OUT aes_ctr_prf_state_t * prf_state)91 generate_sparse_rep(OUT uint64_t *    a,
92                     OUT idx_t         wlist[],
93                     IN const uint32_t weight,
94                     IN const uint32_t len,
95                     IN const uint32_t padded_len,
96                     IN OUT aes_ctr_prf_state_t *prf_state)
97 {
98   assert(padded_len % 64 == 0);
99   // Bits comparison
100   assert((padded_len * 8) >= len);
101 
102   uint64_t ctr = 0;
103 
104   // Generate weight rand numbers
105   do
106   {
107     POSIX_GUARD(get_rand_mod_len(&wlist[ctr], len, prf_state));
108     ctr += is_new(wlist, ctr);
109   } while(ctr < weight);
110 
111   // Initialize to zero
112   memset(a, 0, (len + 7) >> 3);
113 
114   // Assign values to "a"
115   secure_set_bits(a, wlist, padded_len, weight);
116 
117   return SUCCESS;
118 }
119