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