Skip to main content

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
16use core::{marker::PhantomData, ptr::NonNull, task::Poll};
17
18use portable_atomic::{AtomicBool, Ordering};
19use procmacros::{handler, ram};
20
21use crate::{
22    Async,
23    Blocking,
24    DriverMode,
25    asynch::AtomicWaker,
26    interrupt::InterruptHandler,
27    pac,
28    peripherals::RSA,
29    system::{GenericPeripheralGuard, Peripheral as PeripheralEnable},
30    trm_markdown_link,
31    work_queue::{self, Status, VTable, WorkQueue, WorkQueueDriver, WorkQueueFrontend},
32};
33
34/// RSA peripheral driver.
35pub struct Rsa<'d, Dm: DriverMode> {
36    rsa: RSA<'d>,
37    phantom: PhantomData<Dm>,
38    _guard: RsaGuard,
39}
40
41// There are two distinct peripheral versions: ESP32, and all else. There is a naming split in the
42// later devices, and they use different (memory size, operand size increment) parameters, but they
43// are largely the same.
44
45/// How many words are there in an operand size increment.
46///
47/// I.e. if the RSA hardware works with operands of 512, 1024, 1536, ... bits, the increment is 512
48/// bits, or 16 words.
49const WORDS_PER_INCREMENT: u32 = property!("rsa.size_increment") / 32;
50
51struct RsaGuard {
52    _guard: GenericPeripheralGuard<{ PeripheralEnable::Rsa as u8 }>,
53}
54
55impl RsaGuard {
56    fn new() -> Self {
57        let _guard = GenericPeripheralGuard::new();
58        #[cfg(not(esp32))]
59        crate::peripherals::SYSTEM::regs()
60            .rsa_pd_ctrl()
61            .modify(|_, w| {
62                w.rsa_mem_force_pd().clear_bit();
63                w.rsa_mem_force_pu().set_bit();
64                w.rsa_mem_pd().clear_bit()
65            });
66        Self { _guard }
67    }
68}
69
70impl Drop for RsaGuard {
71    fn drop(&mut self) {
72        unsafe {
73            // Stopping the peripheral's clock source pends an interrupt. Since the clocks
74            // are stopped when the handler runs, we're not able to clear the interrupt flag,
75            // which means the interrupt handler keeps getting triggered indefinitely.
76            // To prevent this, we disable interrupts manually before stopping the peripheral.
77            crate::peripherals::RSA::steal().disable_peri_interrupt_on_all_cores();
78        }
79        #[cfg(not(esp32))]
80        crate::peripherals::SYSTEM::regs()
81            .rsa_pd_ctrl()
82            .modify(|_, w| {
83                w.rsa_mem_force_pd().clear_bit();
84                w.rsa_mem_force_pu().clear_bit();
85                w.rsa_mem_pd().set_bit()
86            });
87    }
88}
89
90impl<'d> Rsa<'d, Blocking> {
91    /// Create a new instance in [Blocking] mode.
92    ///
93    /// Optionally an interrupt handler can be bound.
94    pub fn new(rsa: RSA<'d>) -> Self {
95        let this = Self {
96            rsa,
97            phantom: PhantomData,
98            _guard: RsaGuard::new(),
99        };
100
101        while !this.ready() {}
102
103        this
104    }
105
106    /// Reconfigures the RSA driver to operate in asynchronous mode.
107    pub fn into_async(mut self) -> Rsa<'d, Async> {
108        self.set_interrupt_handler(rsa_interrupt_handler);
109        self.enable_disable_interrupt(true);
110
111        Rsa {
112            rsa: self.rsa,
113            phantom: PhantomData,
114            _guard: self._guard,
115        }
116    }
117
118    /// Enables/disables rsa interrupt.
119    ///
120    /// When enabled rsa peripheral would generate an interrupt when a operation
121    /// is finished.
122    pub fn enable_disable_interrupt(&mut self, enable: bool) {
123        self.internal_enable_disable_interrupt(enable);
124    }
125
126    /// Registers an interrupt handler for the RSA peripheral.
127    ///
128    /// Note that this will replace any previously registered interrupt
129    /// handlers.
130    #[instability::unstable]
131    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
132        self.rsa.disable_peri_interrupt_on_all_cores();
133        self.rsa.bind_peri_interrupt(handler);
134    }
135}
136
137impl crate::private::Sealed for Rsa<'_, Blocking> {}
138
139#[instability::unstable]
140impl crate::interrupt::InterruptConfigurable for Rsa<'_, Blocking> {
141    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
142        self.set_interrupt_handler(handler);
143    }
144}
145
146impl<'d> Rsa<'d, Async> {
147    /// Create a new instance in [crate::Blocking] mode.
148    pub fn into_blocking(self) -> Rsa<'d, Blocking> {
149        self.internal_enable_disable_interrupt(false);
150        self.rsa.disable_peri_interrupt_on_all_cores();
151
152        Rsa {
153            rsa: self.rsa,
154            phantom: PhantomData,
155            _guard: self._guard,
156        }
157    }
158}
159
160impl<'d, Dm: DriverMode> Rsa<'d, Dm> {
161    fn internal_enable_disable_interrupt(&self, enable: bool) {
162        cfg_if::cfg_if! {
163            if #[cfg(esp32)] {
164                // Can't seem to actually disable the interrupt, but esp-idf still writes the register
165                self.regs().interrupt().write(|w| w.interrupt().bit(enable));
166            } else {
167                self.regs().int_ena().write(|w| w.int_ena().bit(enable));
168            }
169        }
170    }
171
172    fn regs(&self) -> &pac::rsa::RegisterBlock {
173        self.rsa.register_block()
174    }
175
176    /// After the RSA accelerator is released from reset, the memory blocks
177    /// needs to be initialized, only after that peripheral should be used.
178    /// This function would return without an error if the memory is
179    /// initialized.
180    fn ready(&self) -> bool {
181        cfg_if::cfg_if! {
182            if #[cfg(any(esp32, esp32s2, esp32s3))] {
183                self.regs().clean().read().clean().bit_is_set()
184            } else {
185                self.regs().query_clean().read().query_clean().bit_is_set()
186            }
187        }
188    }
189
190    /// Starts the modular exponentiation operation.
191    fn start_modexp(&self) {
192        cfg_if::cfg_if! {
193            if #[cfg(any(esp32, esp32s2, esp32s3))] {
194                self.regs()
195                    .modexp_start()
196                    .write(|w| w.modexp_start().set_bit());
197            } else {
198                self.regs()
199                    .set_start_modexp()
200                    .write(|w| w.set_start_modexp().set_bit());
201            }
202        }
203    }
204
205    /// Starts the multiplication operation.
206    fn start_multi(&self) {
207        cfg_if::cfg_if! {
208            if #[cfg(any(esp32, esp32s2, esp32s3))] {
209                self.regs().mult_start().write(|w| w.mult_start().set_bit());
210            } else {
211                self.regs()
212                    .set_start_mult()
213                    .write(|w| w.set_start_mult().set_bit());
214            }
215        }
216    }
217
218    /// Starts the modular multiplication operation.
219    fn start_modmulti(&self) {
220        cfg_if::cfg_if! {
221            if #[cfg(esp32)] {
222                // modular-ness is encoded in the multi_mode register value
223                self.start_multi();
224            } else if #[cfg(any(esp32s2, esp32s3))] {
225                self.regs()
226                    .modmult_start()
227                    .write(|w| w.modmult_start().set_bit());
228            } else {
229                self.regs()
230                    .set_start_modmult()
231                    .write(|w| w.set_start_modmult().set_bit());
232            }
233        }
234    }
235
236    /// Clears the RSA interrupt flag.
237    fn clear_interrupt(&mut self) {
238        cfg_if::cfg_if! {
239            if #[cfg(esp32)] {
240                self.regs().interrupt().write(|w| w.interrupt().set_bit());
241            } else {
242                self.regs().int_clr().write(|w| w.int_clr().set_bit());
243            }
244        }
245    }
246
247    /// Checks if the RSA peripheral is idle.
248    fn is_idle(&self) -> bool {
249        cfg_if::cfg_if! {
250            if #[cfg(esp32)] {
251                self.regs().interrupt().read().interrupt().bit_is_set()
252            } else if #[cfg(any(esp32s2, esp32s3))] {
253                self.regs().idle().read().idle().bit_is_set()
254            } else {
255                self.regs().query_idle().read().query_idle().bit_is_set()
256            }
257        }
258    }
259
260    fn wait_for_idle(&mut self) {
261        while !self.is_idle() {}
262        self.clear_interrupt();
263    }
264
265    /// Writes the result size of the multiplication.
266    fn write_multi_mode(&mut self, mode: u32, modular: bool) {
267        let mode = if cfg!(esp32) && !modular {
268            const NON_MODULAR: u32 = 8;
269            mode | NON_MODULAR
270        } else {
271            mode
272        };
273
274        cfg_if::cfg_if! {
275            if #[cfg(esp32)] {
276                self.regs().mult_mode().write(|w| unsafe { w.bits(mode) });
277            } else {
278                self.regs().mode().write(|w| unsafe { w.bits(mode) });
279            }
280        }
281    }
282
283    /// Writes the result size of the modular exponentiation.
284    fn write_modexp_mode(&mut self, mode: u32) {
285        cfg_if::cfg_if! {
286            if #[cfg(esp32)] {
287                self.regs().modexp_mode().write(|w| unsafe { w.bits(mode) });
288            } else {
289                self.regs().mode().write(|w| unsafe { w.bits(mode) });
290            }
291        }
292    }
293
294    fn write_operand_b(&mut self, operand: &[u32]) {
295        for (reg, op) in self.regs().y_mem_iter().zip(operand.iter().copied()) {
296            reg.write(|w| unsafe { w.bits(op) });
297        }
298    }
299
300    fn write_modulus(&mut self, modulus: &[u32]) {
301        for (reg, op) in self.regs().m_mem_iter().zip(modulus.iter().copied()) {
302            reg.write(|w| unsafe { w.bits(op) });
303        }
304    }
305
306    fn write_mprime(&mut self, m_prime: u32) {
307        self.regs().m_prime().write(|w| unsafe { w.bits(m_prime) });
308    }
309
310    fn write_operand_a(&mut self, operand: &[u32]) {
311        for (reg, op) in self.regs().x_mem_iter().zip(operand.iter().copied()) {
312            reg.write(|w| unsafe { w.bits(op) });
313        }
314    }
315
316    fn write_multi_operand_b(&mut self, operand: &[u32]) {
317        for (reg, op) in self
318            .regs()
319            .z_mem_iter()
320            .skip(operand.len())
321            .zip(operand.iter().copied())
322        {
323            reg.write(|w| unsafe { w.bits(op) });
324        }
325    }
326
327    fn write_r(&mut self, r: &[u32]) {
328        for (reg, op) in self.regs().z_mem_iter().zip(r.iter().copied()) {
329            reg.write(|w| unsafe { w.bits(op) });
330        }
331    }
332
333    fn read_out(&self, outbuf: &mut [u32]) {
334        for (reg, op) in self.regs().z_mem_iter().zip(outbuf.iter_mut()) {
335            *op = reg.read().bits();
336        }
337    }
338
339    fn read_results(&mut self, outbuf: &mut [u32]) {
340        self.wait_for_idle();
341        self.read_out(outbuf);
342    }
343
344    /// Enables/disables constant time operation.
345    ///
346    /// Disabling constant time operation increases the performance of modular
347    /// exponentiation by simplifying the calculation concerning the 0 bits
348    /// of the exponent. I.e. the less the Hamming weight, the greater the
349    /// performance.
350    ///
351    /// Note: this compromises security by enabling timing-based side-channel attacks.
352    ///
353    /// For more information refer to the
354    #[doc = trm_markdown_link!("rsa")]
355    #[cfg(not(esp32))]
356    pub fn disable_constant_time(&mut self, disable: bool) {
357        self.regs()
358            .constant_time()
359            .write(|w| w.constant_time().bit(disable));
360    }
361
362    /// Enables/disables search acceleration.
363    ///
364    /// When enabled it would increase the performance of modular
365    /// exponentiation by discarding the exponent's bits before the most
366    /// significant set bit.
367    ///
368    /// Note: this compromises security by effectively decreasing the key length.
369    ///
370    /// For more information refer to the
371    #[doc = trm_markdown_link!("rsa")]
372    #[cfg(not(esp32))]
373    pub fn search_acceleration(&mut self, enable: bool) {
374        self.regs()
375            .search_enable()
376            .write(|w| w.search_enable().bit(enable));
377    }
378
379    /// Checks if the search functionality is enabled in the RSA hardware.
380    #[cfg(not(esp32))]
381    fn is_search_enabled(&mut self) -> bool {
382        self.regs()
383            .search_enable()
384            .read()
385            .search_enable()
386            .bit_is_set()
387    }
388
389    /// Sets the search position in the RSA hardware.
390    #[cfg(not(esp32))]
391    fn write_search_position(&mut self, search_position: u32) {
392        self.regs()
393            .search_pos()
394            .write(|w| unsafe { w.bits(search_position) });
395    }
396}
397
398/// Defines the input size of an RSA operation.
399pub trait RsaMode: crate::private::Sealed {
400    /// The input data type used for the operation.
401    type InputType: AsRef<[u32]> + AsMut<[u32]>;
402}
403
404/// Defines the output type of RSA multiplications.
405pub trait Multi: RsaMode {
406    /// The type of the output produced by the operation.
407    type OutputType: AsRef<[u32]> + AsMut<[u32]>;
408}
409
410/// Defines the exponentiation and multiplication lengths for RSA operations.
411pub mod operand_sizes {
412    for_each_rsa_exponentiation!(
413        ($x:literal) => {
414            paste::paste! {
415                #[doc = concat!(stringify!($x), "-bit RSA operation.")]
416                pub struct [<Op $x>];
417
418                impl crate::private::Sealed for [<Op $x>] {}
419                impl crate::rsa::RsaMode for [<Op $x>] {
420                    type InputType = [u32; $x / 32];
421                }
422            }
423        };
424    );
425
426    for_each_rsa_multiplication!(
427        ($x:literal) => {
428            impl crate::rsa::Multi for paste::paste!( [<Op $x>] ) {
429                type OutputType = [u32; $x * 2 / 32];
430            }
431        };
432    );
433}
434
435/// Support for RSA peripheral's modular exponentiation feature that could be
436/// used to find the `(base ^ exponent) mod modulus`.
437///
438/// Each operand is a little endian byte array of the same size
439pub struct RsaModularExponentiation<'a, 'd, T: RsaMode, Dm: DriverMode> {
440    rsa: &'a mut Rsa<'d, Dm>,
441    phantom: PhantomData<T>,
442}
443
444impl<'a, 'd, T: RsaMode, Dm: DriverMode, const N: usize> RsaModularExponentiation<'a, 'd, T, Dm>
445where
446    T: RsaMode<InputType = [u32; N]>,
447{
448    /// Creates an instance of `RsaModularExponentiation`.
449    ///
450    /// `m_prime` could be calculated using `-(modular multiplicative inverse of
451    /// modulus) mod 2^32`.
452    ///
453    /// For more information refer to the
454    #[doc = trm_markdown_link!("rsa")]
455    pub fn new(
456        rsa: &'a mut Rsa<'d, Dm>,
457        exponent: &T::InputType,
458        modulus: &T::InputType,
459        m_prime: u32,
460    ) -> Self {
461        Self::write_mode(rsa);
462        rsa.write_operand_b(exponent);
463        rsa.write_modulus(modulus);
464        rsa.write_mprime(m_prime);
465
466        #[cfg(not(esp32))]
467        if rsa.is_search_enabled() {
468            rsa.write_search_position(Self::find_search_pos(exponent));
469        }
470
471        Self {
472            rsa,
473            phantom: PhantomData,
474        }
475    }
476
477    fn set_up_exponentiation(&mut self, base: &T::InputType, r: &T::InputType) {
478        self.rsa.write_operand_a(base);
479        self.rsa.write_r(r);
480    }
481
482    /// Starts the modular exponentiation operation.
483    ///
484    /// `r` can be calculated using `2 ^ ( bitlength * 2 ) mod modulus`.
485    ///
486    /// For more information refer to the
487    #[doc = trm_markdown_link!("rsa")]
488    pub fn start_exponentiation(&mut self, base: &T::InputType, r: &T::InputType) {
489        self.set_up_exponentiation(base, r);
490        self.rsa.start_modexp();
491    }
492
493    /// Reads the result to the given buffer.
494    ///
495    /// This is a blocking function: it waits for the RSA operation to complete,
496    /// then reads the results into the provided buffer. `start_exponentiation` must be
497    /// called before calling this function.
498    pub fn read_results(&mut self, outbuf: &mut T::InputType) {
499        self.rsa.read_results(outbuf);
500    }
501
502    #[cfg(not(esp32))]
503    fn find_search_pos(exponent: &T::InputType) -> u32 {
504        for (i, byte) in exponent.iter().rev().enumerate() {
505            if *byte == 0 {
506                continue;
507            }
508            return (exponent.len() * 32) as u32 - (byte.leading_zeros() + i as u32 * 32) - 1;
509        }
510        0
511    }
512
513    /// Sets the modular exponentiation mode for the RSA hardware.
514    fn write_mode(rsa: &mut Rsa<'d, Dm>) {
515        rsa.write_modexp_mode(N as u32 / WORDS_PER_INCREMENT - 1);
516    }
517}
518
519/// Support for RSA peripheral's modular multiplication feature that could be
520/// used to find the `(operand a * operand b) mod modulus`.
521///
522/// Each operand is a little endian byte array of the same size
523pub struct RsaModularMultiplication<'a, 'd, T, Dm>
524where
525    T: RsaMode,
526    Dm: DriverMode,
527{
528    rsa: &'a mut Rsa<'d, Dm>,
529    phantom: PhantomData<T>,
530}
531
532impl<'a, 'd, T, Dm, const N: usize> RsaModularMultiplication<'a, 'd, T, Dm>
533where
534    T: RsaMode<InputType = [u32; N]>,
535    Dm: DriverMode,
536{
537    /// Creates an instance of `RsaModularMultiplication`.
538    ///
539    /// - `r` can be calculated using `2 ^ ( bitlength * 2 ) mod modulus`.
540    /// - `m_prime` can be calculated using `-(modular multiplicative inverse of modulus) mod 2^32`.
541    ///
542    /// For more information refer to the
543    #[doc = trm_markdown_link!("rsa")]
544    pub fn new(
545        rsa: &'a mut Rsa<'d, Dm>,
546        operand_a: &T::InputType,
547        modulus: &T::InputType,
548        r: &T::InputType,
549        m_prime: u32,
550    ) -> Self {
551        rsa.write_multi_mode(N as u32 / WORDS_PER_INCREMENT - 1, true);
552
553        rsa.write_mprime(m_prime);
554        rsa.write_modulus(modulus);
555        rsa.write_operand_a(operand_a);
556        rsa.write_r(r);
557
558        Self {
559            rsa,
560            phantom: PhantomData,
561        }
562    }
563
564    /// Starts the modular multiplication operation.
565    ///
566    /// For more information refer to the
567    #[doc = trm_markdown_link!("rsa")]
568    pub fn start_modular_multiplication(&mut self, operand_b: &T::InputType) {
569        self.set_up_modular_multiplication(operand_b);
570        self.rsa.start_modmulti();
571    }
572
573    /// Reads the result to the given buffer.
574    ///
575    /// This is a blocking function: it waits for the RSA operation to complete,
576    /// then reads the results into the provided buffer. `start_modular_multiplication` must be
577    /// called before calling this function.
578    pub fn read_results(&mut self, outbuf: &mut T::InputType) {
579        self.rsa.read_results(outbuf);
580    }
581
582    fn set_up_modular_multiplication(&mut self, operand_b: &T::InputType) {
583        if cfg!(esp32) {
584            self.rsa.start_multi();
585            self.rsa.wait_for_idle();
586
587            self.rsa.write_operand_a(operand_b);
588        } else {
589            self.rsa.write_operand_b(operand_b);
590        }
591    }
592}
593
594/// Support for RSA peripheral's large number multiplication feature that could
595/// be used to find the `operand a * operand b`.
596///
597/// Each operand is a little endian byte array of the same size
598pub struct RsaMultiplication<'a, 'd, T, Dm>
599where
600    T: RsaMode + Multi,
601    Dm: DriverMode,
602{
603    rsa: &'a mut Rsa<'d, Dm>,
604    phantom: PhantomData<T>,
605}
606
607impl<'a, 'd, T, Dm, const N: usize> RsaMultiplication<'a, 'd, T, Dm>
608where
609    T: RsaMode<InputType = [u32; N]>,
610    T: Multi,
611    Dm: DriverMode,
612{
613    /// Creates an instance of `RsaMultiplication`.
614    pub fn new(rsa: &'a mut Rsa<'d, Dm>, operand_a: &T::InputType) -> Self {
615        // Non-modular multiplication result is twice as wide as its operands.
616        rsa.write_multi_mode(2 * N as u32 / WORDS_PER_INCREMENT - 1, false);
617        rsa.write_operand_a(operand_a);
618
619        Self {
620            rsa,
621            phantom: PhantomData,
622        }
623    }
624
625    /// Starts the multiplication operation.
626    pub fn start_multiplication(&mut self, operand_b: &T::InputType) {
627        self.set_up_multiplication(operand_b);
628        self.rsa.start_multi();
629    }
630
631    /// Reads the result to the given buffer.
632    ///
633    /// This is a blocking function: it waits for the RSA operation to complete,
634    /// then reads the results into the provided buffer. `start_multiplication` must be
635    /// called before calling this function.
636    pub fn read_results<const O: usize>(&mut self, outbuf: &mut T::OutputType)
637    where
638        T: Multi<OutputType = [u32; O]>,
639    {
640        self.rsa.read_results(outbuf);
641    }
642
643    fn set_up_multiplication(&mut self, operand_b: &T::InputType) {
644        self.rsa.write_multi_operand_b(operand_b);
645    }
646}
647
648static WAKER: AtomicWaker = AtomicWaker::new();
649// TODO: this should only be needed for ESP32
650static SIGNALED: AtomicBool = AtomicBool::new(false);
651
652/// `Future` that waits for the RSA operation to complete.
653#[must_use = "futures do nothing unless you `.await` or poll them"]
654struct RsaFuture<'a, 'd> {
655    driver: &'a Rsa<'d, Async>,
656}
657
658impl<'a, 'd> RsaFuture<'a, 'd> {
659    fn new(driver: &'a Rsa<'d, Async>) -> Self {
660        SIGNALED.store(false, Ordering::Relaxed);
661
662        driver.internal_enable_disable_interrupt(true);
663
664        Self { driver }
665    }
666
667    fn is_done(&self) -> bool {
668        SIGNALED.load(Ordering::Acquire)
669    }
670}
671
672impl Drop for RsaFuture<'_, '_> {
673    fn drop(&mut self) {
674        self.driver.internal_enable_disable_interrupt(false);
675    }
676}
677
678impl core::future::Future for RsaFuture<'_, '_> {
679    type Output = ();
680
681    fn poll(
682        self: core::pin::Pin<&mut Self>,
683        cx: &mut core::task::Context<'_>,
684    ) -> core::task::Poll<Self::Output> {
685        WAKER.register(cx.waker());
686        if self.is_done() {
687            Poll::Ready(())
688        } else {
689            Poll::Pending
690        }
691    }
692}
693
694impl<T: RsaMode, const N: usize> RsaModularExponentiation<'_, '_, T, Async>
695where
696    T: RsaMode<InputType = [u32; N]>,
697{
698    /// Asynchronously performs an RSA modular exponentiation operation.
699    pub async fn exponentiation(
700        &mut self,
701        base: &T::InputType,
702        r: &T::InputType,
703        outbuf: &mut T::InputType,
704    ) {
705        self.set_up_exponentiation(base, r);
706        let fut = RsaFuture::new(self.rsa);
707        self.rsa.start_modexp();
708        fut.await;
709        self.rsa.read_out(outbuf);
710    }
711}
712
713impl<T: RsaMode, const N: usize> RsaModularMultiplication<'_, '_, T, Async>
714where
715    T: RsaMode<InputType = [u32; N]>,
716{
717    /// Asynchronously performs an RSA modular multiplication operation.
718    pub async fn modular_multiplication(
719        &mut self,
720        operand_b: &T::InputType,
721        outbuf: &mut T::InputType,
722    ) {
723        if cfg!(esp32) {
724            let fut = RsaFuture::new(self.rsa);
725            self.rsa.start_multi();
726            fut.await;
727
728            self.rsa.write_operand_a(operand_b);
729        } else {
730            self.set_up_modular_multiplication(operand_b);
731        }
732
733        let fut = RsaFuture::new(self.rsa);
734        self.rsa.start_modmulti();
735        fut.await;
736        self.rsa.read_out(outbuf);
737    }
738}
739
740impl<T: RsaMode + Multi, const N: usize> RsaMultiplication<'_, '_, T, Async>
741where
742    T: RsaMode<InputType = [u32; N]>,
743{
744    /// Asynchronously performs an RSA multiplication operation.
745    pub async fn multiplication<const O: usize>(
746        &mut self,
747        operand_b: &T::InputType,
748        outbuf: &mut T::OutputType,
749    ) where
750        T: Multi<OutputType = [u32; O]>,
751    {
752        self.set_up_multiplication(operand_b);
753        let fut = RsaFuture::new(self.rsa);
754        self.rsa.start_multi();
755        fut.await;
756        self.rsa.read_out(outbuf);
757    }
758}
759
760#[handler]
761/// Interrupt handler for RSA.
762pub(super) fn rsa_interrupt_handler() {
763    let rsa = RSA::regs();
764    SIGNALED.store(true, Ordering::Release);
765    cfg_if::cfg_if! {
766        if #[cfg(esp32)] {
767            rsa.interrupt().write(|w| w.interrupt().set_bit());
768        } else  {
769            rsa.int_clr().write(|w| w.int_clr().set_bit());
770        }
771    }
772
773    WAKER.wake();
774}
775
776static RSA_WORK_QUEUE: WorkQueue<RsaWorkItem> = WorkQueue::new();
777const RSA_VTABLE: VTable<RsaWorkItem> = VTable {
778    post: |driver, item| {
779        // Start processing immediately.
780        let driver = unsafe { RsaBackend::from_raw(driver) };
781        Some(driver.process_item(item))
782    },
783    poll: |driver, item| {
784        let driver = unsafe { RsaBackend::from_raw(driver) };
785        driver.process_item(item)
786    },
787    cancel: |driver, item| {
788        let driver = unsafe { RsaBackend::from_raw(driver) };
789        driver.cancel(item)
790    },
791    stop: |driver| {
792        let driver = unsafe { RsaBackend::from_raw(driver) };
793        driver.deinitialize()
794    },
795};
796
797#[derive(Default)]
798enum RsaBackendState<'d> {
799    #[default]
800    Idle,
801    Initializing(Rsa<'d, Blocking>),
802    Ready(Rsa<'d, Blocking>),
803    #[cfg(esp32)]
804    ModularMultiplicationRoundOne(Rsa<'d, Blocking>),
805    Processing(Rsa<'d, Blocking>),
806}
807
808#[procmacros::doc_replace]
809/// RSA processing backend.
810///
811/// The backend processes work items placed in the RSA work queue. The backend needs to be created
812/// and started for operations to be processed. This allows you to perform operations on the RSA
813/// accelerator without carrying around the peripheral singleton, or the driver.
814///
815/// The [`RsaContext`] struct can enqueue work items that this backend will process.
816///
817/// ## Example
818///
819/// ```rust, no_run
820/// # {before_snippet}
821/// use esp_hal::rsa::{RsaBackend, RsaContext, operand_sizes::Op512};
822/// #
823/// let mut rsa_backend = RsaBackend::new(peripherals.RSA);
824/// let _driver = rsa_backend.start();
825///
826/// async fn perform_512bit_big_number_multiplication(
827///     operand_a: &[u32; 16],
828///     operand_b: &[u32; 16],
829///     result: &mut [u32; 32],
830/// ) {
831///     let mut rsa = RsaContext::new();
832///
833///     let mut handle = rsa.multiply::<Op512>(operand_a, operand_b, result);
834///     handle.wait().await;
835/// }
836/// # {after_snippet}
837/// ```
838pub struct RsaBackend<'d> {
839    peri: RSA<'d>,
840    state: RsaBackendState<'d>,
841}
842
843impl<'d> RsaBackend<'d> {
844    #[procmacros::doc_replace]
845    /// Creates a new RSA backend.
846    ///
847    /// ## Example
848    ///
849    /// ```rust, no_run
850    /// # {before_snippet}
851    /// use esp_hal::rsa::RsaBackend;
852    /// #
853    /// let mut rsa = RsaBackend::new(peripherals.RSA);
854    /// # {after_snippet}
855    /// ```
856    pub fn new(rsa: RSA<'d>) -> Self {
857        Self {
858            peri: rsa,
859            state: RsaBackendState::Idle,
860        }
861    }
862
863    #[procmacros::doc_replace]
864    /// Registers the RSA driver to process RSA operations.
865    ///
866    /// The driver stops operating when the returned object is dropped.
867    ///
868    /// ## Example
869    ///
870    /// ```rust, no_run
871    /// # {before_snippet}
872    /// use esp_hal::rsa::RsaBackend;
873    /// #
874    /// let mut rsa = RsaBackend::new(peripherals.RSA);
875    /// // Start the backend, which allows processing RSA operations.
876    /// let _backend = rsa.start();
877    /// # {after_snippet}
878    /// ```
879    pub fn start(&mut self) -> RsaWorkQueueDriver<'_, 'd> {
880        RsaWorkQueueDriver {
881            inner: WorkQueueDriver::new(self, RSA_VTABLE, &RSA_WORK_QUEUE),
882        }
883    }
884
885    // WorkQueue callbacks. They may run in any context.
886
887    unsafe fn from_raw<'any>(ptr: NonNull<()>) -> &'any mut Self {
888        unsafe { ptr.cast::<RsaBackend<'_>>().as_mut() }
889    }
890
891    fn process_item(&mut self, item: &mut RsaWorkItem) -> work_queue::Poll {
892        match core::mem::take(&mut self.state) {
893            RsaBackendState::Idle => {
894                let driver = Rsa {
895                    rsa: unsafe { self.peri.clone_unchecked() },
896                    phantom: PhantomData,
897                    _guard: RsaGuard::new(),
898                };
899                self.state = RsaBackendState::Initializing(driver);
900                work_queue::Poll::Pending(true)
901            }
902            RsaBackendState::Initializing(mut rsa) => {
903                // Wait for the peripheral to finish initializing. Ideally we need a way to
904                // instruct the work queue to wake the polling task immediately.
905                self.state = if rsa.ready() {
906                    rsa.set_interrupt_handler(rsa_work_queue_handler);
907                    rsa.enable_disable_interrupt(true);
908                    RsaBackendState::Ready(rsa)
909                } else {
910                    RsaBackendState::Initializing(rsa)
911                };
912                work_queue::Poll::Pending(true)
913            }
914            RsaBackendState::Ready(mut rsa) => {
915                #[cfg(not(esp32))]
916                {
917                    rsa.disable_constant_time(!item.constant_time);
918                    rsa.search_acceleration(item.search_acceleration);
919                }
920
921                match item.operation {
922                    RsaOperation::Multiplication { x, y } => {
923                        let n = x.len() as u32;
924                        rsa.write_operand_a(unsafe { x.as_ref() });
925
926                        // Non-modular multiplication result is twice as wide as its operands.
927                        rsa.write_multi_mode(2 * n / WORDS_PER_INCREMENT - 1, false);
928                        rsa.write_multi_operand_b(unsafe { y.as_ref() });
929                        rsa.start_multi();
930                    }
931
932                    RsaOperation::ModularMultiplication {
933                        x,
934                        #[cfg(not(esp32))]
935                        y,
936                        m,
937                        m_prime,
938                        r: r_inv,
939                        ..
940                    } => {
941                        let n = x.len() as u32;
942                        rsa.write_operand_a(unsafe { x.as_ref() });
943
944                        rsa.write_multi_mode(n / WORDS_PER_INCREMENT - 1, true);
945
946                        #[cfg(not(esp32))]
947                        rsa.write_operand_b(unsafe { y.as_ref() });
948
949                        rsa.write_modulus(unsafe { m.as_ref() });
950                        rsa.write_mprime(m_prime);
951                        rsa.write_r(unsafe { r_inv.as_ref() });
952
953                        rsa.start_modmulti();
954
955                        #[cfg(esp32)]
956                        {
957                            // ESP32 requires a two-step process where Y needs to be written to the
958                            // X memory.
959                            self.state = RsaBackendState::ModularMultiplicationRoundOne(rsa);
960
961                            return work_queue::Poll::Pending(false);
962                        }
963                    }
964                    RsaOperation::ModularExponentiation {
965                        x,
966                        y,
967                        m,
968                        m_prime,
969                        r_inv,
970                    } => {
971                        let n = x.len() as u32;
972                        rsa.write_operand_a(unsafe { x.as_ref() });
973
974                        rsa.write_modexp_mode(n / WORDS_PER_INCREMENT - 1);
975                        rsa.write_operand_b(unsafe { y.as_ref() });
976                        rsa.write_modulus(unsafe { m.as_ref() });
977                        rsa.write_mprime(m_prime);
978                        rsa.write_r(unsafe { r_inv.as_ref() });
979
980                        #[cfg(not(esp32))]
981                        if item.search_acceleration {
982                            fn find_search_pos(exponent: &[u32]) -> u32 {
983                                for (i, byte) in exponent.iter().rev().enumerate() {
984                                    if *byte == 0 {
985                                        continue;
986                                    }
987                                    return (exponent.len() * 32) as u32
988                                        - (byte.leading_zeros() + i as u32 * 32)
989                                        - 1;
990                                }
991                                0
992                            }
993                            rsa.write_search_position(find_search_pos(unsafe { y.as_ref() }));
994                        }
995
996                        rsa.start_modexp();
997                    }
998                }
999
1000                self.state = RsaBackendState::Processing(rsa);
1001
1002                work_queue::Poll::Pending(false)
1003            }
1004
1005            #[cfg(esp32)]
1006            RsaBackendState::ModularMultiplicationRoundOne(mut rsa) => {
1007                if rsa.is_idle() {
1008                    let RsaOperation::ModularMultiplication { y, .. } = item.operation else {
1009                        unreachable!();
1010                    };
1011
1012                    // Y needs to be written to the X memory.
1013                    rsa.write_operand_a(unsafe { y.as_ref() });
1014                    rsa.start_modmulti();
1015
1016                    self.state = RsaBackendState::Processing(rsa);
1017                } else {
1018                    // Wait for the operation to complete
1019                    self.state = RsaBackendState::ModularMultiplicationRoundOne(rsa);
1020                }
1021                work_queue::Poll::Pending(false)
1022            }
1023
1024            RsaBackendState::Processing(rsa) => {
1025                if rsa.is_idle() {
1026                    rsa.read_out(unsafe { item.result.as_mut() });
1027
1028                    self.state = RsaBackendState::Ready(rsa);
1029                    work_queue::Poll::Ready(Status::Completed)
1030                } else {
1031                    self.state = RsaBackendState::Processing(rsa);
1032                    work_queue::Poll::Pending(false)
1033                }
1034            }
1035        }
1036    }
1037
1038    fn cancel(&mut self, _item: &mut RsaWorkItem) {
1039        // Drop the driver to reset it. We don't read the result, so the work item remains
1040        // unchanged, effectively cancelling it.
1041        self.state = RsaBackendState::Idle;
1042    }
1043
1044    fn deinitialize(&mut self) {
1045        self.state = RsaBackendState::Idle;
1046    }
1047}
1048
1049/// An active work queue driver.
1050///
1051/// This object must be kept around, otherwise RSA operations will never complete.
1052///
1053/// For a usage example, see [`RsaBackend`].
1054pub struct RsaWorkQueueDriver<'t, 'd> {
1055    inner: WorkQueueDriver<'t, RsaBackend<'d>, RsaWorkItem>,
1056}
1057
1058impl<'t, 'd> RsaWorkQueueDriver<'t, 'd> {
1059    /// Finishes processing the current work queue item, then stops the driver.
1060    pub fn stop(self) -> impl Future<Output = ()> {
1061        self.inner.stop()
1062    }
1063}
1064
1065#[derive(Clone)]
1066struct RsaWorkItem {
1067    // Acceleration options
1068    #[cfg(not(esp32))]
1069    search_acceleration: bool,
1070    #[cfg(not(esp32))]
1071    constant_time: bool,
1072
1073    // The operation to execute.
1074    operation: RsaOperation,
1075    result: NonNull<[u32]>,
1076}
1077
1078unsafe impl Sync for RsaWorkItem {}
1079unsafe impl Send for RsaWorkItem {}
1080
1081#[derive(Clone)]
1082enum RsaOperation {
1083    // Z = X * Y
1084    // len(Z) = len(X) + len(Y)
1085    Multiplication {
1086        x: NonNull<[u32]>,
1087        y: NonNull<[u32]>,
1088    },
1089    // Z = X * Y mod M
1090    ModularMultiplication {
1091        x: NonNull<[u32]>,
1092        y: NonNull<[u32]>,
1093        m: NonNull<[u32]>,
1094        r: NonNull<[u32]>,
1095        m_prime: u32,
1096    },
1097    // Z = X ^ Y mod M
1098    ModularExponentiation {
1099        x: NonNull<[u32]>,
1100        y: NonNull<[u32]>,
1101        m: NonNull<[u32]>,
1102        r_inv: NonNull<[u32]>,
1103        m_prime: u32,
1104    },
1105}
1106
1107#[handler]
1108#[ram]
1109fn rsa_work_queue_handler() {
1110    if !RSA_WORK_QUEUE.process() {
1111        // The queue may indicate that it needs to be polled again. In this case, we do not clear
1112        // the interrupt bit, which causes the interrupt to be re-handled.
1113        cfg_if::cfg_if! {
1114            if #[cfg(esp32)] {
1115                RSA::regs().interrupt().write(|w| w.interrupt().set_bit());
1116            } else {
1117                RSA::regs().int_clr().write(|w| w.int_clr().set_bit());
1118            }
1119        }
1120    }
1121}
1122
1123/// An RSA work queue user.
1124///
1125/// This object allows performing [big number multiplication][Self::multiply], [big number modular
1126/// multiplication][Self::modular_multiply] and [big number modular
1127/// exponentiation][Self::modular_exponentiate] with hardware acceleration. To perform these
1128/// operations, the [`RsaBackend`] must be started, otherwise these operations will never complete.
1129#[cfg_attr(
1130    not(esp32),
1131    doc = " \nThe context is created with a secure configuration by default. You can enable hardware acceleration
1132    options using [enable_search_acceleration][Self::enable_search_acceleration] and
1133    [enable_acceleration][Self::enable_acceleration] when appropriate."
1134)]
1135#[derive(Clone)]
1136pub struct RsaContext {
1137    frontend: WorkQueueFrontend<RsaWorkItem>,
1138}
1139
1140impl Default for RsaContext {
1141    fn default() -> Self {
1142        Self::new()
1143    }
1144}
1145
1146impl RsaContext {
1147    /// Creates a new context.
1148    pub fn new() -> Self {
1149        Self {
1150            frontend: WorkQueueFrontend::new(RsaWorkItem {
1151                #[cfg(not(esp32))]
1152                search_acceleration: false,
1153                #[cfg(not(esp32))]
1154                constant_time: true,
1155                operation: RsaOperation::Multiplication {
1156                    x: NonNull::from(&[]),
1157                    y: NonNull::from(&[]),
1158                },
1159                result: NonNull::from(&mut []),
1160            }),
1161        }
1162    }
1163
1164    #[cfg(not(esp32))]
1165    /// Enables search acceleration.
1166    ///
1167    /// When enabled it would increase the performance of modular
1168    /// exponentiation by discarding the exponent's bits before the most
1169    /// significant set bit.
1170    ///
1171    /// > ⚠️ Note: this compromises security by effectively decreasing the key length.
1172    ///
1173    /// For more information refer to the
1174    #[doc = trm_markdown_link!("rsa")]
1175    pub fn enable_search_acceleration(&mut self) {
1176        self.frontend.data_mut().search_acceleration = true;
1177    }
1178
1179    #[cfg(not(esp32))]
1180    /// Enables acceleration by disabling constant time operation.
1181    ///
1182    /// Disabling constant time operation increases the performance of modular
1183    /// exponentiation by simplifying the calculation concerning the 0 bits
1184    /// of the exponent. I.e. the less the Hamming weight, the greater the
1185    /// performance.
1186    ///
1187    /// > ⚠️ Note: this compromises security by enabling timing-based side-channel attacks.
1188    ///
1189    /// For more information refer to the
1190    #[doc = trm_markdown_link!("rsa")]
1191    pub fn enable_acceleration(&mut self) {
1192        self.frontend.data_mut().constant_time = false;
1193    }
1194
1195    fn post(&mut self) -> RsaHandle<'_> {
1196        RsaHandle(self.frontend.post(&RSA_WORK_QUEUE))
1197    }
1198
1199    #[procmacros::doc_replace]
1200    /// Starts a modular exponentiation operation, performing `Z = X ^ Y mod M`.
1201    ///
1202    /// Software needs to pre-calculate the following values:
1203    ///
1204    /// - `r`: `2 ^ ( bitlength * 2 ) mod M`.
1205    /// - `m_prime` can be calculated using `-(modular multiplicative inverse of M) mod 2^32`.
1206    ///
1207    /// It is relatively easy to calculate these values using the `crypto-bigint` crate:
1208    ///
1209    /// ```rust,no_run
1210    /// # {before_snippet}
1211    /// use crypto_bigint::{U512, Uint};
1212    /// const fn compute_r(modulus: &U512) -> U512 {
1213    ///     let mut d = [0_u32; U512::LIMBS * 2 + 1];
1214    ///     d[d.len() - 1] = 1;
1215    ///     let d = Uint::from_words(d);
1216    ///     d.const_rem(&modulus.resize()).0.resize()
1217    /// }
1218    ///
1219    /// const fn compute_mprime(modulus: &U512) -> u32 {
1220    ///     let m_inv = modulus.inv_mod2k(32).to_words()[0];
1221    ///     (-1 * m_inv as i64 & (u32::MAX as i64)) as u32
1222    /// }
1223    ///
1224    /// // Inputs
1225    /// const X: U512 = Uint::from_be_hex(
1226    ///     "c7f61058f96db3bd87dbab08ab03b4f7f2f864eac249144adea6a65f97803b719d8ca980b7b3c0389c1c7c6\
1227    ///    7dc353c5e0ec11f5fc8ce7f6073796cc8f73fa878",
1228    /// );
1229    /// const Y: U512 = Uint::from_be_hex(
1230    ///     "1763db3344e97be15d04de4868badb12a38046bb793f7630d87cf100aa1c759afac15a01f3c4c83ec2d2f66\
1231    ///    6bd22f71c3c1f075ec0e2cb0cb29994d091b73f51",
1232    /// );
1233    /// const M: U512 = Uint::from_be_hex(
1234    ///     "6b6bb3d2b6cbeb45a769eaa0384e611e1b89b0c9b45a045aca1c5fd6e8785b38df7118cf5dd45b9b63d293b\
1235    ///    67aeafa9ba25feb8712f188cb139b7d9b9af1c361",
1236    /// );
1237    ///
1238    /// // Values derived using the functions we defined above:
1239    /// let r = compute_r(&M);
1240    /// let mprime = compute_mprime(&M);
1241    ///
1242    /// use esp_hal::rsa::{RsaContext, operand_sizes::Op512};
1243    ///
1244    /// // Now perform the actual computation:
1245    /// let mut rsa = RsaContext::new();
1246    /// let mut outbuf = [0; 16];
1247    /// let mut handle = rsa.modular_multiply::<Op512>(
1248    ///     X.as_words(),
1249    ///     Y.as_words(),
1250    ///     M.as_words(),
1251    ///     r.as_words(),
1252    ///     mprime,
1253    ///     &mut outbuf,
1254    /// );
1255    /// handle.wait_blocking();
1256    /// # {after_snippet}
1257    /// ```
1258    ///
1259    /// The calculation is done asynchronously. This function returns an [`RsaHandle`] that can be
1260    /// used to poll the status of the calculation, to wait for it to finish, or to cancel the
1261    /// operation (by dropping the handle).
1262    ///
1263    /// When the operation is completed, the result will be stored in `result`.
1264    pub fn modular_exponentiate<'t, OP>(
1265        &'t mut self,
1266        x: &'t OP::InputType,
1267        y: &'t OP::InputType,
1268        m: &'t OP::InputType,
1269        r: &'t OP::InputType,
1270        m_prime: u32,
1271        result: &'t mut OP::InputType,
1272    ) -> RsaHandle<'t>
1273    where
1274        OP: RsaMode,
1275    {
1276        self.frontend.data_mut().operation = RsaOperation::ModularExponentiation {
1277            x: NonNull::from(x.as_ref()),
1278            y: NonNull::from(y.as_ref()),
1279            m: NonNull::from(m.as_ref()),
1280            r_inv: NonNull::from(r.as_ref()),
1281            m_prime,
1282        };
1283        self.frontend.data_mut().result = NonNull::from(result.as_mut());
1284        self.post()
1285    }
1286
1287    /// Starts a modular multiplication operation, performing `Z = X * Y mod M`.
1288    ///
1289    /// Software needs to pre-calculate the following values:
1290    ///
1291    /// - `r`: `2 ^ ( bitlength * 2 ) mod M`.
1292    /// - `m_prime` can be calculated using `-(modular multiplicative inverse of M) mod 2^32`.
1293    ///
1294    /// For an example how these values can be calculated and used, see
1295    /// [Self::modular_exponentiate].
1296    ///
1297    /// The calculation is done asynchronously. This function returns an [`RsaHandle`] that can be
1298    /// used to poll the status of the calculation, to wait for it to finish, or to cancel the
1299    /// operation (by dropping the handle).
1300    ///
1301    /// When the operation is completed, the result will be stored in `result`.
1302    pub fn modular_multiply<'t, OP>(
1303        &'t mut self,
1304        x: &'t OP::InputType,
1305        y: &'t OP::InputType,
1306        m: &'t OP::InputType,
1307        r: &'t OP::InputType,
1308        m_prime: u32,
1309        result: &'t mut OP::InputType,
1310    ) -> RsaHandle<'t>
1311    where
1312        OP: RsaMode,
1313    {
1314        self.frontend.data_mut().operation = RsaOperation::ModularMultiplication {
1315            x: NonNull::from(x.as_ref()),
1316            y: NonNull::from(y.as_ref()),
1317            m: NonNull::from(m.as_ref()),
1318            r: NonNull::from(r.as_ref()),
1319            m_prime,
1320        };
1321        self.frontend.data_mut().result = NonNull::from(result.as_mut());
1322        self.post()
1323    }
1324
1325    #[procmacros::doc_replace]
1326    /// Starts a multiplication operation, performing `Z = X * Y`.
1327    ///
1328    /// The calculation is done asynchronously. This function returns an [`RsaHandle`] that can be
1329    /// used to poll the status of the calculation, to wait for it to finish, or to cancel the
1330    /// operation (by dropping the handle).
1331    ///
1332    /// When the operation is completed, the result will be stored in `result`. The `result` is
1333    /// twice as wide as the inputs.
1334    ///
1335    /// ## Example
1336    ///
1337    /// ```rust,no_run
1338    /// # {before_snippet}
1339    ///
1340    /// // Inputs
1341    /// # let x: [u32; 16] = [0; 16];
1342    /// # let y: [u32; 16] = [0; 16];
1343    /// // let x: [u32; 16] = [...];
1344    /// // let y: [u32; 16] = [...];
1345    /// let mut outbuf = [0; 32];
1346    ///
1347    /// use esp_hal::rsa::{RsaContext, operand_sizes::Op512};
1348    ///
1349    /// // Now perform the actual computation:
1350    /// let mut rsa = RsaContext::new();
1351    /// let mut handle = rsa.multiply::<Op512>(&x, &y, &mut outbuf);
1352    /// handle.wait_blocking();
1353    /// # {after_snippet}
1354    /// ```
1355    pub fn multiply<'t, OP>(
1356        &'t mut self,
1357        x: &'t OP::InputType,
1358        y: &'t OP::InputType,
1359        result: &'t mut OP::OutputType,
1360    ) -> RsaHandle<'t>
1361    where
1362        OP: Multi,
1363    {
1364        self.frontend.data_mut().operation = RsaOperation::Multiplication {
1365            x: NonNull::from(x.as_ref()),
1366            y: NonNull::from(y.as_ref()),
1367        };
1368        self.frontend.data_mut().result = NonNull::from(result.as_mut());
1369        self.post()
1370    }
1371}
1372
1373/// The handle to the pending RSA operation.
1374pub struct RsaHandle<'t>(work_queue::Handle<'t, RsaWorkItem>);
1375
1376impl RsaHandle<'_> {
1377    /// Polls the status of the work item.
1378    #[inline]
1379    pub fn poll(&mut self) -> bool {
1380        self.0.poll()
1381    }
1382
1383    /// Blocks until the work item is processed.
1384    #[inline]
1385    pub fn wait_blocking(self) {
1386        self.0.wait_blocking();
1387    }
1388
1389    /// Waits for the work item to be processed.
1390    #[inline]
1391    pub fn wait(&mut self) -> impl Future<Output = Status> {
1392        self.0.wait()
1393    }
1394}