pub fn modular_exponentiation<'a>(
        &self,
        input: &[u8],
        exponent: &[u8],
        modulus: &[u8],
        mode: ExpModMode,
        window_size: ExpModWindowSize,
        buffer: &'a mut [u8],
    ) -> Result<&'a [u8], ExpModFailure> {
        const PUKCL_EXPMOD_EXPINPUKCCRAM: u16 = 0x02;

        // Modulus validation
        if modulus.len() % 4 != 0 {
            return Err(ExpModFailure::WrongInputParameterAlignment {
                faulty_slice: "modulus",
            });
        }
        // Modulus size must be at least 12 bytes (43.3.5.2.3 of DS60001507F datasheet)
        const MINIMUM_MODULUS_LEN: usize = 12;
        if modulus.len() < MINIMUM_MODULUS_LEN {
            return Err(ExpModFailure::WrongInputParameterLength {
                faulty_slice: "modulus",
                actual_length: modulus.len(),
                expected_length: ExpectedLengthError::AtLeast(MINIMUM_MODULUS_LEN),
            });
        }
        // Input validation
        // Note: Only length is checked but in theory value itself being larger than
        // modulus is probably wrong as well
        if input.len() > modulus.len() {
            return Err(ExpModFailure::WrongInputParameterLength {
                faulty_slice: "input",
                actual_length: input.len(),
                expected_length: ExpectedLengthError::AtMost(modulus.len()),
            });
        }
        // Exponent validation
        // Note: Only length is checked but in theory value itself being larger than
        // modulus is probably wrong as well
        if exponent.len() > modulus.len() {
            return Err(ExpModFailure::WrongInputParameterLength {
                faulty_slice: "exponent",
                actual_length: exponent.len(),
                expected_length: ExpectedLengthError::AtMost(modulus.len()),
            });
        }

        let (modulus_cr, cns_cr, output, workspace, exponent_cr, mut __);

        let cns = self.zp_calculate_cns(buffer, modulus)?;
        let padding_for_cns = padding_for_len(cns.len());
        // Sanity check in case someone changes `zp_calculate_cns` implementation
        assert!(cns.len() + padding_for_cns == modulus.len() + 8);
        let padding_for_exponent = padding_for_len(exponent.len());

        let mut crypto_ram = unsafe { c_abi::CryptoRam::new() };
        // 32-byte padding with zeroes on a MSB side of every parameter is required by
        // PUKCC algorithms (unless said otherwise). Little endianness requires padding
        // *after* a parameter as MSB is placed on high addresses.
        copy_to_cryptoram! {
            crypto_ram,
            (modulus_cr, modulus.iter().cloned().rev()),
            (__, repeat(0).take(4)),
            (cns_cr, cns.iter().cloned().rev()),
            (__, repeat(0).take(padding_for_cns)),
            // 1. `input` is replaced with an outcome of the computation
            // 2. `input` is padded to match `len(modulus)`
            (output, input.iter().cloned().rev().chain(repeat(0).take(modulus.len() - input.len()))),
            // `input` area is used for computation and requires additional 4 0_u32 on MSB side
            (__, repeat(0).take(16)),
            // Exponent is required to have 0_u32 on LSB side
            // `exponent_cr` is only used to get a pointer during `pukcl_params` initialization
            (exponent_cr, repeat(0).take(4)),
            (__, exponent.iter().cloned().rev()),
            (__, repeat(0).take(padding_for_exponent)),
            // Workspace is just marked with a zero length slice just to get its address. As
            // it is placed at the end, idea is that algorithm will use whatever amount of
            // memory it needs
            (workspace, 0..0)
        };
        // Table 43-52; 43.3.5.2.5 in DS60001507F
        let workspace_len: usize = match window_size {
            ExpModWindowSize::One => 3 * (modulus.len() + 4) + 8,
            ExpModWindowSize::Two => 4 * (modulus.len() + 4) + 8,
            ExpModWindowSize::Three => 6 * (modulus.len() + 4) + 8,
            ExpModWindowSize::Four => 10 * (modulus.len() + 4) + 8,
        };
        let workspace_end_ptr = workspace.as_ptr().wrapping_add(workspace_len);
        let crypto_ram_end_ptr = crypto_ram.as_ptr_range().end;
        if workspace_end_ptr > crypto_ram_end_ptr {
            return Err(ExpModFailure::RunOutOfCryptoRam {
                workspace_end_ptr,
                crypto_ram_end_ptr,
            });
        }
        let mut pukcl_params = c_abi::PukclParams::default();
        unsafe {
            // Note: `exponent` outside of Crypto RAM is not supported
            pukcl_params.header.u2Option = PUKCL_EXPMOD_EXPINPUKCCRAM
                | window_size.get_windows_size_mask()
                | mode.get_mode_mask();
            let mut service_params = &mut pukcl_params.params.ExpMod;
            service_params.nu1XBase = output.pukcc_base();
            service_params.nu1ModBase = modulus_cr.pukcc_base();
            service_params.nu1CnsBase = cns_cr.pukcc_base();
            service_params.nu1PrecompBase = workspace.pukcc_base();
            service_params.pfu1ExpBase = exponent_cr.as_ptr() as _;
            service_params.u2ModLength = modulus.len() as _;
            service_params.u2ExpLength = (exponent.len() + padding_for_exponent) as _;
            service_params.u1Blinding = 0;
        }

        unsafe { c_abi::ExpMod::call(&mut pukcl_params) };
        match pukcl_params.header.u2Status.into() {
            PukclReturnCode::Ok => {}
            error_code => return Err(ExpModFailure::ServiceFailure(error_code)),
        }

        buffer
            .iter_mut()
            .zip(output.iter().rev())
            .for_each(|(target_iter, source_iter)| *target_iter = *source_iter);

        Ok(&buffer[..modulus.len()])
    }
