use core::cmp::Ordering;
use rtt_target::rprintln;
use super::Crypto;
use super::CryptoError;
use super::PkaRam;
#[derive(Debug, Eq, PartialEq)]
pub struct BigNum<const MAX_LEN: usize = 64> {
buffer: [u32; MAX_LEN],
size: usize,
}
impl<const MAX_LEN: usize> core::fmt::Display for BigNum<MAX_LEN> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:0x?}", self.inner())
}
}
impl<const MAX_LEN: usize> BigNum<MAX_LEN> {
pub fn new(size: usize) -> Self {
Self {
buffer: [0u32; MAX_LEN],
size,
}
}
pub fn set_size(&mut self, size: usize) {
assert!(size <= MAX_LEN);
self.size = size;
}
pub fn inner(&self) -> &[u32] {
&self.buffer[..self.size]
}
pub fn inner_mut(&mut self) -> &mut [u32] {
&mut self.buffer[..self.size]
}
pub fn add<const L: usize>(&self, rhs: &BigNum<L>) -> Result<BigNum<MAX_LEN>, CryptoError> {
let mut tmp = BigNum::new(self.size.max(rhs.size) + 1);
let len = Crypto::add(self.inner(), rhs.inner(), tmp.inner_mut())?;
tmp.set_size(len);
Ok(tmp)
}
pub fn sub<const L: usize>(&self, rhs: &BigNum<L>) -> Result<BigNum<MAX_LEN>, CryptoError> {
let mut tmp = BigNum::new(self.size.max(rhs.size));
let len = Crypto::sub(self.inner(), rhs.inner(), tmp.inner_mut())?;
tmp.set_size(len);
Ok(tmp)
}
pub fn add_sub(
&self,
c: &BigNum<MAX_LEN>,
b: &BigNum<MAX_LEN>,
) -> Result<BigNum<MAX_LEN>, CryptoError> {
let mut tmp = BigNum::new(self.size);
let len = Crypto::add_sub(self.inner(), c.inner(), b.inner(), tmp.inner_mut())?;
tmp.set_size(len);
Ok(tmp)
}
pub fn mul<const L: usize>(&self, rhs: &BigNum<L>) -> Result<BigNum<MAX_LEN>, CryptoError> {
let mut tmp = BigNum::new(self.size + rhs.size + 6);
let len = Crypto::mul(self.inner(), rhs.inner(), tmp.inner_mut())?;
tmp.set_size(len);
Ok(tmp)
}
pub fn div<const L: usize>(&self, rhs: &BigNum<L>) -> BigNum<MAX_LEN> {
let mut tmp = BigNum::new(self.size + rhs.size + 6);
Crypto::div(self.inner(), rhs.inner(), tmp.inner_mut());
tmp
}
pub fn modulo<const L: usize>(&self, rhs: &BigNum<L>) -> Result<BigNum<MAX_LEN>, CryptoError> {
let mut tmp = BigNum::new(rhs.size + 2);
let len = Crypto::modulo(self.inner(), rhs.inner(), tmp.inner_mut())?;
tmp.set_size(len);
Ok(tmp)
}
pub fn inv_mod<const L: usize>(&self, rhs: &BigNum<L>) -> Result<BigNum<MAX_LEN>, CryptoError> {
let mut tmp = BigNum::new(rhs.size + 1);
Crypto::inv_modulo(self.inner(), rhs.inner(), tmp.inner_mut())?;
Ok(tmp)
}
pub fn exp<const L: usize>(&self, modulus: &BigNum<L>, base: &BigNum<L>) -> BigNum<MAX_LEN> {
let mut tmp = BigNum::new(MAX_LEN);
Crypto::exp(self.inner(), modulus.inner(), base.inner(), tmp.inner_mut());
tmp
}
pub fn compare<const L: usize>(&self, rhs: &BigNum<L>) -> Option<Ordering> {
Crypto::cmp(self.inner(), rhs.inner())
}
}
impl Crypto<'_> {
#[inline]
fn set_a_ptr(offset: usize) {
Self::pka().aptr().write(|w| unsafe { w.bits(offset as u32) });
}
#[inline]
fn set_b_ptr(offset: usize) {
Self::pka().bptr().write(|w| unsafe { w.bits(offset as u32) });
}
#[inline]
fn set_c_ptr(offset: usize) {
Self::pka().cptr().write(|w| unsafe { w.bits(offset as u32) });
}
#[inline]
fn set_d_ptr(offset: usize) {
Self::pka().dptr().write(|w| unsafe { w.bits(offset as u32) });
}
#[inline]
fn set_a_length(length: usize) {
Self::pka()
.alength()
.write(|w| unsafe { w.alength().bits(length as u16) });
}
#[inline]
fn set_b_length(length: usize) {
Self::pka()
.blength()
.write(|w| unsafe { w.blength().bits(length as u16) });
}
pub fn add(
num1: impl AsRef<[u32]>,
num2: impl AsRef<[u32]>,
result: &mut (impl AsMut<[u32]> + ?Sized),
) -> Result<usize, CryptoError> {
let num1 = num1.as_ref();
let num2 = num2.as_ref();
let result = result.as_mut();
if Self::is_pka_in_use() {
return Err(CryptoError::PkaBusy);
}
let pka = Self::pka();
let mut offset: usize = 0;
Self::set_a_ptr(offset);
offset += PkaRam::write_slice(num1, offset);
Self::set_b_ptr(offset >> 2);
offset += PkaRam::write_slice(num2, offset);
Self::set_c_ptr(offset >> 2);
let result_start = offset >> 2;
Self::set_a_length(num1.len());
Self::set_b_length(num2.len());
pka.function().write(|w| w.add().set_bit().run().set_bit());
while Self::is_pka_in_use() {}
let result_end = pka.msw().read().msw_address().bits() as usize;
if pka.msw().read().result_is_zero().bit_is_set() {
result.fill_with(|| 0);
return Ok(0);
}
let len = result_end - result_start + 1;
PkaRam::read_slice(&mut result[..len], result_start << 2);
Ok(len)
}
pub fn sub(
num1: impl AsRef<[u32]>,
num2: impl AsRef<[u32]>,
result: &mut (impl AsMut<[u32]> + ?Sized),
) -> Result<usize, CryptoError> {
let num1 = num1.as_ref();
let num2 = num2.as_ref();
let result = result.as_mut();
if Self::is_pka_in_use() {
return Err(CryptoError::PkaBusy);
}
let pka = Self::pka();
let mut offset: usize = 0;
Self::set_a_ptr(offset);
offset += PkaRam::write_slice(num1, offset);
Self::set_b_ptr(offset >> 2);
offset += PkaRam::write_slice(num2, offset);
Self::set_c_ptr(offset >> 2);
let result_start = offset >> 2;
Self::set_a_length(num1.len());
Self::set_b_length(num2.len());
pka.function()
.write(|w| w.subtract().set_bit().run().set_bit());
while Self::is_pka_in_use() {}
let result_end = pka.msw().read().msw_address().bits() as usize;
if pka.msw().read().result_is_zero().bit_is_set() {
result.fill_with(|| 0);
return Ok(0);
}
let len = result_end - result_start + 1;
PkaRam::read_slice(&mut result[..len], result_start << 2);
Ok(len)
}
pub fn add_sub(
a: impl AsRef<[u32]>,
c: impl AsRef<[u32]>,
b: impl AsRef<[u32]>,
result: &mut (impl AsMut<[u32]> + ?Sized),
) -> Result<usize, CryptoError> {
let a = a.as_ref();
let b = b.as_ref();
let c = c.as_ref();
let result = result.as_mut();
if Self::is_pka_in_use() {
return Err(CryptoError::PkaBusy);
}
let pka = Self::pka();
let mut offset: usize = 0;
Self::set_a_ptr(offset);
offset += PkaRam::write_slice(a, offset);
Self::set_b_ptr(offset >> 2);
offset += PkaRam::write_slice(b, offset);
Self::set_c_ptr(offset >> 2);
offset += PkaRam::write_slice(c, offset);
Self::set_d_ptr(offset >> 2);
let result_start = offset >> 2;
Self::set_a_length(a.len());
pka.function().write(|w| w.addsub().set_bit().run().set_bit());
while Self::is_pka_in_use() {}
let result_end = pka.msw().read().msw_address().bits() as usize;
if pka.msw().read().result_is_zero().bit_is_set() {
result.fill_with(|| 0);
return Ok(0);
}
let len = result_end - result_start + 1;
PkaRam::read_slice(&mut result[..len], result_start << 2);
Ok(len)
}
pub fn mul(
num1: impl AsRef<[u32]>,
num2: impl AsRef<[u32]>,
result: &mut (impl AsMut<[u32]> + ?Sized),
) -> Result<usize, CryptoError> {
let num1 = num1.as_ref();
let num2 = num2.as_ref();
let result = result.as_mut();
if Self::is_pka_in_use() {
return Err(CryptoError::PkaBusy);
}
let pka = Self::pka();
let mut offset: usize = 0;
Self::set_a_ptr(offset);
offset += PkaRam::write_slice(num1, offset);
Self::set_b_ptr(offset >> 2);
offset += PkaRam::write_slice(num2, offset);
Self::set_c_ptr(offset >> 2);
let result_start = offset >> 2;
Self::set_a_length(num1.len());
Self::set_b_length(num2.len());
pka.function()
.write(|w| w.multiply().set_bit().run().set_bit());
while Self::is_pka_in_use() {}
let result_end = pka.msw().read().msw_address().bits() as usize;
if pka.msw().read().result_is_zero().bit_is_set() {
result.fill_with(|| 0);
return Ok(0);
}
let len = result_end - result_start + 1;
PkaRam::read_slice(&mut result[..len], result_start << 2);
Ok(len)
}
#[allow(unused)]
pub fn div(num1: &[u32], num2: &[u32], result: &mut [u32]) {
todo!();
}
pub fn modulo(
num1: impl AsRef<[u32]>,
num2: impl AsRef<[u32]>,
result: &mut (impl AsMut<[u32]> + ?Sized),
) -> Result<usize, CryptoError> {
let num1 = num1.as_ref();
let num2 = num2.as_ref();
let result = result.as_mut();
if Self::is_pka_in_use() {
return Err(CryptoError::PkaBusy);
}
let pka = Self::pka();
let mut offset: usize = 0;
Self::set_a_ptr(offset);
offset += PkaRam::write_slice(num1, offset);
Self::set_b_ptr(offset >> 2);
offset += PkaRam::write_slice(num2, offset);
Self::set_c_ptr(offset >> 2);
Self::set_a_length(num1.len());
Self::set_b_length(num2.len());
pka.function().write(|w| w.modulo().set_bit().run().set_bit());
while Self::is_pka_in_use() {}
if pka.msw().read().result_is_zero().bit_is_set() {
result.fill_with(|| 0);
return Ok(num2.len() + 1);
}
PkaRam::read_slice(&mut result[..num2.len() + 1], offset);
Ok(num2.len() + 1)
}
pub fn inv_modulo(num1: &[u32], num2: &[u32], result: &mut [u32]) -> Result<(), CryptoError> {
if Self::is_pka_in_use() {
return Err(CryptoError::PkaBusy);
}
let pka = Self::pka();
let mut offset: usize = 0;
Self::set_a_ptr(offset);
offset += PkaRam::write_slice(num1, offset);
Self::set_b_ptr(offset >> 2);
offset += PkaRam::write_slice(num2, offset);
Self::set_c_ptr(offset >> 2);
Self::set_a_length(num1.len());
Self::set_b_length(num2.len());
pka.function()
.write(|w| unsafe { w.sequencer_operations().bits(0b111).run().set_bit() });
while Self::is_pka_in_use() {}
let status = pka.shift().read().bits();
match status {
0 => {
PkaRam::read_slice(&mut result[..num1.len()], offset);
Ok(())
}
7 => Err(CryptoError::NoSolution),
31 => Err(CryptoError::PkaFailure),
_ => unreachable!(),
}
}
pub fn exp(
exponent: impl AsRef<[u32]>,
modulus: impl AsRef<[u32]>,
base: impl AsRef<[u32]>,
result: &mut (impl AsMut<[u32]> + ?Sized),
) {
let exponent = exponent.as_ref();
let modulus = modulus.as_ref();
let base = base.as_ref();
let result = result.as_mut();
if Self::is_pka_in_use() {
return;
}
let pka = Self::pka();
let mut offset: usize = 0;
Self::set_a_ptr(offset);
offset += PkaRam::write_slice(exponent, offset);
Self::set_b_ptr(offset >> 2);
offset += PkaRam::write_slice(modulus, offset);
Self::set_c_ptr(offset >> 2);
PkaRam::write_slice(base, offset);
Self::set_d_ptr(offset >> 2);
Self::set_a_length(exponent.len());
Self::set_b_length(modulus.len());
pka.function()
.write(|w| unsafe { w.sequencer_operations().bits(0b010).run().set_bit() });
while Self::is_pka_in_use() {}
let msw_val = pka.msw().read().msw_address().bits() as usize;
if msw_val == 0 || pka.msw().read().result_is_zero().bit_is_set() {
return;
}
let len1 = msw_val + 1;
let len2 = pka.dptr().read().bits() as usize;
let len = len1 - len2;
PkaRam::read_slice(&mut result[..len], offset);
}
pub fn cmp(num1: impl AsRef<[u32]>, num2: impl AsRef<[u32]>) -> Option<Ordering> {
let num1 = num1.as_ref();
let num2 = num2.as_ref();
if Self::is_pka_in_use() {
return None;
}
let pka = Self::pka();
let mut offset = 0;
Self::set_a_ptr(offset);
offset += PkaRam::write_slice(num1, offset);
Self::set_c_ptr(offset >> 2);
PkaRam::write_slice(num2, offset);
Self::set_a_length(num1.len());
pka.function()
.write(|w| w.compare().set_bit().run().set_bit());
while Self::is_pka_in_use() {}
let compare = Crypto::pka().compare().read();
if compare.a_equals_b().bit_is_set() {
Some(Ordering::Equal)
} else if compare.a_less_than_b().bit_is_set() {
Some(Ordering::Less)
} else if compare.a_greater_than_b().bit_is_set() {
Some(Ordering::Greater)
} else {
None
}
}
}