<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Issues with PKA Engine Modular Operations on CC310</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/117528/issues-with-pka-engine-modular-operations-on-cc310</link><description>I&amp;#39;m working on implementing arithmetic operations using the PKA engine on the nrf52840 in Rust, following the CRYPTOCELL — Arm TrustZone CryptoCell 310 datasheet. While I&amp;#39;ve successfully implemented basic arithmetic operations, I&amp;#39;m running into several</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Wed, 02 Apr 2025 11:26:35 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/117528/issues-with-pka-engine-modular-operations-on-cc310" /><item><title>RE: Issues with PKA Engine Modular Operations on CC310</title><link>https://devzone.nordicsemi.com/thread/530211?ContentTypeID=1</link><pubDate>Wed, 02 Apr 2025 11:26:35 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:bd65f97c-7c90-452e-9a86-c218a1c66be4</guid><dc:creator>Frank Aune</dc:creator><description>&lt;p&gt;Very cool to see you working on a Rust port - love it! Note sure how helpful this is, but take a look at Arm&amp;#39;s low level driver in their trustedfirmware repo:&lt;br /&gt;&lt;br /&gt;&lt;a href="https://git.trustedfirmware.org/plugins/gitiles/TF-M/trusted-firmware-m/+/refs/heads/main/platform/ext/target/arm/drivers/cc3xx/low_level_driver"&gt;git.trustedfirmware.org/.../low_level_driver&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Issues with PKA Engine Modular Operations on CC310</title><link>https://devzone.nordicsemi.com/thread/516583?ContentTypeID=1</link><pubDate>Wed, 01 Jan 2025 18:38:50 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:8ded109d-3de9-47c1-83cf-ddfcc5fa58a9</guid><dc:creator>ElsaLopez</dc:creator><description>&lt;p&gt;The problem I see with that is that the calculation of floor (2^(N+64-1)/n) is bigger than the operand size of the modulus, so if I actually set the operand size to be exactly that, when I try to do calculations to obtain that value it is not performed correctly, as it exceeds bounds of the operand size.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;const N: [u32; 8] = [
    0x00000000, 0x00000000, 0x00000000, 0x00000000,
    0x00000000, 0x00000000, 0x00000000, 0x00000015
];

const MAX_OPERAND_SIZE_BITS: usize = 64 * 4 * 8;
const OPERAND_SIZE_BITS: usize = 8 * 4 * 8;
const OPERAND_SIZE_WORDS: usize = OPERAND_SIZE_BITS/8/4;
const MAX_OPERAND_SIZE_WORDS: usize = MAX_OPERAND_SIZE_BITS/8/4;
const OPERAND_MEMORY_OFFSET: u32 = (OPERAND_SIZE_BITS as u32)/8/4 + 2;
const VIRTUAL_MEMORY_SIZE_BITS: usize = 64 * 4 * 8; // 64-bit word size
const VIRTUAL_MEMORY_OFFSET: u32 = (VIRTUAL_MEMORY_SIZE_BITS as u32)/8/4 + 2;

fn main() -&amp;gt; ! {
    info!(&amp;quot;Running.&amp;quot;);

    // Enable the PKA and CryptoCell clock
    let p = pac::Peripherals::take().unwrap();
    let cc_misc = p.cc_misc;
    let cc_pka = p.cc_pka;

    p.cryptocell.enable().write(|w| w.enable().set_bit());
    cc_misc.pka_clk().write(|w| w.enable().set_bit());

    while cc_misc.clk_status().read().pka_clk().bit_is_clear() {
    // Wait for PKA clock to be ready
    }
    info!(&amp;quot;PKA clock ready. PKA engine enabled&amp;quot;);

    // Operand size
    cc_pka.pka_l(1).write(|w| unsafe { w.bits(OPERAND_SIZE_BITS as u32) }); 
    // max opernad size
    cc_pka.pka_l(0).write(|w| unsafe { w.bits(MAX_OPERAND_SIZE_BITS as u32) }); 

    // Configure memory map
    configure_memory_map(&amp;amp;cc_pka);

    // Clear registers
    clear_pka_registers(&amp;amp;cc_pka);

    // Load N
    load_word_array(&amp;amp;cc_pka, 0, &amp;amp;N);
    
    // Calculate Np
    calculate_np(&amp;amp;cc_pka);

   ...

    // exit via semihosting call
    debug::exit(EXIT_SUCCESS);
    loop {}
}