/// Service performing a modular exponentiation.
///
/// ```text
/// result = pow(input, exponent) % modulus
/// ```
///
/// Input parameters:
/// - `input`: `&[u8]`
///     - Requirements:
///         - `len(input) <= len(modulus)`
///     - Message, hash, any slice of data that will undergo modular
///       exponentiation
/// - `exponent`: `&[u8]`
///     - Requirements:
///         - `len(exponent) <= len(modulus)`
/// - `modulus`: `&[u8]`
///     - Requirements:
///         - `len(modulus) % 4`
///         - `12 <= len(modulus) < ?`
///     - Note: Maximum size depends on few factors like CryptoRAM and
///       workspace window size. Consult the table with data layout down
///       below.
/// - `mode`: [`ExpModMode`]
///     - Mode of operation: use regular or fast variant of the underlying
///       algorithm
///     - This parameter does not influence the end result of a computation
/// - `window_size`: [`ExpModWindowSize`]
///     - Enum describing 4 predefined workspace sizes (from smallest to
///       biggest) in CryptoRAM.
///     - Bigger the workspace size - faster the algorithm can operate -
///       greater limitations on input parameters are put (as they occupy
///       CryptoRAM address space as well). Consult the table with data
///       layout down below.
///     - This parameter does not influence the end result of a computation
/// - `buffer`: `&'a mut [u8]`
///     - Requirements:
///         - `len(buffer) >= len(modulus) + 5`
///     - Buffer used internally for CNS calculation. Piece of it is used
///       also for a return value.
///
/// Return value:
/// - `Result::Ok(&'a [u8])`
///     - Length: `len(modulus)`
///     - A result of modular exponentiation
/// - `Result::Err`
///     - Possible failure scenarios are encapsulated in a [`ExpModFailure`]
///       enum type
///
/// Failing to meet the requirements for any input parameter will end up
/// with an error being returned.
///
/// CryptoRAM is `4KiB` (`0x1000` bytes) in size. Data layout in CryptoRAM
/// looks as follows and its size cannot go over the threshold of `4KiB`.
///
/// ```text
/// - modulus: len(modulus) + 4
/// - cns (reduction constant): len(modulus) + 8
/// - output/input (after/before calculation): len(modulus) + 16
/// - exponent: len(exponent) + 4 (+ padding to be % 4)
/// - workspace: (depending on `window_size`)
///     - ExpModWindowSize::One => 3 * (modulus.len() + 4) + 8
///     - ExpModWindowSize::Two => 4 * (modulus.len() + 4) + 8
///     - ExpModWindowSize::Three => 6 * (modulus.len() + 4) + 8
///     - ExpModWindowSize::Four => 10 * (modulus.len() + 4) + 8
/// ```
///
/// # RSA
///
/// This function can be used to perform RSA related computation like
/// encryption, decryption, signature generation and validation.
/// - To **encrypt** `input` value, split _public key_ into _public_
///   `exponent` and `modulus` and pass them into the function. Return value
///   is going to be a cipher of an `input`.
/// - To **decrypt** `input` value, split _private key_ into _private_
///   `exponent` and `modulus` and pass them into the function. Return value
///   is going to be a decrypted `input`.
/// - To **generate a signature**, pass the _hash_ of a message being signed
///   as an `input` into the function and use a _private key_. Return value
///   is going to be a signature (encrypted _hash_).
/// - To **validate a signature**, pass it as an `input` into the function
///   and use the _public key_. Decrypted signature is an expected hash of a
///   message. Calculate the hash of your message and compare it with an
///   expected value. If they are the same, validation can be considered
///   successful.
///
/// All RSA variants up to **RSA4096** (included) will fit into CryptoRAM
/// and therefore are supported.
Service performing a modular exponentiation.





