esp_hal/rsa/
mod.rs

1//! # RSA (Rivest–Shamir–Adleman) accelerator.
2//!
3//! ## Overview
4//!
5//! The RSA accelerator provides hardware support for high precision computation
6//! used in various RSA asymmetric cipher algorithms by significantly reducing
7//! their software complexity. Compared with RSA algorithms implemented solely
8//! in software, this hardware accelerator can speed up RSA algorithms
9//! significantly.
10//!
11//! ## Configuration
12//!
13//! The RSA accelerator also supports operands of different lengths, which
14//! provides more flexibility during the computation.
15//!
16//! ## Examples
17//!
18//! ### Modular Exponentiation, Modular Multiplication, and Multiplication
19//! Visit the [RSA test suite] for an example of using the peripheral.
20//!
21//! [nb]: https://docs.rs/nb/1.1.0/nb/
22//! [RSA test suite]: https://github.com/esp-rs/esp-hal/blob/main/hil-test/tests/rsa.rs
23
24use core::{marker::PhantomData, ptr::copy_nonoverlapping};
25
26use crate::{
27    interrupt::InterruptHandler,
28    pac,
29    peripheral::{Peripheral, PeripheralRef},
30    peripherals::{Interrupt, RSA},
31    system::{Cpu, GenericPeripheralGuard, Peripheral as PeripheralEnable},
32    Async,
33    Blocking,
34};
35
36#[cfg_attr(esp32s2, path = "esp32sX.rs")]
37#[cfg_attr(esp32s3, path = "esp32sX.rs")]
38#[cfg_attr(esp32c3, path = "esp32cX.rs")]
39#[cfg_attr(esp32c6, path = "esp32cX.rs")]
40#[cfg_attr(esp32h2, path = "esp32cX.rs")]
41#[cfg_attr(esp32, path = "esp32.rs")]
42mod rsa_spec_impl;
43
44pub use rsa_spec_impl::operand_sizes;
45
46/// RSA peripheral container
47pub struct Rsa<'d, Dm: crate::DriverMode> {
48    rsa: PeripheralRef<'d, RSA>,
49    phantom: PhantomData<Dm>,
50    _guard: GenericPeripheralGuard<{ PeripheralEnable::Rsa as u8 }>,
51}
52
53impl<'d> Rsa<'d, Blocking> {
54    /// Create a new instance in [crate::Blocking] mode.
55    ///
56    /// Optionally an interrupt handler can be bound.
57    pub fn new(rsa: impl Peripheral<P = RSA> + 'd) -> Self {
58        Self::new_internal(rsa)
59    }
60
61    /// Reconfigures the RSA driver to operate in asynchronous mode.
62    pub fn into_async(mut self) -> Rsa<'d, Async> {
63        self.set_interrupt_handler(asynch::rsa_interrupt_handler);
64        Rsa {
65            rsa: self.rsa,
66            phantom: PhantomData,
67            _guard: self._guard,
68        }
69    }
70
71    /// Registers an interrupt handler for the RSA peripheral.
72    ///
73    /// Note that this will replace any previously registered interrupt
74    /// handlers.
75    #[instability::unstable]
76    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
77        for core in crate::system::Cpu::other() {
78            crate::interrupt::disable(core, Interrupt::RSA);
79        }
80        unsafe { crate::interrupt::bind_interrupt(Interrupt::RSA, handler.handler()) };
81        unwrap!(crate::interrupt::enable(Interrupt::RSA, handler.priority()));
82    }
83}
84
85impl crate::private::Sealed for Rsa<'_, Blocking> {}
86
87#[instability::unstable]
88impl crate::interrupt::InterruptConfigurable for Rsa<'_, Blocking> {
89    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
90        self.set_interrupt_handler(handler);
91    }
92}
93
94impl<'d> Rsa<'d, Async> {
95    /// Create a new instance in [crate::Blocking] mode.
96    pub fn into_blocking(self) -> Rsa<'d, Blocking> {
97        crate::interrupt::disable(Cpu::current(), Interrupt::RSA);
98        Rsa {
99            rsa: self.rsa,
100            phantom: PhantomData,
101            _guard: self._guard,
102        }
103    }
104}
105
106impl<'d, Dm: crate::DriverMode> Rsa<'d, Dm> {
107    fn new_internal(rsa: impl Peripheral<P = RSA> + 'd) -> Self {
108        crate::into_ref!(rsa);
109
110        let guard = GenericPeripheralGuard::new();
111
112        Self {
113            rsa,
114            phantom: PhantomData,
115            _guard: guard,
116        }
117    }
118
119    fn regs(&self) -> &pac::rsa::RegisterBlock {
120        self.rsa.register_block()
121    }
122
123    fn write_operand_b<const N: usize>(&mut self, operand_b: &[u32; N]) {
124        unsafe { copy_nonoverlapping(operand_b.as_ptr(), self.regs().y_mem(0).as_ptr(), N) };
125    }
126
127    fn write_modulus<const N: usize>(&mut self, modulus: &[u32; N]) {
128        unsafe { copy_nonoverlapping(modulus.as_ptr(), self.regs().m_mem(0).as_ptr(), N) };
129    }
130
131    fn write_mprime(&mut self, m_prime: u32) {
132        self.regs().m_prime().write(|w| unsafe { w.bits(m_prime) });
133    }
134
135    fn write_operand_a<const N: usize>(&mut self, operand_a: &[u32; N]) {
136        unsafe { copy_nonoverlapping(operand_a.as_ptr(), self.regs().x_mem(0).as_ptr(), N) };
137    }
138
139    fn write_multi_operand_b<const N: usize>(&mut self, operand_b: &[u32; N]) {
140        unsafe { copy_nonoverlapping(operand_b.as_ptr(), self.regs().z_mem(0).as_ptr().add(N), N) };
141    }
142
143    fn write_r<const N: usize>(&mut self, r: &[u32; N]) {
144        unsafe { copy_nonoverlapping(r.as_ptr(), self.regs().z_mem(0).as_ptr(), N) };
145    }
146
147    fn read_out<const N: usize>(&self, outbuf: &mut [u32; N]) {
148        unsafe {
149            copy_nonoverlapping(
150                self.regs().z_mem(0).as_ptr() as *const u32,
151                outbuf.as_ptr() as *mut u32,
152                N,
153            );
154        }
155    }
156    fn wait_for_idle(&mut self) {
157        while !self.is_idle() {}
158        self.clear_interrupt();
159    }
160
161    fn read_results<const N: usize>(&mut self, outbuf: &mut [u32; N]) {
162        self.wait_for_idle();
163        self.read_out(outbuf);
164    }
165}
166
167/// Defines the input size of an RSA operation.
168pub trait RsaMode: crate::private::Sealed {
169    /// The input data type used for the operation.
170    type InputType;
171}
172
173/// Defines the output type of RSA multiplications.
174pub trait Multi: RsaMode {
175    /// The type of the output produced by the operation.
176    type OutputType;
177}
178
179macro_rules! implement_op {
180    (($x:literal, multi)) => {
181        paste! {
182            #[doc = concat!($x, "-bit RSA operation.")]
183            pub struct [<Op $x>];
184
185            impl Multi for [<Op $x>] {
186                type OutputType = [u32; $x * 2 / 32];
187            }
188
189            impl crate::private::Sealed for [<Op $x>] {}
190
191            impl RsaMode for [<Op $x>] {
192                type InputType = [u32; $x / 32];
193            }
194        }
195    };
196
197    (($x:literal)) => {
198        paste! {
199            /// Represents an RSA operation for the given bit size.
200            pub struct [<Op $x>];
201
202            impl crate::private::Sealed for [<Op $x>] {}
203
204            impl RsaMode for [<Op $x>] {
205                type InputType = [u32; $x / 32];
206            }
207        }
208    };
209
210    ($x:tt, $($y:tt),+) => {
211        implement_op!($x);
212        implement_op!($($y),+);
213    };
214}
215
216use implement_op;
217
218/// Support for RSA peripheral's modular exponentiation feature that could be
219/// used to find the `(base ^ exponent) mod modulus`.
220///
221/// Each operand is a little endian byte array of the same size
222pub struct RsaModularExponentiation<'a, 'd, T: RsaMode, Dm: crate::DriverMode> {
223    rsa: &'a mut Rsa<'d, Dm>,
224    phantom: PhantomData<T>,
225}
226
227impl<'a, 'd, T: RsaMode, Dm: crate::DriverMode, const N: usize>
228    RsaModularExponentiation<'a, 'd, T, Dm>
229where
230    T: RsaMode<InputType = [u32; N]>,
231{
232    /// Creates an instance of `RsaModularExponentiation`.
233    ///
234    /// `m_prime` could be calculated using `-(modular multiplicative inverse of
235    /// modulus) mod 2^32`.
236    ///
237    /// For more information refer to 24.3.2 of <https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>.
238    pub fn new(
239        rsa: &'a mut Rsa<'d, Dm>,
240        exponent: &T::InputType,
241        modulus: &T::InputType,
242        m_prime: u32,
243    ) -> Self {
244        Self::write_mode(rsa);
245        rsa.write_operand_b(exponent);
246        rsa.write_modulus(modulus);
247        rsa.write_mprime(m_prime);
248
249        #[cfg(not(esp32))]
250        if rsa.is_search_enabled() {
251            rsa.write_search_position(Self::find_search_pos(exponent));
252        }
253
254        Self {
255            rsa,
256            phantom: PhantomData,
257        }
258    }
259
260    fn set_up_exponentiation(&mut self, base: &T::InputType, r: &T::InputType) {
261        self.rsa.write_operand_a(base);
262        self.rsa.write_r(r);
263    }
264
265    /// Starts the modular exponentiation operation.
266    ///
267    /// `r` can be calculated using `2 ^ ( bitlength * 2 ) mod modulus`.
268    ///
269    /// For more information refer to 24.3.2 of <https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>.
270    pub fn start_exponentiation(&mut self, base: &T::InputType, r: &T::InputType) {
271        self.set_up_exponentiation(base, r);
272        self.rsa.write_modexp_start();
273    }
274
275    /// Reads the result to the given buffer.
276    ///
277    /// This is a non blocking function that returns without an error if
278    /// operation is completed successfully. `start_exponentiation` must be
279    /// called before calling this function.
280    pub fn read_results(&mut self, outbuf: &mut T::InputType) {
281        self.rsa.read_results(outbuf);
282    }
283}
284
285/// Support for RSA peripheral's modular multiplication feature that could be
286/// used to find the `(operand a * operand b) mod modulus`.
287///
288/// Each operand is a little endian byte array of the same size
289pub struct RsaModularMultiplication<'a, 'd, T: RsaMode, Dm: crate::DriverMode> {
290    rsa: &'a mut Rsa<'d, Dm>,
291    phantom: PhantomData<T>,
292}
293
294impl<'a, 'd, T: RsaMode, Dm: crate::DriverMode, const N: usize>
295    RsaModularMultiplication<'a, 'd, T, Dm>
296where
297    T: RsaMode<InputType = [u32; N]>,
298{
299    /// Creates an instance of `RsaModularMultiplication`.
300    ///
301    /// - `r` can be calculated using `2 ^ ( bitlength * 2 ) mod modulus`.
302    /// - `m_prime` can be calculated using `-(modular multiplicative inverse of
303    ///   modulus) mod 2^32`.
304    ///
305    /// For more information refer to 20.3.1 of <https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf>.
306    pub fn new(
307        rsa: &'a mut Rsa<'d, Dm>,
308        operand_a: &T::InputType,
309        modulus: &T::InputType,
310        r: &T::InputType,
311        m_prime: u32,
312    ) -> Self {
313        Self::write_mode(rsa);
314        rsa.write_mprime(m_prime);
315        rsa.write_modulus(modulus);
316        rsa.write_operand_a(operand_a);
317        rsa.write_r(r);
318
319        Self {
320            rsa,
321            phantom: PhantomData,
322        }
323    }
324
325    /// Starts the modular multiplication operation.
326    ///
327    /// For more information refer to 19.3.1 of <https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf>.
328    pub fn start_modular_multiplication(&mut self, operand_b: &T::InputType) {
329        self.set_up_modular_multiplication(operand_b);
330        self.rsa.write_modmulti_start();
331    }
332
333    /// Reads the result to the given buffer.
334    /// This is a non blocking function that returns without an error if
335    /// operation is completed successfully.
336    pub fn read_results(&mut self, outbuf: &mut T::InputType) {
337        self.rsa.read_results(outbuf);
338    }
339}
340
341/// Support for RSA peripheral's large number multiplication feature that could
342/// be used to find the `operand a * operand b`.
343///
344/// Each operand is a little endian byte array of the same size
345pub struct RsaMultiplication<'a, 'd, T: RsaMode + Multi, Dm: crate::DriverMode> {
346    rsa: &'a mut Rsa<'d, Dm>,
347    phantom: PhantomData<T>,
348}
349
350impl<'a, 'd, T: RsaMode + Multi, Dm: crate::DriverMode, const N: usize>
351    RsaMultiplication<'a, 'd, T, Dm>
352where
353    T: RsaMode<InputType = [u32; N]>,
354{
355    /// Creates an instance of `RsaMultiplication`.
356    pub fn new(rsa: &'a mut Rsa<'d, Dm>, operand_a: &T::InputType) -> Self {
357        Self::write_mode(rsa);
358        rsa.write_operand_a(operand_a);
359
360        Self {
361            rsa,
362            phantom: PhantomData,
363        }
364    }
365
366    /// Starts the multiplication operation.
367    pub fn start_multiplication(&mut self, operand_b: &T::InputType) {
368        self.set_up_multiplication(operand_b);
369        self.rsa.write_multi_start();
370    }
371
372    /// Reads the result to the given buffer.
373    /// This is a non blocking function that returns without an error if
374    /// operation is completed successfully. `start_multiplication` must be
375    /// called before calling this function.
376    pub fn read_results<const O: usize>(&mut self, outbuf: &mut T::OutputType)
377    where
378        T: Multi<OutputType = [u32; O]>,
379    {
380        self.rsa.read_results(outbuf);
381    }
382}
383
384/// Async functionality
385pub(crate) mod asynch {
386    use core::task::Poll;
387
388    use portable_atomic::{AtomicBool, Ordering};
389    use procmacros::handler;
390
391    use crate::{
392        asynch::AtomicWaker,
393        peripherals::RSA,
394        rsa::{
395            Multi,
396            Rsa,
397            RsaMode,
398            RsaModularExponentiation,
399            RsaModularMultiplication,
400            RsaMultiplication,
401        },
402        Async,
403    };
404
405    static WAKER: AtomicWaker = AtomicWaker::new();
406
407    static SIGNALED: AtomicBool = AtomicBool::new(false);
408
409    /// `Future` that waits for the RSA operation to complete.
410    #[must_use = "futures do nothing unless you `.await` or poll them"]
411    struct RsaFuture<'a, 'd> {
412        #[cfg_attr(esp32, allow(dead_code))]
413        driver: &'a Rsa<'d, Async>,
414    }
415
416    impl<'a, 'd> RsaFuture<'a, 'd> {
417        fn new(driver: &'a Rsa<'d, Async>) -> Self {
418            SIGNALED.store(false, Ordering::Relaxed);
419
420            #[cfg(not(esp32))]
421            driver.regs().int_ena().write(|w| w.int_ena().set_bit());
422
423            Self { driver }
424        }
425
426        fn is_done(&self) -> bool {
427            SIGNALED.load(Ordering::Acquire)
428        }
429    }
430
431    impl Drop for RsaFuture<'_, '_> {
432        fn drop(&mut self) {
433            #[cfg(not(esp32))]
434            self.driver
435                .regs()
436                .int_ena()
437                .write(|w| w.int_ena().clear_bit());
438        }
439    }
440
441    impl core::future::Future for RsaFuture<'_, '_> {
442        type Output = ();
443
444        fn poll(
445            self: core::pin::Pin<&mut Self>,
446            cx: &mut core::task::Context<'_>,
447        ) -> core::task::Poll<Self::Output> {
448            WAKER.register(cx.waker());
449            if self.is_done() {
450                Poll::Ready(())
451            } else {
452                Poll::Pending
453            }
454        }
455    }
456
457    impl<T: RsaMode, const N: usize> RsaModularExponentiation<'_, '_, T, Async>
458    where
459        T: RsaMode<InputType = [u32; N]>,
460    {
461        /// Asynchronously performs an RSA modular exponentiation operation.
462        pub async fn exponentiation(
463            &mut self,
464            base: &T::InputType,
465            r: &T::InputType,
466            outbuf: &mut T::InputType,
467        ) {
468            self.set_up_exponentiation(base, r);
469            let fut = RsaFuture::new(self.rsa);
470            self.rsa.write_modexp_start();
471            fut.await;
472            self.rsa.read_out(outbuf);
473        }
474    }
475
476    impl<T: RsaMode, const N: usize> RsaModularMultiplication<'_, '_, T, Async>
477    where
478        T: RsaMode<InputType = [u32; N]>,
479    {
480        /// Asynchronously performs an RSA modular multiplication operation.
481        pub async fn modular_multiplication(
482            &mut self,
483            operand_b: &T::InputType,
484            outbuf: &mut T::InputType,
485        ) {
486            cfg_if::cfg_if! {
487                if #[cfg(esp32)] {
488                    let fut = RsaFuture::new(self.rsa);
489                    self.rsa.write_multi_start();
490                    fut.await;
491
492                    self.rsa.write_operand_a(operand_b);
493                } else {
494                    self.set_up_modular_multiplication(operand_b);
495                }
496            }
497
498            let fut = RsaFuture::new(self.rsa);
499            self.rsa.write_modmulti_start();
500            fut.await;
501            self.rsa.read_out(outbuf);
502        }
503    }
504
505    impl<T: RsaMode + Multi, const N: usize> RsaMultiplication<'_, '_, T, Async>
506    where
507        T: RsaMode<InputType = [u32; N]>,
508    {
509        /// Asynchronously performs an RSA multiplication operation.
510        pub async fn multiplication<const O: usize>(
511            &mut self,
512            operand_b: &T::InputType,
513            outbuf: &mut T::OutputType,
514        ) where
515            T: Multi<OutputType = [u32; O]>,
516        {
517            self.set_up_multiplication(operand_b);
518            let fut = RsaFuture::new(self.rsa);
519            self.rsa.write_multi_start();
520            fut.await;
521            self.rsa.read_out(outbuf);
522        }
523    }
524
525    #[handler]
526    /// Interrupt handler for RSA.
527    pub(super) fn rsa_interrupt_handler() {
528        let rsa = RSA::regs();
529        SIGNALED.store(true, Ordering::Release);
530        cfg_if::cfg_if! {
531            if #[cfg(esp32)] {
532                rsa.interrupt().write(|w| w.interrupt().set_bit());
533            } else  {
534                rsa.int_clr().write(|w| w.int_clr().set_bit());
535            }
536        }
537
538        WAKER.wake();
539    }
540}