fn calculate_np(cc_pka: &amp;amp;pac::CcPka) -&amp;gt; () {

    let total_bits = OPERAND_SIZE_BITS + 64 + 8 - 1;

    // Create big number representing 2^(N+A+X-1)    
    let word_index = total_bits / 32;
    let bit_index = total_bits % 32;
    let mut numerator = [0u32; MAX_OPERAND_SIZE_WORDS];
    numerator[MAX_OPERAND_SIZE_WORDS - 1 - word_index] = 1 &amp;lt;&amp;lt; bit_index;
 
    // Load data in reverse order into a temp register
    load_word_array(&amp;amp;cc_pka, 7, &amp;amp;numerator);
 
    // n is already in R0, execute division
    cc_pka.opcode().write(|w| unsafe {
        w.bits(
        ( 1 &amp;lt;&amp;lt; REG_R_POS)
        | ( 0 &amp;lt;&amp;lt; REG_B_POS)
        | ( 7 &amp;lt;&amp;lt; REG_A_POS)
        | ( 0 &amp;lt;&amp;lt; LEN_POS)
        | ((cc_pka::opcode::Opcode::Division as u32) &amp;lt;&amp;lt; OPCODE_POS)
        )
        });
 }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;INFO Verification of R0: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15]&lt;br /&gt;└─ crypto_cc310::read_word_array @ src/main.rs:287 &lt;br /&gt;INFO Verification of R1: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF]&lt;/p&gt;
&lt;p&gt;In the function calculate_np, I need to use the MAX_OPERAND_SIZE, since that exponent value is bigger than the OPERAND_SIZE. I do not know how to solve this, or if I am implementing it correctly&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Issues with PKA Engine Modular Operations on CC310</title><link>https://devzone.nordicsemi.com/thread/516227?ContentTypeID=1</link><pubDate>Tue, 24 Dec 2024 16:16:45 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:735ac0af-8e2f-4476-ad76-94ed059476c8</guid><dc:creator>Emil Lenngren</dc:creator><description>&lt;p&gt;If operand size in bits according to the PKA_L register is N, then the Np parameter should contain floor(2^(N+64-1)/n), where n is the modulus.&lt;/p&gt;
&lt;p&gt;After doing some testing on my own, it appears the cryptocell has some constraints on n and the operand size. To get correct results, I suggest you to try a larger modulus (bitsize &amp;gt;= 64) and set the operand size in bits (PKA_L) to exactly fit the modulus, or at most 8 bit extra, but not bigger. Not entirely sure though. However, the reference implementation uses 8 extra bits.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Issues with PKA Engine Modular Operations on CC310</title><link>https://devzone.nordicsemi.com/thread/516217?ContentTypeID=1</link><pubDate>Tue, 24 Dec 2024 09:51:02 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:59413595-fbde-41bb-a421-1eb656085c7d</guid><dc:creator>ElsaLopez</dc:creator><description>&lt;p&gt;Thanks for the reference. However, why is A = 64? And X = 8? According to the link you have provided&amp;nbsp; uint32_t A = CC_PKA_WORD_SIZE_IN_BITS;&lt;br /&gt; uint32_t X = PKA_EXTRA_BITS;&lt;/p&gt;
&lt;p&gt;But I cannot find those values anywhere.&lt;/p&gt;
&lt;p&gt;Also, I have implemented the calculation of NP following the c code, but still reductions are not being performed. Here is what I have&lt;br /&gt;&lt;pre class="ui-code" data-mode="text"&gt;... 
// Example constants for positions
const TAG_POS: u8 = 0;         // tag of the operand
const REG_R_POS: u8 = 6;       // Result register position (Bits 6:10)
const REG_R_CTRL_POS: u8 = 11; // Result register control position (Bit 11)
const REG_B_POS: u8 = 12;      // Operand B register position (Bits 12:16)
const REG_B_CTRL_POS: u8 = 17; // Operand B register control position (Bit 17)
const REG_A_POS: u8 = 18;      // Operand A register position (Bits 18:22)
const REG_A_CTRL_POS: u8 = 23; // Operand A register control position (Bit 23)
const LEN_POS: u8 = 24;        // Operand length register index (Bits 24:26)
const OPCODE_POS: u8 = 27;     // Operation code position (Bits 27:31)