Failing to meet the requirements for any input parameter will end up
with an error being returned.

CryptoRAM is `4KiB` (`0x1000` bytes) in size. Data layout in CryptoRAM
looks as follows and its size cannot go over the threshold of `4KiB`.


Service performing a modular exponentiation . Failing to meet the requirements for any input parameter will end up with an error being returned . CryptoRAM is ` 4KiB ` ( ` 0x1000 ` bytes ) in size . Data layout in CryptoRAM looks as follows and its size cannot go over the threshold of ` 4KiB ` .
pub fn modular_exponentiation<'a>(
        &self,
        input: &[u8],
        exponent: &[u8],
        modulus: &[u8],
        mode: ExpModMode,
        window_size: ExpModWindowSize,
        buffer: &'a mut [u8],
    ) -> Result<&'a [u8], ExpModFailure> {
        const PUKCL_EXPMOD_EXPINPUKCCRAM: u16 = 0x02;
        // Modulus validation
        if modulus.len() % 4 != 0 {
            return Err(ExpModFailure::WrongInputParameterAlignment {
                faulty_slice: "modulus",
            });
        }
        // Modulus size must be at least 12 bytes (43.3.5.2.3 of DS60001507F datasheet)
        const MINIMUM_MODULUS_LEN: usize = 12;
        if modulus.len() < MINIMUM_MODULUS_LEN {
            return Err(ExpModFailure::WrongInputParameterLength {
                faulty_slice: "modulus",
                actual_length: modulus.len(),
                expected_length: ExpectedLengthError::AtLeast(MINIMUM_MODULUS_LEN),
            });
        }
        // Input validation
        // Note: Only length is checked but in theory value itself being larger than
        // modulus is probably wrong as well
        if input.len() > modulus.len() {
            return Err(ExpModFailure::WrongInputParameterLength {
                faulty_slice: "input",
                actual_length: input.len(),
                expected_length: ExpectedLengthError::AtMost(modulus.len()),
            });
        }
        // Exponent validation
        // Note: Only length is checked but in theory value itself being larger than
        // modulus is probably wrong as well
        if exponent.len() > modulus.len() {
            return Err(ExpModFailure::WrongInputParameterLength {
                faulty_slice: "exponent",
                actual_length: exponent.len(),
                expected_length: ExpectedLengthError::AtMost(modulus.len()),
            });
        }
        let (modulus_cr, cns_cr, output, workspace, exponent_cr, mut __);
        let cns = self.zp_calculate_cns(buffer, modulus)?;
        let padding_for_cns = padding_for_len(cns.len());
        // Sanity check in case someone changes `zp_calculate_cns` implementation
        assert!(cns.len() + padding_for_cns == modulus.len() + 8);
        let padding_for_exponent = padding_for_len(exponent.len());
        let mut crypto_ram = unsafe { c_abi::CryptoRam::new() };
        // 32-byte padding with zeroes on a MSB side of every parameter is required by
        // PUKCC algorithms (unless said otherwise). Little endianness requires padding
        // *after* a parameter as MSB is placed on high addresses.
        copy_to_cryptoram! {
            crypto_ram,
            (modulus_cr, modulus.iter().cloned().rev()),
            (__, repeat(0).take(4)),
            (cns_cr, cns.iter().cloned().rev()),
            (__, repeat(0).take(padding_for_cns)),
            // 1. `input` is replaced with an outcome of the computation
            // 2. `input` is padded to match `len(modulus)`
            (output, input.iter().cloned().rev().chain(repeat(0).take(modulus.len() - input.len()))),
            // `input` area is used for computation and requires additional 4 0_u32 on MSB side
            (__, repeat(0).take(16)),
            // Exponent is required to have 0_u32 on LSB side
            // `exponent_cr` is only used to get a pointer during `pukcl_params` initialization
            (exponent_cr, repeat(0).take(4)),
            (__, exponent.iter().cloned().rev()),
            (__, repeat(0).take(padding_for_exponent)),
            // Workspace is just marked with a zero length slice just to get its address. As
            // it is placed at the end, idea is that algorithm will use whatever amount of
            // memory it needs
            (workspace, 0..0)
        };
        // Table 43-52; 43.3.5.2.5 in DS60001507F
        let workspace_len: usize = match window_size {
            ExpModWindowSize::One => 3 * (modulus.len() + 4) + 8,
            ExpModWindowSize::Two => 4 * (modulus.len() + 4) + 8,
            ExpModWindowSize::Three => 6 * (modulus.len() + 4) + 8,
            ExpModWindowSize::Four => 10 * (modulus.len() + 4) + 8,
        };
        let workspace_end_ptr = workspace.as_ptr().wrapping_add(workspace_len);
        let crypto_ram_end_ptr = crypto_ram.as_ptr_range().end;
        if workspace_end_ptr > crypto_ram_end_ptr {
            return Err(ExpModFailure::RunOutOfCryptoRam {
                workspace_end_ptr,
                crypto_ram_end_ptr,
            });
        }
        let mut pukcl_params = c_abi::PukclParams::default();
        unsafe {
            // Note: `exponent` outside of Crypto RAM is not supported
            pukcl_params.header.u2Option = PUKCL_EXPMOD_EXPINPUKCCRAM
                | window_size.get_windows_size_mask()
                | mode.get_mode_mask();
            let mut service_params = &mut pukcl_params.params.ExpMod;
            service_params.nu1XBase = output.pukcc_base();
            service_params.nu1ModBase = modulus_cr.pukcc_base();
            service_params.nu1CnsBase = cns_cr.pukcc_base();
            service_params.nu1PrecompBase = workspace.pukcc_base();
            service_params.pfu1ExpBase = exponent_cr.as_ptr() as _;
            service_params.u2ModLength = modulus.len() as _;
            service_params.u2ExpLength = (exponent.len() + padding_for_exponent) as _;
            service_params.u1Blinding = 0;
        }
        unsafe { c_abi::ExpMod::call(&mut pukcl_params) };
        match pukcl_params.header.u2Status.into() {
            PukclReturnCode::Ok => {}
            error_code => return Err(ExpModFailure::ServiceFailure(error_code)),
        }
        buffer
            .iter_mut()
            .zip(output.iter().rev())
            .for_each(|(target_iter, source_iter)| *target_iter = *source_iter);
        Ok(&buffer[..modulus.len()])
    }
