1 /*
2  * Multi-precision integer library
3  * ESP32 H2 hardware accelerated parts based on mbedTLS implementation
4  *
5  * SPDX-FileCopyrightText: The Mbed TLS Contributors
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  *
9  * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD
10  */
11 #include <string.h>
12 #include <sys/param.h>
13 #include "soc/hwcrypto_periph.h"
14 #include "esp_private/periph_ctrl.h"
15 #include "mbedtls/bignum.h"
16 #include "bignum_impl.h"
17 #include "soc/pcr_reg.h"
18 #include "soc/periph_defs.h"
19 #include "soc/system_reg.h"
20 #include "esp_crypto_lock.h"
21 
22 
esp_mpi_hardware_words(size_t words)23 size_t esp_mpi_hardware_words(size_t words)
24 {
25     return words;
26 }
27 
esp_mpi_enable_hardware_hw_op(void)28 void esp_mpi_enable_hardware_hw_op( void )
29 {
30     esp_crypto_mpi_lock_acquire();
31 
32     /* Enable RSA hardware */
33     periph_module_enable(PERIPH_RSA_MODULE);
34 
35     REG_CLR_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_PD);
36 
37     while (REG_READ(RSA_QUERY_CLEAN_REG) != 1) {
38     }
39     // Note: from enabling RSA clock to here takes about 1.3us
40 
41     REG_WRITE(RSA_INT_ENA_REG, 0);
42 }
43 
esp_mpi_disable_hardware_hw_op(void)44 void esp_mpi_disable_hardware_hw_op( void )
45 {
46     REG_SET_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_PD);
47 
48     /* Disable RSA hardware */
49     periph_module_disable(PERIPH_RSA_MODULE);
50 
51     esp_crypto_mpi_lock_release();
52 }
53 
esp_mpi_interrupt_enable(bool enable)54 void esp_mpi_interrupt_enable( bool enable )
55 {
56     REG_WRITE(RSA_INT_ENA_REG, enable);
57 }
58 
esp_mpi_interrupt_clear(void)59 void esp_mpi_interrupt_clear( void )
60 {
61     REG_WRITE(RSA_INT_CLR_REG, 1);
62 }
63 
64 /* Copy mbedTLS MPI bignum 'mpi' to hardware memory block at 'mem_base'.
65 
66    If num_words is higher than the number of words in the bignum then
67    these additional words will be zeroed in the memory buffer.
68 */
mpi_to_mem_block(uint32_t mem_base,const mbedtls_mpi * mpi,size_t num_words)69 static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words)
70 {
71     uint32_t *pbase = (uint32_t *)mem_base;
72     uint32_t copy_words = MIN(num_words, mpi->MBEDTLS_PRIVATE(n));
73 
74     /* Copy MPI data to memory block registers */
75     for (int i = 0; i < copy_words; i++) {
76         pbase[i] = mpi->MBEDTLS_PRIVATE(p)[i];
77     }
78 
79     /* Zero any remaining memory block data */
80     for (int i = copy_words; i < num_words; i++) {
81         pbase[i] = 0;
82     }
83 }
84 
85 /* Read mbedTLS MPI bignum back from hardware memory block.
86 
87    Reads num_words words from block.
88 */
mem_block_to_mpi(mbedtls_mpi * x,uint32_t mem_base,int num_words)89 static inline void mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words)
90 {
91 
92     /* Copy data from memory block registers */
93     const size_t REG_WIDTH = sizeof(uint32_t);
94     for (size_t i = 0; i < num_words; i++) {
95         x->MBEDTLS_PRIVATE(p)[i] = REG_READ(mem_base + (i * REG_WIDTH));
96     }
97     /* Zero any remaining limbs in the bignum, if the buffer is bigger
98        than num_words */
99     for (size_t i = num_words; i < x->MBEDTLS_PRIVATE(n); i++) {
100         x->MBEDTLS_PRIVATE(p)[i] = 0;
101     }
102 }
103 
104 
105 
106 /* Begin an RSA operation. op_reg specifies which 'START' register
107    to write to.
108 */
start_op(uint32_t op_reg)109 static inline void start_op(uint32_t op_reg)
110 {
111     /* Clear interrupt status */
112     REG_WRITE(RSA_INT_CLR_REG, 1);
113 
114     /* Note: above REG_WRITE includes a memw, so we know any writes
115        to the memory blocks are also complete. */
116 
117     REG_WRITE(op_reg, 1);
118 }
119 
120 /* Wait for an RSA operation to complete.
121 */
wait_op_complete(void)122 static inline void wait_op_complete(void)
123 {
124     while (REG_READ(RSA_QUERY_IDLE_REG) != 1)
125     { }
126 
127     /* clear the interrupt */
128     REG_WRITE(RSA_INT_CLR_REG, 1);
129 }
130 
131 
132 /* Read result from last MPI operation */
esp_mpi_read_result_hw_op(mbedtls_mpi * Z,size_t z_words)133 void esp_mpi_read_result_hw_op(mbedtls_mpi *Z, size_t z_words)
134 {
135     wait_op_complete();
136     mem_block_to_mpi(Z, RSA_Z_MEM_REG, z_words);
137 }
138 
139 
140 /* Z = (X * Y) mod M
141 
142    Not an mbedTLS function
143 */
esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi * X,const mbedtls_mpi * Y,const mbedtls_mpi * M,const mbedtls_mpi * Rinv,mbedtls_mpi_uint Mprime,size_t num_words)144 void esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t num_words)
145 {
146     REG_WRITE(RSA_MODE_REG, (num_words - 1));
147 
148     /* Load M, X, Rinv, Mprime (Mprime is mod 2^32) */
149     mpi_to_mem_block(RSA_X_MEM_REG, X, num_words);
150     mpi_to_mem_block(RSA_Y_MEM_REG, Y, num_words);
151     mpi_to_mem_block(RSA_M_MEM_REG, M, num_words);
152     mpi_to_mem_block(RSA_Z_MEM_REG, Rinv, num_words);
153     REG_WRITE(RSA_M_PRIME_REG, Mprime);
154 
155     start_op(RSA_SET_START_MODMULT_REG);
156 }
157 
158 /* Z = (X ^ Y) mod M
159 */
esp_mpi_exp_mpi_mod_hw_op(const mbedtls_mpi * X,const mbedtls_mpi * Y,const mbedtls_mpi * M,const mbedtls_mpi * Rinv,mbedtls_mpi_uint Mprime,size_t num_words)160 void esp_mpi_exp_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t num_words)
161 {
162     size_t y_bits = mbedtls_mpi_bitlen(Y);
163 
164     REG_WRITE(RSA_MODE_REG, (num_words - 1));
165 
166     /* Load M, X, Rinv, Mprime (Mprime is mod 2^32) */
167     mpi_to_mem_block(RSA_X_MEM_REG, X, num_words);
168     mpi_to_mem_block(RSA_Y_MEM_REG, Y, num_words);
169     mpi_to_mem_block(RSA_M_MEM_REG, M, num_words);
170     mpi_to_mem_block(RSA_Z_MEM_REG, Rinv, num_words);
171     REG_WRITE(RSA_M_PRIME_REG, Mprime);
172 
173     /* Enable acceleration options */
174     REG_WRITE(RSA_CONSTANT_TIME_REG, 0);
175     REG_WRITE(RSA_SEARCH_ENABLE_REG, 1);
176     REG_WRITE(RSA_SEARCH_POS_REG, y_bits - 1);
177 
178     /* Execute first stage montgomery multiplication */
179     start_op(RSA_SET_START_MODEXP_REG);
180 
181     REG_WRITE(RSA_SEARCH_ENABLE_REG, 0);
182 }
183 
184 
185 /* Z = X * Y */
esp_mpi_mul_mpi_hw_op(const mbedtls_mpi * X,const mbedtls_mpi * Y,size_t num_words)186 void esp_mpi_mul_mpi_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words)
187 {
188     /* Copy X (right-extended) & Y (left-extended) to memory block */
189     mpi_to_mem_block(RSA_X_MEM_REG, X, num_words);
190     mpi_to_mem_block(RSA_Z_MEM_REG + num_words * 4, Y, num_words);
191     /* NB: as Y is left-exte, we don't zero the bottom words_mult words of Y block.
192        This is OK for now bec zeroing is done by hardware when we do esp_mpi_acquire_hardware().
193     */
194     REG_WRITE(RSA_MODE_REG, (num_words * 2 - 1));
195     start_op(RSA_SET_START_MULT_REG);
196 }
197 
198 
199 
200 /**
201  * @brief Special-case of (X * Y), where we use hardware montgomery mod
202    multiplication to calculate result where either A or B are >2048 bits so
203    can't use the standard multiplication method.
204  *
205  */
esp_mpi_mult_mpi_failover_mod_mult_hw_op(const mbedtls_mpi * X,const mbedtls_mpi * Y,size_t num_words)206 void esp_mpi_mult_mpi_failover_mod_mult_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words)
207 {
208     /* M = 2^num_words - 1, so block is entirely FF */
209     for (int i = 0; i < num_words; i++) {
210         REG_WRITE(RSA_M_MEM_REG + i * 4, UINT32_MAX);
211     }
212 
213     /* Mprime = 1 */
214     REG_WRITE(RSA_M_PRIME_REG, 1);
215     REG_WRITE(RSA_MODE_REG, num_words - 1);
216 
217     /* Load X & Y */
218     mpi_to_mem_block(RSA_X_MEM_REG, X, num_words);
219     mpi_to_mem_block(RSA_Y_MEM_REG, Y, num_words);
220 
221     /* Rinv = 1, write first word */
222     REG_WRITE(RSA_Z_MEM_REG, 1);
223 
224     /* Zero out rest of the Rinv words */
225     for (int i = 1; i < num_words; i++) {
226         REG_WRITE(RSA_Z_MEM_REG + i * 4, 0);
227     }
228 
229     start_op(RSA_SET_START_MODMULT_REG);
230 }
231