1use core::marker::PhantomData;
23
24use crate::{
25    Blocking,
26    DriverMode,
27    interrupt::InterruptHandler,
28    pac,
29    peripherals::{ECC, Interrupt},
30    reg_access::{AlignmentHelper, SocDependentEndianess},
31    system::{self, GenericPeripheralGuard},
32};
33
34pub struct Ecc<'d, Dm: DriverMode> {
36    ecc: ECC<'d>,
37    alignment_helper: AlignmentHelper<SocDependentEndianess>,
38    phantom: PhantomData<Dm>,
39    _guard: GenericPeripheralGuard<{ system::Peripheral::Ecc as u8 }>,
40}
41
42#[derive(Debug)]
44pub enum Error {
45    SizeMismatchCurve,
48    PointNotOnSelectedCurve,
50}
51
52pub enum EllipticCurve {
54    P192 = 0,
56    P256 = 1,
58}
59
60#[derive(Clone)]
61pub enum WorkMode {
64    PointMultiMode          = 0,
66    #[cfg(esp32c2)]
67    DivisionMode            = 1,
69    PointVerif              = 2,
71    PointVerifMulti         = 3,
73    JacobianPointMulti      = 4,
75    #[cfg(esp32h2)]
76    PointAdd                = 5,
78    JacobianPointVerif      = 6,
80    PointVerifJacobianMulti = 7,
82    #[cfg(esp32h2)]
83    ModAdd                  = 8,
85    #[cfg(esp32h2)]
86    ModSub                  = 9,
88    #[cfg(esp32h2)]
89    ModMulti                = 10,
91    #[cfg(esp32h2)]
92    ModDiv                  = 11,
94}
95
96impl<'d> Ecc<'d, Blocking> {
97    pub fn new(ecc: ECC<'d>) -> Self {
99        let guard = GenericPeripheralGuard::new();
100
101        Self {
102            ecc,
103            alignment_helper: AlignmentHelper::default(),
104            phantom: PhantomData,
105            _guard: guard,
106        }
107    }
108}
109
110impl crate::private::Sealed for Ecc<'_, Blocking> {}
111
112#[instability::unstable]
113impl crate::interrupt::InterruptConfigurable for Ecc<'_, Blocking> {
114    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
115        self.set_interrupt_handler(handler);
116    }
117}
118
119impl<Dm: DriverMode> Ecc<'_, Dm> {
120    fn regs(&self) -> &pac::ecc::RegisterBlock {
121        self.ecc.register_block()
122    }
123
124    pub fn reset(&mut self) {
126        self.regs().mult_conf().reset()
127    }
128
129    pub fn affine_point_multiplication(
141        &mut self,
142        curve: &EllipticCurve,
143        k: &[u8],
144        x: &mut [u8],
145        y: &mut [u8],
146    ) -> Result<(), Error> {
147        let curve = match curve {
148            EllipticCurve::P192 => {
149                if k.len() != 24 || x.len() != 24 || y.len() != 24 {
150                    return Err(Error::SizeMismatchCurve);
151                }
152                false
153            }
154            EllipticCurve::P256 => {
155                if k.len() != 32 || x.len() != 32 || y.len() != 32 {
156                    return Err(Error::SizeMismatchCurve);
157                }
158                true
159            }
160        };
161        let mode = WorkMode::PointMultiMode;
162
163        let mut tmp = [0_u8; 32];
164        self.reverse_words(k, &mut tmp);
165        self.alignment_helper.volatile_write_regset(
166            self.regs().k_mem(0).as_ptr(),
167            tmp.as_ref(),
168            32,
169        );
170        self.reverse_words(x, &mut tmp);
171        self.alignment_helper.volatile_write_regset(
172            self.regs().px_mem(0).as_ptr(),
173            tmp.as_ref(),
174            32,
175        );
176        self.reverse_words(y, &mut tmp);
177        self.alignment_helper.volatile_write_regset(
178            self.regs().py_mem(0).as_ptr(),
179            tmp.as_ref(),
180            32,
181        );
182
183        self.regs().mult_conf().write(|w| unsafe {
184            w.work_mode()
185                .bits(mode as u8)
186                .key_length()
187                .bit(curve)
188                .start()
189                .set_bit()
190        });
191
192        while self.is_busy() {}
194
195        self.alignment_helper
196            .volatile_read_regset(self.regs().px_mem(0).as_ptr(), &mut tmp, 32);
197        self.reverse_words(tmp.as_ref(), x);
198        self.alignment_helper
199            .volatile_read_regset(self.regs().py_mem(0).as_ptr(), &mut tmp, 32);
200        self.reverse_words(tmp.as_ref(), y);
201
202        Ok(())
203    }
204
205    #[cfg(esp32c2)]
217    pub fn finite_field_division(
218        &mut self,
219        curve: &EllipticCurve,
220        k: &[u8],
221        y: &mut [u8],
222    ) -> Result<(), Error> {
223        let curve = match curve {
224            EllipticCurve::P192 => {
225                if k.len() != 24 || y.len() != 24 {
226                    return Err(Error::SizeMismatchCurve);
227                }
228                false
229            }
230            EllipticCurve::P256 => {
231                if k.len() != 32 || y.len() != 32 {
232                    return Err(Error::SizeMismatchCurve);
233                }
234                true
235            }
236        };
237        let mode = WorkMode::DivisionMode;
238
239        let mut tmp = [0_u8; 32];
240        self.reverse_words(k, &mut tmp);
241        self.alignment_helper.volatile_write_regset(
242            self.regs().k_mem(0).as_ptr(),
243            tmp.as_ref(),
244            32,
245        );
246        self.reverse_words(y, &mut tmp);
247        self.alignment_helper.volatile_write_regset(
248            self.regs().py_mem(0).as_ptr(),
249            tmp.as_ref(),
250            32,
251        );
252
253        self.regs().mult_conf().write(|w| unsafe {
254            w.work_mode()
255                .bits(mode as u8)
256                .key_length()
257                .bit(curve)
258                .start()
259                .set_bit()
260        });
261
262        while self.is_busy() {}
264
265        self.alignment_helper
266            .volatile_read_regset(self.regs().py_mem(0).as_ptr(), &mut tmp, 32);
267        self.reverse_words(tmp.as_ref(), y);
268
269        Ok(())
270    }
271
272    pub fn affine_point_verification(
285        &mut self,
286        curve: &EllipticCurve,
287        x: &[u8],
288        y: &[u8],
289    ) -> Result<(), Error> {
290        let curve = match curve {
291            EllipticCurve::P192 => {
292                if x.len() != 24 || y.len() != 24 {
293                    return Err(Error::SizeMismatchCurve);
294                }
295                false
296            }
297            EllipticCurve::P256 => {
298                if x.len() != 32 || y.len() != 32 {
299                    return Err(Error::SizeMismatchCurve);
300                }
301                true
302            }
303        };
304        let mode = WorkMode::PointVerif;
305
306        let mut tmp = [0_u8; 32];
307        self.reverse_words(x, &mut tmp);
308        self.alignment_helper.volatile_write_regset(
309            self.regs().px_mem(0).as_ptr(),
310            tmp.as_ref(),
311            32,
312        );
313        self.reverse_words(y, &mut tmp);
314        self.alignment_helper.volatile_write_regset(
315            self.regs().py_mem(0).as_ptr(),
316            tmp.as_ref(),
317            32,
318        );
319
320        self.regs().mult_conf().write(|w| unsafe {
321            w.work_mode()
322                .bits(mode as u8)
323                .key_length()
324                .bit(curve)
325                .start()
326                .set_bit()
327        });
328
329        while self.is_busy() {}
331
332        if !self.regs().mult_conf().read().verification_result().bit() {
333            self.regs().mult_conf().reset();
334            return Err(Error::PointNotOnSelectedCurve);
335        }
336
337        Ok(())
338    }
339
340    #[cfg(not(esp32h2))]
356    pub fn affine_point_verification_multiplication(
357        &mut self,
358        curve: &EllipticCurve,
359        k: &[u8],
360        x: &mut [u8],
361        y: &mut [u8],
362    ) -> Result<(), Error> {
363        let curve = match curve {
364            EllipticCurve::P192 => {
365                if k.len() != 24 || x.len() != 24 || y.len() != 24 {
366                    return Err(Error::SizeMismatchCurve);
367                }
368                false
369            }
370            EllipticCurve::P256 => {
371                if k.len() != 32 || x.len() != 32 || y.len() != 32 {
372                    return Err(Error::SizeMismatchCurve);
373                }
374                true
375            }
376        };
377        let mode = WorkMode::PointVerifMulti;
378
379        let mut tmp = [0_u8; 32];
380        self.reverse_words(k, &mut tmp);
381        self.alignment_helper.volatile_write_regset(
382            self.regs().k_mem(0).as_ptr(),
383            tmp.as_ref(),
384            32,
385        );
386        self.reverse_words(x, &mut tmp);
387        self.alignment_helper.volatile_write_regset(
388            self.regs().px_mem(0).as_ptr(),
389            tmp.as_ref(),
390            32,
391        );
392        self.reverse_words(y, &mut tmp);
393        self.alignment_helper.volatile_write_regset(
394            self.regs().py_mem(0).as_ptr(),
395            tmp.as_ref(),
396            32,
397        );
398
399        self.regs().mult_conf().write(|w| unsafe {
400            w.work_mode()
401                .bits(mode as u8)
402                .key_length()
403                .bit(curve)
404                .start()
405                .set_bit()
406        });
407
408        while self.is_busy() {}
410
411        if !self.regs().mult_conf().read().verification_result().bit() {
412            self.regs().mult_conf().reset();
413            return Err(Error::PointNotOnSelectedCurve);
414        }
415
416        self.alignment_helper
417            .volatile_read_regset(self.regs().px_mem(0).as_ptr(), &mut tmp, 32);
418        self.reverse_words(tmp.as_ref(), x);
419        self.alignment_helper
420            .volatile_read_regset(self.regs().py_mem(0).as_ptr(), &mut tmp, 32);
421        self.reverse_words(tmp.as_ref(), y);
422
423        Ok(())
424    }
425
426    #[expect(clippy::too_many_arguments)]
444    #[cfg(esp32h2)]
445    pub fn affine_point_verification_multiplication(
446        &mut self,
447        curve: &EllipticCurve,
448        k: &[u8],
449        px: &mut [u8],
450        py: &mut [u8],
451        qx: &mut [u8],
452        qy: &mut [u8],
453        qz: &mut [u8],
454    ) -> Result<(), Error> {
455        let curve = match curve {
456            EllipticCurve::P192 => {
457                if k.len() != 24 || px.len() != 24 || py.len() != 24 {
458                    return Err(Error::SizeMismatchCurve);
459                }
460                false
461            }
462            EllipticCurve::P256 => {
463                if k.len() != 32 || px.len() != 32 || py.len() != 32 {
464                    return Err(Error::SizeMismatchCurve);
465                }
466                true
467            }
468        };
469        let mode = WorkMode::PointVerifMulti;
470
471        let mut tmp = [0_u8; 32];
472        self.reverse_words(k, &mut tmp);
473        self.alignment_helper.volatile_write_regset(
474            self.regs().k_mem(0).as_ptr(),
475            tmp.as_ref(),
476            32,
477        );
478        self.reverse_words(px, &mut tmp);
479        self.alignment_helper.volatile_write_regset(
480            self.regs().px_mem(0).as_ptr(),
481            tmp.as_ref(),
482            32,
483        );
484        self.reverse_words(py, &mut tmp);
485        self.alignment_helper.volatile_write_regset(
486            self.regs().py_mem(0).as_ptr(),
487            tmp.as_ref(),
488            32,
489        );
490
491        self.regs().mult_conf().write(|w| unsafe {
492            w.work_mode().bits(mode as u8);
493            w.key_length().bit(curve);
494            w.start().set_bit()
495        });
496
497        while self.is_busy() {}
499
500        if !self.regs().mult_conf().read().verification_result().bit() {
501            self.regs().mult_conf().reset();
502            return Err(Error::PointNotOnSelectedCurve);
503        }
504
505        self.alignment_helper
506            .volatile_read_regset(self.regs().px_mem(0).as_ptr(), &mut tmp, 32);
507        self.reverse_words(tmp.as_ref(), px);
508        self.alignment_helper
509            .volatile_read_regset(self.regs().py_mem(0).as_ptr(), &mut tmp, 32);
510        self.reverse_words(tmp.as_ref(), py);
511        self.alignment_helper
512            .volatile_read_regset(self.regs().qx_mem(0).as_ptr(), &mut tmp, 32);
513        self.reverse_words(tmp.as_ref(), qx);
514        self.alignment_helper
515            .volatile_read_regset(self.regs().qy_mem(0).as_ptr(), &mut tmp, 32);
516        self.reverse_words(tmp.as_ref(), qy);
517        self.alignment_helper
518            .volatile_read_regset(self.regs().qz_mem(0).as_ptr(), &mut tmp, 32);
519        self.reverse_words(tmp.as_ref(), qz);
520
521        Ok(())
522    }
523
524    pub fn jacobian_point_multiplication(
536        &mut self,
537        curve: &EllipticCurve,
538        k: &mut [u8],
539        x: &mut [u8],
540        y: &mut [u8],
541    ) -> Result<(), Error> {
542        let curve = match curve {
543            EllipticCurve::P192 => {
544                if k.len() != 24 || x.len() != 24 || y.len() != 24 {
545                    return Err(Error::SizeMismatchCurve);
546                }
547                false
548            }
549            EllipticCurve::P256 => {
550                if k.len() != 32 || x.len() != 32 || y.len() != 32 {
551                    return Err(Error::SizeMismatchCurve);
552                }
553                true
554            }
555        };
556        let mode = WorkMode::JacobianPointMulti;
557
558        let mut tmp = [0_u8; 32];
559        self.reverse_words(k, &mut tmp);
560        self.alignment_helper.volatile_write_regset(
561            self.regs().k_mem(0).as_ptr(),
562            tmp.as_ref(),
563            32,
564        );
565        self.reverse_words(x, &mut tmp);
566        self.alignment_helper.volatile_write_regset(
567            self.regs().px_mem(0).as_ptr(),
568            tmp.as_ref(),
569            32,
570        );
571        self.reverse_words(y, &mut tmp);
572        self.alignment_helper.volatile_write_regset(
573            self.regs().py_mem(0).as_ptr(),
574            tmp.as_ref(),
575            32,
576        );
577
578        self.regs().mult_conf().write(|w| unsafe {
579            w.work_mode().bits(mode as u8);
580            w.key_length().bit(curve);
581            w.start().set_bit()
582        });
583
584        while self.is_busy() {}
585
586        cfg_if::cfg_if! {
587            if #[cfg(not(esp32h2))] {
588            self.alignment_helper
589                .volatile_read_regset(self.regs().px_mem(0).as_ptr(), &mut tmp, 32);
590            self.reverse_words(tmp.as_ref(), x);
591            self.alignment_helper
592                .volatile_read_regset(self.regs().py_mem(0).as_ptr(), &mut tmp, 32);
593            self.reverse_words(tmp.as_ref(), y);
594            self.alignment_helper
595                .volatile_read_regset(self.regs().k_mem(0).as_ptr(), &mut tmp, 32);
596            self.reverse_words(tmp.as_ref(), k);
597            } else {
598            self.alignment_helper
599                .volatile_read_regset(self.regs().qx_mem(0).as_ptr(), &mut tmp, 32);
600            self.reverse_words(tmp.as_ref(), x);
601            self.alignment_helper
602                .volatile_read_regset(self.regs().qy_mem(0).as_ptr(), &mut tmp, 32);
603            self.reverse_words(tmp.as_ref(), y);
604            self.alignment_helper
605                .volatile_read_regset(self.regs().qz_mem(0).as_ptr(), &mut tmp, 32);
606            self.reverse_words(tmp.as_ref(), k);
607            }
608        }
609
610        Ok(())
611    }
612
613    pub fn jacobian_point_verification(
626        &mut self,
627        curve: &EllipticCurve,
628        x: &[u8],
629        y: &[u8],
630        z: &[u8],
631    ) -> Result<(), Error> {
632        let curve = match curve {
633            EllipticCurve::P192 => {
634                if x.len() != 24 || y.len() != 24 || z.len() != 24 {
635                    return Err(Error::SizeMismatchCurve);
636                }
637                false
638            }
639            EllipticCurve::P256 => {
640                if x.len() != 32 || y.len() != 32 || z.len() != 32 {
641                    return Err(Error::SizeMismatchCurve);
642                }
643                true
644            }
645        };
646        let mode = WorkMode::JacobianPointVerif;
647
648        let mut tmp = [0_u8; 32];
649        self.reverse_words(x, &mut tmp);
650
651        cfg_if::cfg_if! {
652            if #[cfg(not(esp32h2))] {
653                self.alignment_helper
654                    .volatile_write_regset(self.regs().px_mem(0).as_ptr(), tmp.as_ref(), 32);
655                self.reverse_words(y, &mut tmp);
656                self.alignment_helper
657                    .volatile_write_regset(self.regs().py_mem(0).as_ptr(), tmp.as_ref(), 32);
658                self.reverse_words(z, &mut tmp);
659                self.alignment_helper
660                    .volatile_write_regset(self.regs().k_mem(0).as_ptr(), tmp.as_ref(), 32);
661            } else {
662                self.alignment_helper
663                    .volatile_write_regset(self.regs().qx_mem(0).as_ptr(), tmp.as_ref(), 32);
664                self.reverse_words(y, &mut tmp);
665                self.alignment_helper
666                    .volatile_write_regset(self.regs().qy_mem(0).as_ptr(), tmp.as_ref(), 32);
667                self.reverse_words(z, &mut tmp);
668                self.alignment_helper
669                    .volatile_write_regset(self.regs().qz_mem(0).as_ptr(), tmp.as_ref(), 32);
670            }
671        }
672
673        self.regs().mult_conf().write(|w| unsafe {
674            w.work_mode()
675                .bits(mode as u8)
676                .key_length()
677                .bit(curve)
678                .start()
679                .set_bit()
680        });
681
682        while self.is_busy() {}
684
685        if !self.regs().mult_conf().read().verification_result().bit() {
686            self.regs().mult_conf().reset();
687            return Err(Error::PointNotOnSelectedCurve);
688        }
689
690        Ok(())
691    }
692
693    pub fn affine_point_verification_jacobian_multiplication(
709        &mut self,
710        curve: &EllipticCurve,
711        k: &mut [u8],
712        x: &mut [u8],
713        y: &mut [u8],
714    ) -> Result<(), Error> {
715        let curve = match curve {
716            EllipticCurve::P192 => {
717                if k.len() != 24 || x.len() != 24 || y.len() != 24 {
718                    return Err(Error::SizeMismatchCurve);
719                }
720                false
721            }
722            EllipticCurve::P256 => {
723                if k.len() != 32 || x.len() != 32 || y.len() != 32 {
724                    return Err(Error::SizeMismatchCurve);
725                }
726                true
727            }
728        };
729        let mode = WorkMode::PointVerifJacobianMulti;
730
731        let mut tmp = [0_u8; 32];
732        self.reverse_words(k, &mut tmp);
733        self.alignment_helper.volatile_write_regset(
734            self.regs().k_mem(0).as_ptr(),
735            tmp.as_ref(),
736            32,
737        );
738        self.reverse_words(x, &mut tmp);
739        self.alignment_helper.volatile_write_regset(
740            self.regs().px_mem(0).as_ptr(),
741            tmp.as_ref(),
742            32,
743        );
744        self.reverse_words(y, &mut tmp);
745        self.alignment_helper.volatile_write_regset(
746            self.regs().py_mem(0).as_ptr(),
747            tmp.as_ref(),
748            32,
749        );
750
751        self.regs().mult_conf().write(|w| unsafe {
752            w.work_mode().bits(mode as u8);
753            w.key_length().bit(curve);
754            w.start().set_bit()
755        });
756
757        while self.is_busy() {}
759
760        if !self.regs().mult_conf().read().verification_result().bit() {
761            self.regs().mult_conf().reset();
762            return Err(Error::PointNotOnSelectedCurve);
763        }
764
765        if !self.regs().mult_conf().read().verification_result().bit() {
766            self.regs().mult_conf().reset();
767            return Err(Error::PointNotOnSelectedCurve);
768        }
769
770        cfg_if::cfg_if! {
771            if #[cfg(not(esp32h2))] {
772                self.alignment_helper
773                    .volatile_read_regset(self.regs().px_mem(0).as_ptr(), &mut tmp, 32);
774                self.reverse_words(tmp.as_ref(), x);
775                self.alignment_helper
776                    .volatile_read_regset(self.regs().py_mem(0).as_ptr(), &mut tmp, 32);
777                self.reverse_words(tmp.as_ref(), y);
778                self.alignment_helper
779                    .volatile_read_regset(self.regs().k_mem(0).as_ptr(), &mut tmp, 32);
780                self.reverse_words(tmp.as_ref(), k);
781            } else {
782                self.alignment_helper
783                    .volatile_read_regset(self.regs().qx_mem(0).as_ptr(), &mut tmp, 32);
784                self.reverse_words(tmp.as_ref(), x);
785                self.alignment_helper
786                    .volatile_read_regset(self.regs().qy_mem(0).as_ptr(), &mut tmp, 32);
787                self.reverse_words(tmp.as_ref(), y);
788                self.alignment_helper
789                    .volatile_read_regset(self.regs().qz_mem(0).as_ptr(), &mut tmp, 32);
790                self.reverse_words(tmp.as_ref(), k);
791            }
792        }
793
794        Ok(())
795    }
796
797    #[cfg(esp32h2)]
816    pub fn affine_point_addition(
817        &mut self,
818        curve: &EllipticCurve,
819        px: &mut [u8],
820        py: &mut [u8],
821        qx: &mut [u8],
822        qy: &mut [u8],
823        qz: &mut [u8],
824    ) -> Result<(), Error> {
825        let curve = match curve {
826            EllipticCurve::P192 => {
827                if px.len() != 24
828                    || py.len() != 24
829                    || qx.len() != 24
830                    || qy.len() != 24
831                    || qz.len() != 24
832                {
833                    return Err(Error::SizeMismatchCurve);
834                }
835                false
836            }
837            EllipticCurve::P256 => {
838                if px.len() != 32
839                    || py.len() != 32
840                    || qx.len() != 32
841                    || qy.len() != 32
842                    || qz.len() != 32
843                {
844                    return Err(Error::SizeMismatchCurve);
845                }
846                true
847            }
848        };
849        let mode = WorkMode::PointAdd;
850
851        let mut tmp = [0_u8; 32];
852
853        tmp[0..px.len()].copy_from_slice(px);
854        self.alignment_helper
855            .volatile_write_regset(self.regs().px_mem(0).as_ptr(), &tmp, 32);
856        tmp[0..py.len()].copy_from_slice(py);
857        self.alignment_helper
858            .volatile_write_regset(self.regs().py_mem(0).as_ptr(), &tmp, 32);
859        tmp[0..qx.len()].copy_from_slice(qx);
860        self.alignment_helper
861            .volatile_write_regset(self.regs().qx_mem(0).as_ptr(), &tmp, 32);
862        tmp[0..qy.len()].copy_from_slice(qy);
863        self.alignment_helper
864            .volatile_write_regset(self.regs().qy_mem(0).as_ptr(), &tmp, 32);
865        tmp[0..qz.len()].copy_from_slice(qz);
866        self.alignment_helper
867            .volatile_write_regset(self.regs().qz_mem(0).as_ptr(), &tmp, 32);
868
869        self.regs().mult_conf().write(|w| unsafe {
870            w.work_mode()
871                .bits(mode as u8)
872                .key_length()
873                .bit(curve)
874                .start()
875                .set_bit()
876        });
877
878        while self.is_busy() {}
880
881        self.alignment_helper
882            .volatile_read_regset(self.regs().px_mem(0).as_ptr(), &mut tmp, 32);
883        let mut tmp_len = px.len();
884        px[..].copy_from_slice(&tmp[..tmp_len]);
885        self.alignment_helper
886            .volatile_read_regset(self.regs().py_mem(0).as_ptr(), &mut tmp, 32);
887        tmp_len = py.len();
888        py[..].copy_from_slice(&tmp[..tmp_len]);
889        self.alignment_helper
890            .volatile_read_regset(self.regs().qx_mem(0).as_ptr(), &mut tmp, 32);
891        tmp_len = qx.len();
892        qx[..].copy_from_slice(&tmp[..tmp_len]);
893        self.alignment_helper
894            .volatile_read_regset(self.regs().qy_mem(0).as_ptr(), &mut tmp, 32);
895        tmp_len = qy.len();
896        qy[..].copy_from_slice(&tmp[..tmp_len]);
897        self.alignment_helper
898            .volatile_read_regset(self.regs().qz_mem(0).as_ptr(), &mut tmp, 32);
899        tmp_len = qz.len();
900        qz[..].copy_from_slice(&tmp[..tmp_len]);
901
902        Ok(())
903    }
904
905    #[cfg(esp32h2)]
922    pub fn mod_operations(
923        &mut self,
924        curve: &EllipticCurve,
925        a: &mut [u8],
926        b: &mut [u8],
927        work_mode: WorkMode,
928    ) -> Result<(), Error> {
929        let curve = match curve {
930            EllipticCurve::P192 => {
931                if a.len() != 24 || b.len() != 24 {
932                    return Err(Error::SizeMismatchCurve);
933                }
934                false
935            }
936            EllipticCurve::P256 => {
937                if a.len() != 32 || b.len() != 32 {
938                    return Err(Error::SizeMismatchCurve);
939                }
940                true
941            }
942        };
943
944        let mut tmp = [0_u8; 32];
945        tmp[0..a.len()].copy_from_slice(a);
946        self.alignment_helper
947            .volatile_write_regset(self.regs().px_mem(0).as_ptr(), &tmp, 32);
948        tmp[0..b.len()].copy_from_slice(b);
949        self.alignment_helper
950            .volatile_write_regset(self.regs().py_mem(0).as_ptr(), &tmp, 32);
951
952        self.regs().mult_conf().write(|w| unsafe {
953            w.work_mode()
954                .bits(work_mode.clone() as u8)
955                .key_length()
956                .bit(curve)
957                .start()
958                .set_bit()
959        });
960
961        while self.is_busy() {}
963
964        match work_mode {
965            WorkMode::ModAdd | WorkMode::ModSub => {
966                self.alignment_helper.volatile_read_regset(
967                    self.regs().px_mem(0).as_ptr(),
968                    &mut tmp,
969                    32,
970                );
971                let tmp_len = a.len();
972                a[..].copy_from_slice(&tmp[..tmp_len]);
973            }
974            WorkMode::ModMulti | WorkMode::ModDiv => {
975                self.alignment_helper.volatile_read_regset(
976                    self.regs().py_mem(0).as_ptr(),
977                    &mut tmp,
978                    32,
979                );
980                let tmp_len = b.len();
981                b[..].copy_from_slice(&tmp[..tmp_len]);
982            }
983            _ => unreachable!(),
984        }
985
986        Ok(())
987    }
988
989    #[instability::unstable]
994    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
995        for core in crate::system::Cpu::other() {
996            crate::interrupt::disable(core, Interrupt::ECC);
997        }
998        unsafe { crate::interrupt::bind_interrupt(Interrupt::ECC, handler.handler()) };
999        unwrap!(crate::interrupt::enable(Interrupt::ECC, handler.priority()));
1000    }
1001
1002    fn is_busy(&self) -> bool {
1003        self.regs().mult_conf().read().start().bit_is_set()
1004    }
1005
1006    fn reverse_words(&self, src: &[u8], dst: &mut [u8]) {
1007        let n = core::cmp::min(src.len(), dst.len());
1008        let nsrc = if src.len() > n {
1009            src.split_at(n).0
1010        } else {
1011            src
1012        };
1013        let ndst = if dst.len() > n {
1014            dst.split_at_mut(n).0
1015        } else {
1016            dst
1017        };
1018        for (a, b) in nsrc.chunks_exact(4).zip(ndst.rchunks_exact_mut(4)) {
1019            b.copy_from_slice(&u32::from_be_bytes(a.try_into().unwrap()).to_ne_bytes());
1020        }
1021    }
1022}