pub fn modular_exponentiation < ' a > ( & self , input : & [ u8 ] , exponent : & [ u8 ] , modulus : & [ u8 ] , mode : ExpModMode , window_size : ExpModWindowSize , buffer : & ' a mut [ u8 ] , ) -> Result < & ' a [ u8 ] , ExpModFailure > { const PUKCL_EXPMOD_EXPINPUKCCRAM : u16 = 0x02 ; // Modulus validation if modulus . len ( ) % 4 != 0 { return Err ( ExpModFailure :: WrongInputParameterAlignment { faulty_slice : " " , } ) ; } // Modulus size must be at least 12 bytes (43.3.5.2.3 of DS60001507F datasheet) const MINIMUM_MODULUS_LEN : usize = 12 ; if modulus . len ( ) < MINIMUM_MODULUS_LEN { return Err ( ExpModFailure :: WrongInputParameterLength { faulty_slice : " " , actual_length : modulus . len ( ) , expected_length : ExpectedLengthError :: AtLeast ( MINIMUM_MODULUS_LEN ) , } ) ; } // Input validation // Note: Only length is checked but in theory value itself being larger than // modulus is probably wrong as well if input . len ( ) > modulus . len ( ) { return Err ( ExpModFailure :: WrongInputParameterLength { faulty_slice : " " , actual_length : input . len ( ) , expected_length : ExpectedLengthError :: AtMost ( modulus . len ( ) ) , } ) ; } // Exponent validation // Note: Only length is checked but in theory value itself being larger than // modulus is probably wrong as well if exponent . len ( ) > modulus . len ( ) { return Err ( ExpModFailure :: WrongInputParameterLength { faulty_slice : " " , actual_length : exponent . len ( ) , expected_length : ExpectedLengthError :: AtMost ( modulus . len ( ) ) , } ) ; } let ( modulus_cr , cns_cr , output , workspace , exponent_cr , mut __ ) ; let cns = self . zp_calculate_cns ( buffer , modulus ) ? ; let padding_for_cns = padding_for_len ( cns . len ( ) ) ; // Sanity check in case someone changes `zp_calculate_cns` implementation assert ! ( cns len ( ) padding_for_cns modulus len ( ) 8 ) ; let padding_for_exponent = padding_for_len ( exponent . len ( ) ) ; let mut crypto_ram = unsafe { c_abi :: CryptoRam :: new ( ) } ; // 32-byte padding with zeroes on a MSB side of every parameter is required by // PUKCC algorithms (unless said otherwise). Little endianness requires padding // *after* a parameter as MSB is placed on high addresses. copy_to_cryptoram ! { crypto_ram ( modulus_cr modulus iter ( ) cloned ( ) rev ( ) ) ( repeat ( 0 ) take ( 4 ) ) ( cns_cr cns iter ( ) cloned ( ) rev ( ) ) ( repeat ( 0 ) take ( padding_for_cns ) ) // 1. `input` is replaced with an outcome of the computation // 2. `input` is padded to match `len(modulus)` ( output input iter ( ) cloned ( ) rev ( ) chain ( repeat ( 0 ) take ( modulus len ( ) input len ( ) ) ) ) // `input` area is used for computation and requires additional 4 0_u32 on MSB side ( repeat ( 0 ) take ( 16 ) ) // Exponent is required to have 0_u32 on LSB side // `exponent_cr` is only used to get a pointer during `pukcl_params` initialization ( exponent_cr repeat ( 0 ) take ( 4 ) ) ( exponent iter ( ) cloned ( ) rev ( ) ) ( repeat ( 0 ) take ( padding_for_exponent ) ) // Workspace is just marked with a zero length slice just to get its address. As // it is placed at the end, idea is that algorithm will use whatever amount of // memory it needs ( workspace 0 0 ) } ; // Table 43-52; 43.3.5.2.5 in DS60001507F let workspace_len : usize = match window_size { ExpModWindowSize :: One => 3 * ( modulus . len ( ) + 4 ) + 8 , ExpModWindowSize :: Two => 4 * ( modulus . len ( ) + 4 ) + 8 , ExpModWindowSize :: Three => 6 * ( modulus . len ( ) + 4 ) + 8 , ExpModWindowSize :: Four => 10 * ( modulus . len ( ) + 4 ) + 8 , } ; let workspace_end_ptr = workspace . as_ptr ( ) . wrapping_add ( workspace_len ) ; let crypto_ram_end_ptr = crypto_ram . as_ptr_range ( ) . end ; if workspace_end_ptr > crypto_ram_end_ptr { return Err ( ExpModFailure :: RunOutOfCryptoRam { workspace_end_ptr , crypto_ram_end_ptr , } ) ; } let mut pukcl_params = c_abi :: PukclParams :: default ( ) ; unsafe { // Note: `exponent` outside of Crypto RAM is not supported pukcl_params . header . u2Option = PUKCL_EXPMOD_EXPINPUKCCRAM | window_size . get_windows_size_mask ( ) | mode . get_mode_mask ( ) ; let mut service_params = & mut pukcl_params . params . ExpMod ; service_params . nu1XBase = output . pukcc_base ( ) ; service_params . nu1ModBase = modulus_cr . pukcc_base ( ) ; service_params . nu1CnsBase = cns_cr . pukcc_base ( ) ; service_params . nu1PrecompBase = workspace . pukcc_base ( ) ; service_params . pfu1ExpBase = exponent_cr . as_ptr ( ) as _ ; service_params . u2ModLength = modulus . len ( ) as _ ; service_params . u2ExpLength = ( exponent . len ( ) + padding_for_exponent ) as _ ; service_params . u1Blinding = 0 ; } unsafe { c_abi :: ExpMod :: call ( & mut pukcl_params ) } ; match pukcl_params . header . u2Status . into ( ) { PukclReturnCode :: Ok => { } error_code => return Err ( ExpModFailure :: ServiceFailure ( error_code ) ) , } buffer . iter_mut ( ) . zip ( output . iter ( ) . rev ( ) ) . for_each ( | ( target_iter , source_iter ) | * target_iter = * source_iter ) ; Ok ( & buffer [ .. modulus . len ( ) ] ) }
Service performing a modular exponentiation.
Service performing a modular exponentiation .
&self
input
&[u8]
exponent
&[u8]
modulus
&[u8]
mode
ExpModMode
window_size
ExpModWindowSize
buffer
&'a mut [u8]
&self
input
&[u8]
exponent
&[u8]
modulus
&[u8]
mode
ExpModMode
window_size
ExpModWindowSize
buffer
&'a mut [u8]
rsa
This function can be used to perform RSA related computation like
encryption, decryption, signature generation and validation.
To **encrypt** `input` value, split _public key_ into _public_
`exponent` and `modulus` and pass them into the function. Return value
is going to be a cipher of an `input`.
To **decrypt** `input` value, split _private key_ into _private_
`exponent` and `modulus` and pass them into the function. Return value
is going to be a decrypted `input`.
To **generate a signature**, pass the _hash_ of a message being signed
as an `input` into the function and use a _private key_. Return value
is going to be a signature (encrypted _hash_).
To **validate a signature**, pass it as an `input` into the function
and use the _public key_. Decrypted signature is an expected hash of a
message. Calculate the hash of your message and compare it with an
expected value. If they are the same, validation can be considered
successful.

All RSA variants up to **RSA4096** (included) will fit into CryptoRAM
and therefore are supported.
This function can be used to perform RSA related computation like encryption decryption signature generation and validation . To ** encrypt ** ` input ` value split _public key_ into _public_ ` exponent ` and ` modulus ` and pass them into the function . Return value is going to be a cipher of an ` input ` . To ** decrypt ** ` input ` value split _private key_ into _private_ ` exponent ` and ` modulus ` and pass them into the function . Return value is going to be a decrypted ` input ` . To ** generate a signature ** pass the _hash_ of a message being signed as an ` input ` into the function and use a _private key_ . Return value is going to be a signature ( encrypted _hash_ ) . To ** validate a signature ** pass it as an ` input ` into the function and use the _public key_ . Decrypted signature is an expected hash of a message . Calculate the hash of your message and compare it with an expected value . If they are the same validation can be considered successful . All RSA variants up to ** RSA4096 ** ( included ) will fit into CryptoRAM and therefore are supported .