// All virtual registers must be 64 bits word size aligned, and the size of the virtual 
// registers must be at least the size of the largest operand plus an extra 64 bits 
// for internal PKA calculations. 
// These extra 64 bits must be initialized to zero. 
const MAX_OPERAND_SIZE_BITS: usize = 64 * 4 * 8;
const OPERAND_SIZE_BITS: usize = 8 * 4 * 8;
const OPERAND_SIZE_WORDS: usize = OPERAND_SIZE_BITS/8/4;
const MAX_OPERAND_SIZE_WORDS: usize = MAX_OPERAND_SIZE_BITS/8/4;
const OPERAND_MEMORY_OFFSET: u32 = (OPERAND_SIZE_BITS as u32)/8/4 + 2;
const VIRTUAL_MEMORY_SIZE_BITS: usize = 64 * 4 * 8; // 64-bit word size
const VIRTUAL_MEMORY_OFFSET: u32 = (VIRTUAL_MEMORY_SIZE_BITS as u32)/8/4 + 2;

// tests
const N: [u32; 8] = [
    0x00000000, 0x00000000, 0x00000000, 0x00000000,
    0x00000000, 0x00000000, 0x00000000, 0x00000015
];

const B: [u32; 8] = [
    0x00000000, 0x00000000, 0x00000000, 0x00000000,
    0x00000000, 0x00000000, 0x00000000, 0x00000010
];

const A: [u32; 8] = [
    0x00000000, 0x00000000, 0x00000000, 0x00000000,
    0x00000000, 0x00000000, 0x00000000, 0x00000100
];


#[entry]
fn main() -&amp;gt; ! {
    info!(&amp;quot;Running.&amp;quot;);

    // Enable the PKA and CryptoCell clock
    let p = pac::Peripherals::take().unwrap();
    let cc_misc = p.cc_misc;
    let cc_pka = p.cc_pka;

    p.cryptocell.enable().write(|w| w.enable().set_bit());
    cc_misc.pka_clk().write(|w| w.enable().set_bit());

    while cc_misc.clk_status().read().pka_clk().bit_is_clear() {
    // Wait for PKA clock to be ready
    }
    info!(&amp;quot;PKA clock ready. PKA engine enabled&amp;quot;);

    // Operand size
    cc_pka.pka_l(1).write(|w| unsafe { w.bits(OPERAND_SIZE_BITS as u32) }); 
    // max opernad size
    cc_pka.pka_l(0).write(|w| unsafe { w.bits(MAX_OPERAND_SIZE_BITS as u32) }); 

    // Configure memory map
    configure_memory_map(&amp;amp;cc_pka);

    // Clear registers
    clear_pka_registers(&amp;amp;cc_pka);

    // Load N
    load_word_array(&amp;amp;cc_pka, 0, &amp;amp;N);
    
    // Calculate Np
    calculate_np(&amp;amp;cc_pka);

    // Verify data is well written
    cc_pka.pka_sram_wclear();
    read_word_array(&amp;amp;cc_pka, 0);
    read_word_array(&amp;amp;cc_pka, 1);

    // Load data to compute operations
    load_word_array(&amp;amp;cc_pka, 4, &amp;amp;A);
    load_word_array(&amp;amp;cc_pka, 5, &amp;amp;B);
    read_word_array(&amp;amp;cc_pka, 4);
    read_word_array(&amp;amp;cc_pka, 5);

    // example operation 4 * 5 = 6
    execute_operation(&amp;amp;cc_pka, cc_pka::opcode::Opcode::ModMul, 6, 4, 5, 0);

    cc_pka.pka_sram_wclear();
    read_word_array(&amp;amp;cc_pka, 6);

    // exit via semihosting call
    debug::exit(EXIT_SUCCESS);
    loop {}
}


fn configure_memory_map(cc_pka: &amp;amp;pac::CcPka) {
    // Map virtual registers
    // R0: modulus (N)
    // R1: Np
    // R2: a parameter
    // R3: b parameter
    // R4: operand A
    // R5: operand B
    // R6: result
    // R7: temporal
    // R8: temporal
    // T0: register 30
    // T1: register 31
    for i in 0..9 {
        cc_pka.memory_map(i).write(|w| unsafe { 
            w.bits(i as u32 * VIRTUAL_MEMORY_OFFSET) 
        });
    }
    cc_pka.memory_map(30).write(|w| unsafe { 
            w.bits(7 as u32 * VIRTUAL_MEMORY_OFFSET) 
        });
    cc_pka.memory_map(31).write(|w| unsafe { 
        w.bits(8 as u32 * VIRTUAL_MEMORY_OFFSET) 
    });
}

