cryptix-bigint 0.1.0

A bigint library for cryptix
Documentation
use core::mem::{transmute, transmute_copy};

use crate::{BigUInt, digit::Digit};

use super::IsBigInt;

// impl_nlz!(@all u8, u16, u32, u64);

impl<T: Digit, const LEN: usize> IsBigInt for BigUInt<T, LEN> {
    type Dig = T;

    const DIG_LEN: usize = LEN;
    const ONE: Self = {
        let mut one = [T::ZERO; LEN];
        one[0] = T::ONE;
        BigUInt(one)
    };
    const ZERO: Self = BigUInt([T::ZERO; LEN]);

    /// number of leading zeros
    fn bit_nlz(&self) -> usize {
        let mut cnt = 0;
        let mut i = self.0.len() - 1;

        // FIXME: using iterator significantly increases performance
        loop {
            let nlz = self.0[i].nlz();
            cnt += nlz;
            if nlz != Self::DIG_BIT_LEN { break }
            if i == 0 { break }
            i -= 1;
        }

        cnt
    }

    fn bit_len(&self) -> usize {
        Self::BIT_LEN - self.bit_nlz()
    }

    fn seg_len(&self) -> usize {
        (self.bit_len() + Self::DIG_BIT_LEN_MSK) >> Self::DIG_BIT_LEN_SHT
    }

    fn bit(&self, idx: usize) -> bool {
        self.0[idx >> Self::DIG_BIT_LEN_SHT].bit(idx & Self::DIG_BIT_LEN_MSK)
    }

    fn is_negative(&self) -> bool {
        self.bit(Self::BIT_LEN - 1)
    }

    fn is_odd(&self) -> bool {
        self.0[0].is_odd()
    }

    fn is_zero(&self) -> bool {
        let mut i = 0;
        let mut flag = T::ZERO;

        while i < self.0.len() {
            flag = self.0[i] | flag;
            i += 1;
        }

        flag.is_zero()
    }

    fn as_slice(&self) -> &[Self::Dig; Self::DIG_LEN] {
        /*
         * # Safety
         * 
         * Self::DIG_LEN is constrainted to have the same value as LEN, so this is harmless
         */
        unsafe { transmute(&self.0) }
    }

    fn from_slice(arr: &[Self::Dig; Self::DIG_LEN]) -> Self {
        Self(
            /*
             * # Safety
             * 
             * Self::DIG_LEN is constrainted to have the same value as LEN, so this is harmless
             */
            unsafe { transmute_copy(arr) }
        )
    }

    fn to_array(self) -> [Self::Dig; Self::DIG_LEN] {
        /*
         * # Safety
         * 
         * Self::DIG_LEN is constrainted to have the same value as LEN, so this is harmless
         */
        unsafe { core::intrinsics::transmute_unchecked(self) }
    }

    fn from_array(arr: [Self::Dig; Self::DIG_LEN]) -> Self {
        Self(
            /*
             * # Safety
             * 
             * Self::DIG_LEN is constrainted to have the same value as LEN, so this is harmless
             */
            unsafe { core::intrinsics::transmute_unchecked(arr) }
        )
    }

    fn as_bytes(&self) -> &[u8] 
    where
        [(); Self::BYTE_LEN]:
    {
        /*
         * # Safety
         * 
         * Self::DIG_LEN is constrainted to have the same value as LEN, so this is harmless
         */
        unsafe {
            core::slice::from_raw_parts(
                self.as_ptr() as *const u8, 
                Self::BYTE_LEN
            )
        }
    }

    fn set_bit(mut self, idx: usize, bit: bool) -> Self {
        let dig_idx = idx >> Self::DIG_BIT_LEN_SHT;
        self.0[dig_idx] = self.0[dig_idx].set_bit(idx & Self::DIG_BIT_LEN_MSK, bit);
        self
    }
}