fn clear_pka_registers(cc_pka: &amp;amp;pac::CcPka) {
    for i in 0..9 {
        cc_pka.pka_sram_waddr().write(|w| unsafe { 
            w.bits(cc_pka.memory_map(i).read().bits()) 
        });
        
        for i in 0..MAX_OPERAND_SIZE_WORDS {
            cc_pka.pka_sram_wdata().write(|w| unsafe { 
                w.bits(0x00) 
            });
        }
    }
    for i in 30..32 {
        cc_pka.pka_sram_waddr().write(|w| unsafe { 
            w.bits(cc_pka.memory_map(i).read().bits()) 
        });
        
        for i in 0..(64 * 4 * 8) {
            cc_pka.pka_sram_wdata().write(|w| unsafe { 
                w.bits(0x00) 
            });
        }
    }
}

fn load_word_array(cc_pka: &amp;amp;pac::CcPka, reg: usize, data: &amp;amp;[u32]) {
    cc_pka.pka_sram_waddr().write(|w| unsafe { 
        w.bits(cc_pka.memory_map(reg).read().bits()) 
    });
    
    // Load data in reverse order
    for i in 0..data.len() {
        let reverse_index = data.len() - 1 - i;
        cc_pka.pka_sram_wdata().write(|w| unsafe { 
            w.bits(data[reverse_index]) 
        });
    }
    // Add padding zeros
    for _ in 0..2 {
        cc_pka.pka_sram_wdata().write(|w| unsafe { w.bits(0x00) });
    }
}

fn read_word_array(cc_pka: &amp;amp;pac::CcPka, reg: usize) {
    cc_pka.pka_sram_raddr().write(|w| unsafe { 
        w.bits(cc_pka.memory_map(reg).read().bits()) 
    });
    let mut verif = [0u32; MAX_OPERAND_SIZE_WORDS];
    for i in 0..MAX_OPERAND_SIZE_WORDS {
        verif[MAX_OPERAND_SIZE_WORDS - 1 -i] = cc_pka.pka_sram_rdata().read().bits();
        // verif[i] = cc_pka.pka_sram_rdata().read().bits();
    }
    info!(&amp;quot;Verification of R{:?}: {:#X}&amp;quot;, reg, verif);
}

fn execute_operation(cc_pka: &amp;amp;pac::CcPka, opcode: cc_pka::opcode::Opcode, 
    result_reg: u8, operand_a_reg: u8, operand_b_reg: u8, operand_size_idx: u32) {
    cc_pka.opcode().write(|w| unsafe {
    w.bits(
    ((result_reg as u32) &amp;lt;&amp;lt; REG_R_POS)
    | ((operand_b_reg as u32) &amp;lt;&amp;lt; REG_B_POS)
    | ((operand_a_reg as u32) &amp;lt;&amp;lt; REG_A_POS)
    | (operand_size_idx &amp;lt;&amp;lt; LEN_POS)
    | ((opcode as u32) &amp;lt;&amp;lt; OPCODE_POS)
    )
    });

    while cc_pka.pka_done().read().bits() == 0 {}
}


fn calculate_np(cc_pka: &amp;amp;pac::CcPka) -&amp;gt; () {

    let total_bits = OPERAND_SIZE_BITS + 64 + 8 - 1;

    // Create big number representing 2^(N+A+X-1)    
    let word_index = total_bits / 32;
    let bit_index = total_bits % 32;
    let mut numerator = [0u32; MAX_OPERAND_SIZE_WORDS];
    numerator[MAX_OPERAND_SIZE_WORDS - 1 - word_index] = 1 &amp;lt;&amp;lt; bit_index;
 
    // Load data in reverse order into a temp register
    load_word_array(&amp;amp;cc_pka, 7, &amp;amp;numerator);
 
    // n is already in R0, execute division
    cc_pka.opcode().write(|w| unsafe {
        w.bits(
        ( 1 &amp;lt;&amp;lt; REG_R_POS)
        | ( 0 &amp;lt;&amp;lt; REG_B_POS)
        | ( 7 &amp;lt;&amp;lt; REG_A_POS)
        | ( 0 &amp;lt;&amp;lt; LEN_POS)
        | ((cc_pka::opcode::Opcode::Division as u32) &amp;lt;&amp;lt; OPCODE_POS)
        )
        });
 }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The results are still not reduced...&lt;/p&gt;
&lt;p&gt;INFO Verification of R0: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15]&lt;br /&gt;└─ crypto_cc310::read_word_array @ src/main.rs:278 &lt;br /&gt;INFO Verification of R1: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF]&lt;br /&gt;└─ crypto_cc310::read_word_array @ src/main.rs:278 &lt;br /&gt;INFO Verification of R4: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100]&lt;br /&gt;└─ crypto_cc310::read_word_array @ src/main.rs:278 &lt;br /&gt;INFO Verification of R5: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10]&lt;br /&gt;└─ crypto_cc310::read_word_array @ src/main.rs:278 &lt;br /&gt;INFO Verification of R6: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFC1]&lt;/p&gt;
&lt;p&gt;Thanks!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Issues with PKA Engine Modular Operations on CC310</title><link>https://devzone.nordicsemi.com/thread/516171?ContentTypeID=1</link><pubDate>Mon, 23 Dec 2024 17:09:09 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:0f8f3b18-0a9f-46ac-b7ff-9239c04bdbe5</guid><dc:creator>Emil Lenngren</dc:creator><description>&lt;p&gt;According to&amp;nbsp;&lt;a href="https://github.com/ARM-software/cryptocell-312-runtime/blob/update-cc110-bu-00000-r1p4/codesafe/src/crypto_api/pki/common/pka.c#L561"&gt;https://github.com/ARM-software/cryptocell-312-runtime/blob/update-cc110-bu-00000-r1p4/codesafe/src/crypto_api/pki/common/pka.c#L561&lt;/a&gt;,&amp;nbsp;the Np parameter should be floor(2^(N+A+X-1) / n), where N=bitlength of modulus n (according to the PKA_L register I guess corresponding to the modulo parameter), A=64, X=8.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Issues with PKA Engine Modular Operations on CC310</title><link>https://devzone.nordicsemi.com/thread/516170?ContentTypeID=1</link><pubDate>Mon, 23 Dec 2024 16:56:07 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:09b09cf5-48a2-476b-bbfc-f846a638c14b</guid><dc:creator>ElsaLopez</dc:creator><description>&lt;p&gt;For the calculation of Np I used a python script that performs the Euclidean Algorithm.&lt;/p&gt;
&lt;p&gt;(There was a mistake and Np is:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; NP: [u32; &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;0xC30C30C3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0xC30C30C3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0xC30C30C3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0xC30C30C3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;0xC30C30C3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0xC30C30C3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0xC30C30C3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0xC30C30C3&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;];&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;I forgot to change the value of N in the python script that computes Np. Still this seems to not make any difference&lt;/span&gt;)&lt;/div&gt;
&lt;p data-renderer-start-pos="9628"&gt;N&amp;sdot;Np&amp;equiv;&amp;minus;1&amp;nbsp;(mod&amp;nbsp;R)&lt;/p&gt;
&lt;p data-renderer-start-pos="9645"&gt;Where:&lt;/p&gt;
&lt;ul class="ak-ul" data-indent-level="1"&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos="9655"&gt;N is the modulus.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos="9676"&gt;Np​ is the modular multiplicative inverse of N modulo R, usually chosen as R=2^k where k is the bit length of the modulus N.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos="9804"&gt;The equation can be solved using the extended Euclidean Algorithm:&lt;/p&gt;
&lt;p data-renderer-start-pos="9804"&gt;&lt;pre class="ui-code" data-mode="text"&gt;def compute_modular_inverse(N, bit_width):
    &amp;quot;&amp;quot;&amp;quot;
    Compute the modular inverse of N modulo 2^bit_width using the Extended Euclidean Algorithm.

    Args:
    - N (int): The number to compute the modular inverse for.
    - bit_width (int): The bit width of the modulus (e.g., 256 for 2^256).

    Returns:
    - int: The modular inverse of N modulo 2^bit_width, or None if no inverse exists.
    &amp;quot;&amp;quot;&amp;quot;
    R = 2 ** bit_width

    # Check if gcd(N, R) is 1 (coprime condition)
    def gcd(a, b):
        while b:
            a, b = b, a % b
        return a

    if gcd(N, R) != 1:
        return None  # No modular inverse exists if not coprime

    # Extended Euclidean Algorithm to find the inverse
    t, new_t = 0, 1
    r, new_r = R, N

    while new_r != 0:
        quotient = r // new_r
        t, new_t = new_t, t - quotient * new_t
        r, new_r = new_r, r - quotient * new_r

    # Ensure the result is positive
    if t &amp;lt; 0:
        t += R

    # Step 2: Adjust NP_mod to satisfy the condition N * NP ≡ -1 (mod R)
    NP = (R - t) % R
    return NP

# Example usage
if __name__ == &amp;quot;__main__&amp;quot;:
    N_parts = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15]
    N = 0
    for part in N_parts:
        N = (N &amp;lt;&amp;lt; 32) | part

    bit_width = len(N_parts) * 4 * 8

    Np = compute_modular_inverse(N, bit_width)
    if Np is not None:
        print(f&amp;quot;The modular inverse of {N} modulo 2^{bit_width} is:&amp;quot;)
        result_array = print_in_array_format(Np, 32, bit_width)
        print(result_array)  # This will print Np in array format
    else:
        print(f&amp;quot;{N} has no modular inverse modulo 2^{bit_width}.&amp;quot;)
&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Issues with PKA Engine Modular Operations on CC310</title><link>https://devzone.nordicsemi.com/thread/516167?ContentTypeID=1</link><pubDate>Mon, 23 Dec 2024 16:42:40 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:35126302-1ce1-4da1-b4df-d7957ea48ff7</guid><dc:creator>Emil Lenngren</dc:creator><description>&lt;p&gt;How did you come to the conclusion that Np should be an array full of 0x33333333?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Issues with PKA Engine Modular Operations on CC310</title><link>https://devzone.nordicsemi.com/thread/516166?ContentTypeID=1</link><pubDate>Mon, 23 Dec 2024 16:31:20 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:06a166b8-e8d9-4779-9972-460d84670d57</guid><dc:creator>ElsaLopez</dc:creator><description>&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;// Example constants for positions
const TAG_POS: u8 = 0;         // tag of the operand
const REG_R_POS: u8 = 6;       // Result register position (Bits 6:10)
const REG_R_CTRL_POS: u8 = 11; // Result register control position (Bit 11)
const REG_B_POS: u8 = 12;      // Operand B register position (Bits 12:16)
const REG_B_CTRL_POS: u8 = 17; // Operand B register control position (Bit 17)
const REG_A_POS: u8 = 18;      // Operand A register position (Bits 18:22)
const REG_A_CTRL_POS: u8 = 23; // Operand A register control position (Bit 23)
const LEN_POS: u8 = 24;        // Operand length register index (Bits 24:26)
const OPCODE_POS: u8 = 27;     // Operation code position (Bits 27:31)

// All virtual registers must be 64 bits word size aligned, and the size of the virtual 
// registers must be at least the size of the largest operand plus an extra 64 bits 
// for internal PKA calculations. 
// These extra 64 bits must be initialized to zero. 
// In the 1D examples, we would have const OPERAND_SIZE_BITS = 1 * 4 * 8;
const OPERAND_SIZE_BITS: usize = 8 * 4 * 8;
const OPERAND_SIZE_WORDS: usize = OPERAND_SIZE_BITS/8/4;
const OPERAND_MEMORY_OFFSET: u32 = (OPERAND_SIZE_BITS as u32)/8/4 + 2;
const VIRTUAL_MEMORY_SIZE_BITS: usize = 64 * 4 * 8; // 64-bit word size
const VIRTUAL_MEMORY_OFFSET: u32 = (VIRTUAL_MEMORY_SIZE_BITS as u32)/8/4 + 2;

// Define example values for N and Np 
// 1D examples
// const N: [u32; 1] = [0x15];
// const NP: [u32; 1] = [0xC30C30C3];

// Example values for a and b
// 1D examples
// const A: [u32; 1] = [0x02];
// const B: [u32; 1] = [0x07];


//  tests [u32; 8]
const N: [u32; 8] = [
    0x00000000, 0x00000000, 0x00000000, 0x00000000,
    0x00000000, 0x00000000, 0x00000000, 0x00000015
];

const NP: [u32; 8] = [
    0xC30C30C3, 0xC30C30C3, 0xC30C30C3, 0xC30C30C3, 
    0xC30C30C3, 0xC30C30C3, 0xC30C30C3, 0xC30C30C3
];

const B: [u32; 8] = [
    0x00000000, 0x00000000, 0x00000000, 0x00000000,
    0x00000000, 0x00000000, 0x00000000, 0x00000010
];

const A: [u32; 8] = [
    0x00000000, 0x00000000, 0x00000000, 0x00000000,
    0x00000000, 0x00000000, 0x00000000, 0x00000010
];&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;As for the order, I guess that if it is little endian it makes sense that I need to lead them in the memory in reverse order.&lt;/p&gt;
&lt;p&gt;To read the result, I just read register 6:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;    // Wait for the operation to complete
    while cc_pka.pka_done().read().bits() == 0 {}
    
    // When changing from read to write they advise to clear the sram buffer
    cc_pka.pka_sram_wclear();
    
    // Read and log the result
    let mut result = [0u32; OPERAND_SIZE_BITS/8/4 + 2];
    cc_pka.pka_sram_raddr().write(|w| unsafe { w.bits(cc_pka.memory_map(6).read().bits()) });
    for i in 0..result.len() {
        result[i] = cc_pka.pka_sram_rdata().read().bits(); 
    } 

    info!(&amp;quot;Result: {:#X}&amp;quot;, result);

    // exit via semihosting call
    debug::exit(EXIT_SUCCESS);
    loop {}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This is the result:&lt;br /&gt;└─ crypto_cc310::__cortex_m_rt_main @ src/main.rs:172 &lt;br /&gt;INFO Verification of R0: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15]&lt;br /&gt;└─ crypto_cc310::read_word_array @ src/main.rs:305 &lt;br /&gt;INFO Verification of R4: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10]&lt;br /&gt;└─ crypto_cc310::read_word_array @ src/main.rs:305 &lt;br /&gt;INFO Verification of R5: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10]&lt;br /&gt;└─ crypto_cc310::read_word_array @ src/main.rs:305 &lt;br /&gt;INFO Verification of R6: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC1]&lt;/p&gt;
&lt;p&gt;which is clearly not reduced. This is for the ModMul. 10*10=256 = 193 if we subtract 3 times 21 = 0x15&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Issues with PKA Engine Modular Operations on CC310</title><link>https://devzone.nordicsemi.com/thread/516160?ContentTypeID=1</link><pubDate>Mon, 23 Dec 2024 16:05:36 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:b58c28f7-8515-4d54-9f5f-678293b64b97</guid><dc:creator>Emil Lenngren</dc:creator><description>&lt;p&gt;The documentation can be found at &lt;a href="https://docs.nordicsemi.com/bundle/ps_nrf52840/page/cryptocell.html#ariaid-title101"&gt;https://docs.nordicsemi.com/bundle/ps_nrf52840/page/cryptocell.html#ariaid-title101&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What is the value of your OPERAND_SIZE_BITS and VIRTUAL_MEMORY_OFFSET?&lt;/p&gt;
&lt;p&gt;At a first glance, your code looks correct.&amp;nbsp;But the code that reads the result seems to be missing. Can you show it?&lt;/p&gt;
&lt;p&gt;Have you calculated Np correctly? What is your N, Np, A, B and the result?&lt;/p&gt;
&lt;p&gt;Note that the cryptocell uses little endian word order with a word size of 32 bits (not 8-bit bytes). So to write the&amp;nbsp;number 0x0123456789abcdef you should first write the word 0x&lt;span&gt;89abcdef to the PKA_SRAM_WDATA register and then write&amp;nbsp;0x01234567 to the same register.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Note to Nordic Semiconductor: the product specification says:&lt;/span&gt;&lt;/p&gt;
&lt;ol id="cc_sram_pka__ol_ir2_gdf_q1c" class="ol"&gt;
&lt;li class="li"&gt;
&lt;p class="p"&gt;&lt;strong class="ph b"&gt;Set the Address Offset&lt;/strong&gt;: Specify the starting byte address for writing by setting register&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a class="xref" href="https://docs.nordicsemi.com/bundle/ps_nrf52840/page/cryptocell.html#register.PKA_SRAM_WADDR"&gt;PKA_SRAM_WADDR&lt;/a&gt;. An offset value of&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code class="language-plaintext"&gt;0x0&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;points to the first 32-bits word in the PKA SRAM memory. An offset value of&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code class="language-plaintext"&gt;0x10&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;points to the fourth 32-bits word in the PKA SRAM memory.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But this is wrong. The register uses word offset, so an offset value of 0x10 points to the 16th 32-bit word in the PKA SRAM memory.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>