diff --git a/.github/scripts/gdb_test.sh b/.github/scripts/gdb_test.sh index 90eb5ac6b..20f783040 100755 --- a/.github/scripts/gdb_test.sh +++ b/.github/scripts/gdb_test.sh @@ -5,6 +5,17 @@ SIM_LOG=`realpath sim.log` OPENOCD_LOG=`realpath openocd.log` +GCC_PREFIX=riscv64-unknown-elf + +# Ensure that RISC-V toolchain is installed +if ! which ${GCC_PREFIX}-gcc >/dev/null; then + GCC_PREFIX=riscv32-unknown-elf +fi +if ! which ${GCC_PREFIX}-gcc >/dev/null; then + echo "RISC-V toolchain not found, please refer to https://github.com/chipsalliance/caliptra-rtl?tab=readme-ov-file#riscv-toolchain-installation for more details." + exit 1 +fi +export GCC_PREFIX set +e diff --git a/.github/workflows/build-test-verilator.yml b/.github/workflows/build-test-verilator.yml index 53d8b407c..c27e7880d 100644 --- a/.github/workflows/build-test-verilator.yml +++ b/.github/workflows/build-test-verilator.yml @@ -18,7 +18,7 @@ env: SCCACHE_GHA_CACHE_TO: sccache-verilator-10000 SCCACHE_GHA_CACHE_FROM: sccache-verilator- # Change this to a new random value if you suspect the cache is corrupted - SCCACHE_C_CUSTOM_CACHE_BUSTER: f3e6951f0c1d + SCCACHE_C_CUSTOM_CACHE_BUSTER: f3e6951f0c1e jobs: build_tools: @@ -101,9 +101,8 @@ jobs: if: steps.riscv_restore.outputs.cache-hit != 'true' run: | # Building from source takes around 6.65 GB of disk and download size - wget -O toolchain.tar.gz https://github.com/stnolting/riscv-gcc-prebuilt/releases/download/rv64imc-3.0.0/riscv64-unknown-elf.gcc-12.1.0.tar.gz - mkdir /opt/riscv - tar -xzf toolchain.tar.gz -C /opt/riscv/ + wget -O toolchain.tar.gz https://github.com/chipsalliance/caliptra-tools/releases/download/gcc-v12.1.0/riscv64-unknown-elf.gcc-12.1.0.tar.gz + tar -xzf toolchain.tar.gz -C /opt/ - name: Save riscv dir uses: actions/cache/save@v3 diff --git a/.github/workflows/interactive-debugging.yml b/.github/workflows/interactive-debugging.yml index 8415e094d..124e1d5f4 100644 --- a/.github/workflows/interactive-debugging.yml +++ b/.github/workflows/interactive-debugging.yml @@ -22,7 +22,7 @@ jobs: SCCACHE_GHA_CACHE_TO: sccache-verilator-10000 SCCACHE_GHA_CACHE_FROM: sccache-verilator- # Change this to a new random value if you suspect the cache is corrupted - SCCACHE_C_CUSTOM_CACHE_BUSTER: f3e6951f0c1d + SCCACHE_C_CUSTOM_CACHE_BUSTER: f3e6951f0c1e steps: - name: Restore sccache binary @@ -185,9 +185,8 @@ jobs: - name: Install Risc V Toolchain run: | # Building from source takes around 6.65 GB of disk and download size - wget -O toolchain.tar.gz https://github.com/stnolting/riscv-gcc-prebuilt/releases/download/rv64imc-3.0.0/riscv64-unknown-elf.gcc-12.1.0.tar.gz - mkdir /opt/riscv - tar -xzf toolchain.tar.gz -C /opt/riscv/ + wget -O toolchain.tar.gz https://github.com/chipsalliance/caliptra-tools/releases/download/gcc-v12.1.0/riscv64-unknown-elf.gcc-12.1.0.tar.gz + tar -xzf toolchain.tar.gz -C /opt/ - name: Install dependencies run: | @@ -268,9 +267,8 @@ jobs: - name: Install Risc V Toolchain run: | # Building from source takes around 6.65 GB of disk and download size - wget -O toolchain.tar.gz https://github.com/stnolting/riscv-gcc-prebuilt/releases/download/rv64imc-3.0.0/riscv64-unknown-elf.gcc-12.1.0.tar.gz - mkdir /opt/riscv - tar -xzf toolchain.tar.gz -C /opt/riscv/ + wget -O toolchain.tar.gz https://github.com/chipsalliance/caliptra-tools/releases/download/gcc-v12.1.0/riscv64-unknown-elf.gcc-12.1.0.tar.gz + tar -xzf toolchain.tar.gz -C /opt/ - name: Download Verilator binaries uses: actions/download-artifact@v3 diff --git a/README.md b/README.md index 3c86dc341..bc83ec61c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.*_
# **Caliptra Hands-On Guide** # -_*Last Update: 2023/10/17*_ +_*Last Update: 2024/01/17*_ ## **Tools Used** ## @@ -144,12 +144,12 @@ Verilog file lists are generated via VCS and included in the config directory fo ## **Simulation Flow** ## ### Caliptra Top VCS Steps: ### -1. Setup tools, add to PATH (ensure riscv64-unknown-elf-gcc is also available) +1. Setup tools, add to PATH (ensure RISC-V toolchain is also available) 2. Define all environment variables above - For the initial test run after downloading repository, `iccm_lock` is recommended for TESTNAME - See [Regression Tests](#Regression-Tests) for information about available tests. 3. Create a run folder for build outputs (and cd to it) -4. [OPTIONAL] By default, this run flow will use the riscv64 toolchain to compile test firmware (according to TESTNAME) into program.hex, iccm.hex, dccm.hex, and mailbox.hex. As a first pass, integrators may alternatively use the pre-built hexfiles for convenience (available for [iccm_lock](src/integration/test_suites/iccm_lock) test). To do this, copy [iccm_lock.hex](src/integration/test_suites/iccm_lock/iccm_lock.hex) to the run directory and rename to `program.hex`. [dccm.hex](src/integration/test_suites/iccm_lock/iccm_lock.hex) should also be copied to the run directory, as-is. Use `touch iccm.hex mailbox.hex` to create empty hex files, as these are unnecessary for `iccm_lock` test. +4. [OPTIONAL] By default, this run flow will use the RISC-V toolchain to compile test firmware (according to TESTNAME) into program.hex, iccm.hex, dccm.hex, and mailbox.hex. As a first pass, integrators may alternatively use the pre-built hexfiles for convenience (available for [iccm_lock](src/integration/test_suites/iccm_lock) test). To do this, copy [iccm_lock.hex](src/integration/test_suites/iccm_lock/iccm_lock.hex) to the run directory and rename to `program.hex`. [dccm.hex](src/integration/test_suites/iccm_lock/iccm_lock.hex) should also be copied to the run directory, as-is. Use `touch iccm.hex mailbox.hex` to create empty hex files, as these are unnecessary for `iccm_lock` test. 5. Invoke `${CALIPTRA_ROOT}/tools/scripts/Makefile` with target 'program.hex' to produce SRAM initialization files from the firmware found in `src/integration/test_suites/${TESTNAME}` - E.g.: `make -f ${CALIPTRA_ROOT}/tools/scripts/Makefile program.hex` - NOTE: TESTNAME may also be overridden in the makefile command line invocation, e.g. `make -f ${CALIPTRA_ROOT}/tools/scripts/Makefile TESTNAME=iccm_lock program.hex` @@ -165,13 +165,13 @@ Verilog file lists are generated via VCS and included in the config directory fo 8. Simulate project with `caliptra_top_tb` as the top target ### Caliptra Top Verilator Steps: ### -1. Setup tools, add to PATH (ensure Verilator, GCC, and riscv64-unknown-elf-gcc are available) +1. Setup tools, add to PATH (ensure Verilator, GCC, and RISC-V toolchain are available) 2. Define all environment variables above - For the initial test run after downloading repository, `iccm_lock` is recommended for TESTNAME - See [Regression Tests](#Regression-Tests) for information about available tests. 3. Create a run folder for build outputs - Recommended to place run folder under `${CALIPTRA_WORKSPACE}/scratch/$USER/verilator/` -4. [OPTIONAL] By default, this run flow will use the riscv64 toolchain to compile test firmware (according to TESTNAME) into program.hex, iccm.hex, dccm.hex, and mailbox.hex. As a first pass, integrators may alternatively use the pre-built hexfiles for convenience (available for `iccm_lock` test). To do this, copy `iccm_lock.hex` to the run directory and rename to `program.hex`. `dccm.hex` should also be copied to the run directory, as-is. Use `touch iccm.hex mailbox.hex` to create empty hex files, as these are unnecessary for `iccm_lock` test. +4. [OPTIONAL] By default, this run flow will use the RISC-V toolchain to compile test firmware (according to TESTNAME) into program.hex, iccm.hex, dccm.hex, and mailbox.hex. As a first pass, integrators may alternatively use the pre-built hexfiles for convenience (available for `iccm_lock` test). To do this, copy `iccm_lock.hex` to the run directory and rename to `program.hex`. `dccm.hex` should also be copied to the run directory, as-is. Use `touch iccm.hex mailbox.hex` to create empty hex files, as these are unnecessary for `iccm_lock` test. 5. Run Caliptra/tools/scripts/Makefile, which provides steps to run a top-level simulation in Verilator - Example command: `make -C -f ${CALIPTRA_ROOT}/tools/scripts/Makefile TESTNAME=${TESTNAME} debug=1 verilator` @@ -208,7 +208,12 @@ The UVM Framework generation tool was used to create the baseline UVM testbench - UVM 1.1d installation - Mentor Graphics UVM-Framework installation -Steps:
+**Environment Variables**:
+`UVM_HOME`: Filesystem path to the parent directory containing SystemVerilog source code for the UVM library of the desired version. +`UVMF_HOME`: Filesystem path to the parent directory containing source code (uvmf_base_pkg) for the UVM Frameworks library, a tool available from Mentor Graphics for generating baseline UVM projects. +`QUESTA_MVC_HOME`: Filesystem path to the parent directory containing source code for Mentor Graphics QVIP, the verification library from which AHB/APB UVM agents are pulled in the Caliptra UVM environment. + +**Steps:**
1. Compile UVM 1.1d library 1. Compile the AHB/APB QVIP source 1. Compile the Mentor Graphics UVM-Frameworks base library @@ -244,7 +249,7 @@ The UVM Framework generation tool was used to create the baseline UVM testbench - UVM 1.1d installation - Mentor Graphics UVM-Framework installation -Steps:
+**Steps:**
1. Compile UVM 1.1d library 1. Compile the AHB/APB QVIP source 1. Compile the Mentor Graphics UVM-Frameworks base library diff --git a/Release_Notes.md b/Release_Notes.md index d390c9210..60d949a03 100644 --- a/Release_Notes.md +++ b/Release_Notes.md @@ -14,11 +14,33 @@ See the License for the specific language governing permissions and
limitations under the License.*_
# **Release Notes** # -_*Last Update: 2023/11/02*_ +_*Last Update: 2024/01/18*_ -## Rev 1p0-rc1 ## +## Rev 1p0 ## -### Rev 1p0-rc1 release date: 2023/11/03 (1p0 version pending ROM release for official declaration) ### +### Rev 1p0 release date: 2024/01/18 ### +- Caliptra Hardware Specification: Markdown conversion +- Caliptra Integration specification update with synthesis warnings and jtag tck requirement +- Caliptra README updates to clarify test cases and running with VCS +- Makefile updates to support DPI compilation in VCS +- Verification + - Adding ECC, DOE, HMAC_DRBG and SHA512_masked formal Assertion IP + - JTAG with clock gating test cases + - Fixes for UVM caliptra_top test scenarios + - Fixes for UVM KeyVault test scenarios +- Updated synthesis tool from Design Compiler to Fusion Compiler (sanity checks only) +- RTL + - Remove TODO comments on caliptra_top ports + - Remove JTAG IDCODE command from RISC-V processor + +### Bug Fixes ### +[MBOX] Fix ICCM Uncorrectable ECC error driving hw_error_non_fatal bit for LSU reads + +## Previous Releases ## + +### Rev 1p0-rc1 ### + +#### Rev 1p0-rc1 release date: 2023/11/03 (1p0 version pending ROM release for official declaration) ### - Caliptra IP Specification: see docs/ folder - Caliptra Integration Specification: see docs/ folder - Caliptra testplan: see docs/ folder @@ -59,7 +81,7 @@ _*Last Update: 2023/11/02*_ - Automated GitHub action using OpenOCD for interactive JTAG debugging - SHA Formal Verification -### Bug Fixes ### +#### Bug Fixes #### [CLK GATING] Fatal error should wake up clks
[CLK GATING] JTAG accesses need to wake up clocks
[DOE] add zeroize to clear all internal regs
@@ -114,8 +136,6 @@ _*Last Update: 2023/11/02*_ [RST] scan_mode should not corrupt resets
[TOP] EL2 Mem interface is not instantiated with a modport at all levels -## Previous Releases ## - ### Rev 0p8 ### #### DISCALIMER: This is NOT A BUG-FREE MODEL YET. This is a 0p8 release model. Please see testplan document in docs folder to know the status of validation. #### diff --git a/docs/CaliptraHardwareSpecification.md b/docs/CaliptraHardwareSpecification.md new file mode 100644 index 000000000..a69a2b219 --- /dev/null +++ b/docs/CaliptraHardwareSpecification.md @@ -0,0 +1,1591 @@ +![OCP Logo](./images/OCP_logo.png) + +

Caliptra Hardware Specification

+ +

Version 1.0

+ +
+ +# Scope + +This document defines technical specifications for a Caliptra RoT for Measurement (RTM)[1] cryptographic subsystem used in the Open Compute Project (OCP). This document, along with [Caliptra: A Datacenter System on a Chip (SoC) Root of Trust (RoT)](https://chipsalliance.github.io/Caliptra/doc/Caliptra.html), shall comprise the Caliptra technical specification. + +# Overview + +This document provides definitions and requirements for a Caliptra cryptographic subsystem. The document then relates these definitions to existing technologies, enabling device and platform vendors to better understand those technologies in trusted computing terms. + +# Caliptra Core + +For information on the Caliptra Core, see the [High level architecture](https://chipsalliance.github.io/Caliptra/doc/Caliptra.html#high-level-architecture) section of [Caliptra: A Datacenter System on a Chip (SoC) Root of Trust (RoT)](https://chipsalliance.github.io/Caliptra/doc/Caliptra.html). + +## Boot FSM + +The Boot FSM detects that the SoC is bringing Caliptra out of reset. Part of this flow involves signaling to the SoC that Caliptra is awake and ready for fuses. After fuses are populated and the SoC indicates that it is done downloading fuses, Caliptra can wake up the rest of the IP by de-asserting the internal reset. + +The following figure shows the initial power-on arc of the Mailbox Boot FSM. + +*Figure 1: Mailbox Boot FSM state diagram* + +![](./images/HW_mbox_boot_fsm.png) + +The Boot FSM first waits for the SoC to assert cptra\_pwrgood and de-assert cptra\_rst\_b. In the BOOT\_FUSE state, Caliptra signals to the SoC that it is ready for fuses. After the SoC is done writing fuses, it sets the fuse done register and the FSM advances to BOOT\_DONE. + +BOOT\_DONE enables Caliptra reset de-assertion through a two flip-flop synchronizer. + +## FW update reset (Impactless FW update) + +Runtime FW updates write to fw\_update\_reset register to trigger the FW update reset. When this register is written, only the RISC-V core is reset using cptra\_uc\_fw\_rst\_b pin and all AHB slaves are still active. All registers within the slaves and ICCM/DCCM memories are intact after the reset. Since ICCM is locked during runtime, it must be unlocked after the RISC-V reset is asserted. Reset is deasserted synchronously after a programmable number of cycles (currently set to 5 clocks) and normal boot flow updates the ICCM with the new FW from the mailbox SRAM. Reset de-assertion is done through a two flip-flop synchronizer. The boot flow is modified as shown in the following figure. + +*Figure 2: Mailbox Boot FSM state diagram for FW update reset* + +![](./images/mbox_boot_fsm_FW_update_reset.png) + +After Caliptra comes out of global reset and enters the BOOT\_DONE state, a write to the fw\_update\_reset register triggers the FW update reset flow. In the BOOT\_FWRST state, only the reset to the VeeR core is asserted, ICCM is unlocked and the timer is initialized. After the timer expires, the FSM advances from the BOOT\_WAIT to BOOT\_DONE state where the reset is deasserted. + +| Control register | Start address | Description | +| :------- | :---------- | :--------- | +| FW_UPDATE_RESET | 0x30030418 | Register to trigger the FW update reset flow. Setting it to 1 starts the Boot FSM. The field auto-clears to 0. | +| FW_UPDATE_RESET_WAIT_CYCLES | 0x3003041C | Programmable wait time to keep the microcontroller reset asserted. | + +## RISC-V core + +The RISC-V core is VeeR EL2 from CHIPS Alliance. It is a 32-bit CPU core that contains a 4-stage, scalar, in-order pipeline. The core supports RISC-V’s integer(I), compressed instruction(C), multiplication and division (M), instruction-fetch fence, CSR, and subset of bit manipulation instructions (Z) extensions. A link to the RISC-V VeeR EL2 Programmer’s Reference Manual is provided in the [References](#references) section. + +### Configuration + +The RISC-V core is highly configurable and has the following settings. + +| Parameter | Configuration | +| :---------------------- | :------------ | +| Interface | AHB-Lite | +| DCCM | 128 KiB | +| ICCM | 128 KiB | +| I-Cache | Disabled | +| Reset Vector | 0x00000000 | +| Fast Interrupt Redirect | Enabled | +| External Interrupts | 31 | + +### Embedded memory export + +Internal RISC-V SRAM memory components are exported from the Caliptra subsystem to support adaptation to various fabrication processes. For more information, see the [Caliptra Integration Specification](https://github.com/chipsalliance/caliptra-rtl/blob/main/docs/CaliptraIntegrationSpecification.md). + +### Memory map address regions + +The 32-bit address region is subdivided into 16 fixed-sized, contiguous 256 MB regions. The following table describes the address mapping for each of the AHB devices that the RISC-V core interfaces with. + +| Subsystem | Address size | Start address | End address | +| :------------------ | :----------- | :------------ | :---------- | +| ROM | 48 KiB | 0x0000_0000 | 0x0000_BFFF | +| Cryptographic | 512 KiB | 0x1000_0000 | 0x1007_FFFF | +| Peripherals | 32 KiB | 0x2000_0000 | 0x2000_7FFF | +| SoC IFC | 256 KiB | 0x3000_0000 | 0x3003_FFFF | +| RISC-V Core ICCM | 128 KiB | 0x4000_0000 | 0x4001_FFFF | +| RISC-V Core DCCM | 128 KiB | 0x5000_0000 | 0x5001_FFFF | +| RISC-V MM CSR (PIC) | 256 MiB | 0x6000_0000 | 0x6FFF_FFFF | + +#### Cryptographic subsystem + +The following table shows the memory map address ranges for each of the IP blocks in the cryptographic subsystem. + +| IP/Peripheral | Slave \# | Address size | Start address | End address | +| :---------------------------------- | :------- | :----------- | :------------ | :---------- | +| Cryptographic Initialization Engine | 0 | 32 KiB | 0x1000_0000 | 0x1000_7FFF | +| ECC Secp384 | 1 | 32 KiB | 0x1000_8000 | 0x1000_FFFF | +| HMAC384 | 2 | 4 KiB | 0x1001_0000 | 0x1001_0FFF | +| Key Vault | 3 | 8 KiB | 0x1001_8000 | 0x1001_9FFF | +| PCR Vault | 4 | 8 KiB | 0x1001_A000 | 0x1001_BFFF | +| Data Vault | 5 | 8 KiB | 0x1001_C000 | 0x1001_DFFF | +| SHA512 | 6 | 32 KiB | 0x1002_0000 | 0x1002_7FFF | +| SHA256 | 13 | 32 KiB | 0x1002_8000 | 0x1002_FFFF | + +#### Peripherals subsystem + +The following table shows the memory map address ranges for each of the IP blocks in the peripherals’ subsystem. + +| IP/Peripheral | Slave \# | Address size | Start address | End address | +| :------------ | :------- | :----------- | :------------ | :---------- | +| QSPI | 7 | 4 KiB | 0x2000_0000 | 0x2000_0FFF | +| UART | 8 | 4 KiB | 0x2000_1000 | 0x2000_1FFF | +| CSRNG | 15 | 4 KiB | 0x2000_2000 | 0x2000_2FFF | +| ENTROPY SRC | 16 | 4 KiB | 0x2000_3000 | 0x2000_3FFF | + +#### SoC interface subsystem + +The following table shows the memory map address ranges for each of the IP blocks in the SoC interface subsystem. + +| IP/Peripheral | Slave \# | Address size | Start address | End address | +| :------------------------- | :------- | :----------- | :------------ | :---------- | +| Mailbox SRAM Direct Access | 10 | 128 KiB | 0x3000_0000 | 0x3001_FFFF | +| Mailbox CSR | 10 | 4 KiB | 0x3002_0000 | 0x3002_0FFF | +| SHA512 Accelerator CSR | 10 | 4 KiB | 0x3002_1000 | 0x3002_1FFF | +| Mailbox | 10 | 64 KiB | 0x3003_0000 | 0x3003_FFFF | + +#### RISC-V core local memory blocks + +The following table shows the memory map address ranges for each of the local memory blocks that interface with RISC-V core. + +| IP/Peripheral | Slave \# | Address size | Start address | End address | +| :-------------- | :------- | :----------- | :------------ | :---------- | +| ICCM0 (via DMA) | 12 | 128 KiB | 0x4000_0000 | 0x4001_FFFF | +| DCCM | 11 | 128 KiB | 0x5000_0000 | 0x5001_FFFF | + +### Interrupts + +The VeeR-EL2 processor supports multiple types of interrupts, including non-maskable interrupts (NMI), software interrupts, timer interrupts, external interrupts, and local interrupts. Local interrupts are events not specified by the RISC-V standard, such as auxiliary timers and correctable errors. + +Caliptra uses NMI in conjunction with a watchdog timer to support fatal error recovery and system restart. For more information, see the [Watchdog timer](#watchdog-timer) section. + +Software and local interrupts are not implemented in the first generation of Caliptra. Standard RISC-V timer interrupts are implemented using the mtime and mtimecmp registers defined in the RISC-V Privileged Architecture Specification. Both mtime and mtimecmp are included in the soc\_ifc register bank, and are accessible by the internal microprocessor to facilitate precise timing tasks. Frequency for the timers is configured by the SoC using the dedicated timer configuration register, which satisfies the requirement prescribed in the RISC-V specification for such a mechanism. These timer registers drive the timer\_int pin into the internal microprocessor. + +#### Non-maskable interrupts + +Caliptra's RISC-V processor has access to an internal register that allows configuration of the NMI vector. When an NMI occurs, the program counter jumps to the address indicated by the contents of this register. +For more information, see [NMI Vector](https://chipsalliance.github.io/caliptra-rtl/main/internal-regs/?p=clp.soc_ifc_reg.internal_nmi_vector). + +#### External interrupts + +Caliptra uses the external interrupt feature to support event notification from all attached peripheral components in the subsystem. The RISC-V processor supports multiple priority levels (ranging from 1-15), which allows firmware to configure interrupt priority per component. + +Errors and notifications are allocated as interrupt events for each component, with error interrupts assigned a higher priority and expected to be infrequent. + +Notification interrupts are used to alert the processor of normal operation activity, such as completion of requested operations or arrival of SoC requests through the shared interface. + +Vector 0 is reserved by the RISC-V processor and may not be used, so vector assignment begins with Vector 1. Bit 0 of the interrupt port to the processor corresponds with Vector 1. The following table shows assignment of interrupt vectors to the corresponding IP block. The illustrated interrupt priority assignment is only an example, and does not correspond with actual priorities assigned in the final Caliptra firmware. These interrupt priorities are used in the validation firmware that tests the RTL, and are defined in [caliptra_defines.h](https://github.com/chipsalliance/caliptra-rtl/blob/main/src/integration/test_suites/includes/caliptra_defines.h). + +| IP/Peripheral | Interrupt vector | Interrupt priority example
(Increasing, Max 15) | +| :-------------------------------------------------- | :--------------- | :---------------------------------------------- | +| Cryptographic Initialization Engine (Errors) | 1 | 8 | +| Cryptographic Initialization Engine (Notifications) | 2 | 7 | +| ECC (Errors) | 3 | 8 | +| ECC (Notifications) | 4 | 7 | +| HMAC (Errors) | 5 | 8 | +| HMAC (Notifications) | 6 | 7 | +| KeyVault (Errors) | 7 | 8 | +| KeyVault (Notifications) | 8 | 7 | +| SHA512 (Errors) | 9 | 8 | +| SHA512 (Notifications) | 10 | 7 | +| SHA256 (Errors) | 11 | 8 | +| SHA256 (Notifications) | 12 | 7 | +| QSPI (Errors) | 13 | 4 | +| QSPI (Notifications) | 14 | 3 | +| UART (Errors) | 15 | 4 | +| UART (Notifications) | 16 | 3 | +| RESERVED | 17 | 4 | +| RESERVED | 18 | 3 | +| Mailbox (Errors) | 19 | 8 | +| Mailbox (Notifications) | 20 | 7 | + +## Watchdog timer + +The primary function of Caliptra Watchdog Timer (WDT) is to reset the microcontroller (Caliptra), in the event of a software malfunction, by resetting the device if it has not been cleared in software. It is a two-stage timer, independent of the RISCV core. + +### Operation + +The WDT consists of two timers. When enabled in cascade mode (done by enabling Timer 1 alone), the WDT increments Timer 1 until the counter rolls over or times out. Typically, the timer is serviced at regular intervals to prevent it from overflowing or rolling over. If Timer 1 has not timed out, Timer 2 is disabled and held at its initial value. However, when Timer 1 does roll over, it triggers an error interrupt to the RISC-V core. In parallel, Timer 2 is enabled and begins counting. If the interrupt is serviced before Timer 2 times out, the timers are reset and continue to operate normally. If Timer 2 times out, it asserts an SoC fatal error and an NMI. The SoC fatal error is also captured in the CPTRA\_HW\_ERROR\_FATAL register, which can be cleared by the SoC by writing a 1. A warm reset is required by the SoC to reset the timers when Timer 2 times out. + +The WDT timers can be configured to operate independent of each other. When the enable register for Timer 2 is set, the default configuration of cascaded timers is disabled and both timers count independently of each other. In this case, a timeout on Timer 2 causes an error interrupt to the RISC-V core similar to Timer 1. Disabling Timer 2 configures the timers back into the default cascaded mode. + +Each timer has an enable bit, a restart bit, and a 64-bit timeout value register that can be programmed as needed. The restart bit is used to service the timers and restart counting. The timeout period registers can be configured to the desired upper bound of timers. + +If the WDT timers are disabled and then re-enabled with a new timeout period, they must be restarted by setting the appropriate control register (restart bit). If the timers are temporarily disabled and re-enabled with the same timeout period, they resume counting and do not restart from 0. + +For more details regarding the register interface to control the WDT, see the [register documentation](https://chipsalliance.github.io/caliptra-rtl/main/internal-regs/?p=clp.soc_ifc_reg) published in the RTL GitHub repository. + +The following figure shows the two timers. + +*Figure 3: Caliptra Watchdog Timer* + +![](./images/WDT.png) + +### Prescale settings + +Assuming a clock source of 500 MHz, a timeout value of 32’hFFFF\_FFFF results in a timeout period of ~8.5 seconds. Two 32-bit registers are provided for each timer, allowing a 64-bit timeout period to be programmed for each timer. This accommodates a maximum timeout value of over 1000 years for the same 500 Mhz clock source. + +## Microcontroller interface + +The Caliptra microcontroller communicates with the mailbox through its internal AHB-Lite fabric. + +### AHB-lite interface + +AHB-lite is a subset of the full AHB specification. It is primarily used in single master systems. This interface connects VeeR EL2 Core (LSU master) to the slave devices. See [Caliptra Core](#caliptra-core) for information. + +The interface can be customized to support variable address and data widths, and a variable number of slave devices. Each slave device is assigned an address range within the 32-bit address memory map region. The interface includes address decoding logic to route data to the appropriate AHB slave device based on the address specified. + +The integration parameters for Caliptra’s AHB-lite interface are shown in the following table. + +| Parameter | Value | +| :------------ | :---- | +| ADDRESS_WIDTH | 32 | +| DATA_WIDTH | 64 | +| NUM_OF_SLAVES | 17 | + +Each IP component in the Caliptra system uses a native AHB data width of 32-bits (1 dword). The AHB responder logic in each IP component contains width conversion logic that transforms from the fabric data width of 64-bits to this native 32-bit width. The conversion involves calculating the dword offset (either 0 or 1) relative to the native 64-bit width by evaluating bit [2] of the address line. This information is used to extract the correct 32-bits from the native write data line. If there is a data offset, data is shifted down by 32-bits; otherwise, the upper 32-bits are simply truncated. This new dword-address is passed to the internal register interface along with the dword-sized data. A similar conversion works in reverse to correctly place read data in the response data line from the responder. + +As a result of this implementation, 64-bit data transfers are not supported on the Caliptra AHB fabric. Firmware running on the internal microprocessor may only access memory and registers using a 32-bit or smaller request size, as 64-bit transfer requests will be corrupted. + +## Cryptographic subsystem + +For details, see the [Cryptographic subsystem architecture](#cryptographic-subsystem-architecture) section. + +## Peripherals subsystem + +Caliptra includes QSPI and UART peripherals that are used to facilitate alternative operating modes and debug. In the first generation, Caliptra does not support enabling the QSPI interface. Similarly, the UART interface exists to facilitate firmware debug in an FPGA prototype, but should be disabled in final silicon. SystemVerilog defines used to disable these peripherals are described in the [Caliptra Integration Specification](https://github.com/chipsalliance/caliptra-rtl/blob/main/docs/CaliptraIntegrationSpecification.md). Operation of these peripherals is described in the following sections. + +### QSPI Flash Controller + +Caliptra implements a QSPI block that can communicate with 2 QSPI devices. This QSPI block is accessible to FW over the AHB-lite Interface. + +The QSPI block is composed of the spi\_host implementation. For information, see the [SPI\_HOST HWIP Technical Specification](https://opentitan.org/book/hw/ip/spi_host/index.html). The core code (see [spi\_host](https://github.com/lowRISC/opentitan/tree/master/hw/ip/spi_host)) is reused but the interface to the module is changed to AHB-lite and the number of chip select lines supported is increased to 2. The design provides support for Standard SPI, Dual SPI, or Quad SPI commands. The following figure shows the QSPI flash controller. + +*Figure 4: QSPI flash controller* + +![](./images/QSPI_flash.png) + +#### Operation + +Transactions flow through the QSPI block starting with AHB-lite writes to the TXDATA FIFO. Commands are then written and processed by the control FSM, orchestrating transmissions from the TXDATA FIFO and receiving data into the RXDATA FIFO. + +The structure of a command depends on the device and the command itself. In the case of a standard SPI device, the host IP always transmits data on qspi\_d\_io[0] and always receives data from the target device on qspi\_d\_io[1]. In Dual or Quad modes, all data lines are bi-directional, thus allowing full bandwidth in transferring data across 4 data lines. + +A typical SPI command consists of different segments that are combined as shown in the following example. Each segment can configure the length, speed, and direction. As an example, the following SPI read transaction consists of 2 segments. + +*Figure 5: SPI read transaction segments* + +![](./images/SPI_read.png) + +| Segment \# | Length (Bytes) | Speed | Direction | TXDATA FIFO | RXDATA FIFO | +| :--------- | :------------- | :------- | :---------------- | :----------- | :----------------- | +| 1 | 4 | standard | TX
qspi_d_io\[0\] | \[0\] 0x3 (ReadData)
\[1\] Addr\[23:16\]
\[2\] Addr\[15:8\]
\[3\] Addr\[7:0\] | | +| 2 | 1 | standard | RX
qspi_d_io\[1\] | | \[0\] Data \[7:0\] | + +In this example, the ReadData (0x3) command was written to the TXDATA FIFO, followed by the 3B address. This maps to a total of 4 bytes that are transmitted out across qspi\_d\_io[0] in the first segment. The second segment consists of a read command that receives 1 byte of data from the target device across qspi\_d\_io[1]. + +QSPI consists of up to four command segments in which the host: + +1. Transmits instructions or data at the standard rate +2. Transmits instructions address or data on 2 or 4 data lines +3. Holds the bus in a high-impedance state for some number of dummy cycles where neither side transmits +4. Receives information from the target device at the specified rate (derived from the original command) + +The following example shows the QSPI segments. + +*Figure 6: QSPI segments* + +![](./images/QSPI_segments.png) + +| Segment \# | Length (Bytes) | Speed | Direction | TXDATA FIFO | RXDATA FIFO | +| :--------- | :------------- | :------- | :------------------ | :----------- | :---------------- | +| 1 | 1 | standard | TX
qspi_d_io\[3:0\] | \[0\] 0x6B (ReadDataQuad) | | +| 2 | 3\* | quad | TX
qspi_d_io\[3:0\] | \[1\] Addr\[23:16\]
\[2\] Addr\[15:8\]
\[3\] Addr\[7:0\] | | +| 3 | 2 | N/A | None (Dummy) | | | +| 4 | 1 | quad | RX
qspi_d_io\[3:0\] | | \[0\] Data\[7:0\] | + +Note: In the preceding figure, segment 2 doesn’t show bytes 2 and 3 for brevity. + +#### Configuration + +The CONFIGOPTS multi-register has one entry per CSB line and holds clock configuration and timing settings that are specific to each peripheral. After the CONFIGOPTS multi-register is programmed for each SPI peripheral device, the values can be left unchanged. + +The most common differences between target devices are the requirements for a specific SPI clock phase or polarity, CPOL and CPHA. These clock parameters can be set via the CONFIGOPTS.CPOL or CONFIGOPTS.CPHA register fields. + +The SPI clock rate depends on the peripheral clock and a 16b clock divider configured by CONFIGOPTS.CLKDIV. The following equation is used to configure the SPI clock period: + +![](./images/Caliptra_eq_SPI_clk_period.png) + +By default, CLKDIV is set to 0, which means that the maximum frequency that can be achieved is at most half the frequency of the peripheral clock (Fsck = Fclk/2). + +We can rearrange the equation to solve for the CLKDIV: + +![](./images/Caliptra_eq_CLKDIV.png) + +Assuming a 400MHz target peripheral, and a SPI clock target of 100MHz: + +CONFIGOPTS.CLKDIV = (400/(2\*100)) -1 = 1 + +The following figure shows CONFIGOPTS. + +*Figure 7: CONFIGOPTS* + +![](./images/CONFIGOPTS.png) + +#### Signal descriptions + +The QSPI block architecture inputs and outputs are described in the following table. + +| Name | Input or output | Description | +| :------------------ | :-------------- | :-------------------------------------------------------- | +| clk_i | input | All signal timings are related to the rising edge of clk. | +| rst_ni | input | The reset signal is active LOW and resets the core. | +| cio_sck_o | output | SPI clock | +| cio_sck_en_o | output | SPI clock enable | +| cio_csb_o\[1:0\] | output | Chip select \# (one hot, active low) | +| cio_csb_en_o\[1:0\] | output | Chip select \# enable (one hot, active low) | +| cio_csb_sd_o\[3:0\] | output | SPI data output | +| cio_csb_sd_en_o | output | SPI data output enable | +| cio_csb_sd_i\[3:0\] | input | SPI data input | + +#### SPI\_HOST IP programming guide + +The operation of the SPI\_HOST IP proceeds in seven general steps. + +To initialize the IP: + +1. Program the CONFIGOPTS multi-register with the appropriate timing and polarity settings for each csb line. +2. Set the desired interrupt parameters. +3. Enable the IP. + +Then for each command: + +4. Load the data to be transmitted into the FIFO using the TXDATA memory window. +5. Specify the target device by programming the CSID. +6. Specify the structure of the command by writing each segment into the COMMAND register. + + For multi-segment transactions, assert COMMAND.CSAAT for all but the last command segment. + +7. For transactions that expect to receive a reply, the data can then be read back from the RXDATA window. + +Steps 4-7 are then repeated for each subsequent command. + +### UART + +Caliptra implements a UART block that can communicate with a serial device that is accessible to FW over the AHB-lite Interface. This is a configuration that the SoC opts-in by defining CALIPTRA\_INTERNAL\_UART. + +The UART block is composed of the uart implementation. For information, see the [UART HWIP Technical Specification](https://opentitan.org/book/hw/ip/uart/). The design provides support for a programmable baud rate. The UART block is shown in the following figure. + +*Figure 8: UART block* + +![](./images/UART_block.png) + +#### Operation + +Transactions flow through the UART block starting with an AHB-lite write to WDATA, which triggers the transmit module to start a UART TX serial data transfer. The TX module dequeues the byte from the internal FIFO and shifts it out bit by bit at the baud rate. If TX is not enabled, the output is set high and WDATA in the FIFO is queued up. + +The following figure shows the transmit data on the serial lane, starting with the START bit, which is indicated by a high to low transition, followed by the 8 bits of data. + +*Figure 9: Serial transmission frame* + +![](./images/serial_transmission.png) + +On the receive side, after the START bit is detected, the data is sampled at the center of each data bit and stored into a FIFO. A user can monitor the FIFO status and read the data out of RDATA. + +#### Configuration + +The baud rate can be configured using the CTRL.NCO register field. This should be set using the following equation: + +![](./images/Caliptra_eq_NCO.png) + +If the desired baud rate is 115,200bps: + +![](./images/Caliptra_eq_UART.png) + +![](./images/Caliptra_eq_UART2.png) + +#### Signal descriptions + +The UART block architecture inputs and outputs are described in the following table. + +| Name | Input or output | Description | +| :------- | :-------------- | :-------------------------------------------------------- | +| clk_i | input | All signal timings are related to the rising edge of clk. | +| rst_ni | input | The reset signal is active LOW and resets the core. | +| cio_rx_i | input | Serial receive bit | +| cio_tx_o | output | Serial transmit bit | + +## SoC mailbox + +For more information on the mailbox protocol, see [Mailbox](https://github.com/chipsalliance/caliptra-rtl/blob/main/docs/CaliptraIntegrationSpecification.md#mailbox) in the Caliptra Integration Specification. Mailbox registers accessible to the Caliptra microcontroller are defined in [internal-regs/mbox_csr](https://chipsalliance.github.io/caliptra-rtl/main/internal-regs/?p=clp.mbox_csr). + + +## Security state + +Caliptra uses the MSB of the security state input to determine whether or not Caliptra is in debug mode. + +When Caliptra is in debug mode: + +* Security state MSB is set to 0. + +* Caliptra JTAG is opened for the microcontroller and HW debug. + +* Device secrets (UDS, FE, key vault, and obfuscation key) are programmed to debug values. + +If a transition to debug mode happens during ROM operation, any values computed from the use of device secrets may not match expected values. + +Transitions to debug mode trigger a hardware clear of all device secrets, and also trigger an interrupt to FW to inform of the transition. FW is responsible for initiating another hardware clear of device secrets utilizing the clear secrets register, in case any derivations were in progress and stored after the transition was detected. FW may open the JTAG after all secrets are cleared. + +Debug mode values may be set by integrators in the Caliptra configuration files. The default values are shown in the following table. + +| Name | Default value | +| :-------------------------- | :------------ | +| Obfuscation Key Debug Value | All 0x1 | +| UDS Debug Value | All 0x1 | +| Field Entropy Debug Value | All 0x1 | +| Key Vault Debug Value 0 | All 0xA | +| Key Vault Debug Value 1 | All 0x5 | + +## Clock gating + +Caliptra provides a clock gating feature that turns off clocks when the microcontroller is halted. Clock gating is disabled by default, but can be globally enabled via the following register. + +| Control register | Start address | Description | +| :------------------- | :---------------- | :------------------------ | +| CPTRA_CLK_GATING_EN | 0x300300bc | Register bit to enable or disable the clock gating feature. | + +When enabled, halting the microcontroller turns off clocks to all of the cryptographic subsystem, the vaults (keyvault, PCR vault, and data vault), mailbox SRAM, SoC interface, and peripherals subsystem. The Watchdog timer and SoC registers run on the gated RDC clock. The RV core implements its own clock gating mechanism. Halting the core automatically turns off its clock. + +There are a total of 4 clocks in Caliptra: ungated clock, gated clock, gated RDC clock, and gated SoC IFC clock. The following table shows the different modules and their designated clocks. + +| Module | Clock | +| :-------------------- | :-------------------------------------- | +| RV core | Clk | +| SOC IFC | Clk; clk_cg; rdc_clk_cg; soc_ifc_clk_cg | +| Crypto subsystem | Clk_cg | +| Vaults | Clk_cg | +| Peripherals subsystem | Clk_cg | +| AHB Lite IF, 2to1 Mux | Clk_cg | +| TRNG | Clk_cg | + +### Wake up conditions + +For details on halting the core and waking up the core from the halt state, see section 5 of the [RISC-V VeeR EL2 Programmer's Reference Manual](https://github.com/chipsalliance/Cores-VeeR-EL2/blob/main/docs/RISC-V_VeeR_EL2_PRM.pdf). + +When the RV core wakes up, all clocks are enabled. However, when the core is halted, it is possible to wake up Caliptra clocks through: + +* A change in generic\_input\_wires + +* Cptra\_fatal\_error assertion + +* Entry to debug or scan modes + +* JTAG accesses + +* APB transactions + +Activity on the APB interface only wakes up the SoC IFC clock. All other clocks remain off until any other condition is met or the core exits the halt state. + +| Cpu_halt_status | PSEL | Generic input wires
\|\| fatal error
\|\| debug/scan mode
\|\|JTAG access | Expected behavior | +| :-------------- | :--- | :---------- | :-------------- | +| 0 | X | X | All gated clocks active | +| 1 | 0 | 0 | All gated clocks inactive | +| 1 | 0 | 1 | All gated clocks active (as long as condition is true) | +| 1 | 1 | 0 | Soc_ifc_clk_cg active (as long as PSEL = 1)
All other clks inactive | +| 1 | 1 | 1 | Soc_ifc_clk_cg active (as long as condition is true OR PSEL = 1)
All other clks active (as long as condition is true) | + +### Usage + +The following applies to the clock gating feature: + +* The core should only be halted after all pending vault writes are done and cryptographic operations are complete. +* While the core is halted, any APB transaction wakes up the SoC interface clock and leaves all other clocks disabled. If the core is still halted when the APB transactions are done, the SoC interface clock is returned to a disabled state. . +* The RDC clock is similar to an ungated clock and is only disabled when a reset event occurs. This avoids metastability on flops. The RDC clock operates independently of core halt status. + + +### Timing information + +The following figure shows the timing information for clock gating. + +*Figure 10: Clock gating timing* + +![](./images/clock_gating_timing.png) + +## Integrated TRNG + +Caliptra implements a true random number generator (TRNG) block for local use models. Firmware is able to read a random number from the TRNG core by accessing its register block over the AHB-lite interface. This is a configuration that SoC integrators enable by defining CALIPTRA\_INTERNAL\_TRNG. + +This TRNG block is a combination of entropy source and CSRNG implementations. For information, see the [ENTROPY\_SRC HWIP Technical Specification](https://opentitan.org/book/hw/ip/entropy_src/index.html) and the [CSRNG HWIP Technical Specification](https://opentitan.org/book/hw/ip/csrng/). The core code (see [entropy source](https://github.com/lowRISC/opentitan/tree/master/hw/ip/entropy_src) and [csrng](https://github.com/lowRISC/opentitan/tree/master/hw/ip/csrng)) is reused from here but the interface to the module is changed to AHB-lite. This design provides an interface to an external physical random noise generator. This is also referred to as a physical true random number generator (PTRNG). The PTRNG external source is a physical true random noise source. A noise source and its relation to an entropy source are defined by [SP 800-90B](https://csrc.nist.gov/publications/detail/sp/800-90b/final). + +The block is instantiated based on a design parameter chosen at integration time. This is to provide options for SoC to reuse an existing TRNG to build an optimized SoC design. For the optimized scenarios, SoC needs to follow the [External-TRNG REQ HW API](#External-TRNG-REQ-HW-API). + +The following figure shows the integrated TRNG block. + +*Figure 11: Integrated TRNG block* + +![](./images/integrated_TRNG.png) + +The following figure shows the CSRNG block. + +*Figure 12: CSRNG block* + +![](./images/CSRNG_block.png) + +The following figure shows the entropy source block. + +*Figure 13: Entropy source block* + +![](./images/entropy_source_block.png) + +### Operation + +Requests for entropy bits start with [command requests](https://opentitan.org/book/hw/ip/csrng/doc/theory_of_operation.html#general-command-format) over the AHB-lite interface to the csrng [CMD\_REQ](https://chipsalliance.github.io/caliptra-rtl/main/internal-regs/?p=clp.csrng_reg.CMD_REQ) register. + +The following describes the fields of the command request header: + +* Application Command: Selects one of five operations to perform. The commands supported are instantiate, reseed, generate, update, and uninstantiate. + +* Command Length: Number of 32-bit words that can optionally be appended to the command. A value of zero will only transfer the command header. A value of 4'hc transfers the header plus an additional twelve 32-bit words of data. + +* Command Flag0: flag0 is associated with the current command. Setting this field to True (4’h6) enables flag0 to be enabled. Note that flag0 is used for the instantiate and reseed commands only; for all other commands, the flag0 value is ignored. + +* Generate Length: Only defined for the generate command, this field is the total number of cryptographic entropy blocks requested. Each unit represents 128 bits of entropy returned. A value of 8 would return a total of 1024 bits. The maximum size supported is 4096. + +First an instantiate command is requested over the SW application interface to initialize an instance in the CSRNG module. Depending on the flag0 and clen fields in the command header, a request to the entropy\_src module over the entropy interface is sent to seed the csrng. This can take a few milliseconds if the seed entropy is not immediately available. + +Example instantiation: + +acmd = 0x1 (Instantiate) + +clen/flag0 = The seed behavior is described in the following table. + +glen = Not used + +| flag0 | clen | Description | +| :---- | :--- | :----------------------------------------------------------- | +| F | 0 | Only entropy source seed is used. | +| F | 1-12 | Entropy source seed is xor'ed with provided additional data. | +| T | 0 | Seed of zero is used (no entropy source seed used). | +| T | 1-12 | Only provided additional data is used as seed. | + +Next a generate command is used to request generation of cryptographic entropy bits. The glen field defines how many 128 bit words are to be returned to the application interface. After the generated bits are ready, they can be read out via the GENBITS register. This register must be read out glen \* 4 times for each request made. + +Example generate command: + +acmd = 0x3 (Generate) + +clen = 0 + +flag0 = false (4’h9) + +glen = 4 (4 \*128 = 512b) + +This requires 16 reads from GENBITS to read out all of the generated entropy. + +### Configuration + +The HW application interfaces are not supported. Only the SW application interface should be used for this design. + +### Physical true random noise source signal descriptions + +These are the top level signals defined in caliptra\_top. + +| Name | Input or output | Description | +| :---------- | :-------------- | :------------ | +| itrng_data | input | Physical true random noise source data | +| itrng_valid | input | Valid is asserted high for one cycle when data is valid. The expected valid output rate is about 50KHz. | + +The following figure shows the top level signals defined in caliptra\_top. + +*Figure 14: caliptra\_top signals* + +![](./images/caliptra_top_signals.png) + +### Entropy source signal descriptions + +The following table provides descriptions of the entropy source signals. + +| Name | Input or output | Description | +| :------------------ | :-------------- | :--------------- | +| clk_i | input | All signal timings are related to the rising edge of clk. | +| rst_ni | input | The reset signal is active LOW and resets the core. | +| entropy_src_rng_req | output | Request from the entropy_src module to the physical true random noise source to start generating data. | +| entropy_src_rng_rsp | input | Contains the internal TRNG data and a flag indicating the data is valid. Valid is asserted high for one cycle when data is valid. | +| entropy_src_hw_if_i | input | Downstream block request for entropy bits. | +| entropy_src_hw_if_o | output | 384 bits of entropy data. Valid when es_ack is asserted high. | +| cs_aes_halt_i | input | Response from csrng that all requests to AES block are halted. | +| cs_aes_halt_o | output | Request to csrng to halt requests to the AES block for power leveling purposes. | + +The following figure shows the entropy source signals. + +*Figure 15: Entropy source signals* + +![](./images/entropy_source_signals.png) + +### CSRNG signal descriptions + +The following table provides descriptions for the CSRNG signals. + +| Name | Input or output | Description | +| :------------------------- | :-------------- | :---------------------------------------------------------------------------------------------------- | +| clk_i | input | All signal timings are related to the rising edge of clk. | +| rst_ni | input | The reset signal is active LOW and resets the core. | +| otp_en_csrng_sw_app_read_i | input | Enable firmware to access the ctr_drbg internal state and genbits through registers. | +| lc_hw_debug_en_i | input | Lifecycle that selects which diversification value is used for xoring with the seed from entropy_src. | +| entropy_src_hw_if_i | input | 384 bits of entropy data. Valid when es_ack is asserted high. | +| entropy_src_hw_if_o | output | Downstream block request for entropy bits. | +| cs_aes_halt_i | input | Request from entropy_src to halt requests to the AES block for power leveling purposes. | +| cs_aes_halt_o | output | Response to entropy_src that all requests to AES block are halted. | + +The CSRNG may only be enabled if entropy\_src is enabled. After it is disabled, CSRNG may only be re-enabled after entropy\_src has been disabled and re-enabled. + +## External-TRNG REQ HW API + +For SoCs that choose to not instantiate Caliptra’s integrated TRNG, Caliptra provides a TRNGREQ HW API. + +1. Caliptra asserts TRNG\_REQ wire (FW made the request for a TRNG). +2. SoC writes the TRNG architectural registers. +3. SoC writes a done bit in the TRNG architectural registers. +4. Caliptra desserts TRNG\_REQ. + +The reason to have a separate interface from the SoC mailbox is to ensure that this request is not intercepted by any SoC FW agents that communicate with the SoC mailbox. It is required for FIPS compliance that this TRNG HW API is always handled by a SoC HW gasket logic and not handled by SoC ROM/FW code. + +## SoC-SHA accelerator HW API + +Caliptra provides a SHA accelerator HW API for SoC and Caliptra internal FW to use. It is atomic in nature in that only one of them can use the SHA accelerator HW API at the same time. Details of the SHA accelerator register block may be found in the GitHub repository in [documentation](https://chipsalliance.github.io/caliptra-rtl/main/external-regs/?p=caliptra_top_reg.sha512_acc_csr) generated from the register definition file. + +Using the HW API: + +* A user of the HW API first locks the accelerator by reading the LOCK register. A read that returns the value 0 indicates that the resource was locked for exclusive use by the requesting user. A write of ‘1 clears the lock. +* The USER register captures the APB pauser value of the requestor that locked the SHA accelerator. This is the only user that is allowed to control the SHA accelerator by performing APB register writes. Writes by any other agent on the APB interface are dropped. +* MODE register is written to set the SHA execution mode. + * SHA accelerator supports both SHA384 and SHA512 modes of operation. + * SHA supports **streaming** mode: SHA is computed on a stream of incoming data to the DATAIN register. The EXECUTE register, when set, indicates to the accelerator that streaming is complete. The accelerator can then publish the result into the DIGEST register. When the VALID bit of the STATUS register is set, then the result in the DIGEST register is valid. + * SHA supports **Mailbox** mode: SHA is computed on LENGTH (DLEN) bytes of data stored in the mailbox beginning at START\_ADDRESS. This computation is performed when the EXECUTE register is set by the user. When the operation is completed and the result in the DIGEST register is valid, SHA accelerator sets the VALID bit of the STATUS register. + * The SHA computation engine in the SHA accelerator requires big endian data, but the SHA accelerator can accommodate mailbox input data in either the little endian or big endian format. By default, input data is assumed to be little endian and is swizzled to big endian at the byte level prior to computation. For the big endian format, data is loaded into the SHA engine as-is. Users may configure the SHA accelerator to treat data as big endian by setting the ENDIAN\_TOGGLE bit appropriately. + * See the register definition for the encodings. +* SHA engine also provides a ‘zeroize’ function through its CONTROL register to clear any of the SHA internal state. This can be used when the user wants to conceal previous state for debug or security reasons. + +## JTAG implementation + +For specific debug flows, see the [JTAG/TAP Debug](https://chipsalliance.github.io/Caliptra/doc/Caliptra.html#jtagtap-debug) section in Caliptra: A Datacenter System on a Chip (SoC) Root of Trust (RoT). + +The following figure shows the JTAG implementation within the Caliptra boundary. The output of the existing DMI wrapper is used to find the non-Core (Caliptra uncore) aperture to route the JTAG commands. + +Caliptra’s JTAG/TAP should be implemented as a TAP EP. JTAG is open if the debug mode is set at the time of Caliptra reset deassertion. + +Note: If the debug security state switches to debug mode anytime, the security assets and keys are still flushed even though JTAG is not open. + +*Figure 16: JTAG implementation* + +![](./images/JTAG_implementation.png) + +# Cryptographic subsystem architecture + +The architecture of Caliptra cryptographic subsystem includes the following components: + +* Symmetric cryptographic primitives + * De-obfuscation engine + * SHA512/384 (based on NIST FIPS 180-4 [2]) + * SHA256 (based on NIST FIPS 180-4 [2]) + * HMAC384 (based on [NIST FIPS 198-1](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.198-1.pdf) [5] and [RFC 4868](https://tools.ietf.org/html/rfc4868) [6]) +* Public-key cryptography + * NIST Secp384r1 Deterministic Digital Signature Algorithm (based on FIPS-186-4 [11] and RFC 6979 [7]) +* Key vault + * Key slots + * Key slot management + +The high-level architecture of Caliptra cryptographic subsystem is shown in the following figure. + +*Figure 17: Caliptra cryptographic subsystem* + +![](./images/crypto_subsystem.png) + +## SHA512/SHA384 + +SHA512 is a function of cryptographic hash algorithm SHA-2. The hardware implementation is based on [Secworks/SHA512](https://github.com/secworks/sha512) [1]. This implementation complies with the functionality in NIST FIPS 180-4 [2]. The implementation supports the SHA512 variants SHA-512/224, SHA-512/256, SHA384 and SHA512. + +The SHA512 algorithm is described as follows: + +* The message is padded by the host and broken into 1024-bit chunks +* For each chunk: + * The message is fed to the SHA512 core + * The core should be triggered by the host + * The SHA512 core status is changed to ready after hash processing +* The result digest can be read after feeding all message chunks + +### Operation + +#### Padding + +The message should be padded before feeding to the hash core. The input message is taken, and some padding bits are appended to it to get it to the desired length. The bits that are used for padding are simply ‘0’ bits with a leading ‘1’ (100000…000). The appended length of the message (before pre-processing), in bits, is a 128-bit big-endian integer. + +The total size should be equal to 128 bits short of a multiple of 1024 since the goal is to have the formatted message size as a multiple of 1024 bits (N x 1024). The following figure shows the SHA512 input formatting. + +*Figure 18: SHA512 input formatting* + +![](./images/SHA512_input.png) + +#### Hashing + +The SHA512 core performs 80 iterative operations to process the hash value of the given message. The algorithm processes each block of 1024 bits from the message using the result from the previous block. For the first block, the initial vectors (IV) are used for starting the chain processing of each 1024-bit block. + +### FSM + +The SHA512 architecture has the finite-state machine as shown in the following figure. + +*Figure 19: SHA512 FSM* + +![](./images/SHA512_fsm.png) + +### Signal descriptions + +The SHA512 architecture inputs and outputs are described in the following table. + +| Name | Inputs and outputs | Description | +|-----------------|--------------------|---------------------------------------------------------------------------------------------------| +| clk | input | All signal timings are related to the rising edge of clk. | +| reset_n | input | The reset signal is active LOW and resets the core. This is the only active LOW signal. | +| init | input | The core is initialized and processes the first block of message. | +| next | input | The core processes the rest of the message blocks using the result from the previous blocks. | +| mode\[1:0\] | input | Indicates the hash type of the function. This can be:
- SHA512/224
- SHA512/256
- SHA384
- SHA512 | +| zeroize | input | The core clears all internal registers to avoid any SCA information leakage. | +| block\[1023:0\] | input | The input padded block of message. | +| ready | output | When HIGH, the signal indicates the core is ready. | +| digest\[511:0\] | output | The hashed value of the given block. | +| digest_valid | output | When HIGH, the signal indicates that the result is ready. | + +### Address map + +The SHA512 address map is shown here: [sha512\_reg — clp Reference (chipsalliance.github.io)](https://chipsalliance.github.io/caliptra-rtl/main/internal-regs/?p=clp.sha512_reg) + +### Pseudocode + +The following pseudocode demonstrates how the SHA512 interface can be implemented. + +*Figure 20: SHA512 pseudocode* + +![](./images/SHA512_pseudo.png) + +### SCA countermeasure + +We do not propose any countermeasure to protect the hash functions. Inherently, hash functions do not work like other cryptographic engines. Hash functions target integrity without requiring a secret key. Hence, the attacker can target only messages. Also, the attacker cannot build a CPA or DPA platform on the hash function because the same message ideally gives the same side-channel behavior. + +If the attacker works on the multi-message mechanism, the attacker then needs to work with single trace attacks, which are very unlikely in ASIC/FPGA implementations. Also, our hash implementation is a noisy platform. As a result, we do not propose any SCA implementation countermeasure on the hash functions. + +### Performance + +The SHA512 core performance is reported considering two different architectures: pure hardware architecture, and hardware/software architecture. These are described next. + +#### Pure hardware architecture + +In this architecture, the SHA512 interface and controller are implemented in hardware. The performance specification of the SHA512 architecture is shown in the following table. + +| Operation | Cycle count \[CCs\] | Time \[us\] @ 400 MHz | Throughput \[op/s\] | +| :-------------------- | :------------------ | :-------------------- | :------------------ | +| Data_In transmission | | 0.08 | | +| Process | 87 | 0.22 | | +| Data_Out transmission | 16 | 0.04 | | +| Single block | 136 | 0.34 | 2,941,176 | +| Double block | 224 | 0.56 | 1,785,714 | +| 1 KiB message | 840 | 2.10 | 476,190 | +| 128 KiB message | 17,632 | 44.08 | 22,686 | + +#### Hardware/software architecture + +In this architecture, the SHA512 interface and controller are implemented in RISC-V core. The performance specification of the SHA512 architecture is shown in the following table. + +| Operation | Cycle count \[CCs\] | Time \[us\]\] @ 400 MHz | Throughput \[op/s\] | +| :-------------------- | :------------------ | :---------------------- | :------------------ | +| Data_In transmission | 990 | 2.48 | | +| Process | 139 | 0.35 | | +| Data_Out transmission | 387 | 0.97 | | +| Single block | 1,516 | 3.79 | 263,852 | +| Double block | 2,506 | 6.27 | 159,617 | +| 1 KiB message | 9,436 | 23.59 | 42,391 | +| 128 KiB message | 1,015,276 | 2,538.19 | 394 | + +#### Pure software architecture + +In this architecture, the SHA512 algorithm is implemented fully in software. The implementation is derived from the [OpenSSL](https://www.openssl.org/docs/man3.0/man3/SHA512.html) SHA512 implementation [3]. The performance numbers for this architecture are shown in the following table. + +| Data size | Cycle count | +| :------------ | :-------------- | +| 1 KiB | 147,002 | +| 4 KiB | 532,615 | +| 8 KiB | 1,046,727 | +| 12 KiB | 1,560,839 | +| 128 KiB | 16,470,055 | + +## SHA256 + +SHA256 is a function of the SHA-2 cryptographic hash algorithm. The hardware implementation is based on [Secworks/SHA256](https://github.com/secworks/sha256) [1]. The implementation supports the two variants: SHA256/224 and SHA256. + +The SHA256 algorithm is described as follows: + +* The message is padded by the host and broken into 512-bit chunks +* For each chunk: + * The message is fed to the sha256 core + * The core should be triggered by the host + * The sha256 core status is changed to ready after hash processing +* The result digest can be read after feeding all message chunks + + +### Operation + +#### Padding + +The message should be padded before feeding to the hash core. The input message is taken, and some padding bits are appended to the message to get it to the desired length. The bits that are used for padding are simply ‘0’ bits with a leading ‘1’ (100000…000). The appended length of the message (before pre-processing), in bits, is a 64-bit big-endian integer. + +The total size should be equal to 64 bits, short of a multiple of 512 because the goal is to have the formatted message size as a multiple of 512 bits (N x 512). + +The following figure shows SHA256 input formatting. + +*Figure 21: SHA256 input formatting* + +![](./images/SHA256_input.png) + +#### Hashing + +The SHA256 core performs 64 iterative operations to process the hash value of the given message. The algorithm processes each block of 512 bits from the message using the result from the previous block. For the first block, the initial vectors (IV) are used to start the chain processing of each 512-bit block. + +### FSM + +The SHA256 architecture has the finite-state machine as shown in the following figure. + +*Figure 22: SHA256 FSM* + +![](./images/SHA256_fsm.png) + +### Signal descriptions + +The SHA256 architecture inputs and outputs are described as follows. + +| Name | Input or output | Description | +| :-------------- | :-------------- | :------------------------------------------------------------------------------------------- | +| clk | input | All signal timings are related to the rising edge of clk. | +| reset_n | input | The reset signal is active LOW and resets the core. This is the only active LOW signal. | +| init | input | The core is initialized and processes the first block of message. | +| next | input | The core processes the rest of the message blocks using the result from the previous blocks. | +| mode | input | Indicates the hash type of the function. This can be:
- SHA256/224
- SHA256 | +| zeroize | input | The core clears all internal registers to avoid any SCA information leakage. | +| block\[511:0\] | input | The input padded block of message. | +| ready | output | When HIGH, the signal indicates the core is ready. | +| digest\[255:0\] | output | The hashed value of the given block. | +| digest_valid | output | When HIGH, the signal indicates the result is ready. | + +### Address map + +The SHA256 address map is shown here: [sha256\_reg — clp Reference (chipsalliance.github.io)](https://chipsalliance.github.io/caliptra-rtl/main/internal-regs/?p=clp.sha256_reg). + +### Pseudocode + +The following pseudocode demonstrates how the SHA256 interface can be implemented. + +*Figure 23: SHA256 pseudocode* + +![](./images/SHA256_pseudo.png) + +### SCA countermeasure + +We do not propose any countermeasure to protect the hash functions. For more information, see SCA countermeasure in the [SHA512/SHA384](#sha512sha384) section. + +### Performance + +The SHA256 core performance is reported considering two different architectures: pure hardware architecture, and hardware/software architecture. These are described next. + +#### Pure hardware architecture + +In this architecture, the SHA256 interface and controller are implemented in hardware. The performance specification of the SHA256 architecture is reported as shown in the following table. + +| Operation | Cycle count \[CCs\] | Time \[us\] @ 400 MHz | Throughput \[op/s\] | +| :-------------------- | :------------------ | :-------------------- | :------------------ | +| Data_In transmission | 17 | 0.04 | | +| Process | 66 | 0.17 | | +| Data_Out transmission | 8 | 0.02 | | +| Single block | 91 | 0.23 | 4,395,604 | +| Double block | 158 | 0.40 | 2,531,646 | +| 1 KiB message | 1163 | 2.91 | 343,938 | + +#### Hardware/software architecture + +In this architecture, the SHA256 interface and controller are implemented in RISC-V core. The performance specification of the SHA256 architecture is reported as shown in the following table. + +| Operation | Cycle count \[CCs\] | Time \[us\] @ 400 MHz | Throughput \[op/s\] | +| :-------------------- | :------------------ | :-------------------- | :------------------ | +| Data_In transmission | 500 | 1.25 | | +| Process | 66 | 0.17 | | +| Data_Out transmission | 195 | 0.49 | | +| Single block | 761 | 1.90 | 525,624 | +| Double block | 1355 | 3.39 | 295,203 | +| 1 KiB message | 8761 | 21.90 | 45,657 | + +## HMAC384 + +Hash-based message authentication code (HMAC) is a cryptographic authentication technique that uses a hash function and a secret key. HMAC involves a cryptographic hash function and a secret cryptographic key. This implementation supports HMAC-SHA-384-192 as specified in [NIST FIPS 198-1](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.198-1.pdf) [5]. The implementation is compatible with the HMAC-SHA-384-192 authentication and integrity functions defined in [RFC 4868](https://tools.ietf.org/html/rfc4868) [6]. + +Caliptra HMAC implementation uses SHA384 as the hash function, accepts a 384-bit key, and generates a 384-bit tag. + +The implementation also supports PRF-HMAC-SHA-384. The PRF-HMAC-SHA-384 algorithm is identical to HMAC-SHA-384-192, except that variable-length keys are permitted, and the truncation step is not performed. + +The HMAC algorithm is described as follows: +* The key is fed to the HMAC core to be padded +* The message is broken into 1024-bit chunks by the host +* For each chunk: + * The message is fed to the HMAC core + * The HMAC core should be triggered by the host + * The HMAC core status is changed to ready after hash processing +* The result digest can be read after feeding all message chunks + + +### Operation + +#### Padding + +The message should be padded before feeding to the HMAC core. Internally, the i\_padded key is concatenated with the message. The input message is taken, and some padding bits are appended to the message to get it to the desired length. The bits that are used for padding are simply ‘0’ bits with a leading ‘1’ (100000…000). + +The total size should be equal to 128 bits, short of a multiple of 1024 because the goal is to have the formatted message size as a multiple of 1024 bits (N x 1024). + +*Figure 24: HMAC input formatting* + +![](./images/HMAC_input.png) + +The following figures show examples of input formatting for different message lengths. + +*Figure 25: Message length of 1023 bits* + +![](./images/msg_1023.png) + +When the message is 1023 bits long, padding is given in the next block along with message size. + +*Figure 26: 1 bit padding* + +![](./images/1_bit.png) + +When the message size is 895 bits, a padding of ‘1’ is also considered valid, followed by the message size. + +*Figure 27: Multi block message* + +![](./images/msg_multi_block.png) + +Messages with a length greater than 1024 bits are broken down into N 1024-bit blocks. The last block contains padding and the size of the message. + + +#### Hashing + +The HMAC core performs the sha2-384 function to process the hash value of the given message. The algorithm processes each block of the 1024 bits from the message, using the result from the previous block. This data flow is shown in the following figure. + +*Figure 28: HMAC-SHA-384-192 data flow* + +![](./images/HMAC_SHA_384_192.png) + +### FSM + +The HMAC architecture has the finite-state machine as shown in the following figure. + +*Figure 29: HMAC FSM* + +![](./images/HMAC_FSM.png) + +### Signal descriptions + +The HMAC architecture inputs and outputs are described in the following table. + +| Name | Input or output | Description | +| :----------------- | :-------------- | :----------- | +| clk | input | All signal timings are related to the rising edge of clk. | +| reset_n | input | The reset signal is active LOW and resets the core. This is the only active LOW signal. | +| init | input | The core is initialized and processes the key and the first block of the message. | +| next | input | The core processes the rest of the message blocks using the result from the previous blocks. | +| zeroize | input | The core clears all internal registers to avoid any SCA information leakage. | +| key\[383:0\] | input | The input key. | +| block\[1023:0\] | input | The input padded block of message. | +| LFSR_seed\[159:0\] | Input | The input to seed PRNG to enable the masking countermeasure for SCA protection. | +| ready | output | When HIGH, the signal indicates the core is ready. | +| tag\[383:0\] | output | The HMAC value of the given key or block. For PRF-HMAC-SHA-384, a 384-bit tag is required. For HMAC-SHA-384-192, the host is responsible for reading 192 bits from the MSB. | +| tag_valid | output | When HIGH, the signal indicates the result is ready. | + +### Address map + +The HMAC address map is shown here: [hmac\_reg — clp Reference (chipsalliance.github.io)](https://chipsalliance.github.io/caliptra-rtl/main/internal-regs/?p=clp.hmac_reg). + +### Pseudocode + +The following pseudocode demonstrates how the HMAC interface can be implemented. + +*Figure 30: HMAC pseudocode* + +![](./images/HMAC_pseudo.png) + +### SCA countermeasure + +In an attack model, an attacker can form hypotheses about the secret key value and compute the corresponding output values by using the Hamming Distance model as an appropriate leakage model. An attacker who has knowledge of the implementation for open-source architecture has an advantage. The attacker can capture the power consumption traces to verify their hypotheses, by partitioning the acquisitions or using Pearson’s correlation coefficient. + +To protect the HMAC algorithm from side-channel attacks, a masking countermeasure is applied. This means that random values are added to the intermediate variables during the algorithm’s execution, so that the side-channel signals do not reveal any information about them. + +The embedded countermeasures are based on "Differential Power Analysis of HMAC Based on SHA-2, and Countermeasures" by McEvoy et. al. To provide the required random values for masking intermediate values, a lightweight 74-bit LFSR is implemented. Based on “Spin Me Right Round Rotational Symmetry for FPGA-specific AES” by Wegener et. al., LFSR is sufficient for masking statistical randomness. + +Each round of SHA512 execution needs 6,432 random bits, while one HMAC operation needs at least 4 rounds of SHA512 operations. However, the proposed architecture requires only 160-bit LFSR seed and provides first-order DPA attack protection at the cost of 10% latency overhead with negligible hardware resource overhead. + +### Performance + +The HMAC core performance is reported considering two different architectures: pure hardware architecture, and hardware/software architecture. These are described next. + +#### Pure hardware architecture + +In this architecture, the HMAC interface and controller are implemented in hardware. The performance specification of the HMAC architecture is reported as shown in the following table. + +| Operation | Cycle count \[CCs\] | Time \[us\] @ 400 MHz | Throughput \[op/s\] | +| :-------------------- | :------------------ | :-------------------- | :------------------ | +| Data_In transmission | 44 | 0.11 | - | +| Process | 254 | 0.635 | - | +| Data_Out transmission | 12 | 0.03 | - | +| Single block | 310 | 0.775 | 1,290,322 | +| Double block | 513 | 1.282 | 780,031 | +| 1 KiB message | 1,731 | 4.327 | 231,107 | +| 128 KiB message | 207,979 | 519.947 | 1,923 | + +#### Hardware/software architecture + +In this architecture, the HMAC interface and controller are implemented in RISC-V core. The performance specification of the HMAC architecture is reported as shown in the following table. + +| Operation | Cycle count \[CCs\] | Time \[us\] @ 400 MHz | Throughput \[op/s\] | +| :-------------------- | :------------------ | :-------------------- | :------------------ | +| Data_In transmission | 1389 | 3.473 | - | +| Process | 253 | 0.633 | - | +| Data_Out transmission | 290 | 0.725 | - | +| Single block | 1932 | 4.83 | 207,039 | +| Double block | 3166 | 7.915 | 136,342 | +| 1 KiB message | 10,570 | 26.425 | 37,842 | +| 128 KiB message | 1,264,314 | 3,160.785 | 316 | + +## HMAC_DRBG + +Hash-based message authentication code (HMAC) deterministic random bit generator (DRBG) is a cryptographic random bit generator that uses a HMAC function. HMAC_DRBG involves a cryptographic HMAC function and a seed. This architecture is designed as specified in section 10.1.2. of NIST SP 800-90A [12]. For ECC signing operation, the implementation is compatible with section 3.1. of RFC 6979 [7]. + +Caliptra HMAC_DRBG implementation uses HMAC384 as the HMAC function, accepts a 384-bit seed, and generates a 384-bit random value. + +The HMAC algorithm is described as follows: + +* The seed is fed to HMAC_DRBG core by the host +* For each 384-bit random value + * The core should be triggered by the host + * The HMAC_DRBG core status is changed to ready after HMAC processing + * The result digest can be read + + +### Operation + +HMAC_DRBG uses a loop of HMAC(K, V) to generate the random bits. In this algorithm, two constant values of K_init and V_init are used as follows: + + 1. Set V_init = 0x01 0x01 0x01 ... 0x01 (V has 384-bit) + 2. Set K_init = 0x00 0x00 0x00 ... 0x00 (K has 384-bit) + 3. K_tmp = HMAC(K_init, V_init || 0x00 || entropy || nonce) + 4. V_tmp = HMAC(K_tmp, V_init) + 5. K_new = HMAC(K_tmp, V_tmp || 0x01 || entropy || nonce) + 6. V_new = HMAC(K_new, V_tmp) + 7. Set T = [] + 8. T = T || HMAC(K_new, V_new) + 9. Return T if T is within the [1,q-1] range, otherwise: + 10. K_new = HMAC(K_new, V_new || 0x00) + 11. V_new = HMAC(K_new, V_new) + 12. Jump to 8 + +For ECC KeyGen operation, HMAC_DRBG is used to generate privkey as follows: + + Privkey = HMAC_DRBG(seed, nonce) + +For ECC SIGNING operation, HMAC_DRBG is used to generate k as follows: + + K = HMAC_DRBG(privkey, hashed_msg) + +### Signal descriptions + +The HMAC_DRBG architecture inputs and outputs are described in the following table. + +| Name | Input or output | Description | +| :------------------- | :-------------- | :-------------------------------------------------------------------------------------- | +| clk | input | All signal timings are related to the rising edge of clk. | +| reset_n | input | The reset signal is active LOW and resets the core. This is the only active LOW signal. | +| init | input | The core is initialized with the given seed and generates a 384-bit random value. | +| next | input | The core generates a new 384-bit random value using the result from the previous run. | +| zeroize | input | The core clears all internal registers to avoid any SCA information leakage. | +| entropy \[383:0\] | input | The input entropy. | +| nonce \[383:0\] | input | The input nonce. | +| LFSR_seed \[147 :0\] | input | The input to seed PRNG to enable masking countermeasure for SCA protection. | +| ready | output | When HIGH, the signal indicates the core is ready. | +| drbg \[383:0\] | output | The hmac_drbg value of the given inputs. | +| valid | output | When HIGH, the signal indicates the result is ready. | + +### Address map + +The HMAC_DRBG is embedded into ECC architecture, since there is no address map to access it from FW. + +### SCA countermeasure + +For information, see SCA countermeasure in the [HMAC384](#hmac384) section. + +## ECC + +The ECC unit includes the ECDSA (Elliptic Curve Digital Signature Algorithm) engine, offering a variant of the cryptographically secure Digital Signature Algorithm (DSA), which uses elliptic curve (ECC). A digital signature is an authentication method in which a public key pair and a digital certificate are used as a signature to verify the identity of a recipient or sender of information. + +The hardware implementation supports deterministic ECDSA, 384 Bits (Prime Field), also known as NIST-Secp384r1, described in RFC6979. + +Secp384r1 parameters are shown in the following figure. + +*Figure 31: Secp384r1 parameters* + +![](./images/secp384r1_params.png) + +### Operation + +The ECDSA consists of three operations, shown in the following figure. + +*Figure 32: ECDSA operations* + +![](./images/ECDSA_ops.png) + +#### KeyGen + +In the deterministic key generation, the paired key of (privKey, pubKey) is generated by KeyGen(seed, nonce), taking a deterministic seed and nonce. The KeyGen algorithm is as follows: + +* Compute privKey = HMAC_DRBG(seed, nonce) to generate a random integer in the interval [1, n-1] where n is the group order of Secp384 curve. +* Generate pubKey(x,y) as a point on ECC calculated by pubKey=privKey × G, while G is the generator point over the curve. + + +#### Signing + +In the signing algorithm, a signature (r, s) is generated by Sign(privKey, h), taking a privKey and hash of message m, h = hash(m), using a cryptographic hash function, SHA384. The signing algorithm includes: + +* Generate a random number k in the range [1..n-1], while k = HMAC\_DRBG(privKey, h) +* Calculate the random point R = k × G +* Take r = Rx mod n, where Rx is x coordinate of R=(Rx, Ry) +* Calculate the signature proof: s = k-1 × (h + r × privKey) mod n +* Return the signature (r, s), each in the range [1..n-1] + +#### Verifying + +The signature (r, s) can be verified by Verify(pubKey ,h ,r, s) considering the public key pubKey and hash of message m, h=hash(m) using the same cryptographic hash function SHA384. The output is r’ value of verifying a signature. The ECDSA verify algorithm includes: + +* Calculate s1 = s−1 mod n +* Compute R' = (h × s1) × G + (r × s1) × pubKey +* Take r’ = R'x mod n, while R'x is x coordinate of R’=(R'x, R'y) +* Verify the signature by comparing whether r' == r + +### Architecture + +The ECC top-level architecture is shown in the following figure. + +*Figure 33: ECDSA architecture* + +![](./images/ECDSA_arch.png) + +### Signal descriptions + +The ECDSA architecture inputs and outputs are described in the following table. + + +| Name | Input or output | Description | +| :------------------------- | :-------------- | :----------- | +| clk | input | All signal timings are related to the rising edge of clk. | +| reset_n | input | The reset signal is active LOW and resets the core. This is the only active LOW signal. | +| ctrl\[1:0\] | input | Indicates the AES type of the function. This can be:
− 0b00: No Operation
− 0b01: KeyGen
− 0b10: Signing
− 0b11: Verifying | +| zeroize | input | The core clears all internal registers to avoid any SCA information leakage. | +| seed \[383:0\] | input | The deterministic seed for HMAC_DRBG in the KeyGen operation. | +| nonce \[383:0\] | input | The deterministic nonce for HMAC_DRBG in the KeyGen operation. | +| privKey_in\[383:0\] | input | The input private key used in the signing operation. | +| pubKey_in\[1:0\]\[383:0\] | input | The input public key(x,y) used in the verifying operation. | +| hashed_msg\[383:0\] | input | The hash of message using SHA384. | +| ready | output | When HIGH, the signal indicates the core is ready. | +| privKey_out\[383:0\] | output | The generated private key in the KeyGen operation. | +| pubKey_out\[1:0\]\[383:0\] | output | The generated public key(x,y) in the KeyGen operation. | +| r\[383:0\] | output | The signature value of the given priveKey/message. | +| s\[383:0\] | output | The signature value of the given priveKey/message. | +| r’\[383:0\] | Output | The signature verification result. | +| valid | output | When HIGH, the signal indicates the result is ready. | + +### Address map + +The ECDSA address map is shown here: [ecc\_reg — clp Reference (chipsalliance.github.io)](https://chipsalliance.github.io/caliptra-rtl/main/internal-regs/?p=clp.ecc_reg). + +### Pseudocode + +The following pseudocode blocks demonstrate example implementations for KeyGen, Signing, and Verifying. + +#### KeyGen + +*Figure 34: KeyGen pseudocode* + +![](./images/keygen_pseudo.png) + +#### Signing + +*Figure 35: Signing pseudocode* + +![](./images/signing_pseudo.png) + +#### Verifying + +*Figure 36: Verifying pseudocode* + +![](./images/verify_pseudo.png) + +### SCA countermeasure + +The described ECDSA has three main routines: KeyGen, Signing, and Verifying. Since the Verifying routine requires operation with public values rather than a secret value, our side-channel analysis does not cover this routine. Our evaluation covers the KeyGen and Signing routines where the secret values are processed. + +KeyGen consists of HMAC DRBG and scalar multiplication, while Signing first requires a message hashing and then follows the same operations as KeyGen (HMAC DRBG and scalar multiplication). The last step of Signing is generating “S” as the proof of signature. Since HMAC DRBG and hash operations are evaluated separately in our document, this evaluation covers scalar multiplication and modular arithmetic operations. + +#### Scalar multiplication + +To perform the scalar multiplication, the Montgomery ladder is implemented, which is inherently resistant to timing and single power analysis (SPA) attacks. + +Implementation of complete unified addition formula for the scalar multiplication avoids information leakage and enhances architecture from security and mathematical perspectives. + +To protect the architecture against horizontal power/electromagnetic (EM) and differential power analysis (DPA) attacks, several countermeasures are embedded in the design [9]. Since these countermeasures require random inputs, HMAC-DRBG is fed by IV to generate these random values. + +Since HMAC-DRBG generates random value in a deterministic way, firmware MUST feed different IV to ECC engine for EACH keygen and signing operation. + +#### Base point randomization + +This countermeasure is achieved using the randomized base point in projective coordinates. Hence, the base point G=(Gx, Gy) in affine coordinates is transformed and randomized to projective coordinates as (X, Y, Z) using a random value as follows: + +This approach does not have the performance or area overhead because the architecture is variable-base-point implemented. + +#### Scalar blinding + +This countermeasure is achieved by randomizing the scalar as follows: + +Based on [10], half of the bit size of is required to prevent advanced DPA attacks. Therefore, has 192 bits, and the blinded scalar has 576 bits. Hence, this countermeasure extends the Montgomery ladder iterations due to extended scalar. + +This approach is achieved at the cost of 50% more latency on scalar multiplication and adding one lightweight block, including one 32\*32 multiplier and an accumulator. + +Note: the length of rand is configurable to have a trade-off between the required protection and performance. + +#### Making countermeasures embedded into HMAC\_DRBG + +In the first step of the KeyGen operation, the privkey is generated using HMAC\_DRBG by feeding the following two inputs: seed and nonce. To avoid SCA information leakage during this operation, we embed masking countermeasures into the HMAC\_DRBG architecture. + +Each round of SHA512 execution needs 6,432 random bits, and one HMAC operation needs at least 4 rounds of SHA512 operations. Furthermore, each HMAC\_DRBG round needs at least 5 rounds of HMAC operations. However, the proposed architecture uses a lightweight LFSR and provides first-order DPA attack protection with negligible latency and hardware resource overhead. + +#### ECDSA signing nonce leakage + +Generating “S” as the proof of signature at the steps of the signing operation leaks where the hashed message is signed with private key and ephemeral key as follows: + +Since the given message is known or the signature part r is known, the attacker can perform a known-plaintext attack. The attacker can sign multiple messages with the same key, or the attacker can observe part of the signature that is generated with multiple messages but the same key. + +The evaluation shows that the CPA attack can be performed with a small number of traces, respectively. Thus, an arithmetic masked design for these operations is implemented. + +##### Masking signature + +This countermeasure is achieved by randomizing the privkey as follows: + +Although computation of “S” seems the most vulnerable point in our scheme, the operation does not have a big contribution to overall latency. Hence, masking these operations has low overhead on the cost of the design. + +#### Random number generator for SCA countermeasure + +The ECC countermeasure requires several random vectors to randomize the intermediate values, as described in the preceding section. HMAC\_DRBG is used to take one random vector of 384-bit (i.e., ECC\_IV register) and to generate the required random vectors for different countermeasures. + +The state machine of HMAC\_DRBG utilization is shown in the following figure, including three main states: + +1. SCA random generator: Running HMAC\_DRBG with IV and an internal counter to generate the required random vectors. +2. KEYGEN PRIVKEY: Running HMAC\_DRBG with seed and nonce to generate the privkey in KEYGEN operation. +3. SIGNING NONCE: Running HMAC\_DRBG based on RFC6979 in SIGNING operation with privkey and hashed\_msg. + +*Figure 37: HMAC\_DRBG utilization* + +![](./images/HMAC_DRBG_util.png) + +In SCA random generator state: + +* This state (in KeyGen operation mode) generates 3 384-bit random vectors for the following: LFSR, base point randomization, and scalar blinding randomization. +* This state (in signing operation) generates 4 384-bit random vectors for the following: LFSR, base point randomization, scalar blinding, and masking signature randomization. +* HMAC\_DRBG is initialized with IV and an internal counter. This 64-bit counter enables after reset and zeroization and contains different values depending on when ECC is called. +* HMAC\_DRBG is enabled by the INIT command. To generate all required vectors, HMAC-DRBG is continued by the NEXT command that increments the built-in counter inside the HMAC-DRBG unit. +* To initialize the required seed for LFSR, LFSR\_INIT\_SEED is set as a constant by RTL after reset and zeroization. However, this value is updated before enabling HMAC\_DRBG as follows: + * In the first execution of HMAC\_DRBG after reset and zeroization, hmac\_lfsr\_seed is equal to LFSR\_INIT\_SEED XORed by internal 64-bit counter. + * In the next executions of HMAC\_DRBG, hmac\_lfsr\_seed is equal to HMAC\_DRBG output of the first execution XORed by internal 64-bit counter. + +The data flow of the HMAC\_DRBG operation in keygen operation mode is shown in the following figure. + +*Figure 38: HMAC\_DRBG data flow* + +![](./images/HMAC_DRBG_data.png) + +#### TVLA results + +Test vector leakage assessment (TVLA) provides a robust test using a 𝑡-test. This test evaluates the differences between sets of acquisitions to determine if one set of measurement can be distinguished from the other. This technique can detect different types of leakages, providing a clear indication of leakage or lack thereof. + +In practice, observing a t-value greater than a specific threshold (mainly 4.5) indicates the presence of leakage. However, in ECC, due to its latency, around 5 million samples are required to be captured. This latency leads to many false positives and the TVLA threshold can be considered a higher value than 4.5. Based on the following figure from “Side-Channel Analysis and Countermeasure Design for Implementation of Curve448 on Cortex-M4” by Bisheh-Niasar et. al., the threshold can be considered equal to 7 in our case. + +*Figure 39: TVLA threshold as a function of the number of samples per trace* + +![](./images/TVLA_threshold.png) + + +##### KeyGen TVLA + +We detected a leakage using TVLA in the HMAC_DRBG algorithm during ECC key generation, based on 150,000 power traces. The leakage originated from a part of the SHA512 function (w_data) that was not fully protected by masking. The same leakage is expected for HMAC operations. + +*Figure 40: seed/nonce-dependent leakage detection using TVLA for ECC keygen after 150,000 traces* + +![](./images/tvla_keygen.png) + +This leakage is very unlikely to occur in practice, even though it exists in TVLA results. Therefore, we will address it in the next release. + +##### Signing TVLA + +The TVLA results for performing privkey-dependent leakage detection using 20,000 traces is shown in the following figure. Based on this figure, there is no leakage in ECC signing by changing the privkey after 20,000 operations. + +*Figure 41: privkey-dependent leakage detection using TVLA for ECC signing after 20,000 traces* + +![](./images/TVLA_privekey.png) + +The TVLA results for performing message-dependent leakage detection using 64,000 traces is shown in the following figure. Based on this figure, there is no leakage in ECC signing by changing the message after 64,000 operations. + +*Figure 42: Message-dependent leakage detection using TVLA for ECC signing after 64,000 traces* + +![](./images/TVLA_msg_dependent.png) + +The point with t-value equal to -40 is mapped to the Montgomery conversion of the message that is a publicly known value (no secret is there). By ignoring those corresponding samples, there are some sparse samples with a t-value greater than 7, as shown in the following table. + +| Sample | Duration | Cycle | t-value | Operation | +| :-------- | :--------- | :-------- | :------ | :---------------------- | +| 4,746,127 | 214 | 911,381.4 | 11.2 | start of mont_conv(msg) | +| 4,746,341 | | 911,422.5 | -40 | end of mont_conv(msg) | +| 4,757,797 | 1 | 913,622.0 | 7.4 | inv_q | +| 4,768,302 | 1 | 915,639.0 | 7.8 | inv_q | +| 4,779,610 | 1 | 917,810.1 | -9.1 | inv_q | +| 4,788,120 | 1 | 919,444.0 | 7.6 | inv_q | +| 4,813,995 | 1 | 924,412.0 | 7.3 | inv_q | +| 4,822,693 | 1 | 926,082.1 | 7.5 | inv_q | +| 4,858,671 | to the end | 932,989.8 | -7.6 | Ended ECC signing | + +### Performance + +The ECC core performance is reported in the next section. + +### Pure hardware architecture + +In this architecture, the ECC interface and controller are implemented in hardware. The performance specification of the ECC architecture is reported as shown in the following table. + +| Operation | Cycle count \[CCs\] | Time \[ms\] @ 400 MHz | Throughput \[op/s\] | +| :-------- | :------------------ | :-------------------- | :------------------ | +| Keygen | 909,648 | 2.274 | 439 | +| Signing | 932,990 | 2.332 | 428 | +| Verifying | 1,223,938 | 3.060 | 326 | +## PCR vault + +* Platform Configuration Register (PCR) vault is a register file that stores measurements to be used by the microcontroller. +* PCR entries are read-only registers of 384 bits each. +* Control bits allow for entries to be cleared by FW, which sets their values back to 0. +* A lock bit can be set by FW to prevent the entry from being cleared. The lock bit is sticky and only resets on a powergood cycle. + +| PCRV register | Address Offset | Description | +| :---------------------------------| :------------- | :----------------------------- | +| PCR Control\[31:0\] | 0x1001a000 | 32 Control registers, 32 bits each | +| PCR Entry\[31:0\]\[11:0\]\[31:0\] | 0x1001a600 | 32 PCR entries, 384 bits each | + +### PCR vault functional block + +PCR entries are hash extended using a hash extension function. The hash extension function takes the data currently in the PCR entry specified, concatenates data provided by the FW, and performs a SHA384 function on that data, storing the result back into the same PCR entry. + +### PCR hash extend function + +FW provides the PCR entry to use as source and destination of the hash extend. HW copies the PCR into the start of the SHA block and locks those dwords from FW access. FW then provides the new data, and runs the SHA function as usual. After initialization, the locked dwords are unlocked. + +FW must set a last cycle flag before running the last iteration of the SHA engine. This could be the first “init” cycle, or the Nth “next” cycle. This flag allows HW to copy the final resulting hash output back to the source PCR. + +### PCR signing + +* PCR signing uses the key in key slot index 7 for PCR signing +* HW implements a HW function called GEN\_PCR\_HASH + * HW reads all the PCRs from all the PCR slots and hash extends them along with the NONCE that Caliptra FW provides + * PCR Hash = Hash(PCR[0], …, PCR[31], Nonce) +* HW also implements a HW function called SIGN\_PCR. This function takes the PCR digest that was generated by the previous routine and signs it using the key in key slot 7, following the same ECC sign flow defined in the [ECC](#ecc) section. + * The resulting PCR DIGEST is used only once for signing by the HW. If a new PCR signing is required, GEN\_PCR\_HASH needs to be redone. + +## Key vault + +Key Vault (KV) is a register file that stores the keys to be used by the microcontroller, but this register file is not observed by the microcontroller. Each cryptographic function has a control register and functional block designed to read from and write to the KV.  + +| KV register | Description | +| :------------------------------- | :------------------------------------------------------- | +| Key Control\[7:0\] | 8 Control registers, 32 bits each | +| Key Entry\[7:0\]\[15:0\]\[31:0\] | 8 Key entries, 512 bits each
No read or write access | + +### Key vault functional block + +Keys and measurements are stored in 512b register files. These have no read or write path from the microcontroller. The entries are read through a passive read mux driven by each cryptographic block. Locked entries return zeroes.  + +Entries in the KV must be cleared via control register, or by de-assertion of pwrgood.   + +Each entry has a control register that is writable by the microcontroller.  + +The destination valid field is programmed by FW in the cryptographic block generating the key, and it is passed here at generation time. This field cannot be modified after the key is generated and stored in the KV.  + +| KV Entry Ctrl Fields  | Reset  | Description  | +|---------------------------|-------------------|------------------------| +| Lock wr\[0\]  | core_only_rst_b   | Setting the lock wr field prevents the entry from being written by the microcontroller. Keys are always locked. After a lock is set, it cannot be reset until cptra_rst_b is de-asserted.  | +| Lock use\[1\]  | core_only_rst_b   | Setting the lock use field prevents the entry from being used in any cryptographic blocks. After the lock is set, it cannot be reset until cptra_rst_b is de-asserted. | +| Clear\[2\]  | cptra_rst_b  | If unlocked, setting the clear bit causes KV to clear the associated entry. The clear bit is reset after entry is cleared.  | +| Copy\[3\]  | cptra_rst_b  | ENHANCEMENT: Setting the copy bit causes KV to copy the key to the entry written to Copy Dest field.  | +| Copy Dest\[8:4\]  | cptra_rst_b  | ENHANCEMENT: Destination entry for the copy function.  | +| Dest_valid\[16:9\]  | hard_reset_b | KV entry can be used with the associated cryptographic block if the appropriate index is set.
\[0\] - HMAC KEY
\[1\] - HMAC BLOCK
\[2\] - SHA BLOCK
\[2\] - ECC PRIVKEY
\[3\] - ECC SEED
\[7:5\] - RSVD | +| last_dword\[20:19\] | hard_reset_b | Store the offset of the last valid dword, used to indicate the last cycle for read operations. | + +### Key vault cryptographic functional block  + +A generic block is instantiated in each cryptographic block to enable access to KV.  + +Each input to a cryptographic engine can have a key vault read block associated with it. The KV read block takes in a keyvault read control register that drives an FSM to copy an entry from the keyvault into the appropriate input register of the cryptographic engine. + +Each output generated by a cryptographic engine can have its result copied to a slot in the keyvault. The KV write block takes in a keyvault write control register. This register drives an FSM to copy the result from the cryptographic engine into the appropriate keyvault entry. It also programs a control field for that entry to indicate where that entry can be used. + +After programming the key vault read control, FW needs to query the associated key vault read status to confirm that the requested key was copied successfully. After valid is set and the error field reports success, the key is ready to be used. + +Similarly, after programming the key vault write control and initiating the cryptographic function that generates the key to be written, FW needs to query the associated key vault write status to confirm that the requested key was generated and written successfully. + +The following tables describe read, write, and status values for key vault blocks. + +| KV Read Ctrl Reg | Description | +| :------------------- | :------------------------------------------------------------------------------------------------------------------------------------- | +| read_en\[0\] | Indicates that the read data is to come from the key vault. Setting this bit to 1 initiates copying of data from the key vault. | +| read_entry\[5:1\] | Key vault entry to retrieve the read data from the engine. | +| pcr_hash_extend\[6\] | Requested entry is a PCR. This is used only for the SHA engine to hash extend. It is not functional in any other cryptographic engine. | +| rsvd\[31:7\] | Reserved field | + +| KV Write Ctrl Reg | Description | +| :------------------------- | :------------------------------------------------------------------------------------------------------------------------------------- | +| write_en\[0\] | Indicates that the result is to be stored in the key vault. Setting this bit to 1 copies the result to the key vault when it is ready. | +| write_entry\[5:1\] | Key vault entry to store the result. | +| hmac_key_dest_valid\[6\] | HMAC KEY is a valid destination. | +| hmac_block_dest_valid\[7\] | HMAC BLOCK is a valid destination. | +| sha_block_dest_valid\[8\] | SHA BLOCK is a valid destination. | +| ecc_pkey_dest_valid\[9\] | ECC PKEY is a valid destination. | +| ecc_seed_dest_valid\[10\] | ECC SEED is a valid destination. | +| rsvd\[31:11\] | Reserved field | + +| KV Status Reg | Description | +| :------------ | :---------------------------------------------------------------------------------------------------------------------------------------------- | +| ready\[0\] | Key vault control is idle and ready for a command. | +| valid\[1\] | Requested flow is done. | +| error\[9:2\] | SUCCESS - 0x0 - Key Vault flow was successful
KV_READ_FAIL - 0x1 - Key Vault Read flow failed
KV_WRITE_FAIL - 0x2 - Key Vault Write flow failed | + +### De-obfuscation engine + +To protect software intellectual property from different attacks and, particularly, for thwarting an array of supply chain threats, code obfuscation is employed. Hence, the de-obfuscation engine is implemented to decrypt the code. + +Advanced Encryption Standard (AES) is used as a de-obfuscation function to encrypt and decrypt data [4]. The hardware implementation is based on[ Secworks/aes](https://github.com/secworks/aes) [1]. The implementation supports the two variants: 128- and 256-bit keys with a block/chunk size of 128 bits. + +The AES algorithm is described as follows: + +* The key is fed to an AES core to compute and initialize the round key +* The message is broken into 128-bit chunks by the host +* For each chunk: + * The message is fed to the AES core + * The AES core and its working mode (enc/dec) are triggered by the host + * The AES core status is changed to ready after encryption or decryption processing +* The result digest can be read before processing the next message chunks + + +### Key vault de-obfuscation block operation + +A de-obfuscation engine (DOE) is used in conjunction with AES cryptography to de-obfuscate the UDS and field entropy.   + +1. The obfuscation key is driven to the AES key. The data to be decrypted (either obfuscated UDS or obfuscated field entropy) is fed into the AES data.  +2. An FSM manually drives the AES engine and writes the decrypted data back to the key vault.  +3. FW programs the DOE with the requested function (UDS or field entropy de-obfuscation), and the destination for the result.  +4. After de-obfuscation is complete, FW can clear out the UDS and field entropy values from any flops until cptra\_pwrgood de-assertion.   + +The following tables describe DOE register and control fields. + +| DOE Register | Address | Description  | +| :----------- | :--------- | :----------------------------------------------------------------------------------------------------------------------------- | +| IV | 0x10000000 | 128 bit IV for DOE flow. Stored in big-endian representation. | +| CTRL | 0x10000010 | Controls for DOE flows. | +| STATUS | 0x10000014 | Valid indicates the command is done and results are stored in keyvault. Ready indicates the core is ready for another command. | + +| DOE Ctrl Fields  | Reset  | Description  | +| :--------------- | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------- | +| COMMAND\[1:0\]  | Cptra_rst_b  | 2’b00 Idle 
2’b01 Run UDS flow 
2’b10 Run FE flow 
2’b11 Clear Obf Secrets | +| DEST\[4:2\]  | Cptra_rst_b  | Destination register for the result of the de-obfuscation flow. Field entropy writes into DEST and DEST+1 
Key entry only, can’t go to PCR . | + +### Key vault de-obfuscation flow  + +1. ROM loads IV into DOE. ROM writes to the DOE control register the destination for the de-obfuscated result and sets the appropriate bit to run UDS and/or the field entropy flow.  +2. DOE state machine takes over and loads the Caliptra obfuscation key into the key register.  +3. Next, either the obfuscated UDS or field entropy are loaded into the block register 4 DWORDS at a time.  +4. Results are written to the KV entry specified in the DEST field of the DOE control register.  +5. State machine resets the appropriate RUN bit when the de-obfuscated key is written to KV. FW can poll this register to know when the flow is complete. +6. The clear obf secrets command flushes the obfuscation key, the obfuscated UDS, and the field entropy from the internal flops. This should be done by ROM after both de-obfuscation flows are complete. + +## Data vault + +Data vault is a set of generic scratch pad registers with specific lock functionality and clearable on cold and warm resets. + +* 48B scratchpad registers that are lockable but cleared on cold reset (10 registers) +* 48B scratchpad registers that are lockable but cleared on warm reset (10 registers) +* 4B scratchpad registers that are lockable but cleared on cold reset (8 registers) +* 4B scratchpad registers that are lockable but cleared on warm reset (10 registers) +* 4B scratchpad registers that are cleared on warm reset (8 registers) + +## Cryptographic blocks fatal and non-fatal errors + +The following table describes cryptographic errors. + +| Errors | Error type | Description | +| :--------- | :----------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ECC_R_ZERO | HW_ERROR_NON_FATAL | Indicates a non-fatal error in ECC signing if the computed signature R is equal to 0. FW should change the message or privkey to perform a valid signing. | + +# Terminology + +The following terminology is used in this document. + +| Abbreviation | Description | +| :----------- | :--------------------------------------------- | +| AES | Advanced Encryption Standard | +| BMC | Baseboard Management Controller | +| CA | Certificate Authority | +| CDI | Composite Device Identifier | +| CPU | Central Processing Unit | +| CRL | Certificate Revocation List | +| CSR | Certificate Signing Request | +| CSP | Critical Security Parameter | +| DICE | Device Identifier Composition Engine | +| DME | Device Manufacturer Endorsement | +| DPA | Differential Power Analysis | +| DRBG | Deterministic Random Bit Generator | +| DWORD | 32-bit (4-byte) data element | +| ECDSA | Elliptic Curve Digital Signature Algorithm | +| FMC | FW First Mutable Code | +| FSM | Finite State Machine | +| GPU | Graphics Processing Unit | +| HMAC | Hash-based message authentication code | +| IDevId | Initial Device Identifier | +| iRoT | Internal RoT | +| IV | Initial Vector | +| KAT | Known Answer Test | +| KDF | Key Derivation Function | +| LDevId | Locally Significant Device Identifier | +| MCTP | Management Component Transport Protocol | +| NIC | Network Interface Card | +| NIST | National Institute of Standards and technology | +| OCP | Open Compute Project | +| OTP | One-time programmable | +| PCR | Platform Configuration Register | +| PKI | Public Key infrastructure | +| PUF | Physically unclonable function | +| RNG | Random Number Generator | +| RoT | Root of Trust | +| RTI | RoT for Identity | +| RTM | RoT for Measurement | +| RTR | RoT for Reporting | +| SCA | Side-Channel Analysis | +| SHA | Secure Hash Algorithm | +| SoC | System on Chip | +| SPA | Simple Power Analysis | +| SPDM | Security Protocol and Data Model | +| SSD | Solid State Drive | +| TCB | Trusted Computing Base | +| TCI | TCB Component Identifier | +| TCG | Trusted Computing Group | +| TEE | Trusted Execution Environment | +| TRNG | True Random Number Generator | +| UECC | Uncorrectable Error Correction Code | + +# References + +1. J. Strömbergson, "Secworks," \[Online\]. Available at https://github.com/secworks. +2. NIST, Federal Information Processing Standards Publication (FIPS PUB) 180-4 Secure Hash Standard (SHS). +3. OpenSSL \[Online\]. Available at https://www.openssl.org/docs/man3.0/man3/SHA512.html. +4. N. W. Group, RFC 3394, Advanced Encryption Standard (AES) Key Wrap Algorithm, 2002. +5. NIST, Federal Information Processing Standards Publication (FIPS) 198-1, The Keyed-Hash Message Authentication Code, 2008. +6. N. W. Group, RFC 4868, Using HMAC-SHA256, HMAC-SHA384, and HMAC-SHA512 with IPsec, 2007. +7. RFC 6979, Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA), 2013. +8. TCG, Hardware Requirements for a Device Identifier Composition Engine, 2018. +9. Coron, J.-S.: Resistance against differential power analysis for elliptic curve cryptosystems. In: Ko¸c, C¸ .K., Paar, C. (eds.) CHES 1999. LNCS, vol. 1717, pp. 292–302. +10. Schindler, W., Wiemers, A.: Efficient side-channel attacks on scalar blinding on elliptic curves with special structure. In: NISTWorkshop on ECC Standards (2015). +11. National Institute of Standards and Technology, "Digital Signature Standard (DSS)", Federal Information Processing Standards Publication (FIPS PUB) 186-4, July 2013. +12. NIST SP 800-90A, Rev 1: "Recommendation for Random Number Generation Using Deterministic Random Bit Generators", 2012. | +13. CHIPS Alliance, “RISC-V VeeR EL2 Programmer’s Reference Manual” \[Online\] Available at https://github.com/chipsalliance/Cores-VeeR-EL2/blob/main/docs/RISC-V_VeeR_EL2_PRM.pdf. +14. “The RISC-V Instruction Set Manual, Volume I: User-Level ISA, Document Version 20191213”, Editors Andrew Waterman and Krste Asanovi ́c, RISC-V Foundation, December 2019. Available at https://riscv.org/technical/specifications/. +15. “The RISC-V Instruction Set Manual, Volume II: Privileged Architecture, Document Version 20211203”, Editors Andrew Waterman, Krste Asanovi ́c, and John Hauser, RISC-V International, December 2021. Available at https://riscv.org/technical/specifications/. + +[1] _Caliptra.** **Spanish for “root cap” and describes the deepest part of the root_ diff --git a/docs/CaliptraIntegrationSpecification.md b/docs/CaliptraIntegrationSpecification.md index 2663e73a3..1db5c8f2c 100644 --- a/docs/CaliptraIntegrationSpecification.md +++ b/docs/CaliptraIntegrationSpecification.md @@ -2,7 +2,7 @@

Caliptra Integration Specification

-

Version 1.0-rc1

+

Version 1.0

@@ -27,28 +27,20 @@ The blocks described in this document are either obtained from open-source GitHu | IP/Block | GitHub URL | Documentation | Link | | :--------- | :--------- | :--------- |:--------- | | Cores-VeeR | [GitHub - chipsalliance/Cores-VeeR-EL2](https://github.com/chipsalliance/Cores-VeeR-EL2) | VeeR EL2 Programmer’s Reference Manual | [chipsalliance/Cores-VeeR-EL2 · GitHubPDF](http://cores-swerv-el2/RISC-V_SweRV_EL2_PRM.pdf%20at%20master%20%C2%B7) | -| AHB Lite Bus | [aignacio/ahb_lite_bus: AHB Bus lite v3.0 (github.com)](https://github.com/aignacio/ahb_lite_bus) | AHB Lite Protocol
[Figure 2: SoC interface block diagram](#soc-interface-definition) | [ahb_lite_bus/docs at master · aignacio/ahb_lite_bus (github.com)](https://github.com/aignacio/ahb_lite_bus/tree/master/docs)
[ahb_lite_bus/diagram_ahb_bus.png at master · aignacio/ahb_lite_bus (github.com)](https://github.com/aignacio/ahb_lite_bus/blob/master/diagram_ahb_bus.png) | +| AHB Lite Bus | [aignacio/ahb_lite_bus: AHB Bus lite v3.0 (github.com)](https://github.com/aignacio/ahb_lite_bus) | AHB Lite Protocol
[Figure 1: SoC interface block diagram](#soc-interface-definition) | [ahb_lite_bus/docs at master · aignacio/ahb_lite_bus (github.com)](https://github.com/aignacio/ahb_lite_bus/tree/master/docs)
[ahb_lite_bus/diagram_ahb_bus.png at master · aignacio/ahb_lite_bus (github.com)](https://github.com/aignacio/ahb_lite_bus/blob/master/diagram_ahb_bus.png) | | SHA 256 | [secworks/sha256: Hardware implementation of the SHA-256 cryptographic hash function (github.com)](https://github.com/secworks/sha256) | | | | SHA 512 | | | | | SPI Controller | | | | # Caliptra Core -The following figure shows the Caliptra Core. - -*Figure 1: Caliptra block diagram* - -![](./images/Caliptra_HW_diagram.png) - -## Boot Media Dependent (passive) vs Boot Media Integrated (active) profile - -In the BMD profile, QSPI and I3C IO peripherals are disabled using integration-time defines passed to the hardware, which are also exposed to ROM. Peripheral IOs can be tied off appropriately for the BMD profile at SoC integration time. For more information on the BMD vs. BMI profile differences, see the boot flows in [Caliptra profiles](https://chipsalliance.github.io/Caliptra/doc/Caliptra.html#caliptra-profiles). Only the BMD profile is supported for the first generation release of Caliptra. +For information on the Caliptra Core, see the [High level architecture](https://chipsalliance.github.io/Caliptra/doc/Caliptra.html#high-level-architecture) section of [Caliptra: A Datacenter System on a Chip (SoC) Root of Trust (RoT)](https://chipsalliance.github.io/Caliptra/doc/Caliptra.html). # SoC interface definition The following figure shows the SoC interface definition. -*Figure 2: SoC Interface Block Diagram* +*Figure 1: SoC Interface Block Diagram* ![](./images/Caliptra_soc_interface_block.png) @@ -70,12 +62,13 @@ The following table describes integration parameters. | **Defines** | **Defines file** | **Description** | | :--------- | :--------- | :--------- | -| CALIPTRA_APB_ADDR_WIDTH | config_defines.svh | Width of the APB Address field. Default to 32. | -| CALIPTRA_APB_DATA_WIDTH | config_defines.svh | Width of the APB Data field. Default to 32. | -| CALIPTRA_APB_USER_WIDTH | config_defines.svh | Width of the APB PAUSER field. | | CALIPTRA_INTERNAL_TRNG | config_defines.svh | Defining this enables the internal TRNG source. | | CALIPTRA_INTERNAL_UART | config_defines.svh | Defining this enables the internal UART. | | CALIPTRA_INTERNAL_QSPI | config_defines.svh | Defining this enables the internal QSPI. | +| USER_ICG | config_defines.svh | If added by an integrator, provides the name of the custom clock gating module that is used in [clk_gate.sv](../src/libs/rtl/clk_gate.sv). USER_ICG replaces the clock gating module, CALIPTRA_ICG, defined in [caliptra_icg.sv](../src/libs/rtl/caliptra_icg.sv). This substitution is only performed if integrators also define TECH_SPECIFIC_ICG. | +| TECH_SPECIFIC_ICG | config_defines.svh | Defining this causes the custom, integrator-defined clock gate module (indicated by the USER_ICG macro) to be used in place of the native Caliptra clock gate module. | +| USER_EC_RV_ICG | config_defines.svh | If added by an integrator, provides the name of the custom clock gating module that is used in the RISC-V core. USER_EC_RV_ICG replaces the clock gating module, TEC_RV_ICG, defined in [beh_lib.sv](../src/riscv_core/veer_el2/rtl/lib/beh_lib.sv). This substitution is only performed if integrators also define TECH_SPECIFIC_EC_RV_ICG. | +| TECH_SPECIFIC_EC_RV_ICG | config_defines.svh | Defining this causes the custom, integrator-defined clock gate module (indicated by the USER_EC_RV_ICG macro) to be used in place of the native RISC-V core clock gate module. | ## Interface @@ -93,15 +86,15 @@ The following tables describe the interface signals. | Signal name | Width | Driver | Synchronous (as viewed from Caliptra’s boundary) | Description | | :--------- | :--------- | :--------- | :--------- | :--------- | -| PADDR | 32 | Input | Synchronous to clk | Address bus | +| PADDR | CALIPTRA_APB_ADDR_WIDTH | Input | Synchronous to clk | Address bus | | PPROT | 3 | Input | Synchronous to clk | Protection level | | PSEL | 1 | Input | Synchronous to clk | Select line | | PENABLE | 1 | Input | Synchronous to clk | Indicates the second and subsequent cycles. | | PWRITE | 1 | Input | Synchronous to clk | Indicates transfer is a write when high or a read when low. | -| PWDATA | 32 | Input | Synchronous to clk | Write data bus | -| PAUSER | APB_USER_REQ_WIDTH | Input | Synchronous to clk | Sideband signal indicating requestor ID for transfer. | +| PWDATA | CALIPTRA_APB_DATA_WIDTH | Input | Synchronous to clk | Write data bus | +| PAUSER | CALIPTRA_APB_USER_WIDTH | Input | Synchronous to clk | Sideband signal indicating requestor ID for transfer. | | PREADY | 1 | Output | Synchronous to clk | Used to extend an APB transfer by completer. | -| PRDATA | 32 | Output | Synchronous to clk | Read data bus | +| PRDATA | CALIPTRA_APB_DATA_WIDTH | Output | Synchronous to clk | Read data bus | | PSLVERR | 1 | Output | Synchronous to clk | Transfer error | *Table 6: QSPI signals* @@ -177,8 +170,8 @@ The following tables describe the interface signals. | CALIPTRA_ERROR_NON_FATAL | 1 | Output | Synchronous to clk | Indicates a non fatal error from Caliptra. | | BootFSM_BrkPoint | 1 | Input Strap | Asynchronous | Stops the BootFSM to allow TAP writes set up behavior. Examples of these behaviors are skipping or running ROM flows, or stepping through BootFSM. | | eTRNG_REQ | 1 | Output | Synchronous to clk | External source mode: TRNG_REQ to SoC. SoC writes to TRNG architectural registers with a NIST-compliant entropy.
Internal source mode: TRNG_REQ to SoC. SoC enables external RNG digital bitstream input into iTRNG_DATA/iTRNG_VALID. | -| iTRNG_DATA | 4 | Input | Synchronous to clk | External source mode: Not used.
Internal source mode only: RNG digital bit stream from SoC, which is sampled when iTRNG_VALID is high. | -| iTRNG_VALID | 1 | Input | Synchronous to clk | External source mode: Not used.
Internal source mode only: RNG bit valid. This is valid per transaction. TRNG_DATA can be sampled whenever this bit is high. The expected iTRNG_VALID output rate is about 50KHz. | +| iTRNG_DATA | 4 | Input | Synchronous to clk | External source mode: Not used.
Internal source mode only: Physical True Random Noise Source (PTRNG for "Number Generator") digital bit stream from SoC, which is sampled when iTRNG_VALID is high. See the [Hardware Specification](https://github.com/chipsalliance/caliptra-rtl/blob/main/docs/CaliptraHardwareSpecification.md#integrated-trng) for details on PTRNG expectations and iTRNG entropy capabilities. | +| iTRNG_VALID | 1 | Input | Synchronous to clk | External source mode: Not used.
Internal source mode only: RNG bit valid. This is valid per transaction. iTRNG_DATA can be sampled whenever this bit is high. The expected iTRNG_VALID output rate is about 50KHz. | ## Architectural registers and fuses @@ -197,15 +190,17 @@ Although fuse values (and the fuse done register) persist across a warm reset, S ## Interface rules -The following figure shows the reset rules and timing. +The following figure shows the reset rules and timing for cold boot flows. -*Figure 3: Reset rules and timing diagram* +*Figure 2: Reset rules and timing diagram* ![](./images/Caliptra_reset_timing.png) Deassertion of cptra\_pwrgood indicates a power cycle that results in returning Caliptra to its default state. All resettable flops are reset. -De-assertion of cptra\_rst\_b indicates a warm reset cycle that resets all but the “sticky” registers (fuses, error logging, etc.). +Deassertion of cptra\_rst\_b indicates a warm reset cycle that resets all but the “sticky” registers (fuses, error logging, etc.). + +Assertion of BootFSM\_BrkPoint stops the boot flow from releasing Caliptra from reset after fuse download. Writing a 1 to the GO field of the CPTRA\_BOOTFSM\_GO register allows the boot flow to proceed. ### APB arbitration @@ -233,7 +228,7 @@ Caliptra firmware internally has the capability to force release the mailbox bas Straps are signal inputs to Caliptra that are sampled once on reset exit, and the latched value persists throughout the remaining uptime of the system. Straps are sampled on either caliptra pwrgood signal deassertion or cptra\_noncore\_rst\_b deassertion – refer to interface table for list of straps. -### Deobfuscation key +### Obfuscation key SoC drives the key at the tape-in time of the SoC using an Engineering Change Order (ECO) and must be protected from common knowledge. For a given SoC construction, this can be driven using a PUF too. @@ -272,11 +267,11 @@ Caliptra in turn also uses the mailbox to pass information back to the SoC. The The Boot FSM detects that the SoC is bringing Caliptra out of reset. Part of this flow involves signaling to the SoC that Caliptra is ready for fuses. After fuses are populated and the SoC indicates that it is done downloading fuses, Caliptra can wake up the rest of the IP by deasserting the internal reset. The following figure shows the boot FSM state. -*Figure 4: Mailbox Boot FSM state diagram* +*Figure 3: Mailbox Boot FSM state diagram* ![](./images/Caliptra_mbox_boot_FSM.png) -The boot FSM first waits for the SoC to assert cptra\_pwrgood and de-assert cptra\_rst\_b. In the BOOT\_FUSE state, Caliptra signals to the SoC that it is ready for fuses. After the SoC is done writing fuses, it sets the fuse done register and the FSM advances to BOOT\_DONE. +The boot FSM first waits for the SoC to assert cptra\_pwrgood and deassert cptra\_rst\_b. In the BOOT\_FUSE state, Caliptra signals to the SoC that it is ready for fuses. After the SoC is done writing fuses, it sets the fuse done register and the FSM advances to BOOT\_DONE. BOOT\_DONE enables Caliptra reset deassertion through a two flip-flop synchronizer. @@ -294,7 +289,7 @@ When a mailbox is populated by the SoC, initiation of the operation by writing t When a mailbox is populated by the microcontroller, an output wire to the SoC indicates that a command is available in the mailbox. The SoC is responsible for reading from and responding to the command. -Mailboxes are generic data-passing structures with a specific protocol that defines legal operations. This protocol for writing to and reading from the mailbox is enforced in hardware as described in the [Caliptra mailbox errors](#caliptra-mailbox-errors) section. How the command and data are interpreted by the microcontroller and SoC are not enforced in this specification. \ +Mailboxes are generic data-passing structures with a specific protocol that defines legal operations. This protocol for writing to and reading from the mailbox is enforced in hardware as described in the [Caliptra mailbox errors](#caliptra-mailbox-errors) section. How the command and data are interpreted by the microcontroller and SoC are not enforced in this specification. ## Sender Protocol @@ -319,7 +314,7 @@ Mailboxes are generic data-passing structures with a specific protocol that defi Once LOCK is granted, the mailbox is locked until that device has concluded its operation. Caliptra has access to an internal mechanism to terminate a lock early or release the lock if the device does not proceed to use it or to recover from deadlock scenarios. The following figure shows the sender protocol flow. -*Figure 5: Sender protocol flow chart* +*Figure 4: Sender protocol flow chart* ![](./images/Caliptra_mbox-sender.png) @@ -342,7 +337,7 @@ Caliptra will not initiate any mailbox commands that require a response from the The following figure shows the receiver protocol flow. -*Figure 6: Receiver protocol flowchart* +*Figure 5: Receiver protocol flowchart* ![](./images/Caliptra_mbox_receiver.png) @@ -448,9 +443,9 @@ SHA\_LOCK register is set on read. A read of 0 indicates the SHA was unlocked an SHA\_MODE register sets the mode of operation for the SHA. See the Hardware specification for additional details. -* 2’b00 - SHA384 streaming mode -* 2’b01 - SHA512 streaming mode -* 2’b10 - SHA384 mailbox mode (Caliptra only, invalid for SoC requests) +* 2’b00 - SHA384 streaming mode +* 2’b01 - SHA512 streaming mode +* 2’b10 - SHA384 mailbox mode (Caliptra only, invalid for SoC requests) * 2’b11 - SHA512 mailbox mode (Caliptra only, invalid for SoC requests) ## SoC Sender Protocol @@ -485,6 +480,10 @@ Having an interface that is separate from the SoC mailbox ensures that this requ TRNG DATA register is tied to TRNG VALID PAUSER. SoC can program the TRNG VALID PAUSER and lock the register using TRNG\_PAUSER\_LOCK[LOCK]. This ensures that TRNG DATA register is read-writeable by only the PAUSER programmed into the TRNG\_VALID\_PAUSER register. If the CPTRA\_TNRG\_PAUSER\_LOCK.LOCK is set to ‘0, then any agent can write to the TRNG DATA register. If the lock is set, only an agent with a specific TRNG\_VALID\_PAUSER can write. +The ROM and firmware currently time out on the TRNG interface after 250,000 +attempts to read a DONE bit. This bit is set in the architectural registers, as +referenced in 3 in the preceding list. + # SRAM implementation ## Overview @@ -514,7 +513,7 @@ Table 4 indicates the signals contained in the memory interface. Direction is re The following figure shows the SRAM interface timing. -*Figure 7: SRAM interface timing* +*Figure 6: SRAM interface timing* ![](./images/Caliptra_SRAM_interface_timing.png) @@ -543,7 +542,7 @@ This example is applicable to scenarios where an integrator may need control of Note that the example assumes that data and ECC codes are in non-deterministic bit-position in the exposed SRAM interface bus. Accordingly, redundant correction coding is shown in the integrator level logic (i.e., integrator\_ecc(calitpra\_data, caliptra\_ecc)). If the Caliptra data and ECC are deterministically separable at the Caliptra interface, the integrator would have discretion to store the ECC codes directly and calculate integrator ECC codes for the data alone. -*Figure 8: Example machine check reliability implementation* +*Figure 7: Example machine check reliability implementation* ![](./images/Caliptra_machine_reliability.png) @@ -593,7 +592,7 @@ Note that the example assumes that data and ECC codes are in non-deterministic b 2. SoC can look at the Caliptra fatal error register for error source. 3. Assume Caliptra can report a fatal error at any time. 4. Fatal errors are generally hardware in nature. SoC may attempt to recover by full reset of the entire SoC, or can move on and know that Caliptra will be unavailable for the remainder of the current boot. - 5. We cannot assume that uncorrectable errors will be correctly detected by Caliptra, ECC fatal errors shall be reported by SOC MCRIP. + 5. We cannot assume that uncorrectable errors will be correctly detected by Caliptra, ECC fatal errors shall be reported by SOC MCRIP. # SoC integration requirements @@ -603,26 +602,31 @@ The following table describes SoC integration requirements. | Category | Requirement | Definition of done | Rationale | | :--------- | :--------- | :--------- | :--------- | -| Deobfuscation Key | SoC backend flows shall generate deobfuscation key with appropriate NIST compliance as dictated in the Caliptra RoT specification. | Statement of conformance | Required by UDS and Field Entropy threat model | -| Deobfuscation Key | If not driven through PUF, SoC backend flows shall ECO the deobfuscation key before tapeout. | Statement of conformance | Required by UDS and Field Entropy threat model | -| Deobfuscation Key | Rotation of the deobfuscation key (if not driven through PUF) between silicon steppings of a given product (for example, A0 vs. B0 vs. PRQ stepping) is dependent on company-specific policies. | Statement of conformance | Required by UDS and Field Entropy threat model | -| Deobfuscation Key | SoC backend flows should not insert deobfuscation key flops into the scan chain. | Synthesis report | Required by UDS and Field Entropy threat model | -| Deobfuscation Key | For defense in depth, it is strongly recommended that debofuscation key flops are not on the scan chain.
Remove the following signals from the scan chain:
cptra_scan_mode_Latched_d
cptra_scan_mode_Latched_f
field_storage.internal_obf_key | Statement of conformance | Caliptra HW threat model | -| CSR Signing Key | SoC backend flows shall generate CSR signing key with appropriate NIST compliance as dictated in the Caliptra RoT specification. | Statement of conformance | Required by IDevID threat model | -| CSR Signing Key | Rotation of the CSR private key between silicon steppings of a given product (for example, A0 vs. B0 vs. PRQ stepping) is dependent on company-specific policies. | Statement of conformance | | -| CSR Signing Key | SoC backend flows should not insert CSR signing key flops into the scan chain. | Synthesis report | Required by IDevID threat model | +| Obfuscation Key | SoC backend flows shall generate obfuscation key with appropriate NIST compliance as dictated in the Caliptra RoT specification. | Statement of conformance | Required by UDS and Field Entropy threat model | +| Obfuscation Key | If not driven through PUF, SoC backend flows shall ECO the obfuscation key before tapeout. | Statement of conformance | Required by UDS and Field Entropy threat model | +| Obfuscation Key | Rotation of the obfuscation key (if not driven through PUF) between silicon steppings of a given product (for example, A0 vs. B0 vs. PRQ stepping) is dependent on company-specific policies. | Statement of conformance | Required by UDS and Field Entropy threat model | +| Obfuscation Key | SoC backend flows should not insert obfuscation key flops into the scan chain. | Synthesis report | Required by UDS and Field Entropy threat model | +| Obfuscation Key | For defense in depth, it is strongly recommended that debofuscation key flops are not on the scan chain.
Remove the following signals from the scan chain:
cptra_scan_mode_Latched_d
cptra_scan_mode_Latched_f
field_storage.internal_obf_key | Statement of conformance | Caliptra HW threat model | +| Obfuscation Key | SoC shall ensure that obfuscation key is available (and wires are stable) before Caliptra reset is de-asserted. | Statement of conformance | Functionality and security | +| Obfuscation Key | SoC shall implement protections for obfuscation key generation logic and protect against debug/sw/scandump visibility.
1. Any flops outside of Caliptra that store obfuscation key or parts of the key should be excluded from scandump.
2. SoC shall ensure that the obfuscation key is sent only to Caliptra through HW wires, and it is not visible anywhere outside of Caliptra. | Statement of conformance | Required for Caliptra threat model | | DFT | Before scan is enabled (separate signal that SoC implements on scan insertion), SoC shall set Caliptra's scan_mode indication to '1 to allow secrets/assets to be flushed. | Statement of conformance | Required by Caliptra threat model | | DFT | Caliptra’s TAP should be a TAP endpoint. | Statement of conformance | Functional requirement | | Mailbox | SoC shall provide an access path between the mailbox and the application CPU complex on SoCs with such complexes (for example, Host CPUs and Smart NICs). See the [Sender Protocol](#sender-protocol) section for details about error conditions. | Statement of conformance | Required for Project Kirkland and TDISP TSM | | Fuses | SoC shall burn non-field fuses during manufacturing. Required vs. optional fuses are listed in the architectural specification. | Test on silicon | Required for UDS threat model | | Fuses | SoC shall expose an interface for burning field fuses. Protection of this interface is the SoC vendor’s responsibility. | Test on silicon | Required for Field Entropy | | Fuses | SoC shall write fuse registers and fuse done via immutable logic or ROM code. | Statement of conformance | Required for Caliptra threat model | +| Fuses | SoC shall expose an API for programming Field Entropy as described in the architecture documentation. SoC shall ensure that Field Entropy can only be programmed via this API and shall explicitly prohibit burning of discrete Field Entropy bits and re-burning of already burned Field Entropy entries. | Test on silicon | Required for Field Entropy | +| Fuses | SoC shall ensure that any debug read paths for fuses are disabled in PRODUCTION lifecycle state.| Test on silicon | Required for Field Entropy | +| Fuses | SoC shall ensure that UDS_SEED and Field Entropy supplied to Caliptra come directly from OTP fuses and there are no debug paths to inject new values.| Statement of conformance | Required for Caliptra Threat model | +| Fuses | SoC shall add integrity checks for Caliptra fuses as per SoC policy. | Statement of conformance | Reliability | +| Fuses | SoC should apply shielding/obfuscation measures to protect fuse macro. | Statement of conformance | Required for Caliptra Threat model | +| Fuses | SoCs that intend to undergo FIPS 140-3 zeroization shall expose zeroization API as described in zeroization requirements in architecture specification. SoC shall apply appropriate authentication for this API to protect against denial of service and side channel attacks. | Test on silicon | FIPS 140-3 certification | | Security State | SoC shall drive security state wires in accordance with the SoC's security state. | Statement of conformance | Required for Caliptra threat model | | Security State | If SoC is under debug, then SoC shall drive debug security state to Caliptra. | Statement of conformance | Required for Caliptra threat model | | Resets and Clocks | SoC shall start input clock before caliptra_pwrgood assertion. | Statement of conformance | Functional | | Resets and Clocks | SoC reset logic shall assume reset assertions are asynchronous and deassertions are synchronous. | Statement of conformance | Functional | -| Resets and Clocks | SoC shall ensure Caliptra's powergood is the SoC's own powergood. | Statement of conformance | Required for Caliptra threat model | -| TRNG | SoC shall either provision Caliptra with a dedicated TRNG or shared TRNG. | Statement of conformance | Required for Caliptra threat model and Functional | +| Resets and Clocks | SoC shall ensure Caliptra's powergood is tied to SoC’s own powergood or any other reset that triggers SoC’s cold boot flow. | Statement of conformance | Required for Caliptra threat model | +| TRNG | SoC shall either provision Caliptra with a dedicated TRNG or shared TRNG. It is highly recommended to use dedicated ITRNG | Statement of conformance | Required for Caliptra threat model and Functional | | TRNG | SoC shall provision the Caliptra embedded TRNG with an entropy source if that is used (vs. SoC-shared TRNG API support). | Statement of conformance | Functional | | TRNG | If the TRNG is shared, then upon TRNG_REQ, SoC shall use immutable logic or code to program Caliptra's TRNG registers. | Statement of conformance | Required for Caliptra threat model and Functional | | SRAMs | SoC shall ensure timing convergence with 1-cycle read path for SRAMs. | Synthesis report | Functional | @@ -630,7 +634,7 @@ The following table describes SoC integration requirements. | SRAMs | SoC shall write-protect fuses that characterize the SRAM. | Statement of conformance | Required for Caliptra threat model | | SRAMs | SoC shall ensure SRAM content is only destroyed on powergood cycling. | Statement of conformance | Functional (Warm Reset, Hitless Update) | | SRAMs | SoC shall only perform SRAM repair on powergood events and prior to caliptra_rst_b deassertion. | Statement of conformance | Functional (Warm Reset, Hitless Update) | -| Backend convergence | Caliptra is validated and backend converged at 400MHz and at process nodes - TSMC 5nm, -- \ | | Functional | +| Backend convergence | Caliptra supports frequencies up to 400MHz using an industry standard, moderately advanced technology node as of 2023 September. | | Functional | | Power saving | Caliptra clock gating shall be controlled by Caliptra firmware alone. SoC is provided a global clock gating enable signal (and a register) to control. | | Required for Caliptra threat model | | Power saving | SoC shall not power-gate Caliptra independently of the entire SoC. | Statement of conformance | Required for Caliptra threat model | | PAUSER | SoC shall drive PAUSER input in accordance with the IP integration spec. | Statement of conformance | ? | @@ -649,6 +653,39 @@ The following table describes SoC integration requirements. | FUSE PAUSER programming rules | 1 PAUSER attribute register is implemented at SoC interface: CPTRA_FUSE_VALID_PAUSER. | | | | FUSE PAUSER programming rules | CPTRA_FUSE_PAUSER_LOCK locks the programmable valid pauser register, and marks the programmed value as valid. | | | | FUSE PAUSER programming rules | Integrators can choose to harden the valid pauser for fuse access by setting the integration parameter, CPTRA_FUSE_VALID_PAUSER, to the desired value in RTL, and by setting CPTRA_SET_FUSE_PAUSER_INTEG to 1. | | | +| Manufacturing | SoC shall provision an IDevID certificate with fields that conform to the requirements described in [Provisioning IDevID during manufacturing](https://github.com/chipsalliance/Caliptra/blob/main/doc/Caliptra.md#provisioning-idevid-during-manufacturing). | Statement of conformance | Functionality | +| Manufacturing | Caliptra relies on obfuscation for confidentiality of UDS_SEED. It is strongly advised to implement manufacturing policies to protect UDS_SEED as defense in depth measures.
1, Prevent leakage of UDS_SEED on manufacturing floor.
2. Implement policies to prevent cloning (programming same UDS_SEED into multiple devices).
3. Implement policies to prevent signing of spurious IDEVID certs. | Statement of conformance | Required for Caliptra Threat model | +| Chain of trust | SoC shall ensure all mutable code and configuration measurements are stashed into Caliptra. A statement of conformance lists what is considered mutable code and configuration vs. what is not. The statement also describes the start of the boot sequence of the SoC and how Caliptra is incorporated into it. | Statement of conformance | Required for Caliptra Threat model | +| Chain of trust | SoC shall limit the mutable code and configuration that persists across the Caliptra powergood reset. A statement of conformance lists what persists and why this persistence is necessary. | Statement of conformance | Required for Caliptra Threat model | +| Implementation | SoC shall apply size-only constraints on cells tagged with the "u__size_only__" string and shall ensure that these are not optimized in synthesis and PNR | Statement of conformance | Required for Caliptra Threat model | +| GLS FEV | GLS FEV must be run to make sure netlist and RTL match and none of the countermeasures are optimized away. See the following table for example warnings from synthesis runs to resolve through FEV | GLS simulations pass | Functional requirement | + +*Table 18: Caliptra synthesis warnings for FEV evaluation* + +| Module | Warning | Line No. | Description | +| :--------- | :--------- | :--------- | :--------- | +| sha512_acc_top | Empty netlist for always_comb | 417 |Unused logic (no load)| +| ecc_scalar_blinding | Netlist for always_ff block does not contain flip flop | 301 |Output width is smaller than internal signals, synthesis optimizes away the extra internal flops with no loads| +| sha512_masked_core | "masked_carry" is read before being assigned. Synthesized result may not match simulation | 295, 312 || +| ecc_montgomerymultiplier | Netlist for always_ff block does not contain flip flop | 274, 326 |Output width is smaller than internal signals, synthesis optimizes away the extra internal flops with no loads| +| Multiple modules | Signed to unsigned conversion occurs | || + +## Integrator RTL modification requirements + +Several files contain code that may be specific to an integrator's implementation and should be overridden. This overridable code is either configuration parameters with integrator-specific values or modules that implement process-specific functionality. Code in these files should be modified or replaced by integrators using components from the cell library of their fabrication vendor. The following table describes recommended modifications for each file. + +*Table 19: Caliptra integrator custom RTL file list* + +| File | Description | +| :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------- | +| [config_defines.svh](../src/integration/rtl/config_defines.svh) | Enable Caliptra internal TRNG (if applicable).
Declare name of custom clock gate module by defining USER_ICG.
Enable custom clock gate by defining TECH_SPECIFIC_ICG. | +| [soc_ifc_pkg.sv](../src/soc_ifc/rtl/soc_ifc_pkg.sv) | Define PAUSER default behavior and (if applicable) override values. See [Integration Parameters](#integration-parameters). | +| [caliptra_icg.sv](../src/libs/rtl/caliptra_icg.sv) | Replace with technology-specific clock gater.
Modifying this file is not necessary if integrators override the clock gate module that is used by setting TECH_SPECIFIC_ICG. | +| [beh_lib.sv](../src/riscv_core/veer_el2/rtl/lib/beh_lib.sv) | Replace rvclkhdr/rvoclkhdr with technology-specific clock gater.
Modifying this file may not be necessary if integrators override the clock gate module that is used by setting TECH_SPECIFIC_EC_RV_ICG. | +| [caliptra_prim_flop_2sync.sv](../src/caliptra_prim/rtl/caliptra_prim_flop_2sync.sv) | Replace with technology-specific sync cell. | +| [caliptra_2ff_sync.sv](../src/libs/rtl/caliptra_2ff_sync.sv) | Replace with technology-specific sync cell. | +| [dmi_jtag_to_core_sync.v](../src/riscv_core/veer_el2/rtl/dmi/dmi_jtag_to_core_sync.v) | Replace with technology-specific sync cell. | + # CDC analysis and constraints @@ -664,7 +701,7 @@ In an unconstrained environment, several CDC violations are anticipated. CDC ana The following code snippet and schematic diagram illustrate JTAG originating CDC violations. -*Figure 9: Schematic diagram and code snippet showing JTAG-originating CDC violations* +*Figure 8: Schematic diagram and code snippet showing JTAG-originating CDC violations* ![](./images/Caliptra_CDC_JTAG_code_snippet.png) @@ -679,6 +716,7 @@ The following code snippet and schematic diagram illustrate JTAG originating CDC * Pseudo-static: wr\_data, wr\_addr * cdc signal reg\_wr\_data -module dmi\_wrapper -stable * cdc signal reg\_wr\_addr -module dmi\_wrapper -stable +* The core clock frequency must be at least twice the TCK clock frequency for the JTAG data to pass correctly through the synchronizers. ## CDC constraints * cdc report scheme two\_dff -severity violation @@ -688,9 +726,11 @@ The following code snippet and schematic diagram illustrate JTAG originating CDC # Synthesis findings Synthesis experiments have so far found the following: -* Design converges at 400MHz 0.72V using a cutting edge TSMC process. +* Design converges at 400MHz 0.72V using an industry standard, moderately advanced technology node as of 2023 September. * Design converges at 100MHz using TSMC 40nm process. +Note: Any synthesis warnings of logic optimization must be reviewed and accounted for. + # Netlist synthesis data The following table illustrates representative netlist synthesis results using industry standard EDA synthesis tools and tool configurations. @@ -701,7 +741,7 @@ The area is expressed in units of square microns. The target foundry technology node is an industry standard, moderately advanced technology node as of 2023 September. -*Table 18: Netlist synthesis data* +*Table 20: Netlist synthesis data* | **IP Name** | **Date** | **Path Group** | **Target Freq** | **QoR WNS** | **QoR Achieveable Freq** | | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- | @@ -716,11 +756,7 @@ The target foundry technology node is an industry standard, moderately advanced | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- | | CALIPTRA_WRAPPER | 10/4/2023 | 89279 | 7872 | 239937 | 337088 | 45601 | 31 | SUCCEEDED | 156211 | 0 | 0 | 0 | -# LINT rules - -TODO 0p5: This is a WIP list - -## Recommended LINT rules +# Recommended LINT rules The following LINT rules are the recommended minimum set for standalone analysis of Caliptra IP. The same set is recommended as a minimum subset that may be applied by Caliptra integrators. @@ -868,7 +904,7 @@ Fatal: The 'default' or 'others' must be last case in a case statement The following terminology is used in this document. -*Table 19: Terminology* +*Table 21: Terminology* | Abbreviation | Description | diff --git a/docs/Caliptra_Hardware_Specification.pdf b/docs/Caliptra_Hardware_Specification.pdf deleted file mode 100755 index 68f46575c..000000000 Binary files a/docs/Caliptra_Hardware_Specification.pdf and /dev/null differ diff --git a/docs/images/1_bit.png b/docs/images/1_bit.png new file mode 100644 index 000000000..507c29c74 Binary files /dev/null and b/docs/images/1_bit.png differ diff --git a/docs/images/CONFIGOPTS.png b/docs/images/CONFIGOPTS.png new file mode 100644 index 000000000..51757698a Binary files /dev/null and b/docs/images/CONFIGOPTS.png differ diff --git a/docs/images/CSRNG_block.png b/docs/images/CSRNG_block.png new file mode 100644 index 000000000..38eda90c0 Binary files /dev/null and b/docs/images/CSRNG_block.png differ diff --git a/docs/images/Caliptra_eq_CLKDIV.png b/docs/images/Caliptra_eq_CLKDIV.png new file mode 100644 index 000000000..275ece4b5 Binary files /dev/null and b/docs/images/Caliptra_eq_CLKDIV.png differ diff --git a/docs/images/Caliptra_eq_NCO.png b/docs/images/Caliptra_eq_NCO.png new file mode 100644 index 000000000..601d4ad3d Binary files /dev/null and b/docs/images/Caliptra_eq_NCO.png differ diff --git a/docs/images/Caliptra_eq_SPI_clk_period.png b/docs/images/Caliptra_eq_SPI_clk_period.png new file mode 100644 index 000000000..c8b5b0b22 Binary files /dev/null and b/docs/images/Caliptra_eq_SPI_clk_period.png differ diff --git a/docs/images/Caliptra_eq_UART.png b/docs/images/Caliptra_eq_UART.png new file mode 100644 index 000000000..47277cc16 Binary files /dev/null and b/docs/images/Caliptra_eq_UART.png differ diff --git a/docs/images/Caliptra_eq_UART2.png b/docs/images/Caliptra_eq_UART2.png new file mode 100644 index 000000000..dd9dde5d2 Binary files /dev/null and b/docs/images/Caliptra_eq_UART2.png differ diff --git a/docs/images/ECDSA_arch.png b/docs/images/ECDSA_arch.png new file mode 100644 index 000000000..0c5d98087 Binary files /dev/null and b/docs/images/ECDSA_arch.png differ diff --git a/docs/images/ECDSA_ops.png b/docs/images/ECDSA_ops.png new file mode 100644 index 000000000..62a28b72b Binary files /dev/null and b/docs/images/ECDSA_ops.png differ diff --git a/docs/images/HMAC_DRBG_data.png b/docs/images/HMAC_DRBG_data.png new file mode 100644 index 000000000..b0c82ebbc Binary files /dev/null and b/docs/images/HMAC_DRBG_data.png differ diff --git a/docs/images/HMAC_DRBG_util.png b/docs/images/HMAC_DRBG_util.png new file mode 100644 index 000000000..c79bc11cd Binary files /dev/null and b/docs/images/HMAC_DRBG_util.png differ diff --git a/docs/images/HMAC_FSM.png b/docs/images/HMAC_FSM.png new file mode 100644 index 000000000..faf6132f2 Binary files /dev/null and b/docs/images/HMAC_FSM.png differ diff --git a/docs/images/HMAC_SHA_384_192.png b/docs/images/HMAC_SHA_384_192.png new file mode 100644 index 000000000..2838be494 Binary files /dev/null and b/docs/images/HMAC_SHA_384_192.png differ diff --git a/docs/images/HMAC_input.png b/docs/images/HMAC_input.png new file mode 100644 index 000000000..b71fec4b9 Binary files /dev/null and b/docs/images/HMAC_input.png differ diff --git a/docs/images/HMAC_pseudo.png b/docs/images/HMAC_pseudo.png new file mode 100644 index 000000000..f6c4fcde1 Binary files /dev/null and b/docs/images/HMAC_pseudo.png differ diff --git a/docs/images/HW_mbox_boot_fsm.png b/docs/images/HW_mbox_boot_fsm.png new file mode 100644 index 000000000..c6c5a197c Binary files /dev/null and b/docs/images/HW_mbox_boot_fsm.png differ diff --git a/docs/images/JTAG_implementation.png b/docs/images/JTAG_implementation.png new file mode 100644 index 000000000..5b09c7b1c Binary files /dev/null and b/docs/images/JTAG_implementation.png differ diff --git a/docs/images/QSPI_flash.png b/docs/images/QSPI_flash.png new file mode 100644 index 000000000..dc04f8413 Binary files /dev/null and b/docs/images/QSPI_flash.png differ diff --git a/docs/images/QSPI_segments.png b/docs/images/QSPI_segments.png new file mode 100644 index 000000000..bbe35ec73 Binary files /dev/null and b/docs/images/QSPI_segments.png differ diff --git a/docs/images/SHA256_fsm.png b/docs/images/SHA256_fsm.png new file mode 100644 index 000000000..a63a3875b Binary files /dev/null and b/docs/images/SHA256_fsm.png differ diff --git a/docs/images/SHA256_input.png b/docs/images/SHA256_input.png new file mode 100644 index 000000000..8892eb9a3 Binary files /dev/null and b/docs/images/SHA256_input.png differ diff --git a/docs/images/SHA256_pseudo.png b/docs/images/SHA256_pseudo.png new file mode 100644 index 000000000..6e1c5319d Binary files /dev/null and b/docs/images/SHA256_pseudo.png differ diff --git a/docs/images/SHA512_fsm.png b/docs/images/SHA512_fsm.png new file mode 100644 index 000000000..2e17e521e Binary files /dev/null and b/docs/images/SHA512_fsm.png differ diff --git a/docs/images/SHA512_input.png b/docs/images/SHA512_input.png new file mode 100644 index 000000000..fb6d5a4b8 Binary files /dev/null and b/docs/images/SHA512_input.png differ diff --git a/docs/images/SHA512_pseudo.png b/docs/images/SHA512_pseudo.png new file mode 100644 index 000000000..222393fd9 Binary files /dev/null and b/docs/images/SHA512_pseudo.png differ diff --git a/docs/images/SPI_read.png b/docs/images/SPI_read.png new file mode 100644 index 000000000..c49b063fa Binary files /dev/null and b/docs/images/SPI_read.png differ diff --git a/docs/images/TVLA_msg_dependent.png b/docs/images/TVLA_msg_dependent.png new file mode 100644 index 000000000..8bd9a0d06 Binary files /dev/null and b/docs/images/TVLA_msg_dependent.png differ diff --git a/docs/images/TVLA_privekey.png b/docs/images/TVLA_privekey.png new file mode 100644 index 000000000..c086af1ec Binary files /dev/null and b/docs/images/TVLA_privekey.png differ diff --git a/docs/images/TVLA_threshold.png b/docs/images/TVLA_threshold.png new file mode 100644 index 000000000..67e790878 Binary files /dev/null and b/docs/images/TVLA_threshold.png differ diff --git a/docs/images/UART_block.png b/docs/images/UART_block.png new file mode 100644 index 000000000..0ef1ce02a Binary files /dev/null and b/docs/images/UART_block.png differ diff --git a/docs/images/WDT.png b/docs/images/WDT.png new file mode 100644 index 000000000..d678c0934 Binary files /dev/null and b/docs/images/WDT.png differ diff --git a/docs/images/caliptra_top_signals.png b/docs/images/caliptra_top_signals.png new file mode 100644 index 000000000..973047122 Binary files /dev/null and b/docs/images/caliptra_top_signals.png differ diff --git a/docs/images/clock_gating_timing.png b/docs/images/clock_gating_timing.png new file mode 100644 index 000000000..53e8f169c Binary files /dev/null and b/docs/images/clock_gating_timing.png differ diff --git a/docs/images/crypto_subsystem.png b/docs/images/crypto_subsystem.png new file mode 100755 index 000000000..da8db7d78 Binary files /dev/null and b/docs/images/crypto_subsystem.png differ diff --git a/docs/images/entropy_source_block.png b/docs/images/entropy_source_block.png new file mode 100644 index 000000000..adc3af8d3 Binary files /dev/null and b/docs/images/entropy_source_block.png differ diff --git a/docs/images/entropy_source_signals.png b/docs/images/entropy_source_signals.png new file mode 100644 index 000000000..bfbae4a0e Binary files /dev/null and b/docs/images/entropy_source_signals.png differ diff --git a/docs/images/integrated_TRNG.png b/docs/images/integrated_TRNG.png new file mode 100644 index 000000000..67b285471 Binary files /dev/null and b/docs/images/integrated_TRNG.png differ diff --git a/docs/images/keygen_pseudo.png b/docs/images/keygen_pseudo.png new file mode 100644 index 000000000..7d9eb56d9 Binary files /dev/null and b/docs/images/keygen_pseudo.png differ diff --git a/docs/images/mbox_boot_fsm_FW_update_reset.png b/docs/images/mbox_boot_fsm_FW_update_reset.png new file mode 100644 index 000000000..b6b931139 Binary files /dev/null and b/docs/images/mbox_boot_fsm_FW_update_reset.png differ diff --git a/docs/images/msg_1023.png b/docs/images/msg_1023.png new file mode 100644 index 000000000..fd991d1ab Binary files /dev/null and b/docs/images/msg_1023.png differ diff --git a/docs/images/msg_multi_block.png b/docs/images/msg_multi_block.png new file mode 100644 index 000000000..9423d323b Binary files /dev/null and b/docs/images/msg_multi_block.png differ diff --git a/docs/images/secp384r1_params.png b/docs/images/secp384r1_params.png new file mode 100644 index 000000000..138db408f Binary files /dev/null and b/docs/images/secp384r1_params.png differ diff --git a/docs/images/serial_transmission.png b/docs/images/serial_transmission.png new file mode 100644 index 000000000..bf3a1ed36 Binary files /dev/null and b/docs/images/serial_transmission.png differ diff --git a/docs/images/signing_pseudo.png b/docs/images/signing_pseudo.png new file mode 100644 index 000000000..f5bcf0fbe Binary files /dev/null and b/docs/images/signing_pseudo.png differ diff --git a/docs/images/tvla_keygen.png b/docs/images/tvla_keygen.png new file mode 100644 index 000000000..169e39f4d Binary files /dev/null and b/docs/images/tvla_keygen.png differ diff --git a/docs/images/verify_pseudo.png b/docs/images/verify_pseudo.png new file mode 100644 index 000000000..ad4c48db8 Binary files /dev/null and b/docs/images/verify_pseudo.png differ diff --git a/src/ahb_lite_bus/config/compile.yml b/src/ahb_lite_bus/config/compile.yml index 2529a1177..e710a7c4d 100755 --- a/src/ahb_lite_bus/config/compile.yml +++ b/src/ahb_lite_bus/config/compile.yml @@ -15,5 +15,5 @@ targets: rtl_lint: directories: [] waiver_files: - - $COMPILE_ROOT/config/design_lint/ahb_lite_bus/sglint_waivers + - $MSFT_REPO_ROOT/src/ahb_lite_bus/config/design_lint/ahb_lite_bus/sglint_waivers diff --git a/src/caliptra_prim/config/caliptra_prim_pkg.vf b/src/caliptra_prim/config/caliptra_prim_pkg.vf index dfed9ddd5..f97774292 100644 --- a/src/caliptra_prim/config/caliptra_prim_pkg.vf +++ b/src/caliptra_prim/config/caliptra_prim_pkg.vf @@ -6,4 +6,3 @@ ${CALIPTRA_ROOT}/src/caliptra_prim/rtl/caliptra_prim_mubi_pkg.sv ${CALIPTRA_ROOT}/src/caliptra_prim/rtl/caliptra_prim_cipher_pkg.sv ${CALIPTRA_ROOT}/src/caliptra_prim/rtl/caliptra_prim_pkg.sv ${CALIPTRA_ROOT}/src/caliptra_prim/rtl/caliptra_prim_sparse_fsm_pkg.sv -${CALIPTRA_ROOT}/src/caliptra_prim/rtl/caliptra_prim_sparse_fsm_pkg.sv diff --git a/src/datavault/config/compile.yml b/src/datavault/config/compile.yml index 2691979d4..d15f1319f 100644 --- a/src/datavault/config/compile.yml +++ b/src/datavault/config/compile.yml @@ -36,7 +36,7 @@ targets: rtl_lint: directories: [] waiver_files: - - $COMPILE_ROOT/config/design_lint/datavault/sglint_waivers + - $MSFT_REPO_ROOT/src/datavault/config/design_lint/datavault/sglint_waivers black_box: - dv_reg global: diff --git a/src/doe/config/compile.yml b/src/doe/config/compile.yml index 39c70d8c4..c2556d00d 100755 --- a/src/doe/config/compile.yml +++ b/src/doe/config/compile.yml @@ -38,7 +38,7 @@ targets: rtl_lint: directories: [] waiver_files: - - $COMPILE_ROOT/config/design_lint/doe_ctrl/sglint_waivers + - $MSFT_REPO_ROOT/src/doe/config/design_lint/doe_ctrl/sglint_waivers black_box: - doe_reg --- diff --git a/src/doe/formal/properties/fv_constraints.sv b/src/doe/formal/properties/fv_constraints.sv new file mode 100644 index 000000000..b83fa4f52 --- /dev/null +++ b/src/doe/formal/properties/fv_constraints.sv @@ -0,0 +1,206 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +module fv_constraints_m( + + //////////////////////////// + // Input / Output signals // + //////////////////////////// + // Clock and reset. + input clk, + input reset_n, + + input encdec, + input init_cmd, + input next_cmd, + input ready, + input IV_updated, + input keylen, + input [255:0] key, + input [127:0] block_msg, + input [127:0] IV +); + +logic init_reg, iv_updated_reg, next_cmd_reg; +logic keyexp_start,keyexp_done; +logic iv_start, iv_done; + +//////////////////////// +// Default Clock // +//////////////////////// + +default clocking default_clk @(posedge clk); endclocking + + +//////////////////////// +// Helper Logic // +//////////////////////// + +//keyexpansion helper logic +always @ (posedge clk or negedge reset_n) + begin : key_expansion + if (!reset_n) begin + keyexp_start <= 1'b0; + keyexp_done <= 1'b0; + end + else if (init_cmd) begin + keyexp_start <= 1'b1; + keyexp_done <= 1'b0; + end + else if (keyexp_start && doe_core_cbc.key_ready) begin + keyexp_start <= 1'b0; + keyexp_done <= 1'b1; + end + else if (keyexp_done && init_cmd) begin + keyexp_start <= 1'b1; + keyexp_done <= 1'b0; + end + end + +//IV helper logic +always @ (posedge clk or negedge reset_n) + begin : iv_control + if (!reset_n) begin + iv_start <= 1'b0; + iv_done <= 1'b0; + end + else if (keyexp_done && IV_updated) begin + iv_start <= 1'b1; + iv_done <= 1'b0; + end + else if (iv_start && next_cmd) begin + iv_start <= 1'b0; + iv_done <= 1'b1; + end + else if (iv_done && init_cmd) begin + iv_start <= 1'b0; + iv_done <= 1'b0; + end + end + + +//////////////////////////////////// +// CBC Constraint Properties // +/////////////////////////////////// + +//init_cmd, next_cmd and IV_updated can be only received if the doe_core_cbc is ready +cmd_on_ready_a: assume property (disable iff(!reset_n) cmd_on_ready_p); +property cmd_on_ready_p; + !ready +|-> + !init_cmd && !next_cmd && !IV_updated +;endproperty + +//next_cmd can only be received once there is an IV_updated before +next_cmd_order_a: assume property (disable iff(!reset_n) next_cmd_order_p); +property next_cmd_order_p; + !iv_start +|=> + !next_cmd || iv_done +;endproperty + +//next_cmd can only be received once the keyexpansion is done +next_cmd_keyexp_order_a: assume property (disable iff(!reset_n) next_cmd_keyexp_order_p); +property next_cmd_keyexp_order_p; + !keyexp_done +|-> + !next_cmd +;endproperty + +//IV_updated can only be received once there is an IV_updated before +IV_updated_order_a: assume property (disable iff(!reset_n) IV_updated_order_p); +property IV_updated_order_p; + iv_done +|-> + !IV_updated +;endproperty + +//IV_updated is a pulse +iv_updated_pulse_a: assume property (disable iff(!reset_n) iv_updated_pulse_p); +property iv_updated_pulse_p; + IV_updated |=> !IV_updated +;endproperty + +//init_cmd and next_cmd doesn't come together +init_next_a: assume property (disable iff(!reset_n) init_next_p); +property init_next_p; + !(init_cmd && next_cmd) +;endproperty + +//init_cmd and IV_updated doesn't come together +init_iv_a: assume property (disable iff(!reset_n) init_iv_p); +property init_iv_p; + !(init_cmd && IV_updated) +;endproperty + +//IV_updated and next_cmd doesn't come together +next_iv_a: assume property (disable iff(!reset_n) next_iv_p); +property next_iv_p; + !(next_cmd && IV_updated) +;endproperty + +//keylen is stable until there is a new init_cmd +stable_keylen_a: assume property (disable iff(!reset_n) keylen_stable); +property keylen_stable; + $stable(keylen) || init_cmd +;endproperty + +//key is stable until there is a new init_cmd +key_stable_during_expansion_a: assume property (disable iff(!reset_n) key_stable_during_expansion); +property key_stable_during_expansion; + $stable(key) || init_cmd +;endproperty + +//encdec is stable until there is a new next_cmd +encdec_during_operation_a: assume property (disable iff(!reset_n) encdec_during_operation_p); +property encdec_during_operation_p; + $stable(encdec) || next_cmd +;endproperty + +//block message is stable until doe_core_cbc is ready +blkmsg_during_operation_a: assume property (disable iff(!reset_n) blkmsg_during_operation_p); +property blkmsg_during_operation_p; + $stable(block_msg) || ready +;endproperty + +//IV has stable until encrypted block_msg sent to enc_block +iv_during_operation_a: assume property (disable iff(!reset_n) iv_during_operation_p); +property iv_during_operation_p; + ready || !iv_done + |-> + $stable(IV) +;endproperty + +endmodule + +//Connect this constraints module with the DUV +bind doe_core_cbc fv_constraints_m fv_constraints( + .clk(clk), + .reset_n(reset_n && !zeroize), + .encdec(encdec), + .init_cmd(init_cmd), + .next_cmd(next_cmd), + .ready(ready), + .IV_updated(IV_updated), + .key(key), + .block_msg(block_msg), + .keylen(keylen), + .IV(IV) +); + diff --git a/src/doe/formal/properties/fv_cover_points.sv b/src/doe/formal/properties/fv_cover_points.sv new file mode 100644 index 000000000..192b5d0e2 --- /dev/null +++ b/src/doe/formal/properties/fv_cover_points.sv @@ -0,0 +1,91 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +module fv_coverpoints_m( + input logic clk, + input logic reset_n, + input logic zeroize +); + +default clocking default_clk @(posedge clk); endclocking + +//Cover zeroize +cover_zeroize: cover property(disable iff(!reset_n) doe_core_cbc.zeroize ); + +//Assert zeroize input and check the status of all registers. All registers/internal memories should be cleared. +cover_zeroize_after_next: cover property(disable iff(!reset_n ) doe_core_cbc.zeroize && doe_core_cbc.ready && doe_core_cbc.next_cmd ); + +//Cover that checks multiple next_cmd can be received for CBC encryption/decryption. +cover_multiple_next: cover property(disable iff(!reset_n || zeroize) + doe_core_cbc.next_cmd && doe_core_cbc.ready ##1 !doe_core_cbc.init_cmd && doe_core_cbc.next_cmd && doe_core_cbc.ready[->1] +); + +//Cover that checks IV_updated asserted once the keyexapnsion is done +cover_transition_keyexp_to_iv: cover property (disable iff(!reset_n || zeroize) + doe_core_cbc.init_cmd + ##1 + doe_core_cbc.ready[->1] + ##0 + doe_core_cbc.IV_updated[->1] +); + +//Cover transition from keyexpansion to encryption/decryption +cover_transition_keyexp_to_encdec: cover property (disable iff(!reset_n || zeroize) + doe_core_cbc.init_cmd + ##1 + doe_core_cbc.ready[->1] + ##0 + doe_core_cbc.next_cmd[->1] +); + +//Cover transition from keyexpansion to keyexpansion +cover_transition_keyexp_to_keyexp: cover property (disable iff(!reset_n || zeroize) + doe_core_cbc.init_cmd + ##1 + doe_core_cbc.ready[->1] + ##0 + doe_core_cbc.init_cmd[->1] +); + +//Cover transition from encryption/decryption to encryption/decryption +cover_transition_encdec_to_encdec: cover property (disable iff(!reset_n || zeroize) + doe_core_cbc.next_cmd + ##1 + doe_core_cbc.ready[->1] + ##0 + doe_core_cbc.next_cmd[->1] +); + +//Cover transition from encryption/decryption to keyexpansion +cover_transition_encdec_to_keyexp: cover property (disable iff(!reset_n || zeroize) + doe_core_cbc.next_cmd + ##1 + doe_core_cbc.ready[->1] + ##0 + doe_core_cbc.init_cmd[->1] +); + +endmodule + +//Connect this coverpoints module with the DUV +bind doe_core_cbc fv_coverpoints_m fv_coverpoints( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize) +); \ No newline at end of file diff --git a/src/doe/formal/properties/fv_doe_core_cbc.sv b/src/doe/formal/properties/fv_doe_core_cbc.sv new file mode 100644 index 000000000..bfbc562a1 --- /dev/null +++ b/src/doe/formal/properties/fv_doe_core_cbc.sv @@ -0,0 +1,161 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import doe_core_cbc_pkg::*; + +module fv_doe_cbc_checker_m( + + //////////////////////////// + // Input / Output signals // + //////////////////////////// + // Clock and reset. + input clk, + input reset_n, + input zeroize, + + input encdec, + input init_cmd, + input next_cmd, + input enc_ready, + input dec_ready, + input key_ready, + input [127:0] enc_new_block, + input [127:0] dec_new_block, + input [127:0] IV_decry, + input ready, + input [127:0] result, + input result_valid, + input [31 : 0] muxed_sboxw, + input [31 : 0] new_sboxw +); + +//////////////////////// +// Default Clock // +//////////////////////// +default clocking default_clk @(posedge clk); endclocking + +//Internal Signals +logic [31:0] fv_sbox; + +//Helper Logic +assign fv_sbox = get_sbox(muxed_sboxw); + +//////////////////////////////////// +// Core CBC Properties // +/////////////////////////////////// + +//Checks if doe_sbox block produces correct values +sbox_check_a: assert property (disable iff(!reset_n) sbox_check_p); +property sbox_check_p; + !ready +|-> + new_sboxw == fv_sbox +;endproperty + +//Checks if block asserts result_valid upon finishing encryption +result_valid_enc_a: assert property (disable iff(!reset_n) result_valid_enc_p); +property result_valid_enc_p; + encdec && + next_cmd + ##1 enc_ready[->1] +|=> + result_valid +;endproperty + +//Checks if block asserts result_valid upon finishing decryption +result_valid_dec_a: assert property (disable iff(!reset_n) result_valid_dec_p); +property result_valid_dec_p; + !encdec && + next_cmd + ##1 dec_ready[->1] +|=> + result_valid +;endproperty + +//Checks if block asserts ready upon finishing key expansion +ready_kemem_a: assert property (disable iff(!reset_n) ready_kemem_p); +property ready_kemem_p; + init_cmd + ##1 key_ready[->1] + |=> + ready +;endproperty + +//Checks if block asserts ready upon finishing encryption +ready_enc_a: assert property (disable iff(!reset_n) ready_enc_p); +property ready_enc_p; + encdec && + next_cmd + ##1 enc_ready[->1] +|=> + ready +;endproperty + +//Checks if block asserts ready upon finishing decryption +ready_dec_a: assert property (disable iff(!reset_n) ready_dec_p); +property ready_dec_p; + !encdec && + next_cmd + ##1 dec_ready[->1] +|=> + ready +;endproperty + +//Checks if block produces result upon finishing encryption +result_enc_a: assert property (disable iff(!reset_n) result_enc_p); +property result_enc_p; + encdec && + next_cmd + ##1 enc_ready[->1] +|-> + result == enc_new_block +;endproperty + +//Checks if block produces result upon finishing decryption +result_dec_a: assert property (disable iff(!reset_n) result_dec_p); +property result_dec_p; + !encdec && + next_cmd + ##1 dec_ready[->1] +|-> + result == dec_new_block +;endproperty + +endmodule + +//Connect this checker module with the DUV +bind doe_core_cbc fv_doe_cbc_checker_m fv_doe_cbc_inst( + .clk(clk), + .reset_n(reset_n && !zeroize), + .encdec(encdec), + .init_cmd(init_cmd), + .next_cmd(next_cmd), + .enc_ready(enc_ready), + .dec_ready(dec_ready), + .key_ready(key_ready), + .IV_decry(IV_decry), + .enc_new_block(enc_new_block), + .dec_new_block(dec_new_block ^ IV_decry), + .ready(ready), + .result(result), + .result_valid(result_valid), + .muxed_sboxw(muxed_sboxw), + .new_sboxw(new_sboxw) +); + diff --git a/src/doe/formal/properties/fv_doe_core_cbc_pkg.sv b/src/doe/formal/properties/fv_doe_core_cbc_pkg.sv new file mode 100644 index 000000000..4ffdddaed --- /dev/null +++ b/src/doe/formal/properties/fv_doe_core_cbc_pkg.sv @@ -0,0 +1,533 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package doe_core_cbc_pkg; + +// AES S-box +parameter [7:0] fv_sbox[0:255] = '{ + 8'h63, 8'h7C, 8'h77, 8'h7B, 8'hF2, 8'h6B, 8'h6F, 8'hC5, 8'h30, 8'h01, 8'h67, 8'h2B, 8'hFE, 8'hD7, 8'hAB, 8'h76, + 8'hCA, 8'h82, 8'hC9, 8'h7D, 8'hFA, 8'h59, 8'h47, 8'hF0, 8'hAD, 8'hD4, 8'hA2, 8'hAF, 8'h9C, 8'hA4, 8'h72, 8'hC0, + 8'hB7, 8'hFD, 8'h93, 8'h26, 8'h36, 8'h3F, 8'hF7, 8'hCC, 8'h34, 8'hA5, 8'hE5, 8'hF1, 8'h71, 8'hD8, 8'h31, 8'h15, + 8'h04, 8'hC7, 8'h23, 8'hC3, 8'h18, 8'h96, 8'h05, 8'h9A, 8'h07, 8'h12, 8'h80, 8'hE2, 8'hEB, 8'h27, 8'hB2, 8'h75, + 8'h09, 8'h83, 8'h2C, 8'h1A, 8'h1B, 8'h6E, 8'h5A, 8'hA0, 8'h52, 8'h3B, 8'hD6, 8'hB3, 8'h29, 8'hE3, 8'h2F, 8'h84, + 8'h53, 8'hD1, 8'h00, 8'hED, 8'h20, 8'hFC, 8'hB1, 8'h5B, 8'h6A, 8'hCB, 8'hBE, 8'h39, 8'h4A, 8'h4C, 8'h58, 8'hCF, + 8'hD0, 8'hEF, 8'hAA, 8'hFB, 8'h43, 8'h4D, 8'h33, 8'h85, 8'h45, 8'hF9, 8'h02, 8'h7F, 8'h50, 8'h3C, 8'h9F, 8'hA8, + 8'h51, 8'hA3, 8'h40, 8'h8F, 8'h92, 8'h9D, 8'h38, 8'hF5, 8'hBC, 8'hB6, 8'hDA, 8'h21, 8'h10, 8'hFF, 8'hF3, 8'hD2, + 8'hCD, 8'h0C, 8'h13, 8'hEC, 8'h5F, 8'h97, 8'h44, 8'h17, 8'hC4, 8'hA7, 8'h7E, 8'h3D, 8'h64, 8'h5D, 8'h19, 8'h73, + 8'h60, 8'h81, 8'h4F, 8'hDC, 8'h22, 8'h2A, 8'h90, 8'h88, 8'h46, 8'hEE, 8'hB8, 8'h14, 8'hDE, 8'h5E, 8'h0B, 8'hDB, + 8'hE0, 8'h32, 8'h3A, 8'h0A, 8'h49, 8'h06, 8'h24, 8'h5C, 8'hC2, 8'hD3, 8'hAC, 8'h62, 8'h91, 8'h95, 8'hE4, 8'h79, + 8'hE7, 8'hC8, 8'h37, 8'h6D, 8'h8D, 8'hD5, 8'h4E, 8'hA9, 8'h6C, 8'h56, 8'hF4, 8'hEA, 8'h65, 8'h7A, 8'hAE, 8'h08, + 8'hBA, 8'h78, 8'h25, 8'h2E, 8'h1C, 8'hA6, 8'hB4, 8'hC6, 8'hE8, 8'hDD, 8'h74, 8'h1F, 8'h4B, 8'hBD, 8'h8B, 8'h8A, + 8'h70, 8'h3E, 8'hB5, 8'h66, 8'h48, 8'h03, 8'hF6, 8'h0E, 8'h61, 8'h35, 8'h57, 8'hB9, 8'h86, 8'hC1, 8'h1D, 8'h9E, + 8'hE1, 8'hF8, 8'h98, 8'h11, 8'h69, 8'hD9, 8'h8E, 8'h94, 8'h9B, 8'h1E, 8'h87, 8'hE9, 8'hCE, 8'h55, 8'h28, 8'hDF, + 8'h8C, 8'hA1, 8'h89, 8'h0D, 8'hBF, 8'hE6, 8'h42, 8'h68, 8'h41, 8'h99, 8'h2D, 8'h0F, 8'hB0, 8'h54, 8'hBB, 8'h16 +}; + +// AES Inverse S-box +parameter [7:0] fv_inv_sbox[0:255] = '{ + 8'h52, 8'h09, 8'h6A, 8'hD5, 8'h30, 8'h36, 8'hA5, 8'h38, 8'hBF, 8'h40, 8'hA3, 8'h9E, 8'h81, 8'hF3, 8'hD7, 8'hFB, + 8'h7C, 8'hE3, 8'h39, 8'h82, 8'h9B, 8'h2F, 8'hFF, 8'h87, 8'h34, 8'h8E, 8'h43, 8'h44, 8'hC4, 8'hDE, 8'hE9, 8'hCB, + 8'h54, 8'h7B, 8'h94, 8'h32, 8'hA6, 8'hC2, 8'h23, 8'h3D, 8'hEE, 8'h4C, 8'h95, 8'h0B, 8'h42, 8'hFA, 8'hC3, 8'h4E, + 8'h08, 8'h2E, 8'hA1, 8'h66, 8'h28, 8'hD9, 8'h24, 8'hB2, 8'h76, 8'h5B, 8'hA2, 8'h49, 8'h6D, 8'h8B, 8'hD1, 8'h25, + 8'h72, 8'hF8, 8'hF6, 8'h64, 8'h86, 8'h68, 8'h98, 8'h16, 8'hD4, 8'hA4, 8'h5C, 8'hCC, 8'h5D, 8'h65, 8'hB6, 8'h92, + 8'h6C, 8'h70, 8'h48, 8'h50, 8'hFD, 8'hED, 8'hB9, 8'hDA, 8'h5E, 8'h15, 8'h46, 8'h57, 8'hA7, 8'h8D, 8'h9D, 8'h84, + 8'h90, 8'hD8, 8'hAB, 8'h00, 8'h8C, 8'hBC, 8'hD3, 8'h0A, 8'hF7, 8'hE4, 8'h58, 8'h05, 8'hB8, 8'hB3, 8'h45, 8'h06, + 8'hD0, 8'h2C, 8'h1E, 8'h8F, 8'hCA, 8'h3F, 8'h0F, 8'h02, 8'hC1, 8'hAF, 8'hBD, 8'h03, 8'h01, 8'h13, 8'h8A, 8'h6B, + 8'h3A, 8'h91, 8'h11, 8'h41, 8'h4F, 8'h67, 8'hDC, 8'hEA, 8'h97, 8'hF2, 8'hCF, 8'hCE, 8'hF0, 8'hB4, 8'hE6, 8'h73, + 8'h96, 8'hAC, 8'h74, 8'h22, 8'hE7, 8'hAD, 8'h35, 8'h85, 8'hE2, 8'hF9, 8'h37, 8'hE8, 8'h1C, 8'h75, 8'hDF, 8'h6E, + 8'h47, 8'hF1, 8'h1A, 8'h71, 8'h1D, 8'h29, 8'hC5, 8'h89, 8'h6F, 8'hB7, 8'h62, 8'h0E, 8'hAA, 8'h18, 8'hBE, 8'h1B, + 8'hFC, 8'h56, 8'h3E, 8'h4B, 8'hC6, 8'hD2, 8'h79, 8'h20, 8'h9A, 8'hDB, 8'hC0, 8'hFE, 8'h78, 8'hCD, 8'h5A, 8'hF4, + 8'h1F, 8'hDD, 8'hA8, 8'h33, 8'h88, 8'h07, 8'hC7, 8'h31, 8'hB1, 8'h12, 8'h10, 8'h59, 8'h27, 8'h80, 8'hEC, 8'h5F, + 8'h60, 8'h51, 8'h7F, 8'hA9, 8'h19, 8'hB5, 8'h4A, 8'h0D, 8'h2D, 8'hE5, 8'h7A, 8'h9F, 8'h93, 8'hC9, 8'h9C, 8'hEF, + 8'hA0, 8'hE0, 8'h3B, 8'h4D, 8'hAE, 8'h2A, 8'hF5, 8'hB0, 8'hC8, 8'hEB, 8'hBB, 8'h3C, 8'h83, 8'h53, 8'h99, 8'h61, + 8'h17, 8'h2B, 8'h04, 8'h7E, 8'hBA, 8'h77, 8'hD6, 8'h26, 8'hE1, 8'h69, 8'h14, 8'h63, 8'h55, 8'h21, 8'h0C, 8'h7D +}; + +// Rcon values for key schedule +parameter [31:0] fv_rcon[0:15] = '{ +32'h00000000, 32'h01000000, 32'h02000000, 32'h04000000, +32'h08000000, 32'h10000000, 32'h20000000, 32'h40000000, +32'h80000000, 32'h1B000000, 32'h36000000, 32'h6C000000, +32'hD8000000, 32'hAB000000, 32'h4D000000, 32'h9A000000 +}; + +// GF_2 for MixColumns +parameter [7:0] fv_gf2[0:255] = '{ + 8'h00, 8'h02, 8'h04, 8'h06, 8'h08, 8'h0A, 8'h0C, 8'h0E, 8'h10, 8'h12, 8'h14, 8'h16, 8'h18, 8'h1A, 8'h1C, 8'h1E, + 8'h20, 8'h22, 8'h24, 8'h26, 8'h28, 8'h2A, 8'h2C, 8'h2E, 8'h30, 8'h32, 8'h34, 8'h36, 8'h38, 8'h3A, 8'h3C, 8'h3E, + 8'h40, 8'h42, 8'h44, 8'h46, 8'h48, 8'h4a, 8'h4c, 8'h4e, 8'h50, 8'h52, 8'h54, 8'h56, 8'h58, 8'h5a, 8'h5c, 8'h5e, + 8'h60, 8'h62, 8'h64, 8'h66, 8'h68, 8'h6a, 8'h6c, 8'h6e, 8'h70, 8'h72, 8'h74, 8'h76, 8'h78, 8'h7a, 8'h7c, 8'h7e, + 8'h80, 8'h82, 8'h84, 8'h86, 8'h88, 8'h8a, 8'h8c, 8'h8e, 8'h90, 8'h92, 8'h94, 8'h96, 8'h98, 8'h9a, 8'h9c, 8'h9e, + 8'ha0, 8'ha2, 8'ha4, 8'ha6, 8'ha8, 8'haa, 8'hac, 8'hae, 8'hb0, 8'hb2, 8'hb4, 8'hb6, 8'hb8, 8'hba, 8'hbc, 8'hbe, + 8'hc0, 8'hc2, 8'hc4, 8'hc6, 8'hc8, 8'hca, 8'hcc, 8'hce, 8'hd0, 8'hd2, 8'hd4, 8'hd6, 8'hd8, 8'hda, 8'hdc, 8'hde, + 8'he0, 8'he2, 8'he4, 8'he6, 8'he8, 8'hea, 8'hec, 8'hee, 8'hf0, 8'hf2, 8'hf4, 8'hf6, 8'hf8, 8'hfa, 8'hfc, 8'hfe, + 8'h1b, 8'h19, 8'h1f, 8'h1d, 8'h13, 8'h11, 8'h17, 8'h15, 8'h0b, 8'h09, 8'h0f, 8'h0d, 8'h03, 8'h01, 8'h07, 8'h05, + 8'h3b, 8'h39, 8'h3f, 8'h3d, 8'h33, 8'h31, 8'h37, 8'h35, 8'h2b, 8'h29, 8'h2f, 8'h2d, 8'h23, 8'h21, 8'h27, 8'h25, + 8'h5b, 8'h59, 8'h5f, 8'h5d, 8'h53, 8'h51, 8'h57, 8'h55, 8'h4b, 8'h49, 8'h4f, 8'h4d, 8'h43, 8'h41, 8'h47, 8'h45, + 8'h7b, 8'h79, 8'h7f, 8'h7d, 8'h73, 8'h71, 8'h77, 8'h75, 8'h6b, 8'h69, 8'h6f, 8'h6d, 8'h63, 8'h61, 8'h67, 8'h65, + 8'h9b, 8'h99, 8'h9f, 8'h9d, 8'h93, 8'h91, 8'h97, 8'h95, 8'h8b, 8'h89, 8'h8f, 8'h8d, 8'h83, 8'h81, 8'h87, 8'h85, + 8'hbb, 8'hb9, 8'hbf, 8'hbd, 8'hb3, 8'hb1, 8'hb7, 8'hb5, 8'hab, 8'ha9, 8'haf, 8'had, 8'ha3, 8'ha1, 8'ha7, 8'ha5, + 8'hdb, 8'hd9, 8'hdf, 8'hdd, 8'hd3, 8'hd1, 8'hd7, 8'hd5, 8'hcb, 8'hc9, 8'hcf, 8'hcd, 8'hc3, 8'hc1, 8'hc7, 8'hc5, + 8'hfb, 8'hf9, 8'hff, 8'hfd, 8'hf3, 8'hf1, 8'hf7, 8'hf5, 8'heb, 8'he9, 8'hef, 8'hed, 8'he3, 8'he1, 8'he7, 8'he5 +}; + +// GF_3 for MixColumns +parameter [7:0] fv_gf3[0:255] = '{ + 8'h00, 8'h03, 8'h06, 8'h05, 8'h0C, 8'h0f, 8'h0A, 8'h09, 8'h18, 8'h1b, 8'h1E, 8'h1d, 8'h14, 8'h17, 8'h12, 8'h11, + 8'h30, 8'h33, 8'h36, 8'h35, 8'h3C, 8'h3f, 8'h3A, 8'h39, 8'h28, 8'h2b, 8'h2E, 8'h2d, 8'h24, 8'h27, 8'h22, 8'h21, + 8'h60, 8'h63, 8'h66, 8'h65, 8'h6c, 8'h6f, 8'h6a, 8'h69, 8'h78, 8'h7b, 8'h7e, 8'h7d, 8'h74, 8'h77, 8'h72, 8'h71, + 8'h50, 8'h53, 8'h56, 8'h55, 8'h5c, 8'h5f, 8'h5a, 8'h59, 8'h48, 8'h4b, 8'h4e, 8'h4d, 8'h44, 8'h47, 8'h42, 8'h41, + 8'hc0, 8'hc3, 8'hc6, 8'hc5, 8'hcc, 8'hcf, 8'hca, 8'hc9, 8'hd8, 8'hdb, 8'hde, 8'hdd, 8'hd4, 8'hd7, 8'hd2, 8'hd1, + 8'hf0, 8'hf3, 8'hf6, 8'hf5, 8'hfc, 8'hff, 8'hfa, 8'hf9, 8'he8, 8'heb, 8'hee, 8'hed, 8'he4, 8'he7, 8'he2, 8'he1, + 8'ha0, 8'ha3, 8'ha6, 8'ha5, 8'hac, 8'haf, 8'haa, 8'ha9, 8'hb8, 8'hbb, 8'hbe, 8'hbd, 8'hb4, 8'hb7, 8'hb2, 8'hb1, + 8'h90, 8'h93, 8'h96, 8'h95, 8'h9c, 8'h9f, 8'h9a, 8'h99, 8'h88, 8'h8b, 8'h8e, 8'h8d, 8'h84, 8'h87, 8'h82, 8'h81, + 8'h9b, 8'h98, 8'h9d, 8'h9e, 8'h97, 8'h94, 8'h91, 8'h92, 8'h83, 8'h80, 8'h85, 8'h86, 8'h8f, 8'h8c, 8'h89, 8'h8a, + 8'hab, 8'ha8, 8'had, 8'hae, 8'ha7, 8'ha4, 8'ha1, 8'ha2, 8'hb3, 8'hb0, 8'hb5, 8'hb6, 8'hbf, 8'hbc, 8'hb9, 8'hba, + 8'hfb, 8'hf8, 8'hfd, 8'hfe, 8'hf7, 8'hf4, 8'hf1, 8'hf2, 8'he3, 8'he0, 8'he5, 8'he6, 8'hef, 8'hec, 8'he9, 8'hea, + 8'hcb, 8'hc8, 8'hcd, 8'hce, 8'hc7, 8'hc4, 8'hc1, 8'hc2, 8'hd3, 8'hd0, 8'hd5, 8'hd6, 8'hdf, 8'hdc, 8'hd9, 8'hda, + 8'h5b, 8'h58, 8'h5d, 8'h5e, 8'h57, 8'h54, 8'h51, 8'h52, 8'h43, 8'h40, 8'h45, 8'h46, 8'h4f, 8'h4c, 8'h49, 8'h4a, + 8'h6b, 8'h68, 8'h6d, 8'h6e, 8'h67, 8'h64, 8'h61, 8'h62, 8'h73, 8'h70, 8'h75, 8'h76, 8'h7f, 8'h7c, 8'h79, 8'h7a, + 8'h3b, 8'h38, 8'h3d, 8'h3E, 8'h37, 8'h34, 8'h31, 8'h32, 8'h23, 8'h20, 8'h25, 8'h26, 8'h2f, 8'h2C, 8'h29, 8'h2A, + 8'h0b, 8'h08, 8'h0d, 8'h0E, 8'h07, 8'h04, 8'h01, 8'h02, 8'h13, 8'h10, 8'h15, 8'h16, 8'h1f, 8'h1C, 8'h19, 8'h1A +}; + +// GF_9 for MixColumns +parameter [7:0] fv_gf9[0:255] = '{ + 8'h00, 8'h09, 8'h12, 8'h1b, 8'h24, 8'h2d, 8'h36, 8'h3f, 8'h48, 8'h41, 8'h5a, 8'h53, 8'h6c, 8'h65, 8'h7e, 8'h77, + 8'h90, 8'h99, 8'h82, 8'h8b, 8'hb4, 8'hbd, 8'ha6, 8'haf, 8'hd8, 8'hd1, 8'hca, 8'hc3, 8'hfc, 8'hf5, 8'hee, 8'he7, + 8'h3b, 8'h32, 8'h29, 8'h20, 8'h1f, 8'h16, 8'h0d, 8'h04, 8'h73, 8'h7a, 8'h61, 8'h68, 8'h57, 8'h5e, 8'h45, 8'h4c, + 8'hab, 8'ha2, 8'hb9, 8'hb0, 8'h8f, 8'h86, 8'h9d, 8'h94, 8'he3, 8'hea, 8'hf1, 8'hf8, 8'hc7, 8'hce, 8'hd5, 8'hdc, + 8'h76, 8'h7f, 8'h64, 8'h6d, 8'h52, 8'h5b, 8'h40, 8'h49, 8'h3E, 8'h37, 8'h2C, 8'h25, 8'h1A, 8'h13, 8'h08, 8'h01, + 8'he6, 8'hef, 8'hf4, 8'hfd, 8'hc2, 8'hcb, 8'hd0, 8'hd9, 8'hae, 8'ha7, 8'hbc, 8'hb5, 8'h8a, 8'h83, 8'h98, 8'h91, + 8'h4d, 8'h44, 8'h5f, 8'h56, 8'h69, 8'h60, 8'h7b, 8'h72, 8'h05, 8'h0C, 8'h17, 8'h1E, 8'h21, 8'h28, 8'h33, 8'h3A, + 8'hdd, 8'hd4, 8'hcf, 8'hc6, 8'hf9, 8'hf0, 8'heb, 8'he2, 8'h95, 8'h9c, 8'h87, 8'h8e, 8'hb1, 8'hb8, 8'ha3, 8'haa, + 8'hec, 8'he5, 8'hfe, 8'hf7, 8'hc8, 8'hc1, 8'hda, 8'hd3, 8'ha4, 8'had, 8'hb6, 8'hbf, 8'h80, 8'h89, 8'h92, 8'h9b, + 8'h7c, 8'h75, 8'h6e, 8'h67, 8'h58, 8'h51, 8'h4a, 8'h43, 8'h34, 8'h3d, 8'h26, 8'h2f, 8'h10, 8'h19, 8'h02, 8'h0b, + 8'hd7, 8'hde, 8'hc5, 8'hcc, 8'hf3, 8'hfa, 8'he1, 8'he8, 8'h9f, 8'h96, 8'h8d, 8'h84, 8'hbb, 8'hb2, 8'ha9, 8'ha0, + 8'h47, 8'h4e, 8'h55, 8'h5c, 8'h63, 8'h6a, 8'h71, 8'h78, 8'h0f, 8'h06, 8'h1d, 8'h14, 8'h2b, 8'h22, 8'h39, 8'h30, + 8'h9a, 8'h93, 8'h88, 8'h81, 8'hbe, 8'hb7, 8'hac, 8'ha5, 8'hd2, 8'hdb, 8'hc0, 8'hc9, 8'hf6, 8'hff, 8'he4, 8'hed, + 8'h0A, 8'h03, 8'h18, 8'h11, 8'h2E, 8'h27, 8'h3C, 8'h35, 8'h42, 8'h4b, 8'h50, 8'h59, 8'h66, 8'h6f, 8'h74, 8'h7d, + 8'ha1, 8'ha8, 8'hb3, 8'hba, 8'h85, 8'h8c, 8'h97, 8'h9e, 8'he9, 8'he0, 8'hfb, 8'hf2, 8'hcd, 8'hc4, 8'hdf, 8'hd6, + 8'h31, 8'h38, 8'h23, 8'h2A, 8'h15, 8'h1C, 8'h07, 8'h0E, 8'h79, 8'h70, 8'h6b, 8'h62, 8'h5d, 8'h54, 8'h4f, 8'h46 +}; + +// GF_B for MixColumns +parameter [7:0] fv_gfB[0:255] = '{ + 8'h00, 8'h0b, 8'h16, 8'h1d, 8'h2C, 8'h27, 8'h3A, 8'h31, 8'h58, 8'h53, 8'h4e, 8'h45, 8'h74, 8'h7f, 8'h62, 8'h69, + 8'hb0, 8'hbb, 8'ha6, 8'had, 8'h9c, 8'h97, 8'h8a, 8'h81, 8'he8, 8'he3, 8'hfe, 8'hf5, 8'hc4, 8'hcf, 8'hd2, 8'hd9, + 8'h7b, 8'h70, 8'h6d, 8'h66, 8'h57, 8'h5c, 8'h41, 8'h4a, 8'h23, 8'h28, 8'h35, 8'h3E, 8'h0f, 8'h04, 8'h19, 8'h12, + 8'hcb, 8'hc0, 8'hdd, 8'hd6, 8'he7, 8'hec, 8'hf1, 8'hfa, 8'h93, 8'h98, 8'h85, 8'h8e, 8'hbf, 8'hb4, 8'ha9, 8'ha2, + 8'hf6, 8'hfd, 8'he0, 8'heb, 8'hda, 8'hd1, 8'hcc, 8'hc7, 8'hae, 8'ha5, 8'hb8, 8'hb3, 8'h82, 8'h89, 8'h94, 8'h9f, + 8'h46, 8'h4d, 8'h50, 8'h5b, 8'h6a, 8'h61, 8'h7c, 8'h77, 8'h1E, 8'h15, 8'h08, 8'h03, 8'h32, 8'h39, 8'h24, 8'h2f, + 8'h8d, 8'h86, 8'h9b, 8'h90, 8'ha1, 8'haa, 8'hb7, 8'hbc, 8'hd5, 8'hde, 8'hc3, 8'hc8, 8'hf9, 8'hf2, 8'hef, 8'he4, + 8'h3d, 8'h36, 8'h2b, 8'h20, 8'h11, 8'h1A, 8'h07, 8'h0C, 8'h65, 8'h6e, 8'h73, 8'h78, 8'h49, 8'h42, 8'h5f, 8'h54, + 8'hf7, 8'hfc, 8'he1, 8'hea, 8'hdb, 8'hd0, 8'hcd, 8'hc6, 8'haf, 8'ha4, 8'hb9, 8'hb2, 8'h83, 8'h88, 8'h95, 8'h9e, + 8'h47, 8'h4c, 8'h51, 8'h5a, 8'h6b, 8'h60, 8'h7d, 8'h76, 8'h1f, 8'h14, 8'h09, 8'h02, 8'h33, 8'h38, 8'h25, 8'h2E, + 8'h8c, 8'h87, 8'h9a, 8'h91, 8'ha0, 8'hab, 8'hb6, 8'hbd, 8'hd4, 8'hdf, 8'hc2, 8'hc9, 8'hf8, 8'hf3, 8'hee, 8'he5, + 8'h3C, 8'h37, 8'h2A, 8'h21, 8'h10, 8'h1b, 8'h06, 8'h0d, 8'h64, 8'h6f, 8'h72, 8'h79, 8'h48, 8'h43, 8'h5e, 8'h55, + 8'h01, 8'h0A, 8'h17, 8'h1C, 8'h2d, 8'h26, 8'h3b, 8'h30, 8'h59, 8'h52, 8'h4f, 8'h44, 8'h75, 8'h7e, 8'h63, 8'h68, + 8'hb1, 8'hba, 8'ha7, 8'hac, 8'h9d, 8'h96, 8'h8b, 8'h80, 8'he9, 8'he2, 8'hff, 8'hf4, 8'hc5, 8'hce, 8'hd3, 8'hd8, + 8'h7a, 8'h71, 8'h6c, 8'h67, 8'h56, 8'h5d, 8'h40, 8'h4b, 8'h22, 8'h29, 8'h34, 8'h3f, 8'h0E, 8'h05, 8'h18, 8'h13, + 8'hca, 8'hc1, 8'hdc, 8'hd7, 8'he6, 8'hed, 8'hf0, 8'hfb, 8'h92, 8'h99, 8'h84, 8'h8f, 8'hbe, 8'hb5, 8'ha8, 8'ha3 +}; + +// GF_D for MixColumns +parameter [7:0] fv_gfD[0:255] = '{ + 8'h00, 8'h0d, 8'h1A, 8'h17, 8'h34, 8'h39, 8'h2E, 8'h23, 8'h68, 8'h65, 8'h72, 8'h7f, 8'h5c, 8'h51, 8'h46, 8'h4b, + 8'hd0, 8'hdd, 8'hca, 8'hc7, 8'he4, 8'he9, 8'hfe, 8'hf3, 8'hb8, 8'hb5, 8'ha2, 8'haf, 8'h8c, 8'h81, 8'h96, 8'h9b, + 8'hbb, 8'hb6, 8'ha1, 8'hac, 8'h8f, 8'h82, 8'h95, 8'h98, 8'hd3, 8'hde, 8'hc9, 8'hc4, 8'he7, 8'hea, 8'hfd, 8'hf0, + 8'h6b, 8'h66, 8'h71, 8'h7c, 8'h5f, 8'h52, 8'h45, 8'h48, 8'h03, 8'h0E, 8'h19, 8'h14, 8'h37, 8'h3A, 8'h2d, 8'h20, + 8'h6d, 8'h60, 8'h77, 8'h7a, 8'h59, 8'h54, 8'h43, 8'h4e, 8'h05, 8'h08, 8'h1f, 8'h12, 8'h31, 8'h3C, 8'h2b, 8'h26, + 8'hbd, 8'hb0, 8'ha7, 8'haa, 8'h89, 8'h84, 8'h93, 8'h9e, 8'hd5, 8'hd8, 8'hcf, 8'hc2, 8'he1, 8'hec, 8'hfb, 8'hf6, + 8'hd6, 8'hdb, 8'hcc, 8'hc1, 8'he2, 8'hef, 8'hf8, 8'hf5, 8'hbe, 8'hb3, 8'ha4, 8'ha9, 8'h8a, 8'h87, 8'h90, 8'h9d, + 8'h06, 8'h0b, 8'h1C, 8'h11, 8'h32, 8'h3f, 8'h28, 8'h25, 8'h6e, 8'h63, 8'h74, 8'h79, 8'h5a, 8'h57, 8'h40, 8'h4d, + 8'hda, 8'hd7, 8'hc0, 8'hcd, 8'hee, 8'he3, 8'hf4, 8'hf9, 8'hb2, 8'hbf, 8'ha8, 8'ha5, 8'h86, 8'h8b, 8'h9c, 8'h91, + 8'h0A, 8'h07, 8'h10, 8'h1d, 8'h3E, 8'h33, 8'h24, 8'h29, 8'h62, 8'h6f, 8'h78, 8'h75, 8'h56, 8'h5b, 8'h4c, 8'h41, + 8'h61, 8'h6c, 8'h7b, 8'h76, 8'h55, 8'h58, 8'h4f, 8'h42, 8'h09, 8'h04, 8'h13, 8'h1E, 8'h3d, 8'h30, 8'h27, 8'h2A, + 8'hb1, 8'hbc, 8'hab, 8'ha6, 8'h85, 8'h88, 8'h9f, 8'h92, 8'hd9, 8'hd4, 8'hc3, 8'hce, 8'hed, 8'he0, 8'hf7, 8'hfa, + 8'hb7, 8'hba, 8'had, 8'ha0, 8'h83, 8'h8e, 8'h99, 8'h94, 8'hdf, 8'hd2, 8'hc5, 8'hc8, 8'heb, 8'he6, 8'hf1, 8'hfc, + 8'h67, 8'h6a, 8'h7d, 8'h70, 8'h53, 8'h5e, 8'h49, 8'h44, 8'h0f, 8'h02, 8'h15, 8'h18, 8'h3b, 8'h36, 8'h21, 8'h2C, + 8'h0C, 8'h01, 8'h16, 8'h1b, 8'h38, 8'h35, 8'h22, 8'h2f, 8'h64, 8'h69, 8'h7e, 8'h73, 8'h50, 8'h5d, 8'h4a, 8'h47, + 8'hdc, 8'hd1, 8'hc6, 8'hcb, 8'he8, 8'he5, 8'hf2, 8'hff, 8'hb4, 8'hb9, 8'hae, 8'ha3, 8'h80, 8'h8d, 8'h9a, 8'h97 +}; + +// GF_E for MixColumns +parameter [7:0] fv_gfE[0:255] = '{ + 8'h00, 8'h0E, 8'h1C, 8'h12, 8'h38, 8'h36, 8'h24, 8'h2A, 8'h70, 8'h7e, 8'h6c, 8'h62, 8'h48, 8'h46, 8'h54, 8'h5a, + 8'he0, 8'hee, 8'hfc, 8'hf2, 8'hd8, 8'hd6, 8'hc4, 8'hca, 8'h90, 8'h9e, 8'h8c, 8'h82, 8'ha8, 8'ha6, 8'hb4, 8'hba, + 8'hdb, 8'hd5, 8'hc7, 8'hc9, 8'he3, 8'hed, 8'hff, 8'hf1, 8'hab, 8'ha5, 8'hb7, 8'hb9, 8'h93, 8'h9d, 8'h8f, 8'h81, + 8'h3b, 8'h35, 8'h27, 8'h29, 8'h03, 8'h0d, 8'h1f, 8'h11, 8'h4b, 8'h45, 8'h57, 8'h59, 8'h73, 8'h7d, 8'h6f, 8'h61, + 8'had, 8'ha3, 8'hb1, 8'hbf, 8'h95, 8'h9b, 8'h89, 8'h87, 8'hdd, 8'hd3, 8'hc1, 8'hcf, 8'he5, 8'heb, 8'hf9, 8'hf7, + 8'h4d, 8'h43, 8'h51, 8'h5f, 8'h75, 8'h7b, 8'h69, 8'h67, 8'h3d, 8'h33, 8'h21, 8'h2f, 8'h05, 8'h0b, 8'h19, 8'h17, + 8'h76, 8'h78, 8'h6a, 8'h64, 8'h4e, 8'h40, 8'h52, 8'h5c, 8'h06, 8'h08, 8'h1A, 8'h14, 8'h3E, 8'h30, 8'h22, 8'h2C, + 8'h96, 8'h98, 8'h8a, 8'h84, 8'hae, 8'ha0, 8'hb2, 8'hbc, 8'he6, 8'he8, 8'hfa, 8'hf4, 8'hde, 8'hd0, 8'hc2, 8'hcc, + 8'h41, 8'h4f, 8'h5d, 8'h53, 8'h79, 8'h77, 8'h65, 8'h6b, 8'h31, 8'h3f, 8'h2d, 8'h23, 8'h09, 8'h07, 8'h15, 8'h1b, + 8'ha1, 8'haf, 8'hbd, 8'hb3, 8'h99, 8'h97, 8'h85, 8'h8b, 8'hd1, 8'hdf, 8'hcd, 8'hc3, 8'he9, 8'he7, 8'hf5, 8'hfb, + 8'h9a, 8'h94, 8'h86, 8'h88, 8'ha2, 8'hac, 8'hbe, 8'hb0, 8'hea, 8'he4, 8'hf6, 8'hf8, 8'hd2, 8'hdc, 8'hce, 8'hc0, + 8'h7a, 8'h74, 8'h66, 8'h68, 8'h42, 8'h4c, 8'h5e, 8'h50, 8'h0A, 8'h04, 8'h16, 8'h18, 8'h32, 8'h3C, 8'h2E, 8'h20, + 8'hec, 8'he2, 8'hf0, 8'hfe, 8'hd4, 8'hda, 8'hc8, 8'hc6, 8'h9c, 8'h92, 8'h80, 8'h8e, 8'ha4, 8'haa, 8'hb8, 8'hb6, + 8'h0C, 8'h02, 8'h10, 8'h1E, 8'h34, 8'h3A, 8'h28, 8'h26, 8'h7c, 8'h72, 8'h60, 8'h6e, 8'h44, 8'h4a, 8'h58, 8'h56, + 8'h37, 8'h39, 8'h2b, 8'h25, 8'h0f, 8'h01, 8'h13, 8'h1d, 8'h47, 8'h49, 8'h5b, 8'h55, 8'h7f, 8'h71, 8'h63, 8'h6d, + 8'hd7, 8'hd9, 8'hcb, 8'hc5, 8'hef, 8'he1, 8'hf3, 8'hfd, 8'ha7, 8'ha9, 8'hbb, 8'hb5, 8'h9f, 8'h91, 8'h83, 8'h8d +}; + +//Get SBOX value of a word +function logic[31:0] get_sbox(input logic [31:0] index_word); + logic [7:0] int_byte[0:3]; + logic [31:0] sbox_value; + + for (int i = 0; i < 4; i++) + int_byte[3-i] = fv_sbox[index_word[i*8 +: 8]]; + + sbox_value = {int_byte[0],int_byte[1],int_byte[2],int_byte[3]}; + + return sbox_value; +endfunction + +//Get Inverse SBOX value of a word +function logic[31:0] get_invsbox(input logic [31:0] index_word); + logic [7:0] int_byte[0:3]; + logic [31:0] invsbox_value; + + for (int i = 0; i < 4; i++) + int_byte[3-i] = fv_inv_sbox[index_word[i*8 +: 8]]; + + invsbox_value = {int_byte[0],int_byte[1],int_byte[2],int_byte[3]}; + + return invsbox_value; +endfunction + +//Rotation of a word +function logic[31:0] get_rotate_word(input logic [31:0] index_word); + logic [31:0] rotate_word; + rotate_word = {index_word[23:0], index_word[31:24]}; + return rotate_word; +endfunction + +//Get Rcon value +function logic[31:0] get_rcon(input logic [3:0] index); + return fv_rcon[index]; +endfunction + +//Compute Keyexpansion for 128bit configuration +function logic [127 : 0] compute_key_expansion_128(input logic [127 : 0] fv_key_int, input logic [3 : 0] fv_round_int); + logic [31:0] temp; + logic [31:0] w[0:43]; + logic [127:0] fv_round_key[0:10]; + + // The first four words are the original key + for (int i = 0; i < 4; i++) + w[3-i] = fv_key_int[i*32 +: 32]; + + // Compute all words of roundkeys - total of 44 words for 11 keys + for (int i = 4; i < 44; i++) begin + temp = w[i-1]; + if (i % 4 == 0) begin + temp = get_rotate_word(temp); + temp = get_sbox(temp); + temp = temp ^ get_rcon(i/4); + end + w[i] = w[i-4] ^ temp; + end + + //Assign the round keys + for (int i = 0; i < 11; i++) + fv_round_key[i] = {w[i*4], w[i*4+1], w[i*4+2], w[i*4+3]}; + + return fv_round_key[fv_round_int]; +endfunction + +//Compute Keyexpansion for 256bit configuration +function logic [127 : 0] compute_key_expansion_256(input logic [255 : 0] fv_key_int, input logic [3 : 0] fv_round_int); + logic [31:0] temp; + logic [31:0] w[0:59]; + logic [127:0] fv_round_key[0:14]; + + // The first eight words are the original key + for (int i = 0; i < 8; i++) + w[7-i] = fv_key_int[i*32 +: 32]; + + // Compute all words of roundkeys - total of 60 words for 15 keys + for (int i = 8; i < 60; i++) begin + temp = w[i-1]; + if (i % 8 == 0) begin + temp = get_rotate_word(temp); + temp = get_sbox(temp); + temp = temp ^ get_rcon(i/8); + w[i] = w[i-8] ^ temp; + end + else if ((i - (i/8)*8) == 4) begin + temp = get_sbox(temp); + w[i] = w[i-8] ^ temp; + end + else begin + w[i] = w[i-8] ^ w[i-1]; + end + end + + //Assign the round keys + for (int i = 0; i < 15; i++) + fv_round_key[i] = {w[i*4], w[i*4+1], w[i*4+2], w[i*4+3]}; + + return fv_round_key[fv_round_int]; +endfunction + + +//Compute MixColumns of the word +function logic[31:0] compute_mixcolums(input logic [31:0] index_word); + logic [7:0] int_byte[0:3]; + logic [7:0] mixcolumn_byte[0:3]; + logic [31:0] mixcolumn_value; + + for (int i = 0; i < 4; i++) + int_byte[3-i] = index_word[i*8 +: 8]; + + mixcolumn_byte[0] = fv_gf2[int_byte[0]] ^ fv_gf3[int_byte[1]] ^ int_byte[2] ^ int_byte[3]; + mixcolumn_byte[1] = int_byte[0] ^ fv_gf2[int_byte[1]] ^ fv_gf3[int_byte[2]] ^ int_byte[3]; + mixcolumn_byte[2] = int_byte[0] ^ int_byte[1] ^ fv_gf2[int_byte[2]] ^ fv_gf3[int_byte[3]]; + mixcolumn_byte[3] = fv_gf3[int_byte[0]] ^ int_byte[1] ^ int_byte[2] ^ fv_gf2[int_byte[3]]; + + mixcolumn_value = {mixcolumn_byte[0],mixcolumn_byte[1],mixcolumn_byte[2],mixcolumn_byte[3]}; + + return mixcolumn_value; +endfunction + +//Compute Inverse MixColumns of the word +function logic[31:0] compute_invmixcolums(input logic [31:0] index_word); + logic [7:0] int_byte[0:3]; + logic [7:0] invmixcolumn_byte[0:3]; + logic [31:0] invmixcolumn_value; + + for (int i = 0; i < 4; i++) + int_byte[3-i] = index_word[i*8 +: 8]; + + invmixcolumn_byte[0] = fv_gfE[int_byte[0]] ^ fv_gfB[int_byte[1]] ^ fv_gfD[int_byte[2]] ^ fv_gf9[int_byte[3]]; + invmixcolumn_byte[1] = fv_gf9[int_byte[0]] ^ fv_gfE[int_byte[1]] ^ fv_gfB[int_byte[2]] ^ fv_gfD[int_byte[3]]; + invmixcolumn_byte[2] = fv_gfD[int_byte[0]] ^ fv_gf9[int_byte[1]] ^ fv_gfE[int_byte[2]] ^ fv_gfB[int_byte[3]]; + invmixcolumn_byte[3] = fv_gfB[int_byte[0]] ^ fv_gfD[int_byte[1]] ^ fv_gf9[int_byte[2]] ^ fv_gfE[int_byte[3]]; + + invmixcolumn_value = {invmixcolumn_byte[0],invmixcolumn_byte[1],invmixcolumn_byte[2],invmixcolumn_byte[3]}; + + return invmixcolumn_value; +endfunction + +//Compute MixColumns of the msg +function logic[127:0] compute_mixcolums_msg(input logic [127:0] index_msg); + logic [31:0] int_word[0:3], mix_word[0:3]; + logic [127:0] mixcolumn_msg; + + for (int i = 0; i < 4; i++) + int_word[3-i] = index_msg[i*32 +: 32]; + + //Column 0 + mix_word[0] = compute_mixcolums(int_word[0]); + + //Column 1 + mix_word[1] = compute_mixcolums(int_word[1]); + + //Column 2 + mix_word[2] = compute_mixcolums(int_word[2]); + + //Column 3 + mix_word[3] = compute_mixcolums(int_word[3]); + + mixcolumn_msg = {mix_word[0],mix_word[1],mix_word[2],mix_word[3]}; + + return mixcolumn_msg; +endfunction + +//Compute Inverse MixColumns of the msg +function logic[127:0] compute_invmixcolums_msg(input logic [127:0] index_msg); + logic [31:0] int_word[0:3], invmix_word[0:3]; + logic [127:0] invmixcolumn_msg; + + for (int i = 0; i < 4; i++) + int_word[3-i] = index_msg[i*32 +: 32]; + + //Column 0 + invmix_word[0] = compute_invmixcolums(int_word[0]); + + //Column 1 + invmix_word[1] = compute_invmixcolums(int_word[1]); + + //Column 2 + invmix_word[2] = compute_invmixcolums(int_word[2]); + + //Column 3 + invmix_word[3] = compute_invmixcolums(int_word[3]); + + invmixcolumn_msg = {invmix_word[0],invmix_word[1],invmix_word[2],invmix_word[3]}; + + return invmixcolumn_msg; +endfunction + +//Compute AddRoundKey of index_msg with the key +function logic[127:0] compute_add_round_key(input logic [127:0] index_msg, input logic [127:0] index_key); + return (index_msg ^ index_key); +endfunction + +//Compute Shift row1 +function logic [31 : 0] compute_shiftrow1(input logic [31 : 0] index_word); + logic [7:0] int_byte[0:3]; + logic [31:0] shift_word; + + for (int i = 0; i < 4; i++) + int_byte[3-i] = index_word[i*8 +: 8]; + + shift_word = {int_byte[1],int_byte[2],int_byte[3],int_byte[0]}; + + return shift_word; +endfunction + +//Compute Inverse Shift row1 +function logic [31 : 0] compute_invshiftrow1(input logic [31 : 0] index_word); + logic [7:0] int_byte[0:3]; + logic [31:0] invshift_word; + + for (int i = 0; i < 4; i++) + int_byte[3-i] = index_word[i*8 +: 8]; + + invshift_word = {int_byte[3],int_byte[0],int_byte[1],int_byte[2]}; + + return invshift_word; +endfunction + +//Compute Shift row2 +function logic [31 : 0] compute_shiftrow2(input logic [31 : 0] index_word); + logic [7:0] int_byte[0:3]; + logic [31:0] shift_word; + + for (int i = 0; i < 4; i++) + int_byte[3-i] = index_word[i*8 +: 8]; + + shift_word = {int_byte[2],int_byte[3],int_byte[0],int_byte[1]}; + + return shift_word; +endfunction + +//Compute Inverse Shift row2 +function logic [31 : 0] compute_invshiftrow2(input logic [31 : 0] index_word); + logic [7:0] int_byte[0:3]; + logic [31:0] invshift_word; + + for (int i = 0; i < 4; i++) + int_byte[3-i] = index_word[i*8 +: 8]; + + invshift_word = {int_byte[2],int_byte[3],int_byte[0],int_byte[1]}; + + return invshift_word; +endfunction + +//Compute Shift row3 +function logic [31 : 0] compute_shiftrow3(input logic [31 : 0] index_word); + logic [7:0] int_byte[0:3]; + logic [31:0] shift_word; + + for (int i = 0; i < 4; i++) + int_byte[3-i] = index_word[i*8 +: 8]; + + shift_word = {int_byte[3],int_byte[0],int_byte[1],int_byte[2]}; + + return shift_word; +endfunction + +//Compute Inverse Shift row3 +function logic [31 : 0] compute_invshiftrow3(input logic [31 : 0] index_word); + logic [7:0] int_byte[0:3]; + logic [31:0] invshift_word; + + for (int i = 0; i < 4; i++) + int_byte[3-i] = index_word[i*8 +: 8]; + + invshift_word = {int_byte[1],int_byte[2],int_byte[3],int_byte[0]}; + + return invshift_word; +endfunction + +//Compute Shift rows +function logic [127 : 0] compute_shiftrow(input logic [127 : 0] index_msg); + logic [31:0] int_word[0:3]; + logic [31:0] shift_word[0:3]; + logic [127:0] shift_msg; + + for (int i = 0; i < 4; i++) + int_word[3-i] = index_msg[i*32 +: 32]; + + //Row 0 + shift_word[0] = {int_word[0][31:24],int_word[1][31:24],int_word[2][31:24],int_word[3][31:24]}; + + //Row 1 + shift_word[1] = {int_word[0][23:16],int_word[1][23:16],int_word[2][23:16],int_word[3][23:16]}; + shift_word[1] = compute_shiftrow1(shift_word[1]); + + //Row 2 + shift_word[2] = {int_word[0][15:8],int_word[1][15:8],int_word[2][15:8],int_word[3][15:8]}; + shift_word[2] = compute_shiftrow2(shift_word[2]); + + //Row 3 + shift_word[3] = {int_word[0][7:0],int_word[1][7:0],int_word[2][7:0],int_word[3][7:0]}; + shift_word[3] = compute_shiftrow3(shift_word[3]); + + //sent as a updated msg + int_word[0] = {shift_word[0][31:24],shift_word[1][31:24],shift_word[2][31:24],shift_word[3][31:24]}; + int_word[1] = {shift_word[0][23:16],shift_word[1][23:16],shift_word[2][23:16],shift_word[3][23:16]}; + int_word[2] = {shift_word[0][15:8],shift_word[1][15:8],shift_word[2][15:8],shift_word[3][15:8]}; + int_word[3] = {shift_word[0][7:0],shift_word[1][7:0],shift_word[2][7:0],shift_word[3][7:0]}; + + shift_msg = {int_word[0],int_word[1],int_word[2],int_word[3]}; + + return shift_msg; +endfunction + +//Compute Inverse Shift rows +function logic [127 : 0] compute_invshiftrow(input logic [127 : 0] index_msg); + logic [31:0] int_word[0:3]; + logic [31:0] invshift_word[0:3]; + logic [127:0] invshift_msg; + + for (int i = 0; i < 4; i++) + int_word[3-i] = index_msg[i*32 +: 32]; + + //Row 0 + invshift_word[0] = {int_word[0][31:24],int_word[1][31:24],int_word[2][31:24],int_word[3][31:24]}; + + //Row 1 + invshift_word[1] = {int_word[0][23:16],int_word[1][23:16],int_word[2][23:16],int_word[3][23:16]}; + invshift_word[1] = compute_invshiftrow1(invshift_word[1]); + + //Row 2 + invshift_word[2] = {int_word[0][15:8],int_word[1][15:8],int_word[2][15:8],int_word[3][15:8]}; + invshift_word[2] = compute_invshiftrow2(invshift_word[2]); + + //Row 3 + invshift_word[3] = {int_word[0][7:0],int_word[1][7:0],int_word[2][7:0],int_word[3][7:0]}; + invshift_word[3] = compute_invshiftrow3(invshift_word[3]); + + //sent as a updated msg + int_word[0] = {invshift_word[0][31:24],invshift_word[1][31:24],invshift_word[2][31:24],invshift_word[3][31:24]}; + int_word[1] = {invshift_word[0][23:16],invshift_word[1][23:16],invshift_word[2][23:16],invshift_word[3][23:16]}; + int_word[2] = {invshift_word[0][15:8],invshift_word[1][15:8],invshift_word[2][15:8],invshift_word[3][15:8]}; + int_word[3] = {invshift_word[0][7:0],invshift_word[1][7:0],invshift_word[2][7:0],invshift_word[3][7:0]}; + + invshift_msg = {int_word[0],int_word[1],int_word[2],int_word[3]}; + + return invshift_msg; +endfunction + +endpackage diff --git a/src/doe/formal/properties/fv_doe_decryption/fv_constraints.sv b/src/doe/formal/properties/fv_doe_decryption/fv_constraints.sv new file mode 100644 index 000000000..6a8c3fedb --- /dev/null +++ b/src/doe/formal/properties/fv_doe_decryption/fv_constraints.sv @@ -0,0 +1,118 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import doe_core_cbc_pkg::*; + +module fv_dec_constraints_m( + + //////////////////////////// + // Input / Output signals // + //////////////////////////// + input clk, + input reset_n, + + input next_cmd, + + input keylen, + input [3 : 0] round, + input [127 : 0] round_key, + + input [127 : 0] block_msg, + input [127 : 0] new_block, + input ready + +); + +//////////////////////// +// Default Clock // +//////////////////////// +default clocking default_clk @(posedge clk); endclocking + +//Internal Signals +logic [127:0] fv_round_key; +logic [127:0] fv_round_key_array[14:0]; + +//////////////////////// +// Symbolic logic // +//////////////////////// + +sym_roundkey_a: assume property (disable iff(!reset_n) sym_roundkey_p); +property sym_roundkey_p; + ##1 $stable(fv_round_key_array) +;endproperty + + +//Get expanded round keys for input key +function logic[127:0] get_roundkey(input logic [3:0] index_round); + logic [127:0] int_key; + + int_key = fv_round_key_array[index_round]; + + return int_key; +endfunction + +//Helper Logic +assign fv_round_key = get_roundkey(round); + +//////////////////////////////////////// +// Decryption Constraint Properties // +//////////////////////////////////////// + +//Constraint to drive correct value to round_key input +roundkey_constraint_a: assume property (disable iff(!reset_n) roundkey_constraint_p); +property roundkey_constraint_p; + round_key == fv_round_key +;endproperty + +//Constraint to keep keylen input stable +stable_keylen_a: assume property (disable iff(!reset_n) stable_keylen_p); +property stable_keylen_p; + $stable(keylen) || ready +;endproperty + +//Constraint to keep incoming block message stable +stable_blk_msg_a: assume property (disable iff(!reset_n) stable_blk_msg_p); +property stable_blk_msg_p; + $stable(block_msg) || ready +;endproperty + +//next_cmd can be only received if the doe_decipher_block is ready +cmd_on_ready_a: assume property (disable iff(!reset_n) cmd_on_ready_p); +property cmd_on_ready_p; + !ready +|-> + !next_cmd; +endproperty + +`ifdef CBC_BIND + //Constraint to drive correct value to fv_round_key_array signal in fv_decrypt checker + roundkey_array_cbc_a: assume property (disable iff(!reset_n) roundkey_array_cbc_p); + property roundkey_array_cbc_p; + doe_core_cbc.dec_block.fv_decrypt.fv_round_key_array == fv_round_key_array + ;endproperty +`endif + +endmodule + +//Connect this constraints module with the DUV +bind doe_decipher_block fv_dec_constraints_m fv_dec_constraints(.*, + .clk(clk), + .reset_n(reset_n && !zeroize) + ); + diff --git a/src/doe/formal/properties/fv_doe_decryption/fv_cover_points.sv b/src/doe/formal/properties/fv_doe_decryption/fv_cover_points.sv new file mode 100644 index 000000000..94e37ac97 --- /dev/null +++ b/src/doe/formal/properties/fv_doe_decryption/fv_cover_points.sv @@ -0,0 +1,46 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +module fv_dec_coverpoints_m( + input logic clk, + input logic reset_n, + input logic zeroize +); + +default clocking default_clk @(posedge clk); endclocking + +//Cover zeroize +cover_zeroize: cover property(disable iff(!reset_n) doe_decipher_block.zeroize ); + +//Assert zeroize input and check the status of all registers. All registers/internal memories should be cleared. +cover_zeroize_after_next: cover property(disable iff(!reset_n) doe_decipher_block.zeroize && doe_decipher_block.ready && doe_decipher_block.next_cmd ); + +//Cover that checks multiple next_cmd can be received for decipher block. +cover_multiple_next: cover property(disable iff(!reset_n || zeroize) + doe_decipher_block.next_cmd && doe_decipher_block.ready ##1 doe_decipher_block.next_cmd && doe_decipher_block.ready[->1] +); + +endmodule + +//Connect this coverpoints module with the DUV +bind doe_decipher_block fv_dec_coverpoints_m fv_dec_coverpoints( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize) +); \ No newline at end of file diff --git a/src/doe/formal/properties/fv_doe_decryption/fv_doe_decrypt.sv b/src/doe/formal/properties/fv_doe_decryption/fv_doe_decrypt.sv new file mode 100644 index 000000000..5f1f75c80 --- /dev/null +++ b/src/doe/formal/properties/fv_doe_decryption/fv_doe_decrypt.sv @@ -0,0 +1,397 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import doe_core_cbc_pkg::*; + +module fv_decrypt_checker_m ( + + //////////////////////////// + // Input / Output signals // + //////////////////////////// + input clk, + input reset_n, + + input next_cmd, + + input keylen, + input [3 : 0] round, + input [127 : 0] round_key, + + input [127 : 0] block_msg, + input [127 : 0] new_block, + input ready, + + ////////////////////// + // States // + ////////////////////// + + input IDLE, + input Round_Compute, + + ////////////////////// + // Internal Signals // + ////////////////////// + input [127 : 0] block_new, + input [127 : 0] old_block, + + + //Signal for expanded keys + input [127 : 0] fv_round_key_array[14:0] + +); + +//localparams - Respective delays +localparam DLY_128 = 52; //no. of cycles the decryption takes for 128B configuration +localparam DLY_256 = 72; //no. of cycles the decryption takes for 256B configuration +localparam DLY_RND = 5; //no. of cycles the round computation takes +localparam DLY_SBOX = 4; //no. of cycles the SBOX computation takes + +//Compute first round intermediate step value for both 128/256 bit configuration +function logic [127 : 0] compute_firstdecrypt(input logic [127 : 0] index_msg, input logic mode); + logic [127:0] int_msg; + logic [31:0] int_word[0:3]; + + int_msg = index_msg; + + //Initial Step + if(mode) int_msg = compute_add_round_key(int_msg, fv_round_key_array[14]); + else int_msg = compute_add_round_key(int_msg, fv_round_key_array[10]); + + int_msg = compute_invshiftrow(int_msg); + + return int_msg; +endfunction + +//Compute Intermediate steps in each round +function logic [127 : 0] compute_round_decrypt(input logic [127 : 0] index_msg, input logic [3:0] int_rnd); + logic [127:0] int_msg; + logic [31:0] int_word[0:3]; + + int_msg = index_msg; + + //Round encryption + for (int i = 0; i < 4; i++) + int_word[3-i] = int_msg[i*32 +: 32]; + + for (int i = 0; i < 4; i++) + int_word[i] = get_invsbox(int_word[i]); + + int_msg = {int_word[0],int_word[1],int_word[2],int_word[3]}; + + int_msg = compute_add_round_key(int_msg, fv_round_key_array[int_rnd-1]); + + int_msg = compute_invmixcolums_msg(int_msg); + + int_msg = compute_invshiftrow(int_msg); + + return int_msg; +endfunction + +//Compute Intermediate step value in last round for both 128/256 bit configuration +function logic [127 : 0] compute_lastround_decrypt(input logic [127 : 0] index_msg); + logic [127:0] int_msg; + logic [31:0] int_word[0:3]; + + int_msg = index_msg; + + //Round encryption + for (int i = 0; i < 4; i++) + int_word[3-i] = int_msg[i*32 +: 32]; + + for (int i = 0; i < 4; i++) + int_word[i] = get_invsbox(int_word[i]); + + int_msg = {int_word[0],int_word[1],int_word[2],int_word[3]}; + + int_msg = compute_add_round_key(int_msg, fv_round_key_array[0]); + + return int_msg; +endfunction + +//Compute AES_Decryption for 128 bit configuration +function logic [127 : 0] compute_aes_decryption_128(input logic [127 : 0] index_msg); + logic [127:0] int_msg; + logic [31:0] int_word[0:3]; + + int_msg = index_msg; + + //Initial Step + int_msg = compute_add_round_key(int_msg, fv_round_key_array[10]); + + int_msg = compute_invshiftrow(int_msg); + + //Round encryption + for (int rnd = 9; rnd > 0; rnd--) begin + + //Round decryption + for (int i = 0; i < 4; i++) + int_word[3-i] = int_msg[i*32 +: 32]; + + for (int i = 0; i < 4; i++) + int_word[i] = get_invsbox(int_word[i]); + + int_msg = {int_word[0],int_word[1],int_word[2],int_word[3]}; + + int_msg = compute_add_round_key(int_msg, fv_round_key_array[rnd]); + + int_msg = compute_invmixcolums_msg(int_msg); + + int_msg = compute_invshiftrow(int_msg); + end + + //Final Round + for (int i = 0; i < 4; i++) + int_word[3-i] = int_msg[i*32 +: 32]; + + for (int i = 0; i < 4; i++) + int_word[i] = get_invsbox(int_word[i]); + + int_msg = {int_word[0],int_word[1],int_word[2],int_word[3]}; + + int_msg = compute_add_round_key(int_msg, fv_round_key_array[0]); + + return int_msg; +endfunction + +//Compute AES_Decryption for 256 bit configuration +function logic [127 : 0] compute_aes_decryption_256(input logic [127 : 0] index_msg); + logic [127:0] int_msg; + logic [31:0] int_word[0:3]; + + int_msg = index_msg; + + //Initial Step + int_msg = compute_add_round_key(int_msg, fv_round_key_array[14]); + + int_msg = compute_invshiftrow(int_msg); + + //Round encryption + for (int rnd = 13; rnd > 0; rnd--) begin + + //Round encryption + for (int i = 0; i < 4; i++) + int_word[3-i] = int_msg[i*32 +: 32]; + + for (int i = 0; i < 4; i++) + int_word[i] = get_invsbox(int_word[i]); + + int_msg = {int_word[0],int_word[1],int_word[2],int_word[3]}; + + int_msg = compute_add_round_key(int_msg, fv_round_key_array[rnd]); + + int_msg = compute_invmixcolums_msg(int_msg); + + int_msg = compute_invshiftrow(int_msg); + end + + //Final Round + for (int i = 0; i < 4; i++) + int_word[3-i] = int_msg[i*32 +: 32]; + + for (int i = 0; i < 4; i++) + int_word[i] = get_invsbox(int_word[i]); + + int_msg = {int_word[0],int_word[1],int_word[2],int_word[3]}; + + int_msg = compute_add_round_key(int_msg, fv_round_key_array[0]); + + return int_msg; +endfunction + +//////////////////////// +// Default Clock // +//////////////////////// +default clocking default_clk @(posedge clk); endclocking + +//////////////////////////////////// +// Decryption Checker Properties // +/////////////////////////////////// + +// Checks if the design is in IDLE state and ready is low +reset_a: assert property (reset_p); +property reset_p; + $past(!reset_n) +|-> + IDLE && + ready == 1 +;endproperty + +// Checks if block produces correct 128 bit decrypted value +decryption_check_128_a: assert property (disable iff(!reset_n) decryption_check_128_p); +property decryption_check_128_p; + logic [127:0] result, tracked_blk_msg; + + ##0 next_cmd + ##0 !keylen + ##0 (1'b1, tracked_blk_msg = block_msg) + ##DLY_128 (1'b1, result = compute_aes_decryption_128(tracked_blk_msg)) +|-> + ##0 new_block == result + ##0 ready +;endproperty + +// Checks if block produces correct sequence of round outputs for 128 bit configuration +round_check_128_a: assert property (disable iff(!reset_n) round_check_128_p); +property round_check_128_p; + ##0 next_cmd + ##0 !keylen +|-> + ##1 round == 10 && !ready[*DLY_RND] + ##1 round == 9 && !ready[*DLY_RND] + ##1 round == 8 && !ready[*DLY_RND] + ##1 round == 7 && !ready[*DLY_RND] + ##1 round == 6 && !ready[*DLY_RND] + ##1 round == 5 && !ready[*DLY_RND] + ##1 round == 4 && !ready[*DLY_RND] + ##1 round == 3 && !ready[*DLY_RND] + ##1 round == 2 && !ready[*DLY_RND] + ##1 round == 1 && !ready[*DLY_RND] + ##1 round == 0 && !ready + ##1 ready +;endproperty + +// Checks if block produces correct 256 bit decrypted value +decryption_check_256_a: assert property (disable iff(!reset_n) decryption_check_256_p); +property decryption_check_256_p; + logic [127:0] result, tracked_blk_msg; + + ##0 next_cmd + ##0 keylen + ##0 (1'b1, tracked_blk_msg = block_msg) + ##DLY_256 (1'b1, result = compute_aes_decryption_256(tracked_blk_msg)) +|-> + ##0 new_block == result + ##0 ready +;endproperty + +// Checks if block produces correct sequence of round outputs for 256 bit configuration +round_check_256_a: assert property (disable iff(!reset_n) round_check_256_p); +property round_check_256_p; + ##0 next_cmd + ##0 keylen +|-> + ##1 round == 14 && !ready[*DLY_RND] + ##1 round == 13 && !ready[*DLY_RND] + ##1 round == 12 && !ready[*DLY_RND] + ##1 round == 11 && !ready[*DLY_RND] + ##1 round == 10 && !ready[*DLY_RND] + ##1 round == 9 && !ready[*DLY_RND] + ##1 round == 8 && !ready[*DLY_RND] + ##1 round == 7 && !ready[*DLY_RND] + ##1 round == 6 && !ready[*DLY_RND] + ##1 round == 5 && !ready[*DLY_RND] + ##1 round == 4 && !ready[*DLY_RND] + ##1 round == 3 && !ready[*DLY_RND] + ##1 round == 2 && !ready[*DLY_RND] + ##1 round == 1 && !ready[*DLY_RND] + ##1 round == 0 && !ready + ##1 ready +;endproperty + +// Checks if block produces correct encrypted value for the first round +firstround_decrypt_a: assert property (disable iff(!reset_n) firstround_decrypt_p); +property firstround_decrypt_p; + logic [127:0] result, tracked_blk_msg, tracked_mode; + + ##0 next_cmd + ##0 (1'b1, tracked_blk_msg = block_msg) + ##0 (1'b1, tracked_mode = keylen) + ##0 (1'b1, result = compute_firstdecrypt(tracked_blk_msg,tracked_mode)) +|-> + ##1 block_new == result +;endproperty + +// Checks if block produces correct round encrypted value for each round in 128 bit configuration +for (genvar rnd = 9; rnd > 0; rnd--) begin: rndcompute_128 + round_compute_128_a: assert property (disable iff(!reset_n) round_compute_128_p(rnd+1)); +end +property round_compute_128_p(rndcnt); + logic [127:0] rnd_rslt, tracked_block; + ##0 Round_Compute && !keylen + ##0 round == rndcnt + ##1 (1'b1, tracked_block = old_block) + ##0 (1'b1, rnd_rslt = compute_round_decrypt(tracked_block,rndcnt)) +|-> + ##DLY_SBOX block_new == rnd_rslt +;endproperty + +// Checks if block produces correct round encrypted value for each round in 256 bit configuration +for (genvar rnd = 13; rnd > 0; rnd--) begin: rndcompute_256 + round_compute_256_a: assert property (disable iff(!reset_n) round_compute_256_p(rnd+1)); +end +property round_compute_256_p(rndcnt); + logic [127:0] rnd_rslt, tracked_block; + ##0 Round_Compute && keylen + ##0 round == rndcnt + ##1 (1'b1, tracked_block = old_block) + ##0 (1'b1, rnd_rslt = compute_round_decrypt(tracked_block,rndcnt)) +|-> + ##DLY_SBOX block_new == rnd_rslt +;endproperty + +// Checks if block produces correct encrypted value for the first round +lastround_decrypt_a: assert property (disable iff(!reset_n) lastround_decrypt_p); +property lastround_decrypt_p; + logic [127:0] rnd_rslt, tracked_block; + ##0 Round_Compute + ##0 round == 4'h1 + ##1 (1'b1, tracked_block = old_block) + ##0 (1'b1, rnd_rslt = compute_lastround_decrypt(tracked_block)) +|-> + ##DLY_SBOX block_new == rnd_rslt +;endproperty + +endmodule + +//Inputs driven from doe_core_cbc +`ifdef CBC_BIND + + bind doe_decipher_block fv_decrypt_checker_m + fv_decrypt( + .clk(doe_core_cbc.dec_block.clk), + .reset_n(doe_core_cbc.dec_block.reset_n && !doe_core_cbc.dec_block.zeroize), + .next_cmd(doe_core_cbc.dec_block.next_cmd), + .keylen(doe_core_cbc.dec_block.keylen), + .round(doe_core_cbc.dec_block.round), + .round_key(doe_core_cbc.dec_block.round_key), + .block_msg(doe_core_cbc.dec_block.block_msg), + .new_block(doe_core_cbc.dec_block.new_block), + .ready(doe_core_cbc.dec_block.ready), + .IDLE(doe_core_cbc.dec_block.dec_ctrl_reg == 0), + .Round_Compute((doe_core_cbc.dec_block.dec_ctrl_reg == 2'h1) || (doe_core_cbc.dec_block.dec_ctrl_reg == 2'h3)), + .old_block(doe_core_cbc.dec_block.round_logic.old_block), + .block_new(doe_core_cbc.dec_block.block_new), + .fv_round_key_array(doe_core_cbc.keymem.key_mem) + ); + +//Inputs driven with constraints on doe_decipher_block +`else + + bind doe_decipher_block fv_decrypt_checker_m + fv_decrypt(.*, + .clk(clk), + .reset_n(reset_n && !zeroize), + .IDLE(dec_ctrl_reg == 0), + .Round_Compute((dec_ctrl_reg == 2'h1) || (dec_ctrl_reg == 2'h3)), + .old_block(round_logic.old_block), + .block_new(block_new), + .fv_round_key_array(fv_dec_constraints.fv_round_key_array) + ); + +`endif \ No newline at end of file diff --git a/src/doe/formal/properties/fv_doe_encryption/fv_constraints.sv b/src/doe/formal/properties/fv_doe_encryption/fv_constraints.sv new file mode 100644 index 000000000..35b7614cd --- /dev/null +++ b/src/doe/formal/properties/fv_doe_encryption/fv_constraints.sv @@ -0,0 +1,128 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import doe_core_cbc_pkg::*; + +module fv_enc_constraints_m( + + //////////////////////////// + // Input / Output signals // + //////////////////////////// + input clk, + input reset_n, + + input next_cmd, + + input keylen, + input [3 : 0] round, + input [127 : 0] round_key, + + input [31 : 0] sboxw, + input [31 : 0] new_sboxw, + + input [127 : 0] block_msg, + input [127 : 0] new_block, + input ready + +); + +//////////////////////// +// Default Clock // +//////////////////////// +default clocking default_clk @(posedge clk); endclocking + +//Internal Signals +logic [31:0] fv_sbox; +logic [127:0] fv_round_key; +logic [127:0] fv_round_key_array[14:0]; + +//////////////////////// +// Symbolic Logic // +/////////////////////// + +sym_roundkey_a: assume property (disable iff(!reset_n) sym_roundkey_p); +property sym_roundkey_p; + ##1 $stable(fv_round_key_array) +;endproperty + +//Get expanded round keys for input key +function logic[127:0] get_roundkey(input logic [3:0] index_round); + logic [127:0] int_key; + + int_key = fv_round_key_array[index_round]; + + return int_key; +endfunction + +//Helper Logic +assign fv_sbox = get_sbox(sboxw); +assign fv_round_key = get_roundkey(round); + +//////////////////////////////////////// +// Encryption Constraint Properties // +////////////////////////////////////// + +//Constraint to drive correct value to new_sboxw input +sbox_constraint_a: assume property (disable iff(!reset_n) sbox_constraint_p); +property sbox_constraint_p; + new_sboxw == fv_sbox +;endproperty + +//Constraint to drive correct value to round_key input +roundkey_constraint_a: assume property (disable iff(!reset_n) roundkey_constraint_p); +property roundkey_constraint_p; + round_key == fv_round_key +;endproperty + +//Constraint to keep keylen input stable +stable_keylen_a: assume property (disable iff(!reset_n) stable_keylen_p); +property stable_keylen_p; + $stable(keylen) || ready +;endproperty + +//Constraint to keep incoming roundkey stable +stable_blk_msg_a: assume property (disable iff(!reset_n) stable_blk_msg_p); +property stable_blk_msg_p; + $stable(block_msg) || ready +;endproperty + +//next_cmd can be only received if the doe_encipher_block is ready +cmd_on_ready_a: assume property (disable iff(!reset_n) cmd_on_ready_p); +property cmd_on_ready_p; + !ready +|-> + !next_cmd; +endproperty + +`ifdef CBC_BIND + //Constraint to drive correct value to fv_round_key_array signal in fv_encrypt checker + roundkey_array_cbc_a: assume property (disable iff(!reset_n) roundkey_array_cbc_p); + property roundkey_array_cbc_p; + doe_core_cbc.enc_block.fv_encrypt.fv_round_key_array == fv_round_key_array + ;endproperty +`endif + +endmodule + +//Connect this constraints module with the DUV +bind doe_encipher_block fv_enc_constraints_m fv_enc_constraints(.*, + .clk(clk), + .reset_n(reset_n && !zeroize) + ); + diff --git a/src/doe/formal/properties/fv_doe_encryption/fv_cover_points.sv b/src/doe/formal/properties/fv_doe_encryption/fv_cover_points.sv new file mode 100644 index 000000000..a766f6f94 --- /dev/null +++ b/src/doe/formal/properties/fv_doe_encryption/fv_cover_points.sv @@ -0,0 +1,46 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +module fv_enc_coverpoints_m( + input logic clk, + input logic reset_n, + input logic zeroize +); + +default clocking default_clk @(posedge clk); endclocking + +//Cover zeroize +cover_zeroize: cover property(disable iff(!reset_n) doe_encipher_block.zeroize ); + +//Assert zeroize input and check the status of all registers. All registers/internal memories should be cleared. +cover_zeroize_after_next: cover property(disable iff(!reset_n) doe_encipher_block.zeroize && doe_encipher_block.ready && doe_encipher_block.next_cmd ); + +//Cover that checks multiple next_cmd can be received for encipher block. +cover_multiple_next: cover property(disable iff(!reset_n || zeroize) + doe_encipher_block.next_cmd && doe_encipher_block.ready ##1 doe_encipher_block.next_cmd && doe_encipher_block.ready[->1] +); + +endmodule + +//Connect this coverpoints module with the DUV +bind doe_encipher_block fv_enc_coverpoints_m fv_enc_coverpoints( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize) +); \ No newline at end of file diff --git a/src/doe/formal/properties/fv_doe_encryption/fv_doe_encrypt.sv b/src/doe/formal/properties/fv_doe_encryption/fv_doe_encrypt.sv new file mode 100644 index 000000000..ba1603415 --- /dev/null +++ b/src/doe/formal/properties/fv_doe_encryption/fv_doe_encrypt.sv @@ -0,0 +1,348 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import doe_core_cbc_pkg::*; + +module fv_encrypt_checker_m ( + + //////////////////////////// + // Input / Output signals // + //////////////////////////// + input clk, + input reset_n, + + input next_cmd, + + input keylen, + input [3 : 0] round, + input [127 : 0] round_key, + + input [31 : 0] sboxw, + input [31 : 0] new_sboxw, + + input [127 : 0] block_msg, + input [127 : 0] new_block, + input ready, + + ////////////////////// + // States // + ////////////////////// + + input IDLE, + input Round_Compute, + + ////////////////////// + // Internal Signals // + ////////////////////// + input [127 : 0] block_new, + input [127 : 0] old_block, + + //Signal for expanded keys + input [127 : 0] fv_round_key_array[14:0] + +); + +//localparams - Respective delays +localparam DLY_128 = 52; //no. of cycles the decryption takes for 128B configuration +localparam DLY_256 = 72; //no. of cycles the decryption takes for 256B configuration +localparam DLY_RND = 5; //no. of cycles the round computation takes +localparam DLY_SBOX = 4; //no. of cycles the SBOX computation takes + +//Compute Intermediate steps in each round +function logic [127 : 0] compute_round_encrypt(input logic [127 : 0] index_msg, input logic [3:0] int_rnd); + logic [127:0] int_msg; + logic [31:0] int_word[0:3]; + + int_msg = index_msg; + + //Round encryption + for (int i = 0; i < 4; i++) + int_word[3-i] = int_msg[i*32 +: 32]; + + for (int i = 0; i < 4; i++) + int_word[i] = get_sbox(int_word[i]); + + int_msg = {int_word[0],int_word[1],int_word[2],int_word[3]}; + + int_msg = compute_shiftrow(int_msg); + + int_msg = compute_mixcolums_msg(int_msg); + + int_msg = compute_add_round_key(int_msg, fv_round_key_array[int_rnd]); + + return int_msg; +endfunction + +//Compute intermediate steps in last round +function logic [127 : 0] compute_lastround(input logic [127 : 0] index_msg, input logic [3:0] int_rnd); + logic [127:0] int_msg; + logic [31:0] int_word[0:3]; + + int_msg = index_msg; + + //Round encryption + for (int i = 0; i < 4; i++) + int_word[3-i] = int_msg[i*32 +: 32]; + + for (int i = 0; i < 4; i++) + int_word[i] = get_sbox(int_word[i]); + + int_msg = {int_word[0],int_word[1],int_word[2],int_word[3]}; + + int_msg = compute_shiftrow(int_msg); + + int_msg = compute_add_round_key(int_msg, fv_round_key_array[int_rnd]); + + return int_msg; +endfunction + +//Compute AES_Encryption 128 +function logic [127 : 0] compute_aes_encryption_128(input logic [127 : 0] index_msg); + logic [127:0] int_msg; + logic [31:0] int_word[0:3]; + + int_msg = index_msg; + + //Initial Step + int_msg = compute_add_round_key(int_msg, fv_round_key_array[0]); + + //Round encryption + for (int rnd = 1; rnd < 10; rnd++) begin + //Round encryption + int_msg = compute_round_encrypt(int_msg, rnd); + end + + //Final Round + int_msg = compute_lastround(int_msg, 4'ha); + + return int_msg; +endfunction + +//Compute AES_Encryption 256 +function logic [127 : 0] compute_aes_encryption_256(input logic [127 : 0] index_msg); + logic [127:0] int_msg; + logic [31:0] int_word[0:3]; + + int_msg = index_msg; + + //Initial Step + int_msg = compute_add_round_key(int_msg, fv_round_key_array[0]); + + //Round encryption + for (int rnd = 1; rnd < 14; rnd++) begin + //Round encryption + int_msg = compute_round_encrypt(int_msg, rnd); + end + + //Final Round + int_msg = compute_lastround(int_msg, 4'he); + + return int_msg; +endfunction + +//////////////////////// +// Default Clock // +//////////////////////// +default clocking default_clk @(posedge clk); endclocking + +////////////////////////////////////// +// Encryption Checker Properties // +//////////////////////////////////// + +// Checks if the design is in IDLE state and ready is low +reset_a: assert property (reset_p); +property reset_p; + $past(!reset_n) +|-> + IDLE && + ready == 1 +;endproperty + +// Checks if block produces correct 128 bit encrypted value +encryption_check_128_a: assert property (disable iff(!reset_n) encryption_check_128_p); +property encryption_check_128_p; + logic [127:0] result, tracked_blk_msg; + + ##0 next_cmd + ##0 !keylen + ##0 (1'b1, tracked_blk_msg = block_msg) + ##DLY_128 (1'b1, result = compute_aes_encryption_128(tracked_blk_msg)) +|-> + ##0 new_block == result + ##0 ready +;endproperty + +// Checks if block produces correct sequence of round outputs for 128 bit configuration +round_check_128_a: assert property (disable iff(!reset_n) round_check_128_p); +property round_check_128_p; + ##0 next_cmd + ##0 !keylen +|-> + ##1 round == 0 && !ready + ##1 round == 1 && !ready[*DLY_RND] + ##1 round == 2 && !ready[*DLY_RND] + ##1 round == 3 && !ready[*DLY_RND] + ##1 round == 4 && !ready[*DLY_RND] + ##1 round == 5 && !ready[*DLY_RND] + ##1 round == 6 && !ready[*DLY_RND] + ##1 round == 7 && !ready[*DLY_RND] + ##1 round == 8 && !ready[*DLY_RND] + ##1 round == 9 && !ready[*DLY_RND] + ##1 round == 10 && !ready[*DLY_RND] + ##1 ready +;endproperty + +// Checks if block produces correct 256 bit encrypted value +encryption_check_256_a: assert property (disable iff(!reset_n) encryption_check_256_p); +property encryption_check_256_p; + logic [127:0] result, tracked_blk_msg; + + ##0 next_cmd + ##0 keylen + ##0 (1'b1, tracked_blk_msg = block_msg) + ##DLY_256 (1'b1, result = compute_aes_encryption_256(tracked_blk_msg)) +|-> + ##0 new_block == result + ##0 ready +;endproperty + +// Checks if block produces correct sequence of round outputs for 256 bit configuration +round_check_256_a: assert property (disable iff(!reset_n) round_check_256_p); +property round_check_256_p; + ##0 next_cmd + ##0 keylen +|-> + ##1 round == 0 + ##1 round == 1 && !ready[*DLY_RND] + ##1 round == 2 && !ready[*DLY_RND] + ##1 round == 3 && !ready[*DLY_RND] + ##1 round == 4 && !ready[*DLY_RND] + ##1 round == 5 && !ready[*DLY_RND] + ##1 round == 6 && !ready[*DLY_RND] + ##1 round == 7 && !ready[*DLY_RND] + ##1 round == 8 && !ready[*DLY_RND] + ##1 round == 9 && !ready[*DLY_RND] + ##1 round == 10 && !ready[*DLY_RND] + ##1 round == 11 && !ready[*DLY_RND] + ##1 round == 12 && !ready[*DLY_RND] + ##1 round == 13 && !ready[*DLY_RND] + ##1 round == 14 && !ready[*DLY_RND] + ##1 ready +;endproperty + +// Checks if block produces correct round encrypted value for each round in 128 bit configuration +for (genvar rnd = 1; rnd < 10; rnd++) begin: rndcompute_128 + round_compute_128_a: assert property (disable iff(!reset_n) round_compute_128_p(rnd)); +end +property round_compute_128_p(rndcnt); + logic [127:0] result; + ##0 Round_Compute && !keylen + ##1 round == rndcnt + ##0 (1'b1, result = compute_round_encrypt(old_block,rndcnt)) +|-> + ##DLY_SBOX block_new == result +;endproperty + +// Checks if block produces correct round encrypted value for each round in 256 bit configuration +for (genvar rnd = 1; rnd < 14; rnd++) begin: rndcompute_256 + round_compute_256_a: assert property (disable iff(!reset_n) round_compute_256_p(rnd)); +end +property round_compute_256_p(rndcnt); + logic [127:0] result; + ##0 Round_Compute && keylen + ##1 round == rndcnt + ##0 (1'b1, result = compute_round_encrypt(old_block,rndcnt)) +|-> + ##DLY_SBOX block_new == result +;endproperty + +// Checks if block produces correct round encrypted value for last round in 128 bit configuration +lastround_computation_128_a: assert property (disable iff(!reset_n) lastround_computation_128_p); +property lastround_computation_128_p; + logic [127:0] result; + ##0 Round_Compute && !keylen + ##1 round == 4'ha + ##0 (1'b1, result = compute_lastround(old_block,4'ha)) +|-> + ##DLY_SBOX block_new == result +;endproperty + +// Checks if block produces correct round encrypted value for last round in 256 bit configuration +lastround_computation_256_a: assert property (disable iff(!reset_n) lastround_computation_256_p); +property lastround_computation_256_p; + logic [127:0] result; + ##0 Round_Compute && keylen + ##1 round == 4'he + ##0 (1'b1, result = compute_lastround(old_block,4'he)) +|-> + ##DLY_SBOX block_new == result +;endproperty + +// Checks if block produces correct encrypted value for the first round +firstround_compute_a: assert property (disable iff(!reset_n) firstround_compute_p); +property firstround_compute_p; + logic [127:0] result, tracked_blk_msg; + + ##0 next_cmd + ##0 (1'b1, tracked_blk_msg = block_msg) + ##0 (1'b1, result = compute_add_round_key(tracked_blk_msg, fv_round_key_array[0])) +|-> + ##1 block_new == result +;endproperty + +endmodule + +//Inputs driven from doe_core_cbc +`ifdef CBC_BIND + + bind doe_encipher_block fv_encrypt_checker_m + fv_encrypt( + .clk(doe_core_cbc.enc_block.clk), + .reset_n(doe_core_cbc.enc_block.reset_n && !doe_core_cbc.enc_block.zeroize), + .next_cmd(doe_core_cbc.enc_block.next_cmd), + .keylen(doe_core_cbc.enc_block.keylen), + .round(doe_core_cbc.enc_block.round), + .round_key(doe_core_cbc.enc_block.round_key), + .sboxw(doe_core_cbc.enc_block.sboxw), + .new_sboxw(doe_core_cbc.enc_block.new_sboxw), + .block_msg(doe_core_cbc.enc_block.block_msg), + .new_block(doe_core_cbc.enc_block.new_block), + .ready(doe_core_cbc.enc_block.ready), + .IDLE(doe_core_cbc.enc_block.enc_ctrl_reg == 0), + .Round_Compute((doe_core_cbc.enc_block.enc_ctrl_reg == 2'h1) || (doe_core_cbc.enc_block.enc_ctrl_reg == 2'h3)), + .old_block(doe_core_cbc.enc_block.round_logic.old_block), + .block_new(doe_core_cbc.enc_block.block_new), + .fv_round_key_array(doe_core_cbc.keymem.key_mem) + ); + +//Inputs driven with constraints on doe_encipher_block +`else + + bind doe_encipher_block fv_encrypt_checker_m + fv_encrypt(.*, + .clk(clk), + .reset_n(reset_n && !zeroize), + .IDLE(enc_ctrl_reg == 0), + .Round_Compute((enc_ctrl_reg == 2'h1) || (enc_ctrl_reg == 2'h3)), + .old_block(round_logic.old_block), + .block_new(block_new), + .fv_round_key_array(fv_enc_constraints.fv_round_key_array) + ); + +`endif diff --git a/src/doe/formal/properties/fv_doe_iv/fv_doe_iv_process.sv b/src/doe/formal/properties/fv_doe_iv/fv_doe_iv_process.sv new file mode 100644 index 000000000..19d13ac72 --- /dev/null +++ b/src/doe/formal/properties/fv_doe_iv/fv_doe_iv_process.sv @@ -0,0 +1,230 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import doe_iv_process_pkg::*; + +module fv_doe_iv_process_m( + input bit rst, + input bit rst_test, + input bit clk, + + // Inputs + input st_InPacket cmd_in, + input st_InPacket decrypt_in, + input st_InPacket result_in, + + // Outputs + input bit unsigned [127:0] ivdecry_out, + input bit unsigned [127:0] ivencry_out, + input bit doe_ready, + + // Ready signals + input bit cmd_in_ready, + input bit decrypt_in_ready, + input bit result_in_ready, + + // Registers + input bit unsigned [127:0] dec_prev_msg, + + // States + input bit idle, + input bit enc, + input bit dec_first, + input bit dec_next +); + + +default clocking default_clk @(posedge clk); endclocking + +// Checks if the design is in IDLE state and ready is high +reset_a: assert property (reset_p); +property reset_p; + $past(rst) |-> + idle && + doe_ready == 1 +;endproperty + +// Checks if the block updates IV_encry with the encoded message once encryption is done +enc_to_idle_a: assert property (disable iff(rst_test) enc_to_idle_p); +property enc_to_idle_p; + enc && + result_in_ready +|-> + ##1 + idle && + ivencry_out == $past(result_in.encoded_msg, 1); +endproperty + +// Checks if the block switches from idle state to enc state upon receiving next_cmd +idle_to_enc_a: assert property (disable iff(rst) idle_to_enc_p); +property idle_to_enc_p; + idle && + cmd_in_ready && + cmd_in.next_cmd && + cmd_in.encdec +|-> + ##1 + enc; +endproperty + +// Checks if the block waits in enc state until encryption is done +enc_wait_a: assert property (disable iff(rst) enc_wait_p); +property enc_wait_p; + enc && + !result_in_ready +|-> + ##1 + enc; +endproperty + +// Checks if the block waits iv_encry updated with IV +IV_encry_check_a: assert property (disable iff(rst) IV_encry_check_p); +property IV_encry_check_p; + doe_core_cbc.encdec && + cmd_in.IV_Updated_d +|-> + ##1 + ivencry_out == $past(cmd_in.IV, 1); +endproperty + +// Checks if the block switches from idle state to first decrypt state upon receiving next_cmd +// and updates IV_decry with the IV, IV_decry_next with incoming block message +idle_to_dec_first_a: assert property (disable iff(rst) idle_to_dec_first_p); +property idle_to_dec_first_p; + doe_core_cbc.IV_dec_state == 0 && + doe_core_cbc.next_cmd && doe_core_cbc.dec_ready && + !doe_core_cbc.encdec +|-> + ##1 + dec_first && + ivdecry_out == $past(doe_core_cbc.IV) && + dec_prev_msg == $past(doe_core_cbc.block_msg); +endproperty + +// Checks if the block switches from first decrypt state to next decrypt state upon receiving next_cmd +// and updates IV_decry with the previous IV_decry_next, IV_decry_next with incoming block message +dec_first_to_dec_next_a: assert property (disable iff(rst) dec_first_to_dec_next_p); +property dec_first_to_dec_next_p; + dec_first && + decrypt_in_ready +|-> + ##1 + dec_next && + ivdecry_out == $past(doe_core_cbc.IV_decry_next) && + dec_prev_msg == $past(doe_core_cbc.block_msg) +;endproperty + +// Checks if the block switches from next decrypt state to first decrypt state in next cycle +// and holds values of IV_decry, IV_decry_next from previous state +dec_next_to_dec_first_a: assert property (disable iff(rst) dec_next_to_dec_first_p); +property dec_next_to_dec_first_p; + dec_next +|-> + ##1 + dec_first && + ivdecry_out == $past(ivdecry_out) && + dec_prev_msg == $past(dec_prev_msg) +;endproperty + +// Checks if the block switches from first decrypt state to idle state upon receiving IV_updated +// and updates IV_decry, IV_decry_next with incoming IV +dec_first_to_idle_a: assert property (disable iff(rst) dec_first_to_idle_p); +property dec_first_to_idle_p; + dec_first && + decrypt_in.dec_ready && + !decrypt_in.next_cmd && + decrypt_in.IV_Updated_d +|-> + ##1 + idle && + ivdecry_out == $past(doe_core_cbc.IV, 1) && + dec_prev_msg == $past(doe_core_cbc.IV, 1) +;endproperty + +// Checks if the block waits in idle state until encryption/decryption is triggered +idle_wait_a: assert property (disable iff(rst) idle_wait_p); +property idle_wait_p; + idle && + !cmd_in_ready +|-> + ##1 + idle; +endproperty + +// Checks if the block waits in first decrypt state until new decryption starts or IV_updated is received +dec_first_wait_a: assert property (disable iff(rst) dec_first_wait_p); +property dec_first_wait_p; + dec_first && + !decrypt_in_ready && + !decrypt_in.IV_Updated_d +|-> + ##1 + dec_first +;endproperty + + +endmodule + + +module fv_doe_iv_process_ref_wrapper_m; + + +default clocking default_clk @(posedge (doe_core_cbc.clk)); endclocking + + +st_InPacket cmd_in = '{ encoded_msg: (doe_core_cbc.enc_new_block), block_msg: (doe_core_cbc.block_msg), IV: (doe_core_cbc.IV), encdec: (doe_core_cbc.encdec), enc_ready: (doe_core_cbc.enc_ready), dec_ready: (doe_core_cbc.dec_ready), IV_Updated_d: (doe_core_cbc.IV_updated_delayed), next_cmd: (doe_core_cbc.next_cmd), keylen: (doe_core_cbc.keylen) }; +st_InPacket decrypt_in = '{ encoded_msg: (doe_core_cbc.enc_new_block), block_msg: (doe_core_cbc.block_msg), IV: (doe_core_cbc.IV), encdec: (doe_core_cbc.encdec), enc_ready: (doe_core_cbc.enc_ready), dec_ready: (doe_core_cbc.dec_ready), IV_Updated_d: (doe_core_cbc.IV_updated_delayed), next_cmd: (doe_core_cbc.next_cmd), keylen: (doe_core_cbc.keylen) }; +st_InPacket result_in = '{ encoded_msg: (doe_core_cbc.enc_new_block), block_msg: (doe_core_cbc.block_msg), IV: (doe_core_cbc.IV), encdec: (doe_core_cbc.encdec), enc_ready: (doe_core_cbc.enc_ready), dec_ready: (doe_core_cbc.dec_ready), IV_Updated_d: (doe_core_cbc.IV_updated_delayed), next_cmd: (doe_core_cbc.next_cmd), keylen: (doe_core_cbc.keylen) }; + + +fv_doe_iv_process_m fv_doe_iv_process( + .rst(!(doe_core_cbc.reset_n && !doe_core_cbc.zeroize)), + .rst_test(!(doe_core_cbc.reset_n && !doe_core_cbc.zeroize) || $past(!(doe_core_cbc.reset_n && !doe_core_cbc.zeroize))), + .clk(doe_core_cbc.clk), + + // Inputs + .cmd_in(cmd_in), + .decrypt_in(decrypt_in), + .result_in(result_in), + + // Outputs + .ivdecry_out(doe_core_cbc.IV_decry), + .ivencry_out(doe_core_cbc.IV_encry), + .doe_ready(doe_core_cbc.ready), + + // Ready signals + .cmd_in_ready((doe_core_cbc.enc_ready && doe_core_cbc.enc_next) || (doe_core_cbc.dec_ready && doe_core_cbc.dec_next)), + .decrypt_in_ready(doe_core_cbc.dec_next && doe_core_cbc.dec_ready), + .result_in_ready((!$past(doe_core_cbc.enc_ready) && doe_core_cbc.enc_ready) ), + + // Registers + .dec_prev_msg(doe_core_cbc.IV_decry_next), + + // States + .idle(doe_core_cbc.IV_enc_state == 0 || doe_core_cbc.IV_dec_state == 0), + .enc(doe_core_cbc.IV_enc_state == 1), + .dec_first(doe_core_cbc.IV_dec_state == 2), + .dec_next(doe_core_cbc.IV_dec_state == 1) +); + + +endmodule + + +bind doe_core_cbc fv_doe_iv_process_ref_wrapper_m fv_doe_iv_process_ref_wrapper(); diff --git a/src/doe/formal/properties/fv_doe_iv/fv_doe_iv_process_pkg.sv b/src/doe/formal/properties/fv_doe_iv/fv_doe_iv_process_pkg.sv new file mode 100644 index 000000000..eecf72f01 --- /dev/null +++ b/src/doe/formal/properties/fv_doe_iv/fv_doe_iv_process_pkg.sv @@ -0,0 +1,37 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +package doe_iv_process_pkg; + + + typedef struct { + bit unsigned [127:0] encoded_msg; + bit unsigned [127:0] block_msg; + bit unsigned [127:0] IV; + bit encdec; + bit enc_ready; + bit dec_ready; + bit IV_Updated_d; + bit next_cmd; + bit keylen; + } st_InPacket; + + +endpackage diff --git a/src/doe/formal/properties/fv_doe_keymem/fv_constraints.sv b/src/doe/formal/properties/fv_doe_keymem/fv_constraints.sv new file mode 100644 index 000000000..8ab13e7bd --- /dev/null +++ b/src/doe/formal/properties/fv_doe_keymem/fv_constraints.sv @@ -0,0 +1,89 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import doe_core_cbc_pkg::*; + +module fv_key_constraints_m( + + //////////////////////////// + // Input / Output signals // + //////////////////////////// + input clk, + input reset_n, + + input [255 : 0] key, + input keylen, + input init_cmd, + + input [3 : 0] round, + input [127 : 0] round_key, + input ready, + + + input [31 : 0] sboxw, + input [31 : 0] new_sboxw + +); + +//////////////////////// +// Default Clock // +//////////////////////// +default clocking default_clk @(posedge clk); endclocking + +//Internal Signals +logic [31:0] fv_sbox; + +//Helper Logic +assign fv_sbox = get_sbox(sboxw); + +//////////////////////////////////// +// KeyMem Constraint Properties // +/////////////////////////////////// + +//Constraint to drive correct value to new_sboxw input +sbox_constraint_a: assume property (disable iff(!reset_n) sbox_constraint_p); +property sbox_constraint_p; + new_sboxw == fv_sbox +;endproperty + +//Constraint to keep keylen input stable +stable_keylen_a: assume property (disable iff(!reset_n) stable_keylen_p); +property stable_keylen_p; + $stable(keylen) || ready +;endproperty + +//Constraint to keep key input stable +stable_key_a: assume property (disable iff(!reset_n) stable_key_p); +property stable_key_p; + $stable(key) || ready +;endproperty + +//Constraint to get init_cmd only when the design is in IDLE state +init_only_in_idle_a: assume property (disable iff(!reset_n) init_only_in_idle_p); +property init_only_in_idle_p; + init_cmd +|-> + doe_key_mem.key_mem_ctrl_reg == 0 +;endproperty + +endmodule + +//Connect this constraints module with the DUV +bind doe_key_mem fv_key_constraints_m fv_keymem_constraints(.* + ); \ No newline at end of file diff --git a/src/doe/formal/properties/fv_doe_keymem/fv_cover_points.sv b/src/doe/formal/properties/fv_doe_keymem/fv_cover_points.sv new file mode 100644 index 000000000..5f94b0574 --- /dev/null +++ b/src/doe/formal/properties/fv_doe_keymem/fv_cover_points.sv @@ -0,0 +1,46 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +module fv_keymem_coverpoints_m( + input logic clk, + input logic reset_n, + input logic zeroize +); + +default clocking default_clk @(posedge clk); endclocking + +//Cover zeroize +cover_zeroize: cover property(disable iff(!reset_n) doe_key_mem.zeroize ); + +//Assert zeroize input and check the status of all registers. All registers/internal memories should be cleared. +cover_zeroize_after_next: cover property(disable iff(!reset_n) doe_key_mem.zeroize && doe_key_mem.ready && doe_key_mem.init_cmd); + +//Cover that checks multiple init_cmd can be received +cover_multiple_init: cover property(disable iff(!reset_n || zeroize) + doe_key_mem.init_cmd && doe_key_mem.ready ##1 doe_key_mem.init_cmd && doe_key_mem.ready[->1] +); + +endmodule + +//Connect this coverpoints module with the DUV +bind doe_key_mem fv_keymem_coverpoints_m fv_keymem_coverpoints( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize) +); \ No newline at end of file diff --git a/src/doe/formal/properties/fv_doe_keymem/fv_keymem.sv b/src/doe/formal/properties/fv_doe_keymem/fv_keymem.sv new file mode 100644 index 000000000..e45cc6d29 --- /dev/null +++ b/src/doe/formal/properties/fv_doe_keymem/fv_keymem.sv @@ -0,0 +1,273 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import doe_core_cbc_pkg::*; + +module fv_keymem_checker_m ( + + //////////////////////////// + // Input / Output signals // + //////////////////////////// + input clk, + input reset_n, + + input [255 : 0] key, + input keylen, + input init_cmd, + + input [3 : 0] round, + input [127 : 0] round_key, + input ready, + + + input [31 : 0] sboxw, + input [31 : 0] new_sboxw, + + input [127 : 0] roundkey_mem [14 : 0], + + ////////////////////// + // States // + ////////////////////// + + input IDLE, + input Keyexpansion_128, + input Keyexpansion_256 + +); + +//localparams - Respective delays +localparam DLY_128 = 14; //no. of cycles the key expansion takes for 128B configuration +localparam DLY_256 = 18; //no. of cycles the key expansion takes for 256B configuration + +//////////////////////// +// Default Clock // +//////////////////////// +default clocking default_clk @(posedge clk); endclocking + +//////////////////////////////////// +// KeyMem Checker Properties // +/////////////////////////////////// + +logic [6:0] curr_bit; +logic [3:0] idx; + +//////////////////////// +// Symbolic Logic // +//////////////////////// +sym_bit: assume property (##1 $stable(curr_bit)); +sym_idx: assume property (##1 $stable(idx)); + +////////////////////////////////// +// KeyMem Checker Properties // +///////////////////////////////// + +// Checks if the design is in IDLE state and ready is low +reset_a: assert property (reset_p); +property reset_p; + $past(!reset_n) |-> + IDLE && + ready == 0 +;endproperty + +// Checks if ready stays same during IDLE to IDLE state transition +IDLE_to_IDLE_a: assert property (disable iff(!reset_n) IDLE_to_IDLE_p); +property IDLE_to_IDLE_p; + IDLE && + !init_cmd +|-> + ##1 + IDLE && + ready == $past(ready, 1) +;endproperty + +// Checks if ready is low during IDLE to Keyexpansion128 state transition +IDLE_to_keyExpansion128_a: assert property (disable iff(!reset_n) IDLE_to_keyExpansion128_p); +property IDLE_to_keyExpansion128_p; + IDLE && + init_cmd && + !keylen +|-> + ##1 + Keyexpansion_128 && + (ready == 0) +;endproperty + +// Checks if ready is low during IDLE to Keyexpansion256 state transition +IDLE_to_keyExpansion256_a: assert property (disable iff(!reset_n) IDLE_to_keyExpansion256_p); +property IDLE_to_keyExpansion256_p; + IDLE && + init_cmd && + keylen +|-> + ##1 + Keyexpansion_256 && + ready == 0 +;endproperty + +//Properties to load when CBC is considered as top module +`ifdef CBC_BIND + + roundkey_check_128_cbc_a: assert property (disable iff(!reset_n) roundkey_check_128_cbc_p); + property roundkey_check_128_cbc_p; + logic [255:0] tracked_key; + logic [127:0] result; + + ##0 init_cmd + ##0 !keylen + ##0 (1'b1, tracked_key = key) + ##0 (idx < 11) + + ##DLY_128 (1'b1, result = compute_key_expansion_128(tracked_key[255:128], idx)) + |-> + ##0 roundkey_mem[idx][curr_bit] == result[curr_bit] + ##0 ready + ;endproperty + + roundkey_check_256_cbc_a: assert property (disable iff(!reset_n) roundkey_check_256_cbc_p); + property roundkey_check_256_cbc_p; + logic [255:0] tracked_key; + logic [127:0] result; + + ##0 init_cmd + ##0 keylen + ##0 (1'b1, tracked_key = key) + ##0 (idx < 15) + + ##DLY_256 (1'b1, result = compute_key_expansion_256(tracked_key, idx)) + |-> + ##0 roundkey_mem[idx][curr_bit] == result[curr_bit] + ##0 ready + ;endproperty + + // Checks computed roundkeys for 128bit configuration and the ready signal + for (genvar rnd = 0; rnd < 11; rnd++) begin: rndkey128 + roundkey_check_a: assert property (disable iff(!reset_n) roundkey_check_128_p(rnd)); + end + property roundkey_check_128_p(rndcnt); + logic [255:0] tracked_key; + logic [127:0] result; + + ##0 init_cmd + ##0 !keylen + ##0 (1'b1, tracked_key = key) + + ##DLY_128 round == rndcnt + ##0 (1'b1, result = compute_key_expansion_128(tracked_key[255:128], round)) + |-> + ##0 round_key[curr_bit] == result[curr_bit] + ##0 ready + ;endproperty + + // Checks computed roundkeys for 256bit configuration and the ready signal + for (genvar rnd = 0; rnd < 15; rnd++) begin: rndkey256 + roundkey_check_a: assert property (disable iff(!reset_n) roundkey_check_256_p(rnd)); + end + property roundkey_check_256_p(rndcnt); + logic [255:0] tracked_key; + logic [127:0] result; + + ##0 init_cmd + ##0 keylen + ##0 (1'b1, tracked_key = key) + + ##DLY_256 round == rndcnt + ##0 (1'b1, result = compute_key_expansion_256(tracked_key[255:0], round)) + |-> + ##0 round_key[curr_bit] == result[curr_bit] + ##0 ready + ;endproperty + +//Properties to load when doe_key_mem is considered as top module +`else + + // Checks computed roundkeys for 128bit configuration and the ready signal + for (genvar rnd = 0; rnd < 11; rnd++) begin: rndkey128 + roundkey_check_a: assert property (disable iff(!reset_n) roundkey_check_128_p(rnd)); + end + property roundkey_check_128_p(rndcnt); + logic [255:0] tracked_key; + logic [127:0] result; + + ##0 init_cmd + ##0 !keylen + ##0 (1'b1, tracked_key = key) + + ##DLY_128 round == rndcnt + ##0 (1'b1, result = compute_key_expansion_128(tracked_key[255:128], round)) + |-> + ##0 round_key[curr_bit] == result[curr_bit] + ##0 ready + ;endproperty + + // Checks computed roundkeys for 256bit configuration and the ready signal + for (genvar rnd = 0; rnd < 15; rnd++) begin: rndkey256 + roundkey_check_a: assert property (disable iff(!reset_n) roundkey_check_256_p(rnd)); + end + property roundkey_check_256_p(rndcnt); + logic [255:0] tracked_key; + logic [127:0] result; + + ##0 init_cmd + ##0 keylen + ##0 (1'b1, tracked_key = key) + + ##DLY_256 round == rndcnt + ##0 (1'b1, result = compute_key_expansion_256(tracked_key[255:0], round)) + |-> + ##0 round_key[curr_bit] == result[curr_bit] + ##0 ready + ;endproperty + +`endif + +endmodule + +//Inputs driven from doe_core_cbc +`ifdef CBC_BIND + + bind doe_key_mem fv_keymem_checker_m fv_key_mem ( + .clk(doe_core_cbc.keymem.clk), + .reset_n(doe_core_cbc.keymem.reset_n && !doe_core_cbc.keymem.zeroize), + .key(doe_core_cbc.keymem.key), + .keylen(doe_core_cbc.keymem.keylen), + .init_cmd(doe_core_cbc.keymem.init_cmd), + .round(doe_core_cbc.keymem.round), + .round_key(doe_core_cbc.keymem.round_key), + .ready(doe_core_cbc.keymem.ready), + .sboxw(doe_core_cbc.keymem.sboxw), + .new_sboxw(doe_core_cbc.keymem.new_sboxw), + .roundkey_mem(doe_core_cbc.keymem.key_mem [14 : 0]), + .IDLE(doe_key_mem.key_mem_ctrl_reg == 0), + .Keyexpansion_128((doe_key_mem.key_mem_ctrl_reg == 1) && !keylen), + .Keyexpansion_256((doe_key_mem.key_mem_ctrl_reg == 1) && keylen) + ); + +//Inputs driven with constraints on doe_key_mem +`else + + bind doe_key_mem fv_keymem_checker_m fv_key_mem (.*, + .clk(clk), + .reset_n(reset_n && !zeroize), + .roundkey_mem(doe_key_mem.key_mem [14 : 0]), + .IDLE(doe_key_mem.key_mem_ctrl_reg == 0), + .Keyexpansion_128((doe_key_mem.key_mem_ctrl_reg == 1) && !keylen), + .Keyexpansion_256((doe_key_mem.key_mem_ctrl_reg == 1) && keylen) + ); + +`endif \ No newline at end of file diff --git a/src/doe/readme.md b/src/doe/readme.md new file mode 100644 index 000000000..11fb2217b --- /dev/null +++ b/src/doe/readme.md @@ -0,0 +1,195 @@ +# DOE +Date: 29-08-2023 +Author: LUBIS EDA + +## Folder Structure +The following subdirectories are part of the main directory **formal** + +- properties: Contains the assertion IP(AIP) for each submodule of DUT along with the valid system constraints in **fv_constraints.sv** + - keymem: **fv_doe_keymem** folder contains the assertion IP(AIP) for the submodule doe_key_mem along with the constraints for the respective AIP. + - encipher: **fv_doe_encryption** folder contains the assertion IP(AIP) for the submodule doe_encipher_block along with the constraints for the respective AIP. + - decipher: **fv_doe_decryption** folder contains the assertion IP(AIP) for the submodule doe_decipher_block along with the constraints for the respective AIP. + - iv: **fv_doe_iv** folder contains the assertion IP(AIP) for the IV_Controller implementation in the DUT. + - The folder also contains assertion IP(AIP) **fv_doe_core_cbc.sv** that covers few primary IO's properties and **fv_constraints.sv** contains the valid system constraints that drive primary Inputs as intended. + +## DUT Overview + +The DUT doe_core_cbc has the primary inputs and primary outputs as shown below. + +| S.No | Port | Direction | Description | +| ---- | ----------------- | --------- | --------------------------------------------------------------------------------- | +| 1 | clk | input | The positive edge of the clk is used for all the signals | +| 2 | reset_n | input | The reset signal is active low and resets the core | +| 3 | zeroize | input | The core is reseted when this signal is triggered. | +| 4 | encdec | input | The core is driven to perform encryption or decryption. | +| 5 | init_cmd | input | The core is initialised for the key expansion | +| 6 | next_cmd | input | The core is initialised for the encryption or decryption | +| 7 | ready | output | Indicates that core is ready to accept new block in CBC | +| 8 | key[255:0] | input | The input key used for keyexpansion and later for encryption/decryption | +| 9 | keylen | input | The core is initialised for the 128/256 bit configuration | +| 10 | IV[127:0] | input | The 128 bit Initialization_Vector value for CBC | +| 11 | IV_updated | input | The core is initialised when to consider the IV for CBC | +| 12 | block_msg[127:0] | input | The 128 bit input block message for encryption/decryption | +| 13 | result[127:0] | output | The 128 bit encrypted/decrypted message | +| 14 | result_valid | output | Indicates that the /encryption/decryption is done | + +When init_cmd is received, the core module uses the incoming 256 bit key and starts keyexpansion to generate either 10/14 roundkeys based on the incoming keylen. +Once the keyexpansion is done, the core is ready to receive IV_updated. If the core receives IV_updated, it uses incoming IV value else the previous value will be used. +When next_cmd is received, the core starts performing the encryption/decryption. It asserts the ready signal once the encryption/decryption is done. +## Assertion IP Overview + +The Assertion IP signals are bound with the respective signals in the dut. + +**properties** folder contains **global_package.sv** where all the required functions are implemented either for AES encryption or decryption + +### fv_keymem + + **fv_doe_keymem** folder contains the assertion IP(AIP) for the submodule doe_key_mem along with the constraints for the respective AIP. When this submodule is verified individually considers constraints that are in **fv_doe_keymem/fv_constraints.sv** else all inputs are driven from DUT. + +- reset_a: Checks that the ready is low and the state is idle. + +- IDLE_to_IDLE_a: Checks if there isn't any init_cmd in idle state and then the state stays in idle and holds the past value of ready. + +- IDLE_to_keyExpansion128_a: Checks if there is init_cmd in idle state and there isn't keylen input and then the state changes to keyexpansion for 128 bit config and verify that the ready is still low during keyexpansion. + +- IDLE_to_keyExpansion256_a: Checks if there is init_cmd in idle state and there is keylen input and then the state changes to keyexpansion for 256 bit config and verify that the ready is still low during keyexpansion. + +- roundkey_check_128_cbc_a: Checks that once the keyexpansion is done, doe_key_mem module sends out correct round_key of 128bit configuration based on the round input. + +- roundkey_check_256_cbc_a: Checks that once the keyexpansion is done, doe_key_mem module sends out correct round_key of 256bit configuration based on the round input. + +### fv_encrypt + + **fv_doe_encryption** folder contains the assertion IP(AIP) for the submodule doe_encipher_block along with the constraints for the respective AIP. When this submodule is verified individually considers constraints that are in **fv_doe_encryption/fv_constraints.sv** else all inputs are driven from DUT. + +- reset_a: Checks that the ready is high and the state is idle. + +- encryption_check_128_a: Checks that once the encryption is done, doe_encipher_block module sends out the encrypted 128bit message to new_block along with the ready signal + +- round_check_128_a: Checks that round output sends out the correct round number during the encryption of 128 bit block message + +- encryption_check_256_a: Checks that once the encryption is done, doe_encipher_block module sends out the encrypted 256bit message to new_block along with the ready signal + +- round_check_256_a: Checks that round output sends out the correct round number during the encryption of 256 bit block message + +### fv_decrypt + + **fv_doe_decryption** folder contains the assertion IP(AIP) for the submodule doe_decipher_block along with the constraints for the respective AIP. When this submodule is verified individually considers constraints that are in **fv_doe_decryption/fv_constraints.sv** else all inputs are driven from DUT. + +- reset_a: Checks that the ready is high and the state is idle. + +- decryption_check_128_a: Checks that once the decryption is done, doe_encipher_block module sends out the encrypted 128bit message to new_block along with the ready signal + +- round_check_128_a: Checks that round output sends out the correct round number during the decryption of 128 bit block message + +- decryption_check_256_a: Checks that once the decryption is done, doe_encipher_block module sends out the encrypted 256bit message to new_block along with the ready signal + +- round_check_256_a: Checks that round output sends out the correct round number during the decryption of 256 bit block message + + +### fv_doe_iv_process + + **fv_doe_iv** folder contains the assertion IP(AIP) for the IV_Controller implementation for CBC in DUT. This checker uses the same set of constraints that on the doe_core_cbc module which are in **properties/fv_constraints.sv**. + + **doe_iv_process_pkg.sv** consists of defined struct of input data taht will be used in the **fv_doe_iv_process** checker + +- reset_a: Checks that the ready is high and the state is idle. + +- enc_to_idle_a: Checks if encryption is done and state changes to idle while IV_controller loads IV_encry with the encrypted message + +- idle_to_enc_a: Checks if there is next_cmd in idle state and there is encdec input and then the state changes to enc. + +- idle_to_dec_first_a: Checks if the block switches from idle state to first decrypt state upon receiving next_cmd and updates IV_decry with the IV, IV_decry_next with incoming block message + +- dec_first_to_dec_next_a: Checks if the block switches from first decrypt state to next decrypt state upon receiving next_cmd and updates IV_decry with the previous IV_decry_next, IV_decry_next with incoming block message + +- dec_next_to_dec_first_a: Checks if the block switches from next decrypt state to first decrypt state in next cycle and holds values of IV_decry, IV_decry_next from previous state + +- dec_first_to_idle_a: Checks if the block switches from first decrypt state to idle state upon receiving IV_updated and updates IV_decry, IV_decry_next with incoming IV + +- enc_wait_a: Checks if encryption is done else wait in the same state until encryption is finished + +- dec_first_wait_a: Checks if the block waits in first decrypt state until new decryption starts or IV_updated is received + +- idle_wait_a: Checks if there is encryption or decryption request in idle and waits in the same state until either of them are received + + +### fv_doe_cbc_inst + + **properties** folder contains the assertion IP(AIP) for few of the primary outputs in DUT that are not covered in the previous checkers. This checker uses the same set of constraints that on the doe_core_cbc module which are in **properties/fv_constraints.sv**. + +- result_valid_enc_a: Checks if result_valid is asserted once after the encryption is done. + +- result_valid_dec_a: Checks if result_valid is asserted once after the decryption is done. + +- ready_kemem_a: Checks if ready is asserted once after the keyexpansion is done. + +- ready_enc_a: Checks if ready is asserted once after the encryption is done. + +- result_enc_a: Checks if result is stored with the encrypted message once the encryption is done. + +- result_dec_a: Checks if result is stored with the decrypted message once the decryption is done. + +- sbox_check_a: Checks if doe_sbox block produces correct values + +### fv_coverpoints + +- cover_zeroize: Checks that the ready is high and the state is idle. + +- cover_zeroize_after_next: Assert zeroize input and check the status of all registers. All registers/internal memories should be cleared. + +- cover_multiple_next: Cover that checks multiple next_cmd can be received for CBC encryption/decryption. + +- cover_transition_keyexp_to_iv: Cover that checks IV_updated asserted once the keyexapnsion is done + +- cover_transition_keyexp_to_encdec: Cover that checks if design can have a trandition from keyexpansion to encryption/decryption + +- cover_transition_keyexp_to_keyexp: Cover that checks if design can have a trandition from keyexpansion to keyexpansion + +- cover_transition_encdec_to_encdec: Cover that checks if design can have a trandition from encryption/decryption to encryption/decryption + +- cover_transition_encdec_to_keyexp: Cover that checks if design can have a trandition from encryption/decryption to keyexpansion + + +# Reproduce results + +**MACROS :** +CBC_BIND + +- Differentiates the set of assertions and assumptions added when loaded with top as respective submodule or doe_core_cbc. + +- When defined, the assertions and assumptions are considered based on doe_core_cbc module. + +- When not defined, the assertions and assumptions are independednt of doe_core_cbc module. + +- Differentiates the binding of the checker files when loaded with top as respective submodule or doe_core_cbc. + +- When not defined, the inputs are open and necessary inputs are driven from the respective constraints + +- When defined, the inputs are driven from doe_core_cbc based on constraints on doe_core_cbc module. + + +## Proving the submodules + +- Load submodule as top in the formal tool. + +- Load the checker files along with the constraints and respective packages in the formal tool. + +- Run the properties with ASSERT_BIND macro defined to verify that submodule behaves as intended. + +## Proving the top + +- Load all design files in the formal tool and set doe_core_cbc as top module. + +- Load all the checker files with CBC_BIND macro defined along with the constraints and respective packages in the formal tool. + +- Copy all the submodule assertions, covers and assumptions into seperate task and cut the signals from the top that affect the submodule verification. + +- On the main task, disable all submodule assumptions and just keep the assumptions on the doe_core_cbc module. + +- Run the properties on the main task to verify that the top module behaves as intended. + +- Switch the tasks to one of the submodules which consists of the assumptions and assertions of that particular submodule. + +- Run the properties on each submodule task to verify that the submodule behaves as intended. + diff --git a/src/ecc/config/compile.yml b/src/ecc/config/compile.yml index 369d1ed2c..92b109284 100755 --- a/src/ecc/config/compile.yml +++ b/src/ecc/config/compile.yml @@ -40,7 +40,7 @@ targets: rtl_lint: directories: [] waiver_files: - - $COMPILE_ROOT/config/design_lint/ecc_top/sglint_waivers + - $MSFT_REPO_ROOT/src/ecc/config/design_lint/ecc_top/sglint_waivers black_box: - ecc_reg --- diff --git a/src/ecc/formal/fv_ecc_block_overview.pdf b/src/ecc/formal/fv_ecc_block_overview.pdf new file mode 100644 index 000000000..5454274fd Binary files /dev/null and b/src/ecc/formal/fv_ecc_block_overview.pdf differ diff --git a/src/ecc/formal/properties/coverpoints/fv_add_sub_alter_coverpoints.sv b/src/ecc/formal/properties/coverpoints/fv_add_sub_alter_coverpoints.sv new file mode 100644 index 000000000..e0ee82079 --- /dev/null +++ b/src/ecc/formal/properties/coverpoints/fv_add_sub_alter_coverpoints.sv @@ -0,0 +1,45 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_add_sub_alter_coverpoints_m( + input logic clk, + input logic reset_n, + input logic zeroize +); + + default clocking default_clk @(posedge clk); endclocking + + //Cover zeroize: + cover_zeroize: cover property(disable iff(!reset_n) ecc_add_sub_mod_alter.zeroize ); + + cover_prime_p: cover property(disable iff(!reset_n) (ecc_add_sub_mod_alter.prime_i==384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff)); + cover_prime_q: cover property(disable iff(!reset_n)(ecc_add_sub_mod_alter.prime_i==384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973)); + cover_add_en: cover property(disable iff(!reset_n) ecc_add_sub_mod_alter.add_en_i==1); + cover_add_disable: cover property(disable iff(!reset_n) ecc_add_sub_mod_alter.add_en_i==0); + cover_r0_0: cover property(disable iff(!reset_n || zeroize) ecc_add_sub_mod_alter.r0=='0); + cover_r0_1: cover property(disable iff(!reset_n || zeroize) ecc_add_sub_mod_alter.r0=='1); + cover_r0_greater_prime: cover property(disable iff(!reset_n || zeroize) ecc_add_sub_mod_alter.r0 > ecc_add_sub_mod_alter.prime_i); + + +endmodule + +bind ecc_add_sub_mod_alter fv_add_sub_alter_coverpoints_m fv_add_sub_alter_coverpoints( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize) +); diff --git a/src/ecc/formal/properties/coverpoints/fv_arith_unit_coverpoints.sv b/src/ecc/formal/properties/coverpoints/fv_arith_unit_coverpoints.sv new file mode 100644 index 000000000..d024e4294 --- /dev/null +++ b/src/ecc/formal/properties/coverpoints/fv_arith_unit_coverpoints.sv @@ -0,0 +1,86 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_arith_unit_coverpoints_m( + input logic clk, + input logic reset_n, + input logic zeroize +); + + default clocking default_clk @(posedge clk); endclocking + + //Cover zeroize: + cover_zeroize: cover property(disable iff(!reset_n) ecc_arith_unit.zeroize ); + + //cover wea + cover_wea: cover property(disable iff(!reset_n) ( + ecc_arith_unit.ecc_instr_s.opcode.add_en + ##3 + ecc_arith_unit.ram_tdp_file_i.wea)); + + //cover web + cover_wem: cover property(disable iff(!reset_n) + ecc_arith_unit.ecc_instr_s.opcode.mult_en + ##41 + ecc_arith_unit.web_mux_s); + + //cover req_digit when keygen cmd + cover_req_digit_keygen: cover property(disable iff(!reset_n) + ecc_arith_unit.ecc_cmd_i== 3'b001 //KEYGEN_CMD + ##1 + ecc_arith_unit.req_digit[->576]); + + //cover req_digit when signing cmd + cover_req_digit_signing: cover property(disable iff(!reset_n) + ecc_arith_unit.ecc_cmd_i==3'b010 //SIGN_CMD + ##1 + ecc_arith_unit.req_digit[->576]); + + + //cover wr_op_sel_i when ecc_cmd_i is received + cover_wr_op_sel_i: cover property(disable iff(!reset_n) + (ecc_arith_unit.ecc_cmd_i!=3'b0 && !ecc_arith_unit.wr_op_sel_i)); + + //cover wr_en_i when ecc_cmd_i is received + cover_wr_en_i: cover property(disable iff(!reset_n || zeroize) + (ecc_arith_unit.ecc_cmd_i!=3'b0 && !ecc_arith_unit.wr_en_i)); + + //cover sca_en_i + cover_sca_en_always: cover property(disable iff(!reset_n || zeroize) + ecc_arith_unit.sca_en_i ==1); + + //cover digit_in be the MSB bit of secret key + cover_digit_in_msb_secret_key: cover property(disable iff(!reset_n || zeroize) + ecc_arith_unit.req_digit + ##1 + ecc_arith_unit.digit_in == $past(ecc_arith_unit.secret_key[(ecc_arith_unit.REG_SIZE+ecc_arith_unit.RND_SIZE)-1])); + + //cover secret key is shifted with req_digit + cover_req_digit_secret_key: cover property(disable iff(!reset_n || zeroize) + ecc_arith_unit.req_digit + ##1 + ecc_arith_unit.secret_key == $past({ecc_arith_unit.secret_key[(ecc_arith_unit.REG_SIZE+ecc_arith_unit.RND_SIZE)-2 : 0], ecc_arith_unit.secret_key[(ecc_arith_unit.REG_SIZE+ecc_arith_unit.RND_SIZE)-1]})); + + +endmodule + +bind ecc_arith_unit fv_ecc_arith_unit_coverpoints_m fv_ecc_arith_unit_coverpoints( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize) +); \ No newline at end of file diff --git a/src/ecc/formal/properties/coverpoints/fv_ecc_dsa_ctrl_coverpoints.sv b/src/ecc/formal/properties/coverpoints/fv_ecc_dsa_ctrl_coverpoints.sv new file mode 100644 index 000000000..51915d28f --- /dev/null +++ b/src/ecc/formal/properties/coverpoints/fv_ecc_dsa_ctrl_coverpoints.sv @@ -0,0 +1,130 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_dsa_ctrl_coverpoints( + input logic clk, + input logic reset_n, + input logic zeroize +); + + + default clocking default_clk @(posedge clk); endclocking + + //cover zeroize + cover_zeroize: cover property(disable iff(!reset_n) ecc_dsa_ctrl.zeroize_reg ); + +//cover seed_reg + + cover_seed_reg_max: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.seed_reg == 384'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + cover_seed_reg_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.seed_reg =='0); + +//cover nonce_reg + + + cover_nonce_reg_max: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.nonce_reg== 384'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + cover_nonce_reg_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.nonce_reg =='0); + +//cover msg_reg + + cover_msg_reg_max: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.msg_reg == 384'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + cover_msg_reg_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.msg_reg =='0); + + +//cover privkey_reg + + cover_privkey_reg_less_grp_order: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.privkey_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973); + cover_privkey_reg_grt_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.privkey_reg >'0); + +//cover scalar_G_reg + + cover_scalar_G_reg_less_grp_order: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_G_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973); + cover_scalar_G_reg_grt_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_G_reg >'0); + cover_scalar_G_reg_grp_order_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_G_reg == 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972); + cover_scalar_G_reg_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_G_reg == 1); + +//cover scalar_PK_reg + + cover_scalar_PK_reg_less_grp_order: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_PK_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973); + cover_scalar_PK_reg_grt_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_PK_reg >'0); + cover_scalar_PK_reg_grp_order_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_PK_reg == 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972); + cover_scalar_PK_reg_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_PK_reg == 1); + +//cover r_reg + + cover_r_reg_less_grp_order: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.r_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973); + cover_r_reg_grt_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.r_reg >'0); + cover_r_reg_grp_order_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.r_reg == 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972); + cover_r_reg_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.r_reg == 1); + +//cover s_reg + cover_s_reg_less_grp_order: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.s_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973); + cover_s_reg_grt_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.s_reg >'0); + cover_s_reg_grp_order_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.s_reg == 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972); + cover_s_reg_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.s_reg == 1); + + +//cover IV_reg + cover_IV_reg_less_grp_order: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.IV_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973); + cover_IV_reg_grt_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.IV_reg >'0); + cover_IV_reg_grp_order_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.IV_reg == 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972); + cover_IV_reg_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.IV_reg == 1); + +//cover pubkeyx_reg + cover_pubkeyx_reg_less_prime: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.pubkeyx_reg < 384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff); + cover_pubkeyx_reg_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.pubkeyx_reg =='0); + cover_pubkeyx_reg_prime_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.pubkeyx_reg == 384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffe); + cover_pubkeyx_reg_grt_prime: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.pubkeyx_reg > 384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff); + +//cover pubkeyy_reg + cover_pubkeyy_reg_less_prime: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.pubkeyy_reg < 384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff); + cover_pubkeyy_reg_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.pubkeyy_reg =='0); + cover_pubkeyy_reg_prime_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.pubkeyy_reg == 384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffe); + cover_pubkeyy_reg_grt_prime: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.pubkeyy_reg > 384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff); + + +//cover scalar_out_reg + cover_scalar_out_reg_eq_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_out_reg==1); + cover_scalar_out_reg_grp_order_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_out_reg==384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972); + cover_scalar_out_reg_grp_mult: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_out_reg==(1+((2**192)-1)*384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973) ); + cover_scalar_out_reg_grp_order_mult_1: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.scalar_out_reg==(384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972 +((2**192)-1)*384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973) ); + + + +//cover lambda_reg + + cover_lambda_reg_max: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.lambda_reg == 384'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + cover_lambda_reg_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.lambda_reg =='0); + + + +//cover masking_rnd_reg + + cover_masking_rnd_reg_max: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.masking_rnd_reg == 384'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + cover_masking_rnd_reg_zero: cover property(disable iff(!reset_n || zeroize) ecc_dsa_ctrl.masking_rnd_reg =='0); + + + + + +endmodule + +bind ecc_dsa_ctrl fv_ecc_dsa_ctrl_coverpoints fv_ecc_dsa_ctrl_coverpoints_inst ( + .clk(clk), + .reset_n(reset_n), + .zeroize(ecc_dsa_ctrl.zeroize_reg) +); \ No newline at end of file diff --git a/src/ecc/formal/properties/coverpoints/fv_ecc_montgomerymultiplier_coverpoints.sv b/src/ecc/formal/properties/coverpoints/fv_ecc_montgomerymultiplier_coverpoints.sv new file mode 100644 index 000000000..feaf4d2a7 --- /dev/null +++ b/src/ecc/formal/properties/coverpoints/fv_ecc_montgomerymultiplier_coverpoints.sv @@ -0,0 +1,49 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_montgomerymultiplier_coverpoints_m( + input logic clk, + input logic reset_n, + input logic zeroize +); + + default clocking default_clk @(posedge clk); endclocking + +//Cover zeroize: + cover_zeroize: cover property(disable iff(!reset_n) ecc_montgomerymultiplier.zeroize ); + cover_prime_p: cover property(disable iff(!reset_n || zeroize) (ecc_montgomerymultiplier.n_i==384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff)); + cover_group_order: cover property(disable iff(!reset_n || zeroize)(ecc_montgomerymultiplier.n_i==384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973)); + cover_n_prime_i_prime_mu : cover property(disable iff(!reset_n|| zeroize) ecc_montgomerymultiplier.n_prime_i == 32'h00000001); + cover_n_prime_i_group_order_mu : cover property(disable iff(!reset_n|| zeroize) ecc_montgomerymultiplier.n_prime_i == 32'he88fdc45); + cover_opa_i_0 : cover property(disable iff(!reset_n|| zeroize) (ecc_montgomerymultiplier.opa_i == '0)&&(ecc_montgomerymultiplier.opb_i == '0 || ecc_montgomerymultiplier.opb_i == (ecc_montgomerymultiplier.n_i-1)) ); + cover_opa_i_prime_minus_1 : cover property(disable iff(!reset_n|| zeroize) (ecc_montgomerymultiplier.opa_i == (ecc_montgomerymultiplier.n_i-1))&&(ecc_montgomerymultiplier.opb_i == '0 || ecc_montgomerymultiplier.opb_i == (ecc_montgomerymultiplier.n_i-1)) ); + cover_opb_i_0 : cover property(disable iff(!reset_n|| zeroize) (ecc_montgomerymultiplier.opb_i == '0)&&(ecc_montgomerymultiplier.opa_i == '0 || ecc_montgomerymultiplier.opa_i == (ecc_montgomerymultiplier.n_i-1)) ); + cover_opb_i_prime_minus_1 : cover property(disable iff(!reset_n|| zeroize) (ecc_montgomerymultiplier.opb_i == (ecc_montgomerymultiplier.n_i-1))&&(ecc_montgomerymultiplier.opa_i == '0 || ecc_montgomerymultiplier.opa_i == (ecc_montgomerymultiplier.n_i-1)) ); + cover_sub_b_o_zero: cover property(disable iff(!reset_n || zeroize) ecc_montgomerymultiplier.ready_o && ecc_montgomerymultiplier.sub_b_o[2*(ecc_montgomerymultiplier.PE_UNITS+1)]==0); + cover_sub_b_o_one: cover property(disable iff(!reset_n || zeroize) ecc_montgomerymultiplier.ready_o && ecc_montgomerymultiplier.sub_b_o[2*(ecc_montgomerymultiplier.PE_UNITS+1)]== 1); + cover_p_sub_internal: cover property (disable iff(!reset_n || zeroize) !$past(!reset_n || zeroize) && ecc_montgomerymultiplier.ready_o && (ecc_montgomerymultiplier.p_subtracted_internal == ( ecc_montgomerymultiplier.p_internal - ecc_montgomerymultiplier.n_i))); + + + +endmodule + +bind ecc_montgomerymultiplier fv_ecc_montgomerymultiplier_coverpoints_m fv_ecc_montgomerymultiplier_coverpoints( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize) +); \ No newline at end of file diff --git a/src/ecc/formal/properties/coverpoints/fv_ecc_pm_ctrl_coverpoints_m.sv b/src/ecc/formal/properties/coverpoints/fv_ecc_pm_ctrl_coverpoints_m.sv new file mode 100644 index 000000000..60c89d2a7 --- /dev/null +++ b/src/ecc/formal/properties/coverpoints/fv_ecc_pm_ctrl_coverpoints_m.sv @@ -0,0 +1,145 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_pm_ctrl_coverpoints_m import ecc_pm_uop_pkg::*;( + input logic clk, + input logic reset_n, + input logic zeroize +); + + default clocking default_clk @(posedge clk); endclocking + + //cover zeroize + cover_zeroize: cover property(disable iff(!reset_n) ecc_pm_ctrl.zeroize ); + + //cover sca_en_i + cover_sca_en_always: cover property(disable iff(!reset_n || zeroize) + ecc_pm_ctrl.sca_en_i ==1); + + + //cover req_digit when keygen cmd + cover_req_digit_keygen: cover property(disable iff(!reset_n || zeroize) + ecc_pm_ctrl.ecc_cmd_i==KEYGEN_CMD && + ecc_pm_ctrl.prog_cntr == NOP + ##1 + ecc_pm_ctrl.req_digit_o[->576]); + + //cover req_digit when signing cmd + cover_req_digit_signing: cover property(disable iff(!reset_n|| zeroize) + ecc_pm_ctrl.ecc_cmd_i==SIGN_CMD && + ecc_pm_ctrl.prog_cntr == NOP + ##1 + + ecc_pm_ctrl.req_digit_o[->576]); + + //cover req_digit when verifying cmd + cover_req_digit_verifying1: cover property(disable iff(!reset_n|| zeroize) + ecc_pm_ctrl.ecc_cmd_i== VER_PART1_CMD && + ecc_pm_ctrl.prog_cntr == NOP + ##1 + ecc_pm_ctrl.req_digit_o[->384]); + + cover_req_digit_verifying2: cover property(disable iff(!reset_n|| zeroize) + ecc_pm_ctrl.prog_cntr== PM_INIT_PK_S && + ecc_pm_ctrl.ecc_cmd_reg == VER_PART2_CMD + ##1 + ecc_pm_ctrl.req_digit_o[->384]); + + /* + // Keygen Sequence + + cover_keygen_sequence: cover property(disable iff(!reset_n || zeroize) keygen_sequence); + + sequence keygen_sequence; + ecc_pm_ctrl.ecc_cmd_i == KEYGEN_CMD + ##0 ecc_pm_ctrl.prog_cntr == NOP + ##1 ecc_pm_ctrl.prog_cntr == PM_INIT_G_S + ##123 ecc_pm_ctrl.prog_cntr == PM_INIT_S + ##16 ecc_pm_ctrl.prog_cntr == PA_S + ##789 ecc_pm_ctrl.prog_cntr == PD_S + ##910443 ecc_pm_ctrl.prog_cntr == INV_S + ##21201 ecc_pm_ctrl.prog_cntr == CONV_S + ##167 ecc_pm_ctrl.prog_cntr == CONV_E + ##1 ecc_pm_ctrl.prog_cntr == NOP; + endsequence + + + // Signing Sequence + + cover_signing_sequence: cover property(disable iff(!reset_n || zeroize) signing_sequence); + sequence signing_sequence; + ecc_pm_ctrl.ecc_cmd_i == SIGN_CMD + ##0 ecc_pm_ctrl.prog_cntr == NOP + ##1 ecc_pm_ctrl.prog_cntr == PM_INIT_G_S + ##123 ecc_pm_ctrl.prog_cntr == PM_INIT_S + ##16 ecc_pm_ctrl.prog_cntr == PA_S + ##789 ecc_pm_ctrl.prog_cntr == PD_S + ##910443 ecc_pm_ctrl.prog_cntr == INV_S + ##21201 ecc_pm_ctrl.prog_cntr == CONV_S + ##168 ecc_pm_ctrl.prog_cntr == SIGN0_S + ##311 ecc_pm_ctrl.prog_cntr == INVq_S + ##21205 ecc_pm_ctrl.prog_cntr == SIGN1_S + ##131 ecc_pm_ctrl.prog_cntr == NOP; + endsequence + + // Verify Sequence + cover_verify_part0_sequence: cover property(disable iff(!reset_n || zeroize) verify_part0_sequence); + sequence verify_part0_sequence; + ecc_pm_ctrl.ecc_cmd_i == VER_PART0_CMD + ##0 ecc_pm_ctrl.prog_cntr == NOP + ##1 ecc_pm_ctrl.prog_cntr == VER0_P0_S + ##127 ecc_pm_ctrl.prog_cntr == INVq_S + ##21205 ecc_pm_ctrl.prog_cntr == VER0_P1_S + ##168 ecc_pm_ctrl.prog_cntr == NOP; + endsequence + + cover_verify_part1_sequence: cover property(disable iff(!reset_n || zeroize) verify_part1_sequence); + sequence verify_part1_sequence; + ecc_pm_ctrl.ecc_cmd_i == VER_PART1_CMD + ##0 ecc_pm_ctrl.prog_cntr == NOP + ##1 ecc_pm_ctrl.prog_cntr == PM_INIT_G_S + ##123 ecc_pm_ctrl.prog_cntr == PM_INIT_S + ##16 ecc_pm_ctrl.prog_cntr == PA_S + ##789 ecc_pm_ctrl.prog_cntr == PD_S + ##606699 ecc_pm_ctrl.prog_cntr == NOP; + endsequence + + cover_verify_part2_sequence: cover property(disable iff(!reset_n || zeroize) verify_part2_sequence); + + sequence verify_part2_sequence; + ecc_pm_ctrl.ecc_cmd_i == VER_PART2_CMD + ##0 ecc_pm_ctrl.prog_cntr == NOP + ##1 ecc_pm_ctrl.prog_cntr == VER1_ST_S + ##12 ecc_pm_ctrl.prog_cntr == PM_INIT_PK_S + ##86 ecc_pm_ctrl.prog_cntr == PM_INIT_S + ##16 ecc_pm_ctrl.prog_cntr == PA_S + ##789 ecc_pm_ctrl.prog_cntr == PD_S + ##606699 ecc_pm_ctrl.prog_cntr == VER2_PA_S + ##793 ecc_pm_ctrl.prog_cntr == INV_S + ##21201 ecc_pm_ctrl.prog_cntr == CONV_S + ##168 ecc_pm_ctrl.prog_cntr == NOP; + endsequence + +*/ +endmodule + + bind ecc_pm_ctrl fv_ecc_pm_ctrl_coverpoints_m fv_ecc_pm_ctrl_coverpoints( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize) + ); diff --git a/src/ecc/formal/properties/ecc_reduced_instantiations.sv b/src/ecc/formal/properties/ecc_reduced_instantiations.sv new file mode 100644 index 000000000..c292f3430 --- /dev/null +++ b/src/ecc/formal/properties/ecc_reduced_instantiations.sv @@ -0,0 +1,117 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +module ecc_reduced_instantiations #( + parameter REG_SIZE = 48, + parameter RADIX = 4 +) +( + // Clock and reset. + input wire clk, + input wire reset_n, + input wire zeroize, + + // DATA PORT + input wire start_i, + input wire [REG_SIZE-1:0] opa_i, + input wire [REG_SIZE-1:0] opb_i, + input wire [REG_SIZE-1:0] n_i, + input wire [RADIX-1:0] n_prime_i, // only need the last few bits + output logic [REG_SIZE-1:0] p_o, + output logic ready_o, + + input wire start_in, + // DATA PORT + input wire [RADIX-1:0] a_in, + input wire [RADIX-1:0] b_in, + input wire [RADIX-1:0] p_in, + input wire [RADIX-1:0] s_in, + input wire [RADIX-1:0] n_prime_in, + input wire odd, + + output logic [RADIX-1:0] a_out, + output logic [RADIX-1:0] m_out, + output logic [RADIX :0] c_out +); + +ecc_montgomerymultiplier #( + .REG_SIZE(48), + .RADIX(4) + ) + ecc_montmult_reduced ( + // Clock and reset. + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize), + + // DATA PORT + .start_i(start_i), + .opa_i(opa_i), + .opb_i(opb_i), + .n_i(n_i), + .n_prime_i(n_prime_i), + .p_o(p_o), + .ready_o(ready_o) + ); + +ecc_pe_first #(.RADIX(4)) ecc_pe_first_reduced( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize), + + .start_in(start_in), + .a_in(a_in), + .b_in(b_in), + .p_in(p_in), + .s_in(s_in), + .n_prime_in(n_prime_in), + + .odd(odd), + .a_out(a_out), + .m_out(m_out), + + .c_out(c_out) + ); + + ecc_scalar_blinding #( + .REG_SIZE(24), + .RND_SIZE(12), + .RADIX(2) + ) + ecc_scalar_blinding_reduced( + .clk(clk), + .zeroize(zeroize), + .reset_n(reset_n), + .en_i(/* open */), + .data_i(/* open */), + .rnd_i(/* open */), + .data_o(/* open */), + .busy_o(/* open */) + ); + +endmodule + + +bind ecc_dsa_ctrl ecc_reduced_instantiations ecc_reduced_instantiation_inst ( + .clk(clk), + .reset_n(reset_n), + .zeroize(ecc_dsa_ctrl.zeroize_reg) +); + + diff --git a/src/ecc/formal/properties/fv_add_sub_alter.sv b/src/ecc/formal/properties/fv_add_sub_alter.sv new file mode 100644 index 000000000..dc283e0aa --- /dev/null +++ b/src/ecc/formal/properties/fv_add_sub_alter.sv @@ -0,0 +1,138 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_add_sub_alter_m( + input bit rst_n, + input bit clk, + input bit unsigned [383:0] opa_i, + input bit unsigned [383:0] opb_i, + input bit unsigned [383:0] prime_i, + input bit add_en_i, + input bit sub_en_i, + input bit unsigned [383:0] res_o, + input bit ready_o +); + +function logic[383:0] neg_mod (input logic[383:0] a,input logic[383:0] b,input logic[383:0] c); +logic[383:0] d; + if(a + res_o == 0 && + ready_o == 0; +endproperty + + + + +/////////////////////////////////////////////////////////// +// Property to check (a-b)%c, where the case it holds is // +// when we have add_en pulse,sub_i for 3 cycles // +/////////////////////////////////////////////////////////// + + + +sub_a: assert property (disable iff(!rst_n) sub_p); +property sub_p; +logic [383:0] fv_result; + ##0 add_en_i && sub_en_i + ##0 (1'b1, fv_result = neg_mod(opa_i,opb_i,prime_i)) +|-> + ##2 + (res_o== fv_result) && + (res_o < prime_i) && + ready_o + ; +endproperty + + +/////////////////////////////////////////////////////////// +// Property to check (a+b)%c, where the case it holds is // +// when we have add_en pulse,no sub_en_i for 3 cycles // +/////////////////////////////////////////////////////////// + + + + +add_a: assert property (disable iff(!rst_n) add_p); +property add_p; +logic [383:0] fv_result; + ##0 add_en_i && !sub_en_i + ##0 (1'b1, fv_result = ((385'(opa_i + opb_i)%prime_i))) +|-> + ##2 + res_o== fv_result && + (res_o < prime_i) && + ready_o + ; +endproperty + + +/////////////////////////////////////////////////////////////// +// Property to check the if there isn't any cmd for 2 // +// consecutive cycles then the res would have previous value // +// and ready should be deasserted +/////////////////////////////////////////////////////////////// + + + +no_cmd_a: assert property (disable iff(!rst_n) no_cmd_p); +property no_cmd_p; + !(add_en_i || sub_en_i) + ##1 + !(add_en_i || sub_en_i) +|=> + //res_o== $past(res_o) && + ready_o == 0 +; +endproperty + + +endmodule + + + +bind ecc_add_sub_mod_alter fv_add_sub_alter_m fv_add_sub_alter( + .rst_n(reset_n && !zeroize), + .clk(clk), + .opa_i(opa_i), + .opb_i(opb_i), + .prime_i(prime_i), + .add_en_i(add_en_i), + .sub_en_i(sub_i), + .res_o(res_o), + .ready_o(ready_o) +); diff --git a/src/ecc/formal/properties/fv_add_sub_constraints.sv b/src/ecc/formal/properties/fv_add_sub_constraints.sv new file mode 100644 index 000000000..53c6c327d --- /dev/null +++ b/src/ecc/formal/properties/fv_add_sub_constraints.sv @@ -0,0 +1,70 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_add_sub_constraints ( + input logic clk, + input logic rst_n, + + input logic add_en_i, + input logic sub_i, + input logic[383:0] prime_i, + input logic[383:0] opa_i, + input logic[383:0] opb_i + +); + +default clocking default_clk @(posedge clk); endclocking +//--------------------------------// +// Can be any of the 2 primes // +//--------------------------------// + +prime_as_p_q: assume property((prime_i==384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973) || (prime_i==384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff) ); + +//--------------------------------------// +// stable operands once cmd initiated // +//--------------------------------------// + +stable_operands: assume property(add_en_i |-> ((opa_i < prime_i) && (opb_i < prime_i) ##1($stable(opa_i) && $stable(opb_i) && $stable(prime_i))[*2])); + + +//----------------------------------------------// +// cmd sequence: // +// if add then no add and sub for next 2 cycles // +// if sub then no add but sub for next 2 cycles // +//----------------------------------------------// + +if_add_then_cmd_is_pulse: assume property(add_en_i && !sub_i|=> (!add_en_i && !sub_i )[*2]); +if_sub_then_stays_for_2cycles: assume property(add_en_i && sub_i |=> (!add_en_i && sub_i )[*2]); + + +//---------------------------------------------// +// Inputs zero during reset // +//----------------------------------------------// + +inputs_zero_during_reset: assume property($past(!rst_n) |-> opa_i==0 && opb_i==0 && !add_en_i && !sub_i); + +endmodule +bind ecc_add_sub_mod_alter fv_add_sub_constraints fv_constraints_m ( + .clk(clk), + .rst_n(reset_n && !zeroize), + .add_en_i(add_en_i), + .sub_i(sub_i), + .prime_i(prime_i), + .opa_i(opa_i), + .opb_i(opb_i) +); \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_dsa_ctrl_constraints.sv b/src/ecc/formal/properties/fv_dsa_ctrl_constraints.sv new file mode 100644 index 000000000..09d962409 --- /dev/null +++ b/src/ecc/formal/properties/fv_dsa_ctrl_constraints.sv @@ -0,0 +1,204 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_dsa_ctrl_constraints_m + import ecc_params_pkg::*; + import ecc_dsa_uop_pkg::*; + import ecc_reg_pkg::*; + import kv_defines_pkg::*; #( + parameter PM_DLY = 5, + parameter SCA_DLY = 3, + parameter HMAC_DLY = 4 + ) + ( + // Clock and reset. + input wire clk, + input wire reset_n, + input wire cptra_pwrgood, + + // Reg ports. + input ecc_reg__out_t hwif_out, + input ecc_reg__in_t hwif_in, + + // KV interface + input kv_read_t [1:0] kv_read, + input kv_write_t kv_write, + input kv_rd_resp_t [1:0] kv_rd_resp, + input kv_wr_resp_t kv_wr_resp, + + //PCR Signing + input pcr_signing_t pcr_signing_data, + + // Interrupts (from ecc_reg) + input logic error_intr, + input logic notif_intr, + input logic debugUnlock_or_scan_mode_switch + ); + + default clocking default_clk @(posedge clk); endclocking + + //////////////////////////////////////////////////// + // stability of the primary inputs + //////////////////////////////////////////////////// + + logic fv_end_step; + logic fv_new_inp; + always_comb begin: end_step + fv_end_step = (ecc_dsa_ctrl.prog_cntr == DSA_KG_E-1)||(ecc_dsa_ctrl.prog_cntr == DSA_SGN_E-1)||(ecc_dsa_ctrl.prog_cntr == DSA_VER_E-1); + end + always_ff @(posedge clk, negedge reset_n) begin + if(!reset_n) begin + fv_new_inp <= 0; + end + else if (hwif_out.ECC_CTRL.ZEROIZE.value || debugUnlock_or_scan_mode_switch) begin + fv_new_inp <= 0; + end + else begin + if(hwif_in.ecc_ready) begin + fv_new_inp <= 1; + end + else if(fv_end_step) begin + fv_new_inp <= 0; + end + end + end + + + + + property stable_input_p(inp); + fv_new_inp |-> $stable(inp); + endproperty + +for (genvar word=0; word < 12; word++)begin + stable_privkey: assume property(stable_input_p(hwif_out.ECC_PRIVKEY_IN[11-word].PRIVKEY_IN.value)); + stable_seed: assume property(stable_input_p(hwif_out.ECC_SEED[11-word].SEED.value)); + stable_nonce: assume property(stable_input_p(hwif_out.ECC_NONCE[11-word].NONCE.value)); + stable_msg: assume property(stable_input_p(hwif_out.ECC_MSG[11-word].MSG.value)); + stable_pubkx: assume property(stable_input_p(hwif_out.ECC_PUBKEY_X[11-word].PUBKEY_X.value)); + stable_pubky: assume property(stable_input_p(hwif_out.ECC_PUBKEY_Y[11-word].PUBKEY_Y.value)); + stable_r: assume property(stable_input_p(hwif_out.ECC_SIGN_R[11-word].SIGN_R.value)); + stable_s: assume property(stable_input_p(hwif_out.ECC_SIGN_S[11-word].SIGN_S.value)); + stable_IV: assume property(stable_input_p(hwif_out.ECC_IV[11-word].IV.value)); + stable_cmd: assume property(stable_input_p(hwif_out.ECC_CTRL.CTRL.value)); + stable_pcr: assume property(stable_input_p(hwif_out.ECC_CTRL.PCR_SIGN.value)); +end + + + property no_cmd_when_not_ready_p; + !fv_new_inp + |-> + hwif_out.ECC_CTRL.CTRL.value == '0; + endproperty + + no_cmd: assume property(no_cmd_when_not_ready_p); + +`ifndef TOP + + //////////////////////////////////////////////////// + // Reduced working model for busy in order to check the + // design doesn't have deadlock + //////////////////////////////////////////////////// + + logic [5:0] pm_cntr; + logic [5:0] sca_cntr; + logic [5:0] hmac_cntr; + logic pm_busy; + logic sca_busy; + logic hmc_busy; + + always_ff @(posedge clk, negedge reset_n) begin + if(!reset_n) begin + pm_busy <= 0; + hmc_busy <= 0; + sca_busy <= 0; + pm_cntr <= 0; + hmac_cntr <= 0; + sca_cntr <= 0; + end + else if (hwif_out.ECC_CTRL.ZEROIZE.value || debugUnlock_or_scan_mode_switch) begin + pm_busy <= 0; + hmc_busy <= 0; + sca_busy <= 0; + pm_cntr <= 0; + hmac_cntr <= 0; + sca_cntr <= 0; + end + else begin + if(ecc_dsa_ctrl.pm_cmd_reg!=no_cmd)begin + pm_cntr <= PM_DLY; + end + if(ecc_dsa_ctrl.hmac_init) begin + hmac_cntr <= HMAC_DLY; + end + + if(ecc_dsa_ctrl.scalar_sca_en) begin + sca_cntr <= SCA_DLY; + end + if(pm_cntr > 0) begin + pm_busy <= 1; + pm_cntr <= pm_cntr-1; + end + if(pm_cntr == 0) begin + pm_busy <= 0; + end + if(sca_cntr > 0) begin + sca_busy <= 1; + sca_cntr <= sca_cntr-1; + end + if(sca_cntr == 0) begin + sca_busy <= 0; + end + if(hmac_cntr > 0) begin + hmc_busy <= 1; + hmac_cntr <= hmac_cntr-1; + end + if(hmac_cntr == 0) begin + hmc_busy <= 0; + end + end + end + + + pm_busy_assume: assume property(ecc_dsa_ctrl.pm_busy_o == pm_busy); + sca_busy_assume: assume property(ecc_dsa_ctrl.scalar_sca_busy_o == sca_busy); + hmac_busy_assume: assume property(ecc_dsa_ctrl.hmac_busy == hmc_busy); + +`endif + + +endmodule + +bind ecc_dsa_ctrl fv_dsa_ctrl_constraints_m fv_dsa_ctrl_constraints ( + .clk(clk), + .reset_n(reset_n), + .cptra_pwrgood(cptra_pwrgood), + + .hwif_out(hwif_out), + .hwif_in(hwif_in), + + .kv_read(kv_read), + .kv_rd_resp(kv_rd_resp), + .kv_write(kv_write), + .kv_wr_resp(kv_wr_resp), + .pcr_signing_data(pcr_signing_data), + + .error_intr(error_intr), + .notif_intr(notif_intr), + .debugUnlock_or_scan_mode_switch(debugUnlock_or_scan_mode_switch) + ); \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_ecc_arith_unit.sv b/src/ecc/formal/properties/fv_ecc_arith_unit.sv new file mode 100644 index 000000000..674a06b54 --- /dev/null +++ b/src/ecc/formal/properties/fv_ecc_arith_unit.sv @@ -0,0 +1,263 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_arith_unit + #( + parameter REG_SIZE = 384, + parameter RND_SIZE = 192, + parameter RADIX = 32, + parameter ADDR_WIDTH = 6, + parameter [REG_SIZE-1 : 0] p_prime = 384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff, + parameter [RADIX-1 : 0] p_mu = 32'h00000001, + parameter [REG_SIZE-1 : 0] q_grouporder = 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973, + parameter [RADIX-1 : 0] q_mu = 32'he88fdc45 + ) + ( + // Clock and reset. + input wire clk, + input wire rst_n, + + + // DATA PORT + input wire [2 : 0] ecc_cmd_i, + input wire sca_en_i, + input wire [ADDR_WIDTH-1 : 0] addr_i, + input wire wr_op_sel_i, + input wire wr_en_i, + input wire rd_reg_i, + input wire [(REG_SIZE+RND_SIZE)-1 : 0] data_i, + input wire [REG_SIZE-1: 0] data_o, + input wire busy_o + ); + + + default clocking default_clk @(posedge clk); endclocking + +no_busy_assume: assume property($past(!rst_n) |-> !ecc_arith_unit.ecc_busy_s); // used only when pm_ctrl is blackboxed + sequence reset_sequence; + !rst_n ##1 rst_n; + endsequence + + +//////////////////////////////////////////// +// reset property, when reset data_o // +// are zero // +//////////////////////////////////////////// + + + property reset_p; + $past(!rst_n) + |-> + busy_o == '0 && //open wire when black boxed + data_o == '0 && + ecc_arith_unit.reg_dinb_r == '0 && + ecc_arith_unit.reg_addr_r == '0 && + ecc_arith_unit.reg_web_r == 0 && + ecc_arith_unit.secret_key == '0; + endproperty + + reset_a : assert property(reset_p); + + +//////////////////////////////////////////// +// if read reg enabled then data_o has // +// the mem out of b // +//////////////////////////////////////////// + + property dout_p; + rd_reg_i + |=> + data_o == $past(ecc_arith_unit.opb_s); + endproperty + dout_a: assert property(disable iff(!rst_n) dout_p); + + property no_dout_p; + !rd_reg_i + |=> + data_o == '0; + endproperty + no_dout_a: assert property(disable iff(!rst_n) no_dout_p); + + +//////////////////////////////////////////// +// If busy then the mux determines inputs // +// for the ram // +//////////////////////////////////////////// + + + property busy_mux; + ecc_arith_unit.ecc_busy_s + |-> + ecc_arith_unit.addrb_mux_s == ecc_arith_unit.ecc_instr_s.opb_addr && + ecc_arith_unit.web_mux_s == ecc_arith_unit.ecc_instr_s.opcode.mult_we && + ecc_arith_unit.dinb_mux_s ==ecc_arith_unit.mult_res_s; + endproperty + + busy_mux_a: assert property(disable iff(!rst_n) busy_mux); + + +//If not busy then ram addrb takes addr_i + property not_busy_addr_mux_p; + !ecc_arith_unit.ecc_busy_s + |-> + ecc_arith_unit.addrb_mux_s == ecc_arith_unit.reg_addr_r; + + endproperty + not_busy_addr_mux_a: assert property(disable iff(!rst_n) not_busy_addr_mux_p); + + + +//If not busy and the previous cycle there isn't wr_op_sel then web takes wr_en_i + property not_busy_web_mux_p; + !wr_op_sel_i + ##1 !ecc_arith_unit.ecc_busy_s + |-> + ecc_arith_unit.web_mux_s == $past(wr_en_i); + endproperty + not_busy_web_mux_a: assert property(disable iff(!rst_n) not_busy_web_mux_p); + + + +//if not busy and in the previous clcok tick there is wr_en_i and no wr_op_sel then dinb takes data_i + property not_busy_dinb_mux_p; + wr_en_i && + !wr_op_sel_i + ##1 !ecc_arith_unit.ecc_busy_s + |-> + ecc_arith_unit.dinb_mux_s == REG_SIZE'($past(data_i)); + + endproperty + not_busy_dinb_mux_a: assert property(disable iff(!rst_n) not_busy_dinb_mux_p); + + +//If mod_q_sel is set then the prime should be selected as group order + property prime_selection_as_q_p; + ecc_arith_unit.ecc_instr_s.opcode.mod_q_sel + |-> + ecc_arith_unit.adder_prime == q_grouporder && + ecc_arith_unit.mult_mu == q_mu; + endproperty + prime_selection_as_q_a: assert property(disable iff(!rst_n)prime_selection_as_q_p); + +//If mod_q_sel is not set then the prime should be selected as the p (prime) + property prime_selection_as_p_p; + !ecc_arith_unit.ecc_instr_s.opcode.mod_q_sel + |-> + ecc_arith_unit.adder_prime == p_prime && + ecc_arith_unit.mult_mu == p_mu; + endproperty + prime_selection_as_p_a: assert property(disable iff(!rst_n)prime_selection_as_p_p); + +//If req_digit is set and no wr_en then the secret_key should be shifted + property req_digit_p; + ecc_arith_unit.req_digit && + !wr_en_i + |=> + ecc_arith_unit.secret_key == ($past({ecc_arith_unit.secret_key[(REG_SIZE+RND_SIZE)-2 : 0], ecc_arith_unit.secret_key[(REG_SIZE+RND_SIZE)-1]})); + endproperty + req_digit_a: assert property(disable iff(!rst_n)req_digit_p); + + +//If req_digit isn't set then and no wr_En then the secret_key should hold the previous value + property no_req_digit_p; + !ecc_arith_unit.req_digit && + !wr_en_i + |=> + ecc_arith_unit.secret_key == $past( ecc_arith_unit.secret_key); + endproperty + no_req_digit_a: assert property(disable iff(!rst_n) no_req_digit_p); + + +//If wr_en is set and the wr_op_Sel is set then secret_key should take the value of +//data_i and reg_dinb_r should hold the previous value + property wr_en_op_sel_p; + wr_en_i && + wr_op_sel_i + |=> + ecc_arith_unit.secret_key == $past(data_i)&& + ecc_arith_unit.reg_dinb_r == $past(ecc_arith_unit.reg_dinb_r); + endproperty + wr_en_op_sel_a: assert property(disable iff(!rst_n)wr_en_op_sel_p); + + +//If wr_en is set and the wr_op_Sel isn't set then secret_key shouldhold the previous value +//and reg_dinb_r should take the data_i + property wr_en_no_op_sel_p; + wr_en_i && + !wr_op_sel_i + |=> + ecc_arith_unit.secret_key == $past( ecc_arith_unit.secret_key) && + ecc_arith_unit.reg_dinb_r == $past(data_i[REG_SIZE-1 : 0]); + endproperty + wr_en_no_op_sel_a: assert property(disable iff(!rst_n)wr_en_no_op_sel_p); + + +//If no wr_En then reg_dinb_r should hold the previous value + property no_wr_en_i_p; + !wr_en_i + |=> + ecc_arith_unit.reg_dinb_r == $past(ecc_arith_unit.reg_dinb_r); + endproperty + no_wr_en_i_a: assert property(disable iff(!rst_n)no_wr_en_i_p); + + +//reg_addr_r always takes the addr_i + // Helper logic for reset reg to use in disable iff + logic fv_rst_n_reg; + always_ff @(posedge clk) begin + fv_rst_n_reg <= rst_n; + end + + property reg_addr_r_p; + ecc_arith_unit.reg_addr_r == $past(addr_i); + endproperty + reg_addr_r_a: assert property(disable iff(!rst_n || !fv_rst_n_reg)reg_addr_r_p); + + +//digit_in is always equal to the MSB bit of the secretkey, which when shifted becomes secret_key[0] + property digit_in_p; + ecc_arith_unit.digit_in == ecc_arith_unit.secret_key[0]; + endproperty + digit_in_a: assert property(disable iff(!rst_n)digit_in_p); + +endmodule + +bind ecc_arith_unit fv_ecc_arith_unit#( + .REG_SIZE(REG_SIZE), + .RND_SIZE(RND_SIZE), + .RADIX(RADIX), + .ADDR_WIDTH(ADDR_WIDTH), + .p_prime(p_prime), + .p_mu(p_mu), + .q_grouporder(q_grouporder), + .q_mu(q_mu) + ) + fv_ecc_arith_unit_inst ( + .clk(clk), + .rst_n(reset_n && !zeroize), + .ecc_cmd_i(ecc_cmd_i), + .sca_en_i(sca_en_i), + .addr_i(addr_i), + .wr_op_sel_i(wr_op_sel_i), + + .wr_en_i(wr_en_i), + .rd_reg_i(rd_reg_i), + .data_i(data_i), + .data_o(data_o), + .busy_o(busy_o) + ); \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_ecc_dsa_ctrl.sv b/src/ecc/formal/properties/fv_ecc_dsa_ctrl.sv new file mode 100644 index 000000000..cf0a85a76 --- /dev/null +++ b/src/ecc/formal/properties/fv_ecc_dsa_ctrl.sv @@ -0,0 +1,1428 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_dsa_ctrl_m + import ecc_params_pkg::*; + import ecc_dsa_uop_pkg::*; + import ecc_reg_pkg::*; + import kv_defines_pkg::*; + ( + // Clock and reset. + input logic clk, + input logic reset_n, + input logic cptra_pwrgood, + // Reg ports. + input ecc_reg__out_t hwif_out, + input ecc_reg__in_t hwif_in, //output + + // KV interface + input kv_read_t [1:0] kv_read, //output + input kv_write_t kv_write, //output + input kv_rd_resp_t [1:0] kv_rd_resp, + input kv_wr_resp_t kv_wr_resp, + + //PCR Signing + input pcr_signing_t pcr_signing_data, + + // Interrupts (from ecc_reg) + input logic error_intr, //output + input logic notif_intr, //output + input logic debugUnlock_or_scan_mode_switch + ); + + localparam CYC_CNT = 4; // Equivalent to cycle count in DUT + + default clocking default_clk @(posedge clk); endclocking + + + //////////////////////////////////////////// + // Helper logic used for defining zeroize + //////////////////////////////////////////// + + logic fv_zeroize; + + always_comb begin: logic_zeroize + fv_zeroize = hwif_out.ECC_CTRL.ZEROIZE.value || debugUnlock_or_scan_mode_switch; + end + + //////////////////////////////////////////// + // Helper logic used in disabling the proofs + // once the error is set in the design + // then fv_error_set stays asserted until reset_n or zeroize + //////////////////////////////////////////// + + logic fv_error_set, fv_error; + always_ff @(posedge clk, negedge reset_n) begin + if(!reset_n) begin + fv_error_set <= 0; + end + else if(fv_zeroize) begin + fv_error_set <= 0; + end + else begin + if(ecc_dsa_ctrl.error_flag) begin + fv_error_set <= 1; + end + end + end + + + //////////////////////////////////////////// + // Helper logic for write_reg look up + + logic [(REG_SIZE+RND_SIZE)-1 : 0] fv_write_reg; + logic [DSA_OPR_ADDR_WIDTH-1:0] fv_reg_id; + + assign fv_reg_id = ecc_dsa_ctrl.prog_instr.reg_id; + + always_comb begin: fv_write_reg_logic + fv_write_reg = '0; + if(ecc_dsa_ctrl.prog_instr.opcode == DSA_UOP_WR_CORE) begin + unique casez (fv_reg_id) + CONST_ZERO_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ZERO_CONST}; + CONST_ONE_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ONE_CONST}; + CONST_E_a_MONT_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, E_a_MONT}; + CONST_E_b_MONT_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, E_b_MONT}; + CONST_E_3b_MONT_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, E_3b_MONT}; + CONST_ONE_p_MONT_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ONE_p_MONT}; + CONST_R2_p_MONT_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, R2_p_MONT}; + CONST_G_X_MONT_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, G_X_MONT}; + CONST_G_Y_MONT_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, G_Y_MONT}; + CONST_R2_q_MONT_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, R2_q_MONT}; + CONST_ONE_q_MONT_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ONE_q_MONT}; + MSG_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ecc_dsa_ctrl.msg_reduced_reg}; + PRIVKEY_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ecc_dsa_ctrl.privkey_reg}; + PUBKEYX_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ecc_dsa_ctrl.pubkeyx_reg}; + PUBKEYY_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ecc_dsa_ctrl.pubkeyy_reg}; + R_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ecc_dsa_ctrl.r_reg}; + S_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ecc_dsa_ctrl.s_reg}; + SCALAR_G_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ecc_dsa_ctrl.scalar_G_reg}; + LAMBDA_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ecc_dsa_ctrl.lambda_reg}; + MASKING_ID : fv_write_reg = {ecc_dsa_ctrl.zero_pad, ecc_dsa_ctrl.masking_rnd_reg}; + default : fv_write_reg = '0; + endcase + end + else if(ecc_dsa_ctrl.prog_instr.opcode == DSA_UOP_WR_SCALAR) begin + unique casez (fv_reg_id) + SCALAR_G_ID : fv_write_reg = (ecc_dsa_ctrl.scalar_G_reg << RND_SIZE); + SCALAR_PK_ID : fv_write_reg = (ecc_dsa_ctrl.scalar_PK_reg << RND_SIZE); + SCALAR_ID : fv_write_reg = ecc_dsa_ctrl.scalar_out_reg; // SCA + default : fv_write_reg = '0; + endcase + end + + end + + + //////////////////////////////////////////// + // Helper logic for read_reg look up + + logic [DSA_PROG_ADDR_W-1 : 0] fv_prog_cntr_reg; + logic fv_hw_privkey_we; + logic fv_hw_pubkeyx_we; + logic fv_hw_pubkeyy_we; + logic fv_hw_r_we; + logic fv_hw_s_we; + logic fv_hw_scalar_G_we ; + logic fv_hw_scalar_PK_we; + logic fv_hw_verify_r_we; + logic fv_hw_pk_chk_we; + + always_ff @(posedge clk) begin + fv_prog_cntr_reg <= ecc_dsa_ctrl.prog_cntr; + end + + always_comb begin: wr_en_logic + fv_hw_privkey_we = 0; + fv_hw_pubkeyx_we = 0; + fv_hw_pubkeyy_we = 0; + fv_hw_r_we = 0; + fv_hw_s_we = 0; + fv_hw_scalar_G_we = 0; + fv_hw_scalar_PK_we = 0; + fv_hw_verify_r_we = 0; + fv_hw_pk_chk_we = 0; + if (ecc_dsa_ctrl.prog_instr.opcode == DSA_UOP_RD_CORE && fv_prog_cntr_reg!= ecc_dsa_ctrl.prog_cntr) begin + unique casez (fv_reg_id) + PRIVKEY_ID : fv_hw_privkey_we = 1; + PUBKEYX_ID : fv_hw_pubkeyx_we = 1; + PUBKEYY_ID : fv_hw_pubkeyy_we = 1; + R_ID : fv_hw_r_we = 1; + S_ID : fv_hw_s_we = 1; + SCALAR_G_ID : fv_hw_scalar_G_we = 1; + SCALAR_PK_ID : fv_hw_scalar_PK_we = 1; + VERIFY_R_ID : fv_hw_verify_r_we = 1; + PK_VALID_ID : fv_hw_pk_chk_we = 1; + default : + begin + fv_hw_privkey_we = 0; + fv_hw_pubkeyx_we = 0; + fv_hw_pubkeyy_we = 0; + fv_hw_r_we = 0; + fv_hw_s_we = 0; + fv_hw_scalar_G_we = 0; + fv_hw_scalar_PK_we = 0; + fv_hw_verify_r_we = 0; + fv_hw_pk_chk_we = 0; + end + endcase + end + end + + sequence reset_sequence; + (!reset_n || fv_zeroize) ##1 reset_n && !fv_zeroize; + endsequence + + + //////////////////////////////////////////// + // reset property, when reset all the o/p // + // are zero // + //////////////////////////////////////////// + + property reset_p; + $past(!reset_n || fv_zeroize) + |-> + + ecc_dsa_ctrl.prog_cntr == DSA_RESET && + ecc_dsa_ctrl.cycle_cnt == '0 && + ecc_dsa_ctrl.pm_cmd_reg == '0 && + hwif_in.ECC_STATUS.VALID.next == '0 && + ecc_dsa_ctrl.scalar_G_sel == '0 && + ecc_dsa_ctrl.hmac_mode == '0 && + ecc_dsa_ctrl.hmac_init == '0 && + ecc_dsa_ctrl.scalar_sca_en == '0 && + ecc_dsa_ctrl.keygen_process == '0 && + ecc_dsa_ctrl.signing_process == '0 && + ecc_dsa_ctrl.scalar_G_reg == '0 && + ecc_dsa_ctrl.scalar_PK_reg == '0 && + ecc_dsa_ctrl.pk_chk_reg == '0 && + ecc_dsa_ctrl.kv_reg == '0 && + ecc_dsa_ctrl.scalar_in_reg == '0 && + ecc_dsa_ctrl.verifying_process == '0 && + ecc_dsa_ctrl.kv_read_data_present == '0; + endproperty + + reset_a : assert property(reset_p); + + + //////////////////////////////////////////// + // zeroize property, when set the resp. o/p // + // are zero // + //////////////////////////////////////////// + + + property zeroize_p(word); + (fv_zeroize) + |-> + hwif_in.ECC_PRIVKEY_IN[word].PRIVKEY_IN.hwclr && + hwif_in.ECC_PRIVKEY_OUT[word].PRIVKEY_OUT.hwclr && + hwif_in.ECC_NONCE[word].NONCE.hwclr && + hwif_in.ECC_MSG[word].MSG.hwclr && + hwif_in.ECC_PUBKEY_X[word].PUBKEY_X.hwclr && + hwif_in.ECC_PUBKEY_Y[word].PUBKEY_Y.hwclr && + hwif_in.ECC_SIGN_R[word].SIGN_R.hwclr && + hwif_in.ECC_SIGN_S[word].SIGN_S.hwclr && + hwif_in.ECC_VERIFY_R[word].VERIFY_R.hwclr && + hwif_in.ECC_IV[word].IV.hwclr && + hwif_in.ECC_SEED[word].SEED.hwclr ; + endproperty + + + property no_zeroize_p(word); + !(fv_zeroize) + |-> + ! hwif_in.ECC_PRIVKEY_IN[word].PRIVKEY_IN.hwclr && + ! hwif_in.ECC_PRIVKEY_OUT[word].PRIVKEY_OUT.hwclr && + ! hwif_in.ECC_NONCE[word].NONCE.hwclr && + ! hwif_in.ECC_MSG[word].MSG.hwclr && + ! hwif_in.ECC_PUBKEY_X[word].PUBKEY_X.hwclr && + ! hwif_in.ECC_PUBKEY_Y[word].PUBKEY_Y.hwclr && + ! hwif_in.ECC_SIGN_R[word].SIGN_R.hwclr && + ! hwif_in.ECC_VERIFY_R[word].VERIFY_R.hwclr && + ! hwif_in.ECC_IV[word].IV.hwclr; + endproperty + + + // seed clr when there isn't any zeroize depends on the keyvault read status + property no_zeroize_seed_clr_p(word); + !(fv_zeroize) + |-> + hwif_in.ECC_SEED[word].SEED.hwclr == (ecc_dsa_ctrl.privkey_out_we && ecc_dsa_ctrl.kv_read_data_present); + endproperty + + for(genvar i=0 ;i< REG_NUM_DWORDS;i++) begin + no_zeroize_a: assert property(no_zeroize_p(i)); + zeroize_a: assert property(zeroize_p(i)); + no_zeroize_seed_clr_a: assert property(disable iff(fv_error_set)no_zeroize_seed_clr_p(i)); + end + + + + + // Store constant values once the reset or zeorize triggered. + + + property store_const_after_reset_p; + ecc_dsa_ctrl.prog_cntr == DSA_RESET + |-> + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 1 + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 2 + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 3 + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 4 + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 5 + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 6 + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 7 + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 8 + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 9 + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 10 + ##CYC_CNT ecc_dsa_ctrl.prog_cntr == 11; + endproperty + store_const_after_reset_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)store_const_after_reset_p); + + + property store_const_end_p; + (ecc_dsa_ctrl.prog_cntr == 11) [*CYC_CNT] + |=> + ecc_dsa_ctrl.prog_cntr == DSA_NOP; + endproperty + + store_const_end_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)store_const_end_p); + + + // Before start of operations these constants are stored and stays stable until unless reset or zeroize + property stable_const_mem_p; + ecc_dsa_ctrl.prog_cntr >= DSA_NOP + |-> + $stable(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.mem[0]) && + $stable(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.mem[1]) && + $stable(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.mem[2]) && + $stable(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.mem[3]) && + $stable(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.mem[4]) && + $stable(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.mem[5]) && + $stable(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.mem[6]) && + $stable(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.mem[7]) && + $stable(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.mem[28]) && + $stable(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.mem[29]); + endproperty + stable_const_mem_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)stable_const_mem_p); + + +///////////////////////////////////////////////////////////////////////////////////// +// ---------------------------------BEGIN----------------------------------------- // +// Checking the counter integrity that the sequence is performed one after another // +///////////////////////////////////////////////////////////////////////////////////// + + logic [DSA_PROG_ADDR_W-1 : 0] counter_const_a, counter_const_b; + logic triggered_counter_const_a,triggered_counter_const_b; + + + counter_const_a_assume: assume property(disable iff(!reset_n || fv_zeroize) (counter_const_a >=0) && (counter_const_a <=DSA_NOP) && $stable(counter_const_a)); + counter_const_b_assume: assume property(disable iff(!reset_n || fv_zeroize) (counter_const_b <=DSA_NOP) && (counter_const_b > counter_const_a) && $stable(counter_const_b)); + + + always_ff @(posedge clk, negedge reset_n) begin + if(!reset_n ||fv_zeroize ) begin + triggered_counter_const_a <= 0; + triggered_counter_const_b <= 0; + end + else begin + + if(ecc_dsa_ctrl.prog_cntr==counter_const_a) + triggered_counter_const_a <=1; + if (ecc_dsa_ctrl.prog_cntr==counter_const_b) + triggered_counter_const_b <= 1; + end + end + + + property counter_const_liveness_p(trigered); + ecc_dsa_ctrl.prog_cntr == DSA_RESET && + !(ecc_dsa_ctrl.error_flag_edge) && + !(ecc_dsa_ctrl.subcomponent_busy) + |-> + s_eventually(trigered); + endproperty + + counter_const_a_liveness_a: assert property(disable iff(!reset_n || fv_zeroize|| fv_error_set)counter_const_liveness_p(triggered_counter_const_a)); + counter_const_b_liveness_a: assert property(disable iff(!reset_n || fv_zeroize|| fv_error_set) counter_const_liveness_p(triggered_counter_const_b)); + + + property order_check_p(triggered_a,triggered_b); + triggered_b + |=> + $past(triggered_a); + endproperty + counter_integrity_const_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) order_check_p(triggered_counter_const_a,triggered_counter_const_b)); + + + + +///////////////////////////////////////////////////////////////////////////////////// +// ------------------------------------END---------------------------------------- // +///////////////////////////////////////////////////////////////////////////////////// + + +`ifdef REDUCED_PM_CTRL + + // This property works on the reduced version of the pm_ctrl + property keygen_sequence_p; + hwif_out.ECC_CTRL.CTRL.value == KEYGEN && + ecc_dsa_ctrl.prog_cntr == DSA_NOP && + !(ecc_dsa_ctrl.error_flag_edge) && + !(ecc_dsa_ctrl.subcomponent_busy) + |=> + ecc_dsa_ctrl.prog_cntr == DSA_KG_S + ##4 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 1 + ##2 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 2 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 3 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 4 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 5 + ##2 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 6 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 7 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 8 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 9 + ##26 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 10 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 11 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_KG_S+ 12 + ; + endproperty + + keygen_sequence_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)keygen_sequence_p); + `endif + + + // Proves the liveliness that once the cmd is triggered eventually it would have a valid + property sequence_valid_p(cmd); + hwif_out.ECC_CTRL.CTRL.value == cmd && + ecc_dsa_ctrl.prog_cntr == DSA_NOP && + !(ecc_dsa_ctrl.error_flag_edge) && + !(ecc_dsa_ctrl.subcomponent_busy) + |-> + s_eventually(hwif_in.ECC_STATUS.VALID.next); + endproperty + + keygen_sequence_valid_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)sequence_valid_p(KEYGEN)); + signing_sequence_valid_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)sequence_valid_p(SIGN)); + verify_sequence_valid_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)sequence_valid_p(VERIFY)); + + + // At the last step of the cmd sequence, the valid signal should be asserted + property valid_set_end_seq_p(end_st); + ecc_dsa_ctrl.prog_cntr == end_st + ##1 ecc_dsa_ctrl.prog_cntr != fv_prog_cntr_reg + |-> + hwif_in.ECC_STATUS.VALID.next; + endproperty + keygen_valid_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)valid_set_end_seq_p(DSA_KG_E)); + signing_valid_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)valid_set_end_seq_p(DSA_SGN_E)); + verify_valid_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)valid_set_end_seq_p(DSA_VER_E)); + + + //If the prog_cntr isn't in last step of the sequences and the DSA_NOP then valid should be deasserted + property no_valid_p; + (ecc_dsa_ctrl.prog_cntr != DSA_KG_E && + ecc_dsa_ctrl.prog_cntr != DSA_SGN_E && + ecc_dsa_ctrl.prog_cntr != DSA_VER_E && + ecc_dsa_ctrl.prog_cntr != DSA_NOP) //Review: After the completion of seq. if no new input is set then the valid stays + |=> + !hwif_in.ECC_STATUS.VALID.next; + endproperty + no_valid_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)no_valid_p); + + // TODO: ready and valid together + +///////////////////////////////////////////////////////////////////////////////////// +// ---------------------------------BEGIN----------------------------------------- // +// Checking the counter integrity that the sequence is performed one after another // +///////////////////////////////////////////////////////////////////////////////////// + + logic [DSA_PROG_ADDR_W-1 : 0] counter_keygen_a, counter_keygen_b; + logic triggered_counter_keygen_a,triggered_counter_keygen_b; + + + counter_keygen_a_assume: assume property(disable iff(!reset_n || fv_zeroize) (counter_keygen_a >=DSA_KG_S) && (counter_keygen_a <=DSA_KG_E) && $stable(counter_keygen_a)); + counter_keygen_b_assume: assume property(disable iff(!reset_n || fv_zeroize) (counter_keygen_b <=DSA_KG_E) && (counter_keygen_b > counter_keygen_a) && $stable(counter_keygen_b)); + + + always_ff @(posedge clk, negedge reset_n) begin + if(!reset_n ||fv_zeroize ) begin + triggered_counter_keygen_a <= 0; + triggered_counter_keygen_b <= 0; + end + else begin + + if(ecc_dsa_ctrl.prog_cntr==counter_keygen_a) + triggered_counter_keygen_a <=1; + if (ecc_dsa_ctrl.prog_cntr==counter_keygen_b) + triggered_counter_keygen_b <= 1; + end + end + + property counter_liveness_p(cmd,trigered); + hwif_out.ECC_CTRL.CTRL.value == cmd && + ecc_dsa_ctrl.prog_cntr == DSA_NOP && + !(ecc_dsa_ctrl.error_flag_edge) && + !(ecc_dsa_ctrl.subcomponent_busy) + |-> + s_eventually(trigered); + endproperty + + counter_keygen_a_liveness_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)counter_liveness_p(KEYGEN,triggered_counter_keygen_a)); + counter_keygen_b_liveness_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) counter_liveness_p(KEYGEN,triggered_counter_keygen_b)); + + counter_keygen_integrity_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) order_check_p(triggered_counter_keygen_a,triggered_counter_keygen_b)); + + + + +///////////////////////////////////////////////////////////////////////////////////// +// ------------------------------------END---------------------------------------- // +///////////////////////////////////////////////////////////////////////////////////// + + +`ifdef REDUCED_PM_CTRL + // This property works on the reduced version of the pm_ctrl + property signing_sequence_p; + hwif_out.ECC_CTRL.CTRL.value == SIGN && + ecc_dsa_ctrl.prog_cntr == DSA_NOP && + !(ecc_dsa_ctrl.error_flag_edge) && + !(ecc_dsa_ctrl.subcomponent_busy) + |=> + ecc_dsa_ctrl.prog_cntr == DSA_SGN_S + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 1 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 2 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 3 + ##2 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 4 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 5 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 6 + ##2 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 7 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 8 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 9 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 10 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 11 + ##39 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 12 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 13 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_SGN_S+ 14 + ; + endproperty + + signing_sequence_a: assert property(disable iff(!reset_n || fv_zeroize || ecc_dsa_ctrl.error_flag_edge)signing_sequence_p); +`endif + + + + + +///////////////////////////////////////////////////////////////////////////////////// +// ---------------------------------BEGIN----------------------------------------- // +// Checking the counter integrity that the sequence is performed one after another // +///////////////////////////////////////////////////////////////////////////////////// + + logic [DSA_PROG_ADDR_W-1 : 0] counter_sign_a, counter_sign_b; + logic triggered_counter_sign_a,triggered_counter_sign_b; + + + counter_sign_a_assume: assume property(disable iff(!reset_n || fv_zeroize) (counter_sign_a >=DSA_SGN_S) && (counter_sign_a <=DSA_SGN_E) && $stable(counter_sign_a)); + counter_sign_b_assume: assume property(disable iff(!reset_n || fv_zeroize) (counter_sign_b <=DSA_SGN_E) && (counter_sign_b > counter_sign_a) && $stable(counter_sign_b)); + + always_ff @(posedge clk, negedge reset_n) begin + if(!reset_n || fv_zeroize ) begin + triggered_counter_sign_a <= 0; + triggered_counter_sign_b <= 0; + end + else begin + + if(ecc_dsa_ctrl.prog_cntr==counter_sign_a) + triggered_counter_sign_a <=1; + if (ecc_dsa_ctrl.prog_cntr==counter_sign_b) + triggered_counter_sign_b <= 1; + end + end + + + counter_sign_a_liveness_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)counter_liveness_p(SIGN,triggered_counter_sign_a)); + counter_sign_b_liveness_a: assert property(disable iff(!reset_n || fv_zeroize|| fv_error_set) counter_liveness_p(SIGN,triggered_counter_sign_b)); + + counter_integrity_sign_a: assert property(disable iff(!reset_n || fv_zeroize|| fv_error_set) order_check_p(triggered_counter_sign_a,triggered_counter_sign_b)); + + + + +///////////////////////////////////////////////////////////////////////////////////// +// ------------------------------------END---------------------------------------- // +///////////////////////////////////////////////////////////////////////////////////// + + `ifdef REDUCED_PM_CTRL + // This property works on the reduced version of the pm_ctrl + property verify_sequence_p; + hwif_out.ECC_CTRL.CTRL.value == VERIFY && + ecc_dsa_ctrl.prog_cntr == DSA_NOP && + !(ecc_dsa_ctrl.error_flag_edge) && + !(ecc_dsa_ctrl.subcomponent_busy) + |=> + ecc_dsa_ctrl.prog_cntr == DSA_VER_S + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 1 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 2 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 3 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 4 + ##42 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 5 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 6 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 7 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 8 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 9 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 10 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 11 + ##14 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 12 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 13 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 14 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 15 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 16 + ##18 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 17 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 18 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 19 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 20 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 21 + ##34 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 22 + ##4 ecc_dsa_ctrl.prog_cntr == DSA_VER_S+ 23 + ; + endproperty + + verify_sequence_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)verify_sequence_p); +`endif + + +///////////////////////////////////////////////////////////////////////////////////// +// ---------------------------------BEGIN----------------------------------------- // +// Checking the counter integrity that the sequence is performed one after another // +///////////////////////////////////////////////////////////////////////////////////// + + logic [DSA_PROG_ADDR_W-1 : 0] counter_verify_a, counter_verify_b; + logic triggered_counter_verify_a,triggered_counter_verify_b; + + + counter_verify_a_assume: assume property(disable iff(!reset_n || fv_zeroize) (counter_verify_a >=DSA_SGN_S) && (counter_verify_a <=DSA_SGN_E) && $stable(counter_verify_a)); + counter_verify_b_assume: assume property(disable iff(!reset_n || fv_zeroize) (counter_verify_b <=DSA_SGN_E) && (counter_verify_b > counter_verify_a) && $stable(counter_verify_b)); + + always_ff @(posedge clk, negedge reset_n) begin + if(!reset_n ||fv_zeroize ) begin + triggered_counter_verify_a <= 0; + triggered_counter_verify_b <= 0; + end + else begin + + if(ecc_dsa_ctrl.prog_cntr==counter_verify_a) + triggered_counter_verify_a <=1; + if (ecc_dsa_ctrl.prog_cntr==counter_verify_b) + triggered_counter_verify_b <= 1; + end + end + + + counter_verify_a_liveness_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)counter_liveness_p(VERIFY,triggered_counter_verify_a)); + counter_verify_b_liveness_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) counter_liveness_p(VERIFY,triggered_counter_verify_b)); + + counter_integrity_verify_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) order_check_p(triggered_counter_verify_a,triggered_counter_verify_b)); + + + + +///////////////////////////////////////////////////////////////////////////////////// +// ------------------------------------END---------------------------------------- // +///////////////////////////////////////////////////////////////////////////////////// + + + + + + + //---------------------------------------------------------------------// + // Primary output // + //---------------------------------------------------------------------// + + + //Primary outputs connect to primary inputs + property output_directconnection_input_p; + hwif_in.reset_b == reset_n && + hwif_in.hard_reset_b == cptra_pwrgood && + hwif_in.ECC_NAME[0].NAME.next == ECC_CORE_NAME[31 : 0] && + hwif_in.ECC_NAME[1].NAME.next == ECC_CORE_NAME[63 : 32] && + hwif_in.ECC_VERSION[0].VERSION.next == ECC_CORE_VERSION[31 : 0] && + hwif_in.ECC_VERSION[1].VERSION.next == ECC_CORE_VERSION[63 : 32] && + error_intr == hwif_out.intr_block_rf.error_global_intr_r.intr && + notif_intr == hwif_out.intr_block_rf.notif_global_intr_r.intr && + hwif_in.ECC_CTRL.CTRL.hwclr == |hwif_out.ECC_CTRL.CTRL.value && + hwif_in.ECC_CTRL.PCR_SIGN.hwclr == hwif_out.ECC_CTRL.PCR_SIGN.value; + endproperty + + output_directconnection_input_a: assert property(output_directconnection_input_p); + + + // Primary outputs connected to the submodule outputs, here it is read_reg + property output_connectedto_submodules_p(word); + hwif_in.ECC_PRIVKEY_OUT[word].PRIVKEY_OUT.next == ecc_dsa_ctrl.read_reg[(REG_NUM_DWORDS-1)- word]&& + hwif_in.ECC_SEED[word].SEED.next == ecc_dsa_ctrl.kv_seed_write_data && + hwif_in.ECC_MSG[word].MSG.next == pcr_signing_data.pcr_hash[word] && + hwif_in.ECC_PUBKEY_Y[word].PUBKEY_Y.next == ecc_dsa_ctrl.read_reg[(REG_NUM_DWORDS-1)- word] && + hwif_in.ECC_SIGN_R[word].SIGN_R.next == ecc_dsa_ctrl.read_reg[(REG_NUM_DWORDS-1)- word] && + hwif_in.ECC_SIGN_S[word].SIGN_S.next == ecc_dsa_ctrl.read_reg[(REG_NUM_DWORDS-1)- word] && + hwif_in.ECC_VERIFY_R[word].VERIFY_R.next == ecc_dsa_ctrl.read_reg[(REG_NUM_DWORDS-1)- word] && + hwif_in.ECC_PUBKEY_X[word].PUBKEY_X.next == ecc_dsa_ctrl.read_reg[(REG_NUM_DWORDS-1)- word]; + endproperty + for(genvar i=0;i< REG_NUM_DWORDS;i++) begin + output_connectedto_submodules_a: assert property(output_connectedto_submodules_p(i)); + end + + + // If pcr sign is set then msg we and privkey_in we should be ! zeroize and privkey_in should take data from pcr_Signing + property pcr_sign_mode_p(word); + hwif_out.ECC_CTRL.PCR_SIGN.value + |-> + hwif_in.ECC_MSG[word].MSG.we == !(fv_zeroize) && + hwif_in.ECC_PRIVKEY_IN[word].PRIVKEY_IN.next == pcr_signing_data.pcr_signing_privkey[word] && + hwif_in.ECC_PRIVKEY_IN[word].PRIVKEY_IN.we == !(fv_zeroize) + ; + endproperty + + for(genvar i=0;i< REG_NUM_DWORDS;i++) begin + pcr_sign_mode_a: assert property(pcr_sign_mode_p(i)); + end + + + // If pcr sign isn't enabled then for msg no we and privkey_in is dependent on keyvault write_en + property no_pcr_sign_mode_p(word); + !hwif_out.ECC_CTRL.PCR_SIGN.value + |-> + !hwif_in.ECC_MSG[word].MSG.we && + hwif_in.ECC_PRIVKEY_IN[word].PRIVKEY_IN.next == (ecc_dsa_ctrl.kv_privkey_write_en ? ecc_dsa_ctrl.kv_privkey_write_data : ecc_dsa_ctrl.read_reg[(REG_NUM_DWORDS-1)-word] )&& + hwif_in.ECC_PRIVKEY_IN[word].PRIVKEY_IN.we == ((ecc_dsa_ctrl.kv_privkey_write_en & (ecc_dsa_ctrl.kv_privkey_write_offset == word)) & !(fv_zeroize)) + ; + endproperty + for(genvar i=0;i< REG_NUM_DWORDS;i++) begin + no_pcr_sign_mode_a: assert property(no_pcr_sign_mode_p(i)); + end + + + //If privkey_out i.e reading from the reg after the privkey computation and + //if the seed is not rom the keyvault then privkey_out we is equal to !zeroize + property privkey_out_we_p(word); + ecc_dsa_ctrl.privkey_out_we && + !(ecc_dsa_ctrl.dest_keyvault | ecc_dsa_ctrl.kv_read_data_present) + |-> + hwif_in.ECC_PRIVKEY_OUT[word].PRIVKEY_OUT.we == !(fv_zeroize); + endproperty + for(genvar i=0;i< REG_NUM_DWORDS;i++) begin + privkey_out_we_a: assert property(disable iff(fv_error_set) privkey_out_we_p(i)); + end + + + //If no privkey_out or keyvault is choose as desitination then prvkey_out we is deasserted + property no_privkey_out_we_p(word); + (!ecc_dsa_ctrl.privkey_out_we || + (ecc_dsa_ctrl.dest_keyvault | ecc_dsa_ctrl.kv_read_data_present)) + |-> + !hwif_in.ECC_PRIVKEY_OUT[word].PRIVKEY_OUT.we ; + endproperty + for(genvar i=0;i< REG_NUM_DWORDS;i++) begin + no_privkey_out_we_a: assert property(no_privkey_out_we_p(i)); + end + + + // if keyvault write is enabled and offset is equal to each word the seed we is equal to !zeroize + property seed_we_p(word); + (ecc_dsa_ctrl.kv_seed_write_en && + (ecc_dsa_ctrl.kv_seed_write_offset == word)) + |-> + hwif_in.ECC_SEED[word].SEED.we == !(fv_zeroize); + endproperty + for(genvar i=0;i< REG_NUM_DWORDS;i++) begin + seed_we_a: assert property(seed_we_p(i)); + end + + + // if keyvault write is not enabled and offset is not equal to each word then seed we is deasserted + property no_seed_we_p(word); + (!ecc_dsa_ctrl.kv_seed_write_en || + (ecc_dsa_ctrl.kv_seed_write_offset != word)) + |-> + !hwif_in.ECC_SEED[word].SEED.we; + endproperty + for(genvar i=0;i< REG_NUM_DWORDS;i++) begin + no_seed_we_a: assert property(no_seed_we_p(i)); + end + + + // Rest we are triggered with rd_core opcode and cycle_cnt=0 + property rd_core_we_p(word); + hwif_in.ECC_PUBKEY_X[word].PUBKEY_X.we == (fv_hw_pubkeyx_we & !(fv_zeroize)) && + hwif_in.ECC_PUBKEY_Y[word].PUBKEY_Y.we == (fv_hw_pubkeyy_we & !(fv_zeroize)) && + hwif_in.ECC_SIGN_S[word].SIGN_S.we == (fv_hw_s_we & !(fv_zeroize)) && + hwif_in.ECC_VERIFY_R[word].VERIFY_R.we == (fv_hw_verify_r_we & !(fv_zeroize)) && + hwif_in.ECC_SIGN_R[word].SIGN_R.we == (fv_hw_r_we & !(fv_zeroize)); + endproperty + for(genvar i=0;i< REG_NUM_DWORDS;i++) begin + rd_core_we_a: assert property(disable iff(fv_error_set)rd_core_we_p(i)); + end + + + // keyvault privkey read ctrl reg is connected to primary input kv_rd_pkey_ctrl + property kv_privkey_read_ctrl_reg_p; + ecc_dsa_ctrl.kv_privkey_read_ctrl_reg.rsvd == '0 && + ecc_dsa_ctrl.kv_privkey_read_ctrl_reg.pcr_hash_extend == hwif_out.ecc_kv_rd_pkey_ctrl.pcr_hash_extend.value && + ecc_dsa_ctrl.kv_privkey_read_ctrl_reg.read_entry == hwif_out.ecc_kv_rd_pkey_ctrl.read_entry.value && + ecc_dsa_ctrl.kv_privkey_read_ctrl_reg.read_en == hwif_out.ecc_kv_rd_pkey_ctrl.read_en.value; + endproperty + + kv_privkey_read_ctrl_reg_a: assert property(kv_privkey_read_ctrl_reg_p); + + + // keyvault seed read ctrl reg is connected to primary input kv_rd_seed_ctrl + property kv_seed_read_ctrl_reg_p; + ecc_dsa_ctrl.kv_seed_read_ctrl_reg.rsvd == '0 && + ecc_dsa_ctrl.kv_seed_read_ctrl_reg.pcr_hash_extend == hwif_out.ecc_kv_rd_seed_ctrl.pcr_hash_extend.value && + ecc_dsa_ctrl.kv_seed_read_ctrl_reg.read_entry == hwif_out.ecc_kv_rd_seed_ctrl.read_entry.value && + ecc_dsa_ctrl.kv_seed_read_ctrl_reg.read_en == hwif_out.ecc_kv_rd_seed_ctrl.read_en.value; + endproperty + + kv_seed_read_ctrl_reg_a: assert property(kv_seed_read_ctrl_reg_p); + + + // keyvault write ctrl reg is connected to primary input kv_wr_pkey_ctrl + property kv_write_ctrl_reg_p; + ecc_dsa_ctrl.kv_write_ctrl_reg.rsvd == '0 && + ecc_dsa_ctrl.kv_write_ctrl_reg.write_dest_vld[0] == hwif_out.ecc_kv_wr_pkey_ctrl.hmac_key_dest_valid.value && + ecc_dsa_ctrl.kv_write_ctrl_reg.write_dest_vld[1] == hwif_out.ecc_kv_wr_pkey_ctrl.hmac_block_dest_valid.value && + ecc_dsa_ctrl.kv_write_ctrl_reg.write_dest_vld[2] == hwif_out.ecc_kv_wr_pkey_ctrl.sha_block_dest_valid.value && + ecc_dsa_ctrl.kv_write_ctrl_reg.write_dest_vld[3] == hwif_out.ecc_kv_wr_pkey_ctrl.ecc_pkey_dest_valid.value && + ecc_dsa_ctrl.kv_write_ctrl_reg.write_dest_vld[4] == hwif_out.ecc_kv_wr_pkey_ctrl.ecc_seed_dest_valid.value && + ecc_dsa_ctrl.kv_write_ctrl_reg.write_entry == hwif_out.ecc_kv_wr_pkey_ctrl.write_entry.value && + ecc_dsa_ctrl.kv_write_ctrl_reg.write_en == hwif_out.ecc_kv_wr_pkey_ctrl.write_en.value; + endproperty + + kv_write_ctrl_reg_a: assert property(kv_write_ctrl_reg_p); + + + // kv_read data present stays asserted until privkey is generated if read_en of kv is set + property kv_read_data_present_p; + ecc_dsa_ctrl.kv_seed_read_ctrl_reg.read_en + |=> + ecc_dsa_ctrl.kv_read_data_present until_with ecc_dsa_ctrl.privkey_out_we; + endproperty + kv_read_data_present_a: assert property(disable iff(!reset_n || fv_zeroize) kv_read_data_present_p); + + + // Once kv_read_data_present is set then it deasserts if privkey is ready to be read and no new read_en + property no_kv_read_data_present_p; + ecc_dsa_ctrl.kv_read_data_present && + ecc_dsa_ctrl.privkey_out_we && + !ecc_dsa_ctrl.kv_seed_read_ctrl_reg.read_en //Review: Fails because if read_en is continously high then it won't be deasserted. + |=> + !ecc_dsa_ctrl.kv_read_data_present; + endproperty + no_kv_read_data_present_a: assert property(disable iff(!reset_n || fv_zeroize) no_kv_read_data_present_p); + + + // If privkey is ready to read and keyvault is choosen as destination then kv_reg will have the privkey + property kv_reg_p; + ecc_dsa_ctrl.privkey_out_we && + (ecc_dsa_ctrl.dest_keyvault | ecc_dsa_ctrl.kv_read_data_present) + |=> + ecc_dsa_ctrl.kv_reg == $past(ecc_dsa_ctrl.read_reg); + endproperty + + kv_reg_a: assert property(disable iff(!reset_n || fv_zeroize)kv_reg_p); + + + // kv_reg stays stable if privkey isn't ready or kv is not choosen as dest. + property stable_kv_reg_p; + !ecc_dsa_ctrl.privkey_out_we || + !(ecc_dsa_ctrl.dest_keyvault | ecc_dsa_ctrl.kv_read_data_present) + |=> + ecc_dsa_ctrl.kv_reg == $past(ecc_dsa_ctrl.kv_reg); + endproperty + + stable_kv_reg_a: assert property(disable iff(!reset_n || fv_zeroize)stable_kv_reg_p); + + + + // Primary outputs directly connected to kv(submodule) outputs + property primaryout_connected_to_kvout_p; + hwif_in.ecc_kv_rd_pkey_status.ERROR.next == ecc_dsa_ctrl.kv_privkey_error && + hwif_in.ecc_kv_rd_seed_status.ERROR.next == ecc_dsa_ctrl.kv_seed_error && + hwif_in.ecc_kv_wr_pkey_status.ERROR.next == ecc_dsa_ctrl.kv_write_error && + //ready when fsm is not busy + hwif_in.ecc_kv_rd_pkey_status.READY.next == ecc_dsa_ctrl.kv_privkey_ready && + hwif_in.ecc_kv_rd_seed_status.READY.next == ecc_dsa_ctrl.kv_seed_ready && + hwif_in.ecc_kv_wr_pkey_status.READY.next == ecc_dsa_ctrl.kv_write_ready && + //set valid when fsm is done + hwif_in.ecc_kv_rd_pkey_status.VALID.hwset == ecc_dsa_ctrl.kv_privkey_done && + hwif_in.ecc_kv_rd_seed_status.VALID.hwset == ecc_dsa_ctrl.kv_seed_done && + hwif_in.ecc_kv_wr_pkey_status.VALID.hwset == ecc_dsa_ctrl.kv_write_done && + //clear valid when new request is made + hwif_in.ecc_kv_rd_pkey_status.VALID.hwclr == hwif_out.ecc_kv_rd_pkey_ctrl.read_en.value && + hwif_in.ecc_kv_rd_seed_status.VALID.hwclr == hwif_out.ecc_kv_rd_seed_ctrl.read_en.value && + hwif_in.ecc_kv_wr_pkey_status.VALID.hwclr == hwif_out.ecc_kv_wr_pkey_ctrl.write_en.value && + //clear enable when busy + hwif_in.ecc_kv_rd_pkey_ctrl.read_en.hwclr == !ecc_dsa_ctrl.kv_privkey_ready && + hwif_in.ecc_kv_rd_seed_ctrl.read_en.hwclr == !ecc_dsa_ctrl.kv_seed_ready && + hwif_in.ecc_kv_wr_pkey_ctrl.write_en.hwclr == !ecc_dsa_ctrl.kv_write_ready; + + endproperty + + primaryout_connected_to_kvout_a: assert property(primaryout_connected_to_kvout_p); + + + // If pm_ctrl is not busy and prog_cntr is equal to DSA_NOP then ecc_ready to accept cmds + property ready_p; + !ecc_dsa_ctrl.pm_busy_o && + ecc_dsa_ctrl.prog_cntr == DSA_NOP + |-> + hwif_in.ECC_STATUS.READY.next && + hwif_in.ecc_ready; + endproperty + + ready_a: assert property(disable iff(!reset_n || fv_zeroize)ready_p); + + + // If pm_ctrl is busy or prog_cntr is in cmd execution or memory write steps then ecc isn't ready + property no_ready_p; + ecc_dsa_ctrl.pm_busy_o || + ecc_dsa_ctrl.prog_cntr != DSA_NOP + |-> + !hwif_in.ECC_STATUS.READY.next && + !hwif_in.ecc_ready; + endproperty + + no_ready_a: assert property(disable iff(!reset_n || fv_zeroize)no_ready_p); + + + + //-------------------------------------------------------// + // Notif interrupt and error sequences // + //-------------------------------------------------------// + + + logic [REG_NUM_DWORDS-1 : 0][RADIX-1:0] privkey_reg; + for(genvar i=0;i< REG_NUM_DWORDS;i++) begin + assign privkey_reg[i] = hwif_out.ECC_PRIVKEY_IN[(REG_NUM_DWORDS-1)-i].PRIVKEY_IN.value; + end + + // During sign subroutine if input privkey is zero or >= Group_order or while writing + // the outputs s and r are equal to zero error is triggered + property error_sign_p; + ((ecc_dsa_ctrl.prog_cntr <= DSA_SGN_E) && + (ecc_dsa_ctrl.prog_cntr >= DSA_SGN_S)) && + (((privkey_reg == '0) | (privkey_reg >= GROUP_ORDER)) || + (fv_hw_s_we &&(ecc_dsa_ctrl.read_reg==0)) || + (fv_hw_r_we &&(ecc_dsa_ctrl.read_reg==0))) + |=> + hwif_in.intr_block_rf.error_internal_intr_r.error_internal_sts.hwset; + endproperty + + error_sign_a: assert property(disable iff(!reset_n || fv_zeroize) error_sign_p); + + + // If keygen subroutine is the cmd then input cannot have pcr_sign, this results in error + property error_keygen_p; + (ecc_dsa_ctrl.cmd_reg== KEYGEN) && + hwif_out.ECC_CTRL.PCR_SIGN.value + |=> + hwif_in.intr_block_rf.error_internal_intr_r.error_internal_sts.hwset; + endproperty + + error_keygen_a: assert property(disable iff(!reset_n || fv_zeroize) error_keygen_p); + + + // During verifying subroutine if r and s inputs are equal to zero or greater than group order or + // the pubkey is greater than prime or + // If the cmd is just set as verify after reset then pcr_sign cannot be set along this results in error + property error_verify_p; + (((ecc_dsa_ctrl.prog_cntr <= DSA_VER_E) && + (ecc_dsa_ctrl.prog_cntr >= DSA_VER_S)) && + (((ecc_dsa_ctrl.r_reg == 0) || + (ecc_dsa_ctrl.r_reg >= GROUP_ORDER)) || + ((ecc_dsa_ctrl.s_reg == 0) || + (ecc_dsa_ctrl.s_reg >= GROUP_ORDER)) || + (ecc_dsa_ctrl.pubkeyx_reg >= PRIME) || + (ecc_dsa_ctrl.pubkeyy_reg >= PRIME))) || + ((ecc_dsa_ctrl.cmd_reg==VERIFY) & hwif_out.ECC_CTRL.PCR_SIGN.value) + |=> + hwif_in.intr_block_rf.error_internal_intr_r.error_internal_sts.hwset; + endproperty + + error_verify_a: assert property(disable iff(!reset_n || fv_zeroize) error_verify_p); + + + // Once valid signal is set then interrupt is triggered as a pulse + property notif_interrupt_p; + $rose(hwif_in.ECC_STATUS.VALID.next) + |-> + hwif_in.intr_block_rf.notif_internal_intr_r.notif_cmd_done_sts.hwset + ##1 + !hwif_in.intr_block_rf.notif_internal_intr_r.notif_cmd_done_sts.hwset; + endproperty + notif_interrupt_a: assert property(disable iff(!reset_n || fv_zeroize)notif_interrupt_p); + + + // If pm_ctrl busy or sca_blinding modules are busy or if hmac is not ready then subcomponent_busy is asserted + property subcomponent_busy_p; + ecc_dsa_ctrl.pm_busy_o || + ecc_dsa_ctrl.scalar_sca_busy_o || + !ecc_dsa_ctrl.hmac_ready + |-> + ecc_dsa_ctrl.subcomponent_busy; + endproperty + + subcomponent_busy_a: assert property(disable iff(!reset_n || fv_zeroize) subcomponent_busy_p); + + + // If none of the subcomponents are busy then subcomponent_busy is deasserted + property no_subcomponent_busy_p; + !ecc_dsa_ctrl.pm_busy_o && + !ecc_dsa_ctrl.scalar_sca_busy_o && + ecc_dsa_ctrl.hmac_ready + |-> + !ecc_dsa_ctrl.subcomponent_busy; + endproperty + + no_subcomponent_busy_a: assert property(disable iff(!reset_n || fv_zeroize) no_subcomponent_busy_p); + + + +//-------------------------------------------------------------------------// +// HMAC_Interface +//-------------------------------------------------------------------------// + + //If hmac_drbg is enabled from seq then if no error flag and cyc_cnt=3 hmac_init is triggered until the + // prog_cntr advances + property hmac_init_p; + ecc_dsa_ctrl.prog_instr.opcode.hmac_drbg_en && + (ecc_dsa_ctrl.prog_cntr == fv_prog_cntr_reg) && //represents CYC=2 + !ecc_dsa_ctrl.error_flag_edge + ##1 (ecc_dsa_ctrl.prog_cntr != fv_prog_cntr_reg) // represents CYC=3 + |-> + ecc_dsa_ctrl.hmac_init s_until_with (ecc_dsa_ctrl.prog_cntr != fv_prog_cntr_reg); + endproperty + + hmac_init_a: assert property(disable iff(!reset_n ||fv_zeroize)hmac_init_p); + + // If hmac_drbg en is set and the cntr is stable then hmac_init isn't set + property no_hmac_init_less3cyc_p; + ecc_dsa_ctrl.prog_instr.opcode.hmac_drbg_en && + (ecc_dsa_ctrl.prog_cntr == fv_prog_cntr_reg) && + !ecc_dsa_ctrl.error_flag_edge + ##1 (ecc_dsa_ctrl.prog_cntr == fv_prog_cntr_reg) + |-> + !ecc_dsa_ctrl.hmac_init; + endproperty + + no_hmac_init_less3cyc_a: assert property(disable iff(!reset_n ||fv_zeroize)no_hmac_init_less3cyc_p); + + + // If subcomponent busy or prog_cntr is DSA_NOP or there isn't hmac_drbg_en then no hmac_init + property no_hmac_init_p; + (!ecc_dsa_ctrl.prog_instr.opcode.hmac_drbg_en && + (ecc_dsa_ctrl.prog_cntr != fv_prog_cntr_reg)) || + ecc_dsa_ctrl.error_flag_edge || + (ecc_dsa_ctrl.prog_cntr == DSA_NOP) || + (ecc_dsa_ctrl.subcomponent_busy) + |=> + !ecc_dsa_ctrl.hmac_init ; + endproperty + + no_hmac_init_a: assert property(disable iff(!reset_n ||fv_zeroize)no_hmac_init_p); + + + // If sign subroutine is set the no subcomponent busy then hmac_mode is set + property hmac_mode_p; + (hwif_out.ECC_CTRL.CTRL.value == SIGN && + ecc_dsa_ctrl.prog_cntr == DSA_NOP ) && + !ecc_dsa_ctrl.subcomponent_busy + |=> + ecc_dsa_ctrl.hmac_mode; + endproperty + + hmac_mode_a: assert property(disable iff(!reset_n ||fv_zeroize || fv_error_set)hmac_mode_p); + + // Once hmac_mode is stays stable until keygen subroutine triggers + property continue_hmac_mode_p; + ecc_dsa_ctrl.hmac_mode + |-> + (ecc_dsa_ctrl.hmac_mode until ecc_dsa_ctrl.keygen_process); //no ovelapping condition and intial tick both cannot be occured + endproperty + continue_hmac_mode_a: assert property(disable iff(!reset_n ||fv_zeroize || fv_error_set)continue_hmac_mode_p); + + + //If keygen subroutine is set then no hmac_mode + property no_hmac_mode_p; + (hwif_out.ECC_CTRL.CTRL.value == KEYGEN && + ecc_dsa_ctrl.prog_cntr == DSA_NOP ) && + !ecc_dsa_ctrl.subcomponent_busy + |=> + !ecc_dsa_ctrl.hmac_mode; + endproperty + + no_hmac_mode_a: assert property(disable iff(!reset_n ||fv_zeroize || fv_error_set)no_hmac_mode_p); + + // Once hmac_mode deasserted stays stable until new sign subroutine is triggered + property continue_no_hmac_mode_p; + !ecc_dsa_ctrl.hmac_mode + |-> + (!ecc_dsa_ctrl.hmac_mode until ecc_dsa_ctrl.signing_process); + endproperty + continue_no_hmac_mode_a: assert property(disable iff(!reset_n ||fv_zeroize || fv_error_set)continue_no_hmac_mode_p); + + + + // Hmac inputs directly connected to the primary inputs + property hmac_input_reg_p(word); + ecc_dsa_ctrl.privkey_reg[word] == hwif_out.ECC_PRIVKEY_IN[(REG_NUM_DWORDS-1)-word].PRIVKEY_IN.value && + ecc_dsa_ctrl.seed_reg[word] == hwif_out.ECC_SEED[(REG_NUM_DWORDS-1)-word].SEED.value && + ecc_dsa_ctrl.nonce_reg[word] == hwif_out.ECC_NONCE[(REG_NUM_DWORDS-1)-word].NONCE.value && + ecc_dsa_ctrl.msg_reg[word] == hwif_out.ECC_MSG[(REG_NUM_DWORDS-1)-word].MSG.value && + ecc_dsa_ctrl.IV_reg[word] == hwif_out.ECC_IV[(REG_NUM_DWORDS-1)-word].IV.value; + endproperty + for(genvar i=0;i< REG_NUM_DWORDS;i++) begin + hmac_input_reg_a: assert property(hmac_input_reg_p(i)); + end + + + + +//-------------------------------------------------------------------------// +// Scalar_blinding +//-------------------------------------------------------------------------// + + //If sca_en is enabled from seq then if no error flag and cyc_cnt=3 scalar_en is triggered until the + // prog_cntr advances + property scalar_en_p; + ecc_dsa_ctrl.prog_instr.opcode.sca_en && + (ecc_dsa_ctrl.prog_cntr == fv_prog_cntr_reg) && + !ecc_dsa_ctrl.error_flag_edge + ##1 (ecc_dsa_ctrl.prog_cntr != fv_prog_cntr_reg) + |-> + ecc_dsa_ctrl.scalar_sca_en s_until_with (ecc_dsa_ctrl.prog_cntr != fv_prog_cntr_reg); + endproperty + + scalar_en_a: assert property(disable iff(!reset_n ||fv_zeroize)scalar_en_p); + + + + // If sca_en is set and the cntr is stable then scalar_en isn't set + property no_scalar_en_less3cyc_p; + ecc_dsa_ctrl.prog_instr.opcode.sca_en && + (ecc_dsa_ctrl.prog_cntr == fv_prog_cntr_reg) && + !ecc_dsa_ctrl.error_flag_edge + ##1 (ecc_dsa_ctrl.prog_cntr == fv_prog_cntr_reg) + |-> + !ecc_dsa_ctrl.scalar_sca_en; + endproperty + no_scalar_en_less3cyc_a: assert property(disable iff(!reset_n ||fv_zeroize)no_scalar_en_less3cyc_p); + + + + // If subcomponent busy or prog_cntr is DSA_NOP or there isn't sca_en then no scalar_en + property no_scalar_en_p; + (!ecc_dsa_ctrl.prog_instr.opcode.sca_en && + (ecc_dsa_ctrl.prog_cntr != fv_prog_cntr_reg)) || + ecc_dsa_ctrl.error_flag_edge || + (ecc_dsa_ctrl.prog_cntr == DSA_NOP) || + (ecc_dsa_ctrl.subcomponent_busy) + |=> + !ecc_dsa_ctrl.scalar_sca_en; + endproperty + no_scalar_en_a: assert property(disable iff(!reset_n ||fv_zeroize)no_scalar_en_p); + + + // Input for scalar_blinding is from scalar_g_reg + property scalar_in_reg_p; + ecc_dsa_ctrl.prog_instr.opcode.sca_en && + !ecc_dsa_ctrl.verifying_process + |=> + ecc_dsa_ctrl.scalar_in_reg == $past(ecc_dsa_ctrl.scalar_G_reg); + endproperty + + scalar_in_reg_a: assert property(disable iff(!reset_n ||fv_zeroize)scalar_in_reg_p); + + + // Input stays stable if sca not enabled or in verifying process + property stable_scalar_in_reg_p; + !ecc_dsa_ctrl.prog_instr.opcode.sca_en || + ecc_dsa_ctrl.verifying_process + |=> + ecc_dsa_ctrl.scalar_in_reg == $past(ecc_dsa_ctrl.scalar_in_reg); + endproperty + + stable_scalar_in_reg_a: assert property(disable iff(!reset_n ||fv_zeroize)stable_scalar_in_reg_p); + +//-------------------------------------------------------------------------// +// Arithmetic unit +//-------------------------------------------------------------------------// + + // If no error and prog_cntr is not equal to DSA_NOP and none of the subcomponents are busy and cyc cnt ==3 then + // pm_ctrl cmd is equal to dsa_seq opcode pm_cmd + property pm_cmd_reg_p; + !ecc_dsa_ctrl.error_flag_edge && + (ecc_dsa_ctrl.prog_cntr!= DSA_NOP) && + (!ecc_dsa_ctrl.subcomponent_busy) && + (ecc_dsa_ctrl.cycle_cnt==3) + |=> + ecc_dsa_ctrl.pm_cmd_reg == $past(ecc_dsa_ctrl.prog_instr.opcode.pm_cmd); + endproperty + pm_cmd_reg_a: assert property(disable iff(!reset_n ||fv_zeroize)pm_cmd_reg_p); + + + // If error is triggered or prog_cntr is equal to DSA_NOP or subcomponents are busy then pm_cmd ==0 + property no_pm_cmd_reg_p; + ecc_dsa_ctrl.error_flag_edge || + (ecc_dsa_ctrl.prog_cntr == DSA_NOP) || + (ecc_dsa_ctrl.subcomponent_busy) + |=> + ecc_dsa_ctrl.pm_cmd_reg =='0; + endproperty + + no_pm_cmd_reg_a: assert property(disable iff(!reset_n ||fv_zeroize)no_pm_cmd_reg_p); + + + // If cmd is acceptable but cyc cnt is less than 3 then pm_cmd stays stable + property pm_cmd_when_cyc3less_p; + !ecc_dsa_ctrl.error_flag_edge && + (ecc_dsa_ctrl.prog_cntr!= DSA_NOP) && + (!ecc_dsa_ctrl.subcomponent_busy) && + (ecc_dsa_ctrl.cycle_cnt < (CYC_CNT-1)) + |=> + ecc_dsa_ctrl.pm_cmd_reg == $past(ecc_dsa_ctrl.pm_cmd_reg); + endproperty + + pm_cmd_when_cyc3less_a: assert property(disable iff(!reset_n ||fv_zeroize)pm_cmd_when_cyc3less_p); + + +//-------------------------------------------------------------------------// +// Address Liveliness +//-------------------------------------------------------------------------// + + + property wr_core_addr_eventually_in_memory_p; + logic [DSA_OPR_ADDR_WIDTH-1 : 0] temp; + ecc_dsa_ctrl.prog_instr.opcode == DSA_UOP_WR_CORE + ##0 (1'b1, temp = ecc_dsa_ctrl.prog_instr.mem_addr) + |-> + s_eventually(ecc_dsa_ctrl.ecc_arith_unit_i.ram_tdp_file_i.addrb == temp); + endproperty + + wr_core_addr_eventually_in_memory_a: assert property(disable iff(!reset_n ||fv_zeroize)wr_core_addr_eventually_in_memory_p); + + + + + + //-------------------------------------------------------------------------// + // write_reg to the core + //-------------------------------------------------------------------------// + + + + property write_reg_p; + ecc_dsa_ctrl.prog_instr.opcode == DSA_UOP_WR_CORE + |-> + ecc_dsa_ctrl.write_reg == fv_write_reg; + endproperty + write_reg_a: assert property(write_reg_p); + + property write_reg_no_cmd_p; + ecc_dsa_ctrl.prog_instr.opcode != DSA_UOP_WR_CORE && + ecc_dsa_ctrl.prog_instr.opcode != DSA_UOP_WR_SCALAR + |-> + ecc_dsa_ctrl.write_reg == '0; + endproperty + write_reg_no_cmd_a:assert property(write_reg_no_cmd_p); + + property write_reg_sca_p; + ecc_dsa_ctrl.prog_instr.opcode == DSA_UOP_WR_SCALAR + |-> + ecc_dsa_ctrl.write_reg == fv_write_reg; + endproperty + write_reg_sca_a:assert property(write_reg_sca_p); + + //-------------------------------------------------------------------------// + // read_reg from the core + //-------------------------------------------------------------------------// + + + property we_p; + ecc_dsa_ctrl.prog_instr.opcode == DSA_UOP_RD_CORE && + ecc_dsa_ctrl.prog_cntr !=fv_prog_cntr_reg + |-> + ecc_dsa_ctrl.hw_privkey_we == fv_hw_privkey_we && + ecc_dsa_ctrl.hw_pubkeyx_we == fv_hw_pubkeyx_we && + ecc_dsa_ctrl.hw_pubkeyy_we == fv_hw_pubkeyy_we && + ecc_dsa_ctrl.hw_r_we == fv_hw_r_we && + ecc_dsa_ctrl.hw_s_we == fv_hw_s_we && + ecc_dsa_ctrl.hw_scalar_G_we == fv_hw_scalar_G_we && + ecc_dsa_ctrl.hw_scalar_PK_we == fv_hw_scalar_PK_we && + ecc_dsa_ctrl.hw_verify_r_we == fv_hw_verify_r_we && + ecc_dsa_ctrl.hw_pk_chk_we == fv_hw_pk_chk_we; + endproperty + + we_a: assert property(disable iff (fv_error_set)we_p); + + property no_rd_we_p; + (ecc_dsa_ctrl.prog_instr.opcode != DSA_UOP_RD_CORE) || + ecc_dsa_ctrl.prog_cntr ==fv_prog_cntr_reg + |-> + ecc_dsa_ctrl.hw_privkey_we == 0 && + ecc_dsa_ctrl.hw_pubkeyx_we == 0 && + ecc_dsa_ctrl.hw_pubkeyy_we == 0 && + ecc_dsa_ctrl.hw_r_we == 0 && + ecc_dsa_ctrl.hw_s_we == 0 && + ecc_dsa_ctrl.hw_scalar_G_we == 0 && + ecc_dsa_ctrl.hw_scalar_PK_we == 0 && + ecc_dsa_ctrl.hw_verify_r_we == 0 && + ecc_dsa_ctrl.hw_pk_chk_we == 0; + endproperty + no_rd_we_a: assert property(no_rd_we_p); + + + property read_reg_r_p; + fv_hw_r_we + |-> + (ecc_dsa_ctrl.read_reg != '0) && + (ecc_dsa_ctrl.read_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973); + endproperty + read_reg_r_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) read_reg_r_p); + + + property read_reg_s_p; + fv_hw_s_we + |-> + ecc_dsa_ctrl.read_reg != '0 && + ecc_dsa_ctrl.read_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973; + endproperty + read_reg_s_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) read_reg_s_p); + + + property read_reg_ver_r_p; + fv_hw_verify_r_we + |-> + ecc_dsa_ctrl.read_reg != '0 && + ecc_dsa_ctrl.read_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973; + endproperty + read_reg_ver_r_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) read_reg_ver_r_p); + + + //-----------------------------------------------------------// + // scalar_G_reg and scalar_G_sel + //-----------------------------------------------------------// + + + property hmac_drbg_in_scalar_G_reg_p; + (ecc_dsa_ctrl.prog_cntr < DSA_VER_S) + |=> + ecc_dsa_ctrl.scalar_G_reg == $past(ecc_dsa_ctrl.hmac_drbg_result) && + (ecc_dsa_ctrl.scalar_G_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973) + ; + endproperty + + hmac_drbg_in_scalar_G_reg_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) hmac_drbg_in_scalar_G_reg_p); + + + property read_reg_scalar_G_reg_p; + (ecc_dsa_ctrl.prog_cntr >= DSA_VER_S) && + fv_hw_scalar_G_we + |=> + ecc_dsa_ctrl.scalar_G_reg == $past(ecc_dsa_ctrl.read_reg)&& + (ecc_dsa_ctrl.scalar_G_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973) && + (ecc_dsa_ctrl.scalar_G_reg >'0); + endproperty + + read_reg_scalar_G_reg_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) read_reg_scalar_G_reg_p); + + property no_read_reg_scalar_G_reg_p; + (ecc_dsa_ctrl.prog_cntr >= DSA_VER_S) && + !fv_hw_scalar_G_we + |=> + ecc_dsa_ctrl.scalar_G_reg == $past(ecc_dsa_ctrl.scalar_G_reg); + endproperty + + no_read_reg_scalar_G_reg_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set) no_read_reg_scalar_G_reg_p); + + + + + //------------------------------------------------// + // scalar_Pk_reg + //------------------------------------------------// + + + property we_scalar_pk_reg_p; + fv_hw_scalar_PK_we + |=> + ecc_dsa_ctrl.scalar_PK_reg == $past(ecc_dsa_ctrl.read_reg) && + (ecc_dsa_ctrl.scalar_PK_reg < 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973) && + (ecc_dsa_ctrl.scalar_PK_reg >'0); + endproperty + + we_scalar_pk_reg_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)we_scalar_pk_reg_p); + + property no_we_scalar_pk_reg_p; + !fv_hw_scalar_PK_we + |=> + ecc_dsa_ctrl.scalar_PK_reg == $past(ecc_dsa_ctrl.scalar_PK_reg); + endproperty + + no_we_scalar_pk_reg_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)no_we_scalar_pk_reg_p); + + + //------------------------------------------------// + // pk_chk_reg + //------------------------------------------------// + + property pk_chk_reg_p; + fv_hw_pk_chk_we + |=> + ecc_dsa_ctrl.pk_chk_reg == $past(ecc_dsa_ctrl.read_reg); + endproperty + pk_chk_reg_a: assert property(disable iff(!reset_n || fv_zeroize || fv_error_set)pk_chk_reg_p); + + property no_pk_chk_reg_p; + !fv_hw_pk_chk_we + |=> + ecc_dsa_ctrl.pk_chk_reg == $past(ecc_dsa_ctrl.pk_chk_reg); + endproperty + no_pk_chk_reg_a: assert property(disable iff(!reset_n || fv_zeroize)no_pk_chk_reg_p); + +endmodule + + +bind ecc_dsa_ctrl fv_ecc_dsa_ctrl_m fv_ecc_dsa_ctrl ( + .clk(clk), + .reset_n(reset_n), + .cptra_pwrgood(cptra_pwrgood), + + .hwif_out(hwif_out), + .hwif_in(hwif_in), + + .kv_read(kv_read), + .kv_rd_resp(kv_rd_resp), + .kv_write(kv_write), + .kv_wr_resp(kv_wr_resp), + .pcr_signing_data(pcr_signing_data), + + .error_intr(error_intr), + .notif_intr(notif_intr), + .debugUnlock_or_scan_mode_switch(debugUnlock_or_scan_mode_switch) + ); \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_ecc_dsa_sequencer.sv b/src/ecc/formal/properties/fv_ecc_dsa_sequencer.sv new file mode 100644 index 000000000..895625f5d --- /dev/null +++ b/src/ecc/formal/properties/fv_ecc_dsa_sequencer.sv @@ -0,0 +1,355 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_dsa_sequencer + import ecc_pm_uop_pkg::*; + import ecc_dsa_uop_pkg::*; + #( + parameter ADDR_WIDTH = 8, + parameter DATA_WIDTH = 32 + ) + ( + input wire clk, + input wire rst_n, + input wire ena, + input wire [ADDR_WIDTH-1 : 0] addra, + input logic [DATA_WIDTH-1 : 0] douta + ); + + /////////////////////////////////////////////// + // Helper logic for driving the addra, these assertions + // are used only at block level + /////////////////////////////////////////////// + + logic [ADDR_WIDTH-1 : 0] fv_cntr_const,fv_cntr_kgn,fv_cntr_sgn,fv_cntr_ver; + logic fv_const_set, fv_kgn_set,fv_sgn_set,fv_ver_set; + + always_ff @(posedge clk or negedge rst_n) begin + if(!rst_n) begin + fv_cntr_const <= '0; + fv_cntr_kgn <= '0; + fv_cntr_sgn <= '0; + fv_cntr_ver <= '0; + fv_const_set <= 0; + fv_kgn_set <= 0; + fv_sgn_set <= 0; + fv_ver_set <= 0; + end + else begin + if(addra ==0) begin + fv_ver_set <= 0; + fv_const_set <=1; + fv_cntr_const <= addra+1; + end + else if(fv_const_set) begin + fv_cntr_const <= fv_cntr_const+1; + end + if(addra ==DSA_KG_S) begin + fv_const_set <=0; + fv_kgn_set <= 1; + fv_cntr_kgn <= addra+1; + end + else if(fv_kgn_set) begin + fv_cntr_kgn <= fv_cntr_kgn+1; + end + if(addra == DSA_SGN_S) begin + fv_kgn_set <=0; + fv_sgn_set <= 1; + fv_cntr_sgn <= addra +1; + end + else if(fv_sgn_set) begin + fv_cntr_sgn <= fv_cntr_sgn+1; + end + if(addra == DSA_VER_S) begin + fv_sgn_set <=0; + fv_ver_set <= 1; + fv_cntr_ver <= addra +1; + end + else if(fv_ver_set) begin + fv_cntr_ver <= fv_cntr_ver+1; + end + + + end + end + + cntr_assume: assume property(disable iff(!rst_n) fv_const_set |-> addra == fv_cntr_const); + cntr_assume_kgn: assume property(disable iff(!rst_n) fv_kgn_set |-> addra == fv_cntr_kgn); + cntr_assume_sgn: assume property(disable iff(!rst_n) fv_sgn_set |-> addra == fv_cntr_sgn); + cntr_assume_ver: assume property(disable iff(!rst_n) fv_ver_set |-> addra == fv_cntr_ver); + always_enable: assume property(disable iff(!rst_n) ena == 1'b1); + + default clocking default_clk @(posedge clk); endclocking + + + sequence reset_sequence; + !rst_n ##1 rst_n; + endsequence + + + //////////////////////////////////////////// + // reset property, when reset out a and b // + // are zero // + //////////////////////////////////////////// + + property reset_p; + $past(!rst_n) + |-> + douta == '0; + endproperty + + reset_a : assert property(reset_p); + + + //If the addra input has illegal addresses then the output douta should be zero + property illegal_addr_p; + ((addra > DSA_NOP) && (addra < DSA_KG_S)) || + ((addra > DSA_KG_E) && (addra < DSA_SGN_S)) || + ((addra > DSA_SGN_E) && (addra < DSA_VER_S)) || + (addra > DSA_VER_E) + |=> + douta == '0; + endproperty + illegal_addr_a : assert property(disable iff(!rst_n) illegal_addr_p); + + + + //Checks the sequence where some constant values are written into the memory + property const_p; + addra == 0 + |-> + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} //no operation + ##1 douta == {DSA_UOP_WR_CORE, CONST_ZERO_ID, UOP_OPR_CONST_ZERO} // write to the memory addr zero with value zero + ##1 douta == {DSA_UOP_WR_CORE, CONST_ONE_ID, UOP_OPR_CONST_ONE} // write to the memory addr one with value one + ##1 douta == {DSA_UOP_WR_CORE, CONST_E_a_MONT_ID, UOP_OPR_CONST_E_a} // write to the memory addr two with value mont_a + ##1 douta == {DSA_UOP_WR_CORE, CONST_E_3b_MONT_ID, UOP_OPR_CONST_E_3b} // write to the memory addr three with value mont_3b + ##1 douta == {DSA_UOP_WR_CORE, CONST_ONE_p_MONT_ID, UOP_OPR_CONST_ONE_MONT} // write to the memory addr four with value const_one in mont for mod p + ##1 douta == {DSA_UOP_WR_CORE, CONST_R2_p_MONT_ID, UOP_OPR_CONST_R2_p} // write to the memory addr five with value R2 in mont domain mod p, used for converting normal domain to mont domain + ##1 douta == {DSA_UOP_WR_CORE, CONST_G_X_MONT_ID, UOP_OPR_CONST_GX_MONT} // write to the memory addr six with value Gx in mont domain + ##1 douta == {DSA_UOP_WR_CORE, CONST_G_Y_MONT_ID, UOP_OPR_CONST_GY_MONT} // write to the memory addr seven with value Gy in mont domain + ##1 douta == {DSA_UOP_WR_CORE, CONST_R2_q_MONT_ID, UOP_OPR_CONST_R2_q} // write to the memory addr 29 with value R2 in mont domain mod q, used for converting normal domain to mont domain + ##1 douta == {DSA_UOP_WR_CORE, CONST_ONE_q_MONT_ID, UOP_OPR_CONST_ONE_q_MONT} //// write to the memory addr 28 with value const_one in mont for mod p + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE}; + endproperty + + + const_a: assert property (disable iff(!rst_n) const_p); + + + // Checks the sequence of operations for the keygen operation + property keygen_p; + addra == DSA_KG_S + |-> + ##1 douta <= {DSA_UOP_HMAC_DRBG, NOP_ID, UOP_OPR_DONTCARE} // Input seed for lamda, scalar, privkey genration + ##1 douta <= {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta <= {DSA_UOP_WR_CORE, SCALAR_G_ID, UOP_OPR_SCALAR_G} // Writing scalar here it is privkey to the memory + ##1 douta <= {DSA_UOP_RD_CORE, PRIVKEY_ID, UOP_OPR_SCALAR_G} // Read the generated privkey, used for out + ##1 douta <= {DSA_UOP_SCALAR_SCA, SCALAR_G_ID, UOP_OPR_DONTCARE} // passing the generated scalar to scalar blinding as input + ##1 douta <= {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta <= {DSA_UOP_WR_SCALAR, SCALAR_ID, UOP_OPR_DONTCARE} // the scalar blinded privkey is used as a secret key + ##1 douta <= {DSA_UOP_WR_CORE, LAMBDA_ID, UOP_OPR_LAMBDA} // lamda generated by hmac_drbg is stored into memory + ##1 douta <= {DSA_UOP_KEYGEN, NOP_ID, UOP_OPR_DONTCARE} // keygen cmd triggered in pm_ctrl to generate pub key + ##1 douta <= {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta <= {DSA_UOP_RD_CORE, PUBKEYX_ID, UOP_OPR_Qx_AFFN} // reading the generated pubkey x and y from memory + ##1 douta <= {DSA_UOP_RD_CORE, PUBKEYY_ID, UOP_OPR_Qy_AFFN} + ##1 douta <= {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE}; + endproperty + + keygen_a: assert property (disable iff(!rst_n) keygen_p); + + + // Checks the sequence of operations for the signing operation + property sign_p; + addra == DSA_SGN_S + |-> + ##1 douta == {DSA_UOP_WR_CORE, MSG_ID, UOP_OPR_HASH_MSG} //Input hash msg + ##1 douta == {DSA_UOP_WR_CORE, PRIVKEY_ID, UOP_OPR_PRIVKEY} //Input priv key + ##1 douta == {DSA_UOP_HMAC_DRBG, NOP_ID, UOP_OPR_DONTCARE} // Feed in h and pk for k genration + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta == {DSA_UOP_WR_CORE, SCALAR_G_ID, UOP_OPR_SCALAR_G} // write to memory with the generated k + ##1 douta == {DSA_UOP_SCALAR_SCA, SCALAR_G_ID, UOP_OPR_DONTCARE} // enable the scalar blinding with k as input + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta == {DSA_UOP_WR_SCALAR, SCALAR_ID, UOP_OPR_DONTCARE} // the randmoised k is written to the secret key in pm ctrl + ##1 douta == {DSA_UOP_WR_CORE, LAMBDA_ID, UOP_OPR_LAMBDA} // lamda generated by hmac_drbg is stored into memory + ##1 douta == {DSA_UOP_WR_CORE, MASKING_ID, UOP_OPR_MASKING} // mask value generated by hmac_drbg is stored into the memory + ##1 douta == {DSA_UOP_SIGN, NOP_ID, UOP_OPR_DONTCARE} // signing cmd is passed to the pm_ctrl + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta == {DSA_UOP_RD_CORE, R_ID, UOP_OPR_SIGN_R} // read the generated r from the memory + ##1 douta == {DSA_UOP_RD_CORE, S_ID, UOP_OPR_SIGN_S} // read the generated s from the memory + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE}; + endproperty + + sign_a: assert property(disable iff(!rst_n) sign_p); + + + + // Checks the sequence of operations for the verifying operation + property verify_p; + addra == DSA_VER_S + |-> + ##1 douta == {DSA_UOP_WR_CORE, CONST_E_b_MONT_ID, UOP_OPR_CONST_E_b} // writing to the memory const b, which is in mont domain + ##1 douta == {DSA_UOP_WR_CORE, PUBKEYX_ID, UOP_OPR_Qx_AFFN} // writing to the memory input pubkey + ##1 douta == {DSA_UOP_WR_CORE, PUBKEYY_ID, UOP_OPR_Qy_AFFN} + ##1 douta == {DSA_UOP_PK_CHK, NOP_ID, UOP_OPR_DONTCARE} // Cmd to pm ctrl to check if the pubkey is on the curve + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta == {DSA_UOP_RD_CORE, PK_VALID_ID, UOP_OPR_PK_VALID} // Reading the result from memory if the pubkey is valid point on the curve + ##1 douta == {DSA_UOP_WR_CORE, MSG_ID, UOP_OPR_HASH_MSG} // writing to the memory input hash msg + ##1 douta == {DSA_UOP_WR_CORE, R_ID, UOP_OPR_SIGN_R} // writing to the memory input r + ##1 douta == {DSA_UOP_WR_CORE, S_ID, UOP_OPR_SIGN_S} // writing to the memory input s + ##1 douta == {DSA_UOP_WR_CORE, CONST_ONE_ID, UOP_OPR_LAMBDA} // writing to the memory for lamda as value 1 + ##1 douta == {DSA_UOP_VERIFY0, NOP_ID, UOP_OPR_DONTCARE} // verify0_cmd triggered in pm ctrl + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta == {DSA_UOP_RD_CORE, SCALAR_G_ID, UOP_OPR_SCALAR_G} // reading from memory (h*s_inv) value in normal domain + ##1 douta == {DSA_UOP_RD_CORE, SCALAR_PK_ID, UOP_OPR_SCALAR_PK} // reading from memory (r*s_inv) value in normal domain + ##1 douta == {DSA_UOP_WR_SCALAR, SCALAR_G_ID, UOP_OPR_DONTCARE} // (h*s_inv) value shifted by RND_SIZE and provided to pm as secret key + ##1 douta == {DSA_UOP_VERIFY1, NOP_ID, UOP_OPR_DONTCARE} // verify1_cmd passed to pm_ctrl, result in R0_x,y,z + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta == {DSA_UOP_WR_CORE, PUBKEYX_ID, UOP_OPR_Qx_AFFN} // writing into memory the pubkey again + ##1 douta == {DSA_UOP_WR_CORE, PUBKEYY_ID, UOP_OPR_Qy_AFFN} + ##1 douta == {DSA_UOP_WR_SCALAR, SCALAR_PK_ID, UOP_OPR_DONTCARE} // (r*s_inv) value shifted by RND_SIZE and provided to pm as secret key + ##1 douta == {DSA_UOP_VERIFY2, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE} + ##1 douta == {DSA_UOP_RD_CORE, VERIFY_R_ID, UOP_OPR_Qx_AFFN} //Computed r' in normal domain read back from memory + ##1 douta == {DSA_UOP_NOP, NOP_ID, UOP_OPR_DONTCARE}; + endproperty + + verify_a: assert property(disable iff(!rst_n) verify_p); + + + +//If the first field is DSA_UOP_NOP, the next fields should be NOP_ID and UOP_OPR_DONTCARE, respectively. + + property when_nop_both_id_addr_0_p; + douta[19:12] == DSA_UOP_NOP + |-> + douta[11:0]== {NOP_ID,UOP_OPR_DONTCARE}; + endproperty + +when_nop_both_id_addr_0_a: assert property(disable iff(!rst_n) when_nop_both_id_addr_0_p); + + +//If the first field is DSA_UOP_WR_CORE, the next fields should include a valid ID and ADDRESS, respectively. + + property when_wr_both_id_addr_not_0_p; + douta[19:12] == DSA_UOP_WR_CORE + |-> + douta[11:0] == {CONST_ZERO_ID, UOP_OPR_CONST_ZERO} || + douta[11:0] == {CONST_ONE_ID, UOP_OPR_CONST_ONE} || + douta[11:0] == {CONST_E_a_MONT_ID, UOP_OPR_CONST_E_a} || + douta[11:0] == {CONST_E_3b_MONT_ID, UOP_OPR_CONST_E_3b} || + douta[11:0] == {CONST_ONE_p_MONT_ID, UOP_OPR_CONST_ONE_MONT} || + douta[11:0] == {CONST_R2_p_MONT_ID, UOP_OPR_CONST_R2_p} || + douta[11:0] == {CONST_G_X_MONT_ID, UOP_OPR_CONST_GX_MONT} || + douta[11:0] == {CONST_G_Y_MONT_ID, UOP_OPR_CONST_GY_MONT} || + douta[11:0] == {CONST_R2_q_MONT_ID, UOP_OPR_CONST_R2_q} || + douta[11:0] == {CONST_ONE_q_MONT_ID, UOP_OPR_CONST_ONE_q_MONT} || + douta[11:0] == {SCALAR_G_ID, UOP_OPR_SCALAR_G} || + douta[11:0] == {LAMBDA_ID, UOP_OPR_LAMBDA} || + douta[11:0] == {MSG_ID, UOP_OPR_HASH_MSG} || + douta[11:0] == {PRIVKEY_ID, UOP_OPR_PRIVKEY} || + douta[11:0] == {MASKING_ID, UOP_OPR_MASKING} || + douta[11:0] == {CONST_E_b_MONT_ID, UOP_OPR_CONST_E_b} || + douta[11:0] == {R_ID, UOP_OPR_SIGN_R} || + douta[11:0] == {S_ID, UOP_OPR_SIGN_S} || + douta[11:0] == {CONST_ONE_ID, UOP_OPR_LAMBDA} || + douta[11:0] == {PUBKEYX_ID, UOP_OPR_Qx_AFFN} || + douta[11:0] == {PUBKEYY_ID, UOP_OPR_Qy_AFFN}; + endproperty + +when_wr_both_id_addr_not_0_a: assert property(disable iff(!rst_n) when_wr_both_id_addr_not_0_p); + + +//If the first field is DSA_UOP_HMAC_DRBG, the next fields should be NOP_ID and UOP_OPR_DONTCARE, respectively. + property when_drbg_both_id_addr_0_p; + douta[19:12] == DSA_UOP_HMAC_DRBG + |-> + douta[11:0] == {NOP_ID,UOP_OPR_DONTCARE}; + endproperty + +when_drbg_both_id_addr_0_a: assert property(disable iff(!rst_n) when_drbg_both_id_addr_0_p); + +//If the first field is DSA_UOP_SCALAR_SCA, the next fields should be SCALAR_G_ID and UOP_OPR_DONTCARE, respectively. + property when_scalar_both_id_addr_p; + douta[19:12] == DSA_UOP_SCALAR_SCA + |-> + douta[11:0] == {SCALAR_G_ID,UOP_OPR_DONTCARE}; + endproperty + +when_scalar_both_id_addr_a: assert property(disable iff(!rst_n) when_scalar_both_id_addr_p); + +//If the first field is DSA_UOP_WR_SCALAR, the next fields should be SCALAR_ID/ SCALAR_G_ID/ SCALAR_G_ID and UOP_OPR_DONTCARE, respectively. + property when_wr_scalar_both_id_addr_p; + douta[19:12] == DSA_UOP_WR_SCALAR + |-> + (douta[11:6] == SCALAR_G_ID || + douta[11:6] == SCALAR_ID || + douta[11:6] == SCALAR_PK_ID ) && + douta[5:0] == UOP_OPR_DONTCARE; + endproperty + +when_wr_scalar_both_id_addr_a: assert property(disable iff(!rst_n) when_wr_scalar_both_id_addr_p); + + + +//If the first field is DSA_UOP_KEYGEN/ DSA_UOP_KEYGEN/ DSA_UOP_VERIFY0-2, the next fields should be NOP_ID and UOP_OPR_DONTCARE, respectively. + + property when_commands_both_id_addr_0_p; + douta[19:12] == DSA_UOP_KEYGEN || + douta[19:12] == DSA_UOP_SIGN || + douta[19:12] == DSA_UOP_VERIFY0 || + douta[19:12] == DSA_UOP_VERIFY1 || + douta[19:12] == DSA_UOP_VERIFY2 + |-> + douta[11:0] == {NOP_ID,UOP_OPR_DONTCARE}; + endproperty + +when_commands_both_id_addr_0_a: assert property(disable iff(!rst_n) when_commands_both_id_addr_0_p); + +//o If the first field is DSA_UOP_RD_CORE, the next fields should include a valid ID and ADDRESS, respectively. + + property when_rd_both_id_addr_not_0_p; + douta[19:12] == DSA_UOP_RD_CORE + |-> + douta[11:0] == {PRIVKEY_ID, UOP_OPR_SCALAR_G} || + douta[11:0] == {PUBKEYX_ID, UOP_OPR_Qx_AFFN} || + douta[11:0] == {PUBKEYY_ID, UOP_OPR_Qy_AFFN} || + douta[11:0] == {R_ID, UOP_OPR_SIGN_R} || + douta[11:0] == {S_ID, UOP_OPR_SIGN_S} || + douta[11:0] == {PK_VALID_ID, UOP_OPR_PK_VALID} || + douta[11:0] == {SCALAR_G_ID, UOP_OPR_SCALAR_G} || + douta[11:0] == {SCALAR_PK_ID, UOP_OPR_SCALAR_PK} || + douta[11:0] == {VERIFY_R_ID, UOP_OPR_Qx_AFFN}; + endproperty + +when_rd_both_id_addr_not_0_a: assert property(disable iff(!rst_n) when_rd_both_id_addr_not_0_p); + + +endmodule + + +bind ecc_dsa_sequencer fv_ecc_dsa_sequencer + #(.ADDR_WIDTH(ADDR_WIDTH), + .DATA_WIDTH(DATA_WIDTH) + ) + fv_ecc_dsa_sequencer_inst( + .clk(clka), + .rst_n(reset_n && !zeroize), + .ena(ena), + .addra(addra), + .douta(douta) + ); diff --git a/src/ecc/formal/properties/fv_ecc_fau.sv b/src/ecc/formal/properties/fv_ecc_fau.sv new file mode 100644 index 000000000..b1f85eb10 --- /dev/null +++ b/src/ecc/formal/properties/fv_ecc_fau.sv @@ -0,0 +1,167 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_fau_m #( + parameter REG_SIZE = 384, + parameter RADIX = 32 + ) + ( + // Clock and reset. + input wire clk, + input wire rst_n, + // DATA PORT + input wire add_en_i, + input wire sub_i, + input wire mult_en_i, + input wire [REG_SIZE-1:0] prime_i, + input wire [RADIX-1 : 0] mult_mu_i, + input wire [REG_SIZE-1:0] opa_i, + input wire [REG_SIZE-1:0] opb_i, + input wire [REG_SIZE-1:0] add_res_o, + input wire [REG_SIZE-1:0] mult_res_o + ); + + + default clocking default_clk @(posedge clk); endclocking + + sequence reset_sequence; + (!rst_n) ##1 rst_n; + endsequence + + + /////////////////////////////////////////// + // reset property, when reset all the o/p // + // are zero // + //////////////////////////////////////////// + + property reset_p; + $past(!rst_n) + |-> + `ifdef TOP + add_res_o == '0 && //need to be defined on top as at block level open inputs and could take any value being comb + `endif + mult_res_o == '0 && + ecc_fau.mult_start_edge == '0 && + ecc_fau.sub == '0 && + ecc_fau.add_start_edge == '0 ; + endproperty + + reset_a : assert property(reset_p); + + //When ever mult_en_i is triggered, it would just generate one pulse + + property mult_pulse_p; + $rose(mult_en_i) + |=> + ecc_fau.mult_start_edge + ##1 + !ecc_fau.mult_start_edge; + endproperty + + mult_pulse_a: assert property(disable iff(!rst_n) mult_pulse_p); + + + //Once edge triggered from next cycle on it stays out until there is an another mult cmd + property no_mult_edge_p; + ecc_fau.mult_start_edge + |=> + !ecc_fau.mult_start_edge s_until_with mult_en_i; + endproperty + no_mult_edge_a: assert property(disable iff(!rst_n)no_mult_edge_p); + + + //When ever add_en_i is triggered, it would just generate one pulse + property add_pulse_p; + $rose(add_en_i) + |=> + ecc_fau.add_start_edge + ##1 + !ecc_fau.add_start_edge; + endproperty + + add_pulse_a: assert property(disable iff(!rst_n) add_pulse_p); + + + //Once edge triggered from next cycle on it stays out until there is an another add cmd + property no_add_edge_p; + ecc_fau.add_start_edge + |=> + !ecc_fau.add_start_edge s_until_with add_en_i; + endproperty + no_add_edge_a: assert property(disable iff(!rst_n)no_add_edge_p); + + + //Primary outputs connected to primary outputs of submodules + property outputs_p; + mult_res_o == ecc_fau.mult_res_s && + add_res_o == ecc_fau.add_res_s; + endproperty + + outputs_a: assert property(disable iff(!rst_n) outputs_p); + + + //Primary inputs connected to primary inputs of submodules + property inputs_p; + ecc_fau.mult_opa == opa_i && + ecc_fau.mult_opb == opb_i; + endproperty + + inputs_a: assert property(disable iff(!rst_n) inputs_p); + + + //When add and mult ready + property garbage_ready_p; + ecc_fau.ready_garbage_bit == (ecc_fau.add_ready_o & ecc_fau.mult_ready_o); + endproperty + garbage_ready_a: assert property(disable iff(!rst_n) garbage_ready_p); + + + // Always the results should be less than the prime + `ifdef TOP + property data_out_prime_p(ready,result); + (ready) + |-> + ((result < prime_i)) + ;endproperty + data_out_add_sub_res_prime_a: assert property(disable iff(!rst_n) data_out_prime_p(ecc_fau.add_ready_o,add_res_o)); + data_out_mult_res_prime_a: assert property(disable iff(!rst_n) data_out_prime_p(ecc_fau.mult_ready_o,mult_res_o)); + `endif + +endmodule + bind ecc_fau fv_ecc_fau_m #( + .REG_SIZE(REG_SIZE), + .RADIX(RADIX) + ) + ecc_fau_i + ( + // Clock and reset. + .clk(clk), + .rst_n(reset_n && !zeroize), + + // DATA PORT + .add_en_i(add_en_i), + .sub_i(sub_i), + .mult_en_i(mult_en_i), + .prime_i(prime_i), + .mult_mu_i(mult_mu_i), + .opa_i(opa_i), + .opb_i(opb_i), + .add_res_o(add_res_o), + .mult_res_o(mult_res_o) + ); + diff --git a/src/ecc/formal/properties/fv_ecc_hmac_drbg_interface.sv b/src/ecc/formal/properties/fv_ecc_hmac_drbg_interface.sv new file mode 100644 index 000000000..3a4c45390 --- /dev/null +++ b/src/ecc/formal/properties/fv_ecc_hmac_drbg_interface.sv @@ -0,0 +1,547 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +`define hiearchy ecc_hmac_drbg_interface + +module fv_ecc_hmac_drbg_interface_m#( + parameter REG_SIZE = 384, + parameter [REG_SIZE-1 : 0] GROUP_ORDER = 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973, + parameter [147 : 0] LFSR_INIT_SEED = 148'h6_04E7_A407_54F1_4487_A021_11AC_D0DF_8C55_57A0 // a random value + ) + ( + // Clock and reset. + input wire clk, + input wire rst_n, + input wire keygen_sign, + input wire en, + input wire ready, + + //Inputs + input wire [REG_SIZE-1 : 0] keygen_seed, + input wire [REG_SIZE-1 : 0] keygen_nonce, + input wire [REG_SIZE-1 : 0] privKey, + input wire [REG_SIZE-1 : 0] hashed_msg, + input wire [REG_SIZE-1 : 0] IV, + + //Outputs + input wire [REG_SIZE-1 : 0] lambda, + input wire [REG_SIZE-1 : 0] scalar_rnd, + input wire [REG_SIZE-1 : 0] masking_rnd, + input wire [REG_SIZE-1 : 0] drbg + ); + + localparam [3 : 0] IDLE_ST = 4'd0; + localparam [3 : 0] LFSR_ST = 4'd1; + localparam [3 : 0] LAMBDA_ST = 4'd2; + localparam [3 : 0] SCALAR_RND_ST = 4'd3; + localparam [3 : 0] RND_DONE_ST = 4'd4; + localparam [3 : 0] MASKING_RND_ST = 4'd5; + localparam [3 : 0] KEYGEN_ST = 4'd6; + localparam [3 : 0] SIGN_ST = 4'd7; + localparam [3 : 0] DONE_ST = 4'd8; + + default clocking default_clk @(posedge clk); endclocking + + sequence reset_sequence; + (!rst_n) ##1 rst_n; + endsequence + + /////////////////////////////////////////// + // constraint on hashed msg + /////////////////////////////////////////// + hash_msg_less_than_grp_order: assume property(disable iff(!rst_n) hashed_msg < GROUP_ORDER); + + + /////////////////////////////////////////// + // Helper logic for lfsr_seed + /////////////////////////////////////////// + + logic [147 : 0] fv_lfsr_seed_reg; + logic [383:0] fv_hmac_drbg_result_reg; + logic fv_hmac_drbg_valid_reg; + always_ff @(posedge clk, negedge rst_n) begin + if(!rst_n) + fv_lfsr_seed_reg <= LFSR_INIT_SEED; + else begin + fv_hmac_drbg_valid_reg <= `hiearchy.hmac_drbg_valid; + fv_hmac_drbg_result_reg <= `hiearchy.hmac_drbg_result; + if(`hiearchy.state_reg == LFSR_ST && `hiearchy.hmac_drbg_valid && !fv_hmac_drbg_valid_reg) begin + fv_lfsr_seed_reg <= `hiearchy.hmac_drbg_result[147 : 0]; + end + end + end + + + /////////////////////////////////////////// + // reset property, when reset all the o/p // + // are zero // + //////////////////////////////////////////// + + property reset_p; + $past(!rst_n) + |-> + `hiearchy.state_reg == IDLE_ST && + lambda == '0 && + scalar_rnd == '0 && + masking_rnd == '0 && + drbg == '0 && + ready == 1; + endproperty + + reset_a : assert property(reset_p); + + + //State transitioning from idle to lfsr if en and hmac_drbg_ready + property idle_to_lfsr_p; + `hiearchy.state_reg == IDLE_ST && + (en & `hiearchy.hmac_drbg_ready) + |=> + `hiearchy.state_reg == LFSR_ST && + `hiearchy.hmac_drbg_init == 1 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == IV && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + `hiearchy.hmac_drbg_nonce == $past(`hiearchy.counter_nonce) && + ready == 0 && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg) + ; + + endproperty + + idle_to_lfsr_a: assert property(disable iff(!rst_n) idle_to_lfsr_p); + + + // If en and hmac_drbg isn't ready then stays back in idle state + property idle_wait_p; + `hiearchy.state_reg == IDLE_ST && + !(en & `hiearchy.hmac_drbg_ready) + |=> + `hiearchy.state_reg == IDLE_ST && + ready == 1 && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == '0 && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + `hiearchy.hmac_drbg_nonce == (`hiearchy.counter_nonce_reg) && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + + idle_wait_a: assert property(disable iff(!rst_n) idle_wait_p); + + + // State transition from lfsr to lambda when hmac_drbg_valid is set + property lfsr_to_lambda_p; + `hiearchy.state_reg== LFSR_ST && + $rose(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == LAMBDA_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 1 && + `hiearchy.hmac_drbg_entropy == IV && + ready == 0 && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + `hiearchy.hmac_lfsr_seed == $past(`hiearchy.hmac_drbg_result[147 : 0]) ^ `hiearchy.counter_nonce[147 : 0] && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + + lfsr_to_lambda_a: assert property(disable iff(!rst_n) lfsr_to_lambda_p); + + + // If hmac_drbg_valid isn't set then stays back in same state + property lfsr_wait_p; + `hiearchy.state_reg == LFSR_ST && + !(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == LFSR_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == IV && + ready == 0 && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg) + ; + endproperty + lfsr_wait_a: assert property(disable iff(!rst_n) lfsr_wait_p); + + + //State transition from lamda to scalar_rnd when hmac_drbg_valid is set + property lambda_to_scalar_rnd_p; + `hiearchy.state_reg == LAMBDA_ST && + $rose(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == SCALAR_RND_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 1 && + `hiearchy.hmac_drbg_entropy == IV && + ready == 0 && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + `hiearchy.hmac_lfsr_seed == fv_lfsr_seed_reg ^ `hiearchy.counter_nonce[147 : 0] && + lambda == $past(`hiearchy.hmac_drbg_result) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + + lambda_to_scalar_rnd_a: assert property(disable iff(!rst_n) lambda_to_scalar_rnd_p); + + + //If hmac_drbg_valid isn't set then stays back in same state + property lambda_wait_p; + `hiearchy.state_reg == LAMBDA_ST && + !(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == LAMBDA_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == IV && + ready == 0 && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + lambda_wait_a: assert property(disable iff(!rst_n) lambda_wait_p); + + + //State transition from scalar_rnd to rnd_done when hmac_drbg_valid is set + property scalar_rnd_to_rnd_done_p; + `hiearchy.state_reg == SCALAR_RND_ST && + $rose(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == RND_DONE_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == '0 && + ready == 0 && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + lambda == $past(lambda) && + scalar_rnd == $past(`hiearchy.hmac_drbg_result) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + scalar_rnd_to_rnd_done_a: assert property(disable iff(!rst_n) scalar_rnd_to_rnd_done_p); + + + //If hmac_drbg_valid isn't set then stays back in same state + property scalar_rnd_wait_p; + `hiearchy.state_reg == SCALAR_RND_ST && + !(`hiearchy.hmac_drbg_valid) + + |=> + `hiearchy.state_reg == SCALAR_RND_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == IV && + ready == 0 && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + scalar_rnd_wait_a: assert property(disable iff(!rst_n) scalar_rnd_wait_p); + + + // if in rnd_done state then if keygen_sign is set then state changes to masking_rnd + property rnd_done_to_masking_rnd_p; + `hiearchy.state_reg == RND_DONE_ST && + keygen_sign + |=> + `hiearchy.state_reg == MASKING_RND_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 1 && + `hiearchy.hmac_drbg_entropy == IV && + ready == 0 && + `hiearchy.hmac_lfsr_seed == fv_lfsr_seed_reg ^ `hiearchy.counter_nonce[147 : 0] && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + rnd_done_to_masking_rnd_a: assert property(disable iff(!rst_n) rnd_done_to_masking_rnd_p); + + + // if in rnd_done state then if keygen_sign isn't set then state changes to keygen + property rnd_done_to_keygen_p; + `hiearchy.state_reg == RND_DONE_ST && + !keygen_sign + |=> + `hiearchy.state_reg == KEYGEN_ST && + `hiearchy.hmac_drbg_init == 1 && + `hiearchy.hmac_drbg_next == 0 && + ready == 0 && + `hiearchy.hmac_drbg_entropy == keygen_seed && + `hiearchy.hmac_lfsr_seed == fv_lfsr_seed_reg ^ `hiearchy.counter_nonce[147 : 0] && + `hiearchy.hmac_drbg_nonce == keygen_nonce && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + rnd_done_to_keygen_a: assert property(disable iff(!rst_n) rnd_done_to_keygen_p); + + + //State transition from masking_rnd to sign when hmac_drbg_valid is set + property masking_rnd_to_sign_p; + `hiearchy.state_reg == MASKING_RND_ST && + $rose(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == SIGN_ST && + `hiearchy.hmac_drbg_init == 1 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == privKey && + ready == 0 && + `hiearchy.hmac_drbg_nonce == hashed_msg && + `hiearchy.hmac_lfsr_seed == fv_lfsr_seed_reg ^ `hiearchy.counter_nonce[147 : 0] && + masking_rnd == $past(`hiearchy.hmac_drbg_result) && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + + drbg == $past(drbg); + endproperty + masking_rnd_to_sign_a: assert property(disable iff(!rst_n) masking_rnd_to_sign_p); + + //If hmac_drbg_valid isn't set then stays back in same state + property masking_rnd_wait_p; + `hiearchy.state_reg == MASKING_RND_ST && + !(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == MASKING_RND_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == IV && + ready == 0 && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + masking_rnd_wait_a: assert property(disable iff(!rst_n) masking_rnd_wait_p); + + + //State transition from keygen to done when hmac_drbg_valid is set + property keygen_to_done_p; + `hiearchy.state_reg == KEYGEN_ST && + $rose(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == DONE_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == '0 && + ready == 0 && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(`hiearchy.hmac_drbg_result); + endproperty + keygen_to_done_a: assert property(disable iff(!rst_n) keygen_to_done_p); + + //If hmac_drbg_valid isn't set then stays back in same state + property keygen_wait_p; + `hiearchy.state_reg == KEYGEN_ST && + !(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == KEYGEN_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == keygen_seed && + ready == 0 && + `hiearchy.hmac_drbg_nonce == keygen_nonce && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + keygen_wait_a: assert property(disable iff(!rst_n) keygen_wait_p); + + + + + //State transition from sign to done when hmac_drbg_valid is set + property sign_to_done_p; + `hiearchy.state_reg == SIGN_ST && + $rose(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == DONE_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == '0 && + ready == 0 && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(`hiearchy.hmac_drbg_result); + endproperty + sign_to_done_a: assert property(disable iff(!rst_n) sign_to_done_p); + + + //If hmac_drbg_valid isn't set then stays back in same state + property sign_wait_p; + `hiearchy.state_reg == SIGN_ST && + !(`hiearchy.hmac_drbg_valid) + |=> + `hiearchy.state_reg == SIGN_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == privKey && + ready == 0 && + `hiearchy.hmac_drbg_nonce == hashed_msg && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + sign_wait_a: assert property(disable iff(!rst_n) sign_wait_p); + + + + property done_to_idle_p; + `hiearchy.state_reg == DONE_ST + |=> + `hiearchy.state_reg == IDLE_ST && + `hiearchy.hmac_drbg_init == 0 && + `hiearchy.hmac_drbg_next == 0 && + `hiearchy.hmac_drbg_entropy == '0 && + ready == 1 && + `hiearchy.hmac_drbg_nonce == `hiearchy.counter_nonce_reg && + `hiearchy.hmac_lfsr_seed == (fv_lfsr_seed_reg) ^ `hiearchy.counter_nonce[147:0] && + lambda == $past(lambda) && + scalar_rnd == $past(scalar_rnd) && + masking_rnd == $past(masking_rnd) && + drbg == $past(drbg); + endproperty + done_to_idle_a: assert property(disable iff(!rst_n) done_to_idle_p); + + + + + //counter_reg is checked if it adds 1 after everycycle + + // Helper logic for reset reg to use in disable iff + logic fv_rst_n_reg; + always_ff @(posedge clk) begin + fv_rst_n_reg <= rst_n; + end + + property counter_reg_p; + `hiearchy.counter_reg == $past(`hiearchy.counter_reg)+1; + endproperty + counter_reg_a: assert property(disable iff(!rst_n || !fv_rst_n_reg) counter_reg_p); + + + + //counter_nonce_reg has counter_nonce onece en is triggered. + property counter_nonce_reg_p; + en + |=> + `hiearchy.counter_nonce_reg == $past(`hiearchy.counter_nonce); + endproperty + counter_nonce_reg_a: assert property(disable iff(!rst_n) counter_nonce_reg_p); + + // counter_nonce_reg stable if no en + property counter_nonce_reg_stable_p; + !en + |=> + `hiearchy.counter_nonce_reg == $past(`hiearchy.counter_nonce_reg); + endproperty + counter_nonce_reg_stable_a: assert property(disable iff(!rst_n) counter_nonce_reg_stable_p); + + + + + + //done_edge is a pulse from the hmac_drbg_valid + property done_pulse_p; + $rose(`hiearchy.hmac_drbg_valid) + |-> + `hiearchy.hmac_done_edge + ##1 + !`hiearchy.hmac_done_edge; + endproperty + + done_pulse_a: assert property(disable iff(!rst_n) done_pulse_p); + + + // eventually ready==1, once the fsm triggered + property ready_liveliness_p; + `hiearchy.state_reg == IDLE_ST && + (en & `hiearchy.hmac_drbg_ready) + |-> + s_eventually(ready); + endproperty + ready_liveliness_a: assert property(disable iff(!rst_n) ready_liveliness_p); + +endmodule + +bind ecc_hmac_drbg_interface fv_ecc_hmac_drbg_interface_m#( + .REG_SIZE(REG_SIZE), + .GROUP_ORDER(GROUP_ORDER) + ) + fv_ecc_hmac_drbg_interface ( + .clk(clk), + .rst_n(reset_n && !zeroize), + .keygen_sign(keygen_sign), + .en(en), + .ready(ready), + .keygen_seed(keygen_seed), + .keygen_nonce(keygen_nonce), + .privKey(privKey), + .hashed_msg(hashed_msg), + .IV(IV), + .lambda(lambda), + .scalar_rnd(scalar_rnd), + .masking_rnd(masking_rnd), + .drbg(drbg) + ); + + + + + + + + + \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_ecc_hmac_drbg_interface_constraints.sv b/src/ecc/formal/properties/fv_ecc_hmac_drbg_interface_constraints.sv new file mode 100644 index 000000000..6e8f9a07c --- /dev/null +++ b/src/ecc/formal/properties/fv_ecc_hmac_drbg_interface_constraints.sv @@ -0,0 +1,113 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_hmac_drbg_interface_constraints_m #( + parameter time_window = 3)( + input logic clk, + input logic rst_n, + input logic hmac_drbg_ready, + input logic hmac_drbg_init, + input logic hmac_drbg_next, + input logic hmac_drbg_valid, + input logic [383:0] counter_nonce +); + +default clocking default_clk @(posedge clk); endclocking + + + +property hmac_drbg_ready_after_reset(hmac_drbg_ready); + (!rst_n) + |=> + hmac_drbg_ready; + endproperty +assume_hmac_drbg_ready_after_reset : assume property(@(posedge clk) hmac_drbg_ready_after_reset(hmac_drbg_ready)); + + sequence idletonext(hmac_drbg_ready, hmac_drbg_init, hmac_drbg_next); + hmac_drbg_ready && + (hmac_drbg_init || hmac_drbg_next); + endsequence + + property hmac_drbg_not_ready(hmac_drbg_ready, hmac_drbg_init, hmac_drbg_next,time_window); + idletonext(hmac_drbg_ready, hmac_drbg_init, hmac_drbg_next) + |=> + !hmac_drbg_ready[*time_window] + ##1 + hmac_drbg_ready; + endproperty + assume_hmac_drbg_not_ready : assume property(@(posedge clk)disable iff(!rst_n ) hmac_drbg_not_ready(hmac_drbg_ready, hmac_drbg_init, hmac_drbg_next,time_window)); + + + property hmac_drbg_result_then_ready(hmac_drbg_valid, hmac_drbg_ready); + hmac_drbg_valid + |-> + hmac_drbg_ready; + endproperty + assume_hmac_drbg_result_then_ready : assume property(@(posedge clk) hmac_drbg_result_then_ready(hmac_drbg_valid, hmac_drbg_ready)); + + + property for_init(hmac_drbg_init, hmac_drbg_next, hmac_drbg_valid, time_window); + hmac_drbg_init || hmac_drbg_next + |-> + ##(time_window+1) + hmac_drbg_valid; + endproperty + assume_hmac_drbg_valid_after_init_next : assume property(@(posedge clk)disable iff(!rst_n ) for_init(hmac_drbg_init, hmac_drbg_next, hmac_drbg_valid, time_window)); + + + property for_valid(hmac_drbg_valid, hmac_drbg_init, hmac_drbg_next); + hmac_drbg_valid && + !(hmac_drbg_init || hmac_drbg_next) + |=> + hmac_drbg_valid; + endproperty + assume_hmac_drbg_valid_continous : assume property(@(posedge clk)disable iff(!rst_n ) for_valid(hmac_drbg_valid, hmac_drbg_init, hmac_drbg_next)); + + property hmac_drbg_ready_until_init_next(hmac_drbg_ready, hmac_drbg_init, hmac_drbg_next); + hmac_drbg_ready && + (hmac_drbg_init || hmac_drbg_next) + |=> + !hmac_drbg_ready +;endproperty + assume_hmac_drbg_ready_until_init_next : assume property ( @(posedge clk) disable iff(!rst_n ) hmac_drbg_ready_until_init_next(hmac_drbg_ready, hmac_drbg_init, hmac_drbg_next)); + + + property hmac_drbg_valid_zero_in_all_state(hmac_drbg_valid, hmac_drbg_init, hmac_drbg_next,time_window); + !hmac_drbg_valid && + (hmac_drbg_init || hmac_drbg_next) + |=> + !hmac_drbg_valid[*time_window] + ##1 + hmac_drbg_valid; + endproperty + assume_hmac_drbg_valid_zero_in_all_states : assume property (@(posedge clk) disable iff(!rst_n ) hmac_drbg_valid_zero_in_all_state(hmac_drbg_valid, hmac_drbg_init, hmac_drbg_init, time_window)); + + + assume_cntr_nonce_only_64bit: assume property(@(posedge clk) disable iff(!rst_n ) counter_nonce <= 64'hffffffffffffffff); + +endmodule + +bind ecc_hmac_drbg_interface fv_ecc_hmac_drbg_interface_constraints_m fv_ecc_hmac_drbg_interface_constraints ( + .clk(clk), + .rst_n(reset_n && !zeroize), + .hmac_drbg_init(ecc_hmac_drbg_interface.hmac_drbg_init), + .hmac_drbg_next(ecc_hmac_drbg_interface.hmac_drbg_next), + .hmac_drbg_ready(ecc_hmac_drbg_interface.hmac_drbg_ready), + .hmac_drbg_valid(ecc_hmac_drbg_interface.hmac_drbg_valid), + .counter_nonce(ecc_hmac_drbg_interface.counter_nonce) +); \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_ecc_pm_ctrl_abstract.sv b/src/ecc/formal/properties/fv_ecc_pm_ctrl_abstract.sv new file mode 100644 index 000000000..48dfb1b7f --- /dev/null +++ b/src/ecc/formal/properties/fv_ecc_pm_ctrl_abstract.sv @@ -0,0 +1,1101 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_pm_ctrl_abstract + import ecc_pm_uop_pkg::*; + #( + parameter REG_SIZE = 384, + parameter RND_SIZE = 192, + parameter INSTR_SIZE = 24, + parameter MULT_DLY = 38, + parameter ADD_DLY = 1, + parameter Secp384_MONT_COUNT = 384, + parameter Secp384_SCA_MONT_COUNT = 576 + ) + ( + // Clock and reset. + input wire clk, + input wire rst_n, + + + // from arith_unit + input wire [2 : 0] ecc_cmd_i, + input wire sca_en_i, + input wire digit_i, + input pm_instr_struct_t instr_o, + input logic req_digit_o, + input wire busy_o +); + + /////////////////////////////////////////////////////////////////// + // All the sequences latency from start to end + // The function dly, has the arguments as no. of mult, no. of add+sub + // no. of store operations, rest operations in the sequence + /////////////////////////////////////////////////////////////////// + + localparam CHK_DLY = dly(6,6,3,3,4); + localparam PM_INT_G_DLY = dly(3,3,0,0,0); + localparam PM_INT_DLY = dly(0,0,3,3,4); + localparam PA_DLY = dly(17,17,23,23,0); + localparam PD_DLY = dly(17,17,23,23,4); + localparam CONV_VER0_P1_DLY = dly(4,4,0,0,4); + localparam INV_DLY = dly(519,519,1,1,0); + localparam SIGN0_DLY = dly(7,7,5,5,4); + localparam INVQ_DLY = dly(519,519,1,1,4); + localparam SIGN1_DLY = dly(3,3,1,1,4); + localparam VER0_P0_DLY = dly(3,3,0,0,4); + localparam VER_ST_DLY = dly(0,0,3,3,0); + localparam PM_INT_PK_DLY = dly(2,2,1,1,0); + localparam VER_PA_DLY = dly(17,17,24,24,0); + + localparam PIP_DLY = 3; // The pipeline delay from having the data in instr_o from prog_instr + + + + + + ////////////////////////////////////////// + //Delay computation // + ////////////////////////////////////////// + + function logic [24:0] dly(input logic[11:0] num_mul,input logic[11:0] st_mul,input logic[11:0] num_add_sub,input logic[11:0] st_add_sub,input logic[11:0] rest); + logic [24:0] fv_total_mult_dly; + logic [24:0] fv_total_add_sub_dly; + fv_total_mult_dly = (num_mul*(MULT_DLY+2))+(st_mul); + fv_total_add_sub_dly = (num_add_sub*(ADD_DLY+2))+(st_add_sub); + return(fv_total_mult_dly+fv_total_add_sub_dly+rest-1); + endfunction + + + + + default clocking default_clk @(posedge clk); endclocking + + sequence reset_sequence; + !rst_n ##1 rst_n; + endsequence + + + //////////////////////////////////////////// + // reset property, when reset out and reg // + // are zero // + //////////////////////////////////////////// + + property reset_p; + $past(!rst_n) + |-> + ecc_pm_ctrl.prog_cntr == NOP && + ecc_pm_ctrl.mont_cntr <= '0 && + ecc_pm_ctrl.stall_cntr <= '0 && + ecc_pm_ctrl.stalled <= '0 && + ecc_pm_ctrl.mont_ladder <= '0 && + ecc_pm_ctrl.ecc_cmd_reg <= '0 && + instr_o == '0 && + req_digit_o == '0 && + busy_o == 0; + endproperty + + reset_a : assert property(reset_p); + + + //--------------------------------// + // Unabstracted counter properties// + //-------------------------------// + + // Validates once the check public key cmd is set then the sequence is triggered and finally ends in NOP + property check_point_p(delay); + ecc_cmd_i == CHK_PK_CMD && + ecc_pm_ctrl.prog_cntr == NOP + |=> + ecc_pm_ctrl.prog_cntr == CHK_PK_S + ##delay ecc_pm_ctrl.prog_cntr == CHK_PK_E + ##1 ecc_pm_ctrl.prog_cntr == NOP; + endproperty + check_point_a: assert property(disable iff(!rst_n) check_point_p(CHK_DLY)); + + + // validates once the cmd is set initally it would traverse through PM_INIT_G_S and PM_INIT_S + property pm_init_g_s_to_pm_init_s_p(cmd,delay); + ecc_cmd_i == cmd && + ecc_pm_ctrl.prog_cntr == NOP + |=> + ecc_pm_ctrl.prog_cntr == PM_INIT_G_S && // Initialise R1 with G + ecc_pm_ctrl.mont_cntr == $past((sca_en_i)? ecc_pm_ctrl.Secp384_SCA_MONT_COUNT : ecc_pm_ctrl.Secp384_MONT_COUNT) + ##delay ecc_pm_ctrl.prog_cntr == PM_INIT_G_E + ##1 ecc_pm_ctrl.prog_cntr == PM_INIT_S; // Initialise R0 with (0:1:0) + endproperty + keygen_stage0_a: assert property(disable iff(!rst_n) pm_init_g_s_to_pm_init_s_p(KEYGEN_CMD,PM_INT_G_DLY)); + signing_stage0_a: assert property(disable iff(!rst_n) pm_init_g_s_to_pm_init_s_p(SIGN_CMD,PM_INT_G_DLY)); + + // validates if cmd sequence is ongoing then it would traverse from PM_INIT_S till PA_S + property pm_init_s_to_pa_s_p(cmd,delay); + ecc_pm_ctrl.ecc_cmd_reg == cmd && + ecc_pm_ctrl.prog_cntr == PM_INIT_S + |-> + ##delay ecc_pm_ctrl.prog_cntr == PM_INIT_E + ##1 ecc_pm_ctrl.prog_cntr == PA_S && + ecc_pm_ctrl.mont_cntr == $past(ecc_pm_ctrl.mont_cntr)-1; // Point add + endproperty + keygen_stage1_a: assert property(disable iff(!rst_n) pm_init_s_to_pa_s_p(KEYGEN_CMD,PM_INT_DLY)); + signing_stage1_a: assert property(disable iff(!rst_n) pm_init_s_to_pa_s_p(SIGN_CMD,PM_INT_DLY)); + verify_part1_stage1_a: assert property(disable iff(!rst_n) pm_init_s_to_pa_s_p(VER_PART1_CMD,PM_INT_DLY)); + verify_part2_stage1_a: assert property(disable iff(!rst_n) pm_init_s_to_pa_s_p(VER_PART2_CMD,PM_INT_DLY)); + + + + //validates if cmd sequence is ongoing then it would traverse from PA_S to PD_S + property pa_s_to_pd_s_p(cmd,delay); + ecc_pm_ctrl.ecc_cmd_reg == cmd && + ecc_pm_ctrl.prog_cntr == PA_S + |-> + ##delay ecc_pm_ctrl.prog_cntr == PA_E + ##1 ecc_pm_ctrl.prog_cntr == PD_S; + endproperty + keygen_stage1_1_a: assert property(disable iff(!rst_n) pa_s_to_pd_s_p(KEYGEN_CMD,PA_DLY)); + signing_stage1_1_a: assert property(disable iff(!rst_n) pa_s_to_pd_s_p(SIGN_CMD,PA_DLY)); + verify_part1_stage1_1_a: assert property(disable iff(!rst_n) pa_s_to_pd_s_p(VER_PART1_CMD,PA_DLY)); + verify_part2_stage1_1_a: assert property(disable iff(!rst_n) pa_s_to_pd_s_p(VER_PART2_CMD,PA_DLY)); + + + + //validates if cmd sequence is ongoing then it would traverse from PD_S to PD_E + property pd_s_to_pd_e_p(cmd,delay); + ecc_pm_ctrl.ecc_cmd_reg == cmd && + ecc_pm_ctrl.prog_cntr == PD_S + |-> + ##delay ecc_pm_ctrl.prog_cntr == PD_E; + endproperty + keygen_stage2_1_a: assert property(disable iff(!rst_n) pd_s_to_pd_e_p(KEYGEN_CMD,PD_DLY)); + signing_stage2_1_a: assert property(disable iff(!rst_n) pd_s_to_pd_e_p(SIGN_CMD,PD_DLY)); + verify_part1_stage2_1_a: assert property(disable iff(!rst_n) pd_s_to_pd_e_p(VER_PART1_CMD,PD_DLY)); + verify_part2_stage2_1_a: assert property(disable iff(!rst_n) pd_s_to_pd_e_p(VER_PART2_CMD,PD_DLY)); + + + //validates if cmd sequence is ongoing then it would traverse from PD_E to INV_S when the mont_cntr is zero + property pd_e_to_invs_p(cmd); + ecc_pm_ctrl.ecc_cmd_reg == cmd && + ecc_pm_ctrl.prog_cntr == PD_E && + ecc_pm_ctrl.mont_cntr == 0 + |-> + ##1 ecc_pm_ctrl.prog_cntr == INV_S; + endproperty + keygen_stage2_a: assert property(disable iff(!rst_n) pd_e_to_invs_p(KEYGEN_CMD)); + signing_stage2_a: assert property(disable iff(!rst_n) pd_e_to_invs_p(SIGN_CMD)); + + // validates if cmd sequence is ongoing then it would traverse from PD_E to PA_S when the mont_cntr is not zero + property pd_e_to_pa_s_p(cmd); + ecc_pm_ctrl.ecc_cmd_reg == cmd && + ecc_pm_ctrl.prog_cntr == PD_E && + ecc_pm_ctrl.mont_cntr != 0 + |-> + ##1 ecc_pm_ctrl.prog_cntr == PA_S && + ecc_pm_ctrl.mont_cntr == $past(ecc_pm_ctrl.mont_cntr)-1; + endproperty + keygen_stage2_loop_a: assert property(disable iff(!rst_n) pd_e_to_pa_s_p(KEYGEN_CMD)); + signing_stage2_loop_a: assert property(disable iff(!rst_n) pd_e_to_pa_s_p(SIGN_CMD)); + verify_part1_stage2_loop_a: assert property(disable iff(!rst_n) pd_e_to_pa_s_p(VER_PART1_CMD)); + verify_part2_stage2_loop_a: assert property(disable iff(!rst_n) pd_e_to_pa_s_p(VER_PART2_CMD)); + + //validates if cmd sequence is ongoing then it would traverse from INV_E to CONV_S + property inve_to_convs_p(cmd); + ecc_pm_ctrl.ecc_cmd_reg == cmd && + ecc_pm_ctrl.prog_cntr == INV_E[*(MULT_DLY+2)] //[*3] for mult delay 1 + |-> + ##1 ecc_pm_ctrl.prog_cntr == CONV_S; + endproperty + keygen_stage3_a: assert property(disable iff(!rst_n) inve_to_convs_p(KEYGEN_CMD)); + signing_stage3_a: assert property(disable iff(!rst_n) inve_to_convs_p(SIGN_CMD)); + verify_part2_stage3_2_a: assert property(disable iff(!rst_n) inve_to_convs_p(VER_PART2_CMD)); + + //validates if cmd sequence is ongoing then it would traverse from INV_S to INV_E + property invs_to_inve_p(cmd,delay); + ecc_pm_ctrl.ecc_cmd_reg == cmd && + ecc_pm_ctrl.prog_cntr == INV_S //[*3] for mult delay 1 + |-> + ##delay ecc_pm_ctrl.prog_cntr == INV_E; + endproperty + keygen_stage3_1_a: assert property(disable iff(!rst_n) invs_to_inve_p(KEYGEN_CMD,INV_DLY)); + signing_stage3_1_a: assert property(disable iff(!rst_n) invs_to_inve_p(SIGN_CMD,INV_DLY)); + verify_part2_stage3_1_a: assert property(disable iff(!rst_n) invs_to_inve_p(VER_PART2_CMD,INV_DLY)); + + + //validates if cmd sequence is ongoing then it would traverse from CONV_S to NOP + property convs_to_nop(cmd,delay); + ecc_pm_ctrl.ecc_cmd_reg == cmd && + ecc_pm_ctrl.prog_cntr == CONV_S + |-> + ##delay ecc_pm_ctrl.prog_cntr == CONV_E //##19 mult delay 1 + ##1 ecc_pm_ctrl.prog_cntr == NOP; + endproperty + keygen_stage4_a: assert property(disable iff(!rst_n) convs_to_nop(KEYGEN_CMD,CONV_VER0_P1_DLY)); + verify_part2_stage4_a: assert property(disable iff(!rst_n) convs_to_nop(VER_PART2_CMD,CONV_VER0_P1_DLY)); + + + +///////////////////////////////////////////////////////////////////////////////////// +// ---------------------------------BEGIN----------------------------------------- // +// Checking the counter integrity that the sequence is performed one after another // +///////////////////////////////////////////////////////////////////////////////////// + + logic [PROG_ADDR_W-1 : 0] counter_keygen_a; + logic [PROG_ADDR_W-1 : 0] counter_keygen_b; + logic trigger_counter_keygen_a_reg; + logic trigger_counter_keygen_b_reg; + logic triggered_counter_keygen_a; + logic triggered_counter_keygen_b; + + counter_nonreachable_values: assume property (disable iff(!rst_n)counter_nonreachable_values_p); + property counter_nonreachable_values_p; + counter_keygen_a != PM_INIT_G_E+1 && counter_keygen_b != PM_INIT_G_E+1 && + counter_keygen_a != PM_INIT_E+1 && counter_keygen_b != PM_INIT_E+1 && + counter_keygen_a != INV_E+1 && counter_keygen_b != INV_E+1 && + counter_keygen_a != PA_E+1 && counter_keygen_b != PA_E+1 && + counter_keygen_a != PD_E+1 && counter_keygen_b != PD_E+1 && + counter_keygen_a != INV_E+1 && counter_keygen_b != INV_E+1; + endproperty + + counter_keygen_a_assume: assume property(disable iff(!rst_n) (counter_keygen_a >=PM_INIT_G_S) && (counter_keygen_a <=CONV_E) && $stable(counter_keygen_a)); + counter_keygen_b_assume: assume property(disable iff(!rst_n) (counter_keygen_b <=CONV_E) && (counter_keygen_b > counter_keygen_a) && $stable(counter_keygen_b)); + + assign trigger_counter_keygen_a_reg = (ecc_pm_ctrl.prog_cntr==counter_keygen_a); + assign trigger_counter_keygen_b_reg = (ecc_pm_ctrl.prog_cntr==counter_keygen_b); + always_ff @(posedge clk, negedge rst_n) begin + if(!rst_n) begin + triggered_counter_keygen_a <= '0; + triggered_counter_keygen_b <= '0; + end + else begin + if(ecc_pm_ctrl.ecc_cmd_reg==KEYGEN_CMD) begin + if(trigger_counter_keygen_a_reg) begin + triggered_counter_keygen_a <= 1; + end + if(trigger_counter_keygen_b_reg) begin + triggered_counter_keygen_b <= 1; + end + end + end + end + + property liveness_p(cmd,trigered); + ecc_cmd_i == cmd && + ecc_pm_ctrl.prog_cntr == NOP + |-> + s_eventually(trigered); + endproperty + counter_keygen_a_liveness_a: assert property(disable iff(!rst_n) liveness_p(KEYGEN_CMD,triggered_counter_keygen_a)); + counter_keygen_b_liveness_a: assert property(disable iff(!rst_n) liveness_p(KEYGEN_CMD,triggered_counter_keygen_b)); + + //property to order_check + property order_check_p(triggered_a,triggered_b); + triggered_b + |=> + $past(triggered_a); + endproperty + keygen_order_check_a: assert property(disable iff(!rst_n) order_check_p(triggered_counter_keygen_a,triggered_counter_keygen_b)); + +///////////////////////////////////////////////////////////////////////////////////// +// ------------------------------------END---------------------------------------- // +///////////////////////////////////////////////////////////////////////////////////// + + //------------------------------------// + // Signing staging + //------------------------------------// + + + //validates if signing sequence is ongoing then it would traverse from CONV_S till INVq_S + property signing_stage3_2_p(delay1,delay2); + ecc_pm_ctrl.ecc_cmd_reg == SIGN_CMD && + ecc_pm_ctrl.prog_cntr == CONV_S + |-> + ##delay1 ecc_pm_ctrl.prog_cntr == CONV_E // conversion to affine r compute done + ##1 ecc_pm_ctrl.prog_cntr == SIGN0_S // (d + r (privKey-d)),((h-d) + r.d) + ##delay2 ecc_pm_ctrl.prog_cntr == SIGN0_E + ##1 ecc_pm_ctrl.prog_cntr == INVq_S; // k inverse ##52 mult delay 1 + endproperty + signing_stage3_2_a: assert property(disable iff(!rst_n) signing_stage3_2_p(CONV_VER0_P1_DLY,SIGN0_DLY)); + + + //validates if signing sequence is ongoing then it would traverse from INVq_S till INVq_E + property signing_stage4_1_p(delay); + ecc_pm_ctrl.ecc_cmd_reg == SIGN_CMD && + ecc_pm_ctrl.prog_cntr == INVq_S + |-> + ##delay ecc_pm_ctrl.prog_cntr == INVq_E; + endproperty + signing_stage4_1_a: assert property(disable iff(!rst_n) signing_stage4_1_p(INVQ_DLY)); + + + //validates if signing sequence is ongoing then it would traverse from INVq_E till NOP + property signing_stage4_p(delay); + ecc_pm_ctrl.ecc_cmd_reg == SIGN_CMD && + ecc_pm_ctrl.prog_cntr == INVq_E + |-> + ##1 ecc_pm_ctrl.prog_cntr == SIGN1_S // final value s [k^-1((h-d) + r (privKey-d))] + [k^-1(d + r.d)] mod q + ##delay ecc_pm_ctrl.prog_cntr == SIGN1_E + ##1 ecc_pm_ctrl.prog_cntr == NOP ; // ##20 mult delay 1 + endproperty + signing_stage4_a: assert property(disable iff(!rst_n) signing_stage4_p(SIGN1_DLY)); + + + +///////////////////////////////////////////////////////////////////////////////////// +// ---------------------------------BEGIN----------------------------------------- // +// Checking the counter integrity that the sequence is performed one after another // +///////////////////////////////////////////////////////////////////////////////////// + + logic [PROG_ADDR_W-1 : 0] counter_sign_a; + logic [PROG_ADDR_W-1 : 0] counter_sign_b; + logic trigger_counter_sign_a_reg; + logic trigger_counter_sign_b_reg; + logic triggered_counter_sign_a; + logic triggered_counter_sign_b; + + counter_nonreachable_values_in_sign: assume property (disable iff(!rst_n)counter_nonreachable_values_in_sign_p); + property counter_nonreachable_values_in_sign_p; + counter_sign_a != PM_INIT_G_E+1 && counter_sign_b != PM_INIT_G_E+1 && + counter_sign_a != PM_INIT_E+1 && counter_sign_b != PM_INIT_E+1 && + counter_sign_a != INV_E+1 && counter_sign_b != INV_E+1 && + counter_sign_a != PA_E+1 && counter_sign_b != PA_E+1 && + counter_sign_a != PD_E+1 && counter_sign_b != PD_E+1 && + counter_sign_a != INV_E+1 && counter_sign_b != INV_E+1 && + counter_sign_a != CONV_E+1 && counter_sign_b != CONV_E+1 && + counter_sign_a != SIGN0_E+1 && counter_sign_b != SIGN0_E+1 && + counter_sign_a != INVq_E+1 && counter_sign_b != INVq_E+1 + ; + endproperty + + counter_sign_a_assume: assume property(disable iff(!rst_n) (counter_sign_a >=PM_INIT_G_S) && (counter_sign_a <=SIGN1_E) && $stable(counter_sign_a)); + counter_sign_b_assume: assume property(disable iff(!rst_n) (counter_sign_b <=SIGN1_E) && (counter_sign_b > counter_sign_a) && $stable(counter_sign_b)); + + assign trigger_counter_sign_a_reg = (ecc_pm_ctrl.prog_cntr==counter_sign_a); + assign trigger_counter_sign_b_reg = (ecc_pm_ctrl.prog_cntr==counter_sign_b); + always_ff @(posedge clk, negedge rst_n) begin + if(!rst_n) begin + triggered_counter_sign_a <= '0; + triggered_counter_sign_b <= '0; + end + else begin + if(ecc_pm_ctrl.ecc_cmd_reg==SIGN_CMD) begin + if(trigger_counter_sign_a_reg) begin + triggered_counter_sign_a <= 1; + end + if(trigger_counter_sign_b_reg) begin + triggered_counter_sign_b <= 1; + end + end + end + end + + counter_sign_a_liveness_a: assert property(disable iff(!rst_n) liveness_p(SIGN_CMD,triggered_counter_sign_a)); + + counter_sign_b_liveness_a: assert property(disable iff(!rst_n) liveness_p(SIGN_CMD,triggered_counter_sign_b)); + + order_check_sign_a: assert property(disable iff(!rst_n) order_check_p(triggered_counter_sign_a,triggered_counter_sign_b)); + + + + +///////////////////////////////////////////////////////////////////////////////////// +// ------------------------------------END---------------------------------------- // +///////////////////////////////////////////////////////////////////////////////////// + + + //--------------------------------------// + // Verifying staging + //-------------------------------------// + + //Validates once the VER_PART0_CMD is triggered then it would traverse itll INVq_S + property verify_part0_stage0_p(delay); + ecc_cmd_i == VER_PART0_CMD && + ecc_pm_ctrl.prog_cntr == NOP + |=> + ecc_pm_ctrl.prog_cntr == VER0_P0_S //convert h,r,s inputs to mont + ##delay ecc_pm_ctrl.prog_cntr == VER0_P0_E + ##1 ecc_pm_ctrl.prog_cntr == INVq_S; // compute s inverse //##16 mult delay 1 + endproperty + verify_part0_stage0_a: assert property(disable iff(!rst_n) verify_part0_stage0_p(VER0_P0_DLY)); + + + //validates if the verify part0 is ongoing then it would traverse from INVq_s to INVq_E + property verify_part0_stage1_1_p(delay); + ecc_pm_ctrl.ecc_cmd_reg == VER_PART0_CMD && + ecc_pm_ctrl.prog_cntr == INVq_S + |-> + ##delay ecc_pm_ctrl.prog_cntr == INVq_E; + endproperty + verify_part0_stage1_1_a: assert property(disable iff(!rst_n) verify_part0_stage1_1_p(INVQ_DLY)); + + + //validates if the verify part0 is ongoing then finally it would end in NOP + property verify_part0_stage1_p(delay); + ecc_pm_ctrl.ecc_cmd_reg == VER_PART0_CMD && + ecc_pm_ctrl.prog_cntr == INVq_E + |-> + ##1 ecc_pm_ctrl.prog_cntr == VER0_P1_S // compute h*s_inv and r*s_inv + ##delay ecc_pm_ctrl.prog_cntr == VER0_P1_E + ##1 ecc_pm_ctrl.prog_cntr == NOP; // ##20 mult delay 1 + endproperty + verify_part0_stage1_a: assert property(disable iff(!rst_n) verify_part0_stage1_p(CONV_VER0_P1_DLY)); + + + +///////////////////////////////////////////////////////////////////////////////////// +// ---------------------------------BEGIN----------------------------------------- // +// Checking the counter integrity that the sequence is performed one after another // +///////////////////////////////////////////////////////////////////////////////////// + + logic [PROG_ADDR_W-1 : 0] counter_ver_p0_a; + logic [PROG_ADDR_W-1 : 0] counter_ver_p0_b; + logic [PROG_ADDR_W-1 : 0] counter_ver_p0_c; + logic [PROG_ADDR_W-1 : 0] counter_ver_p0_a_1; + logic [PROG_ADDR_W-1 : 0] counter_ver_p0_b_1; + logic [PROG_ADDR_W-1 : 0] counter_ver_p0_c_1; + logic trigger_counter_ver_p0_a_reg; + logic trigger_counter_ver_p0_b_reg; + logic trigger_counter_ver_p0_c_reg; + logic trigger_counter_ver_p0_a_1_reg; + logic trigger_counter_ver_p0_b_1_reg; + logic trigger_counter_ver_p0_c_1_reg; + logic triggered_counter_ver_p0_a; + logic triggered_counter_ver_p0_b; + logic triggered_counter_ver_p0_c; + logic triggered_counter_ver_p0_a_1; + logic triggered_counter_ver_p0_b_1; + logic triggered_counter_ver_p0_c_1; + + + + counter_ver_p0_a_assume: assume property(disable iff(!rst_n) (counter_ver_p0_a <=VER0_P0_E) && (counter_ver_p0_a >=VER0_P0_S) && $stable(counter_ver_p0_a)); + counter_ver_p0_a_1_assume: assume property(disable iff(!rst_n) (counter_ver_p0_a_1 <=VER0_P0_E) && (counter_ver_p0_a_1 > counter_ver_p0_a) && $stable(counter_ver_p0_a_1)); + counter_ver_p0_b_assume: assume property(disable iff(!rst_n) (counter_ver_p0_b >=INVq_S) && (counter_ver_p0_b <=INVq_E) && $stable(counter_ver_p0_b)); + counter_ver_p0_b_1_assume: assume property(disable iff(!rst_n) (counter_ver_p0_b_1 >counter_ver_p0_b) && (counter_ver_p0_b_1 <=INVq_E) && $stable(counter_ver_p0_b_1)); + counter_ver_p0_c_assume: assume property(disable iff(!rst_n) (counter_ver_p0_c <=VER0_P1_E) && ((counter_ver_p0_c >=VER0_P1_S)) && $stable(counter_ver_p0_c)); + counter_ver_p0_c_1_assume: assume property(disable iff(!rst_n) (counter_ver_p0_c_1 <=VER0_P1_E) && ((counter_ver_p0_c_1 > counter_ver_p0_c)) && $stable(counter_ver_p0_c_1)); + + assign trigger_counter_ver_p0_a_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p0_a); + assign trigger_counter_ver_p0_b_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p0_b); + assign trigger_counter_ver_p0_c_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p0_c); + assign trigger_counter_ver_p0_a_1_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p0_a_1); + assign trigger_counter_ver_p0_b_1_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p0_b_1); + assign trigger_counter_ver_p0_c_1_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p0_c_1); + + always_ff @(posedge clk, negedge rst_n) begin + if(!rst_n) begin + triggered_counter_ver_p0_a <= '0; + triggered_counter_ver_p0_b <= '0; + triggered_counter_ver_p0_c <= '0; + triggered_counter_ver_p0_a_1 <= '0; + triggered_counter_ver_p0_b_1 <= '0; + triggered_counter_ver_p0_c_1 <= '0; + end + else begin + if(ecc_pm_ctrl.ecc_cmd_reg==VER_PART0_CMD) begin + if(trigger_counter_ver_p0_a_reg) begin + triggered_counter_ver_p0_a <= 1; + end + if(trigger_counter_ver_p0_b_reg) begin + triggered_counter_ver_p0_b <= 1; + end + if(trigger_counter_ver_p0_c_reg) begin + triggered_counter_ver_p0_c <= 1; + end + if(trigger_counter_ver_p0_a_1_reg) begin + triggered_counter_ver_p0_a_1 <= 1; + end + if(trigger_counter_ver_p0_b_1_reg) begin + triggered_counter_ver_p0_b_1 <= 1; + end + if(trigger_counter_ver_p0_c_1_reg) begin + triggered_counter_ver_p0_c_1 <= 1; + end + end + end + end + + + counter_ver_p0_a_liveness_a: assert property(disable iff(!rst_n) liveness_p(VER_PART0_CMD,triggered_counter_ver_p0_a)); + + counter_ver_p0_b_liveness_a: assert property(disable iff(!rst_n) liveness_p(VER_PART0_CMD,triggered_counter_ver_p0_b)); + + counter_ver_p0_c_liveness_a: assert property(disable iff(!rst_n) liveness_p(VER_PART0_CMD,triggered_counter_ver_p0_c)); + + counter_intrnl_ver0_p0_s_a: assert property(disable iff(!rst_n) order_check_p(triggered_counter_ver_p0_a,triggered_counter_ver_p0_a_1)); + + counter_staging0_ver_p0_a: assert property(disable iff(!rst_n) order_check_p((triggered_counter_ver_p0_a & triggered_counter_ver_p0_a_1 & triggered_counter_ver_p0_b),triggered_counter_ver_p0_b_1)); + + counter_staging1_ver_p0_a: assert property(disable iff(!rst_n) order_check_p((triggered_counter_ver_p0_a & triggered_counter_ver_p0_b & triggered_counter_ver_p0_c & triggered_counter_ver_p0_a_1 & triggered_counter_ver_p0_b_1),triggered_counter_ver_p0_c_1)); + + + + +///////////////////////////////////////////////////////////////////////////////////// +// ------------------------------------END---------------------------------------- // +///////////////////////////////////////////////////////////////////////////////////// + + + + + //validates once the verify part1 is set initally it would traverse through PM_INIT_G_S and PM_INIT_S + property verify_part1_stage0_p(delay); + ecc_cmd_i == VER_PART1_CMD && + ecc_pm_ctrl.prog_cntr == NOP + |=> + ecc_pm_ctrl.prog_cntr == PM_INIT_G_S && // Initialise R1 with G + ecc_pm_ctrl.mont_cntr == ecc_pm_ctrl.Secp384_MONT_COUNT + ##delay ecc_pm_ctrl.prog_cntr == PM_INIT_G_E + ##1 ecc_pm_ctrl.prog_cntr == PM_INIT_S; // Initialise R0 with (0:1:0) + endproperty + verify_part1_stage0_a: assert property(disable iff(!rst_n) verify_part1_stage0_p(PM_INT_G_DLY)); + + + //validates if verify part1 sequence is ongoing then it would traverse from PD_E to NOP when the mont_cntr is zero + property verify_part1_stage2_p; + ecc_pm_ctrl.ecc_cmd_reg == VER_PART1_CMD && + ecc_pm_ctrl.prog_cntr == PD_E && + ecc_pm_ctrl.mont_cntr == 0 + |-> + ##1 ecc_pm_ctrl.prog_cntr == NOP; //(h*s^-1)*G + endproperty + verify_part1_stage2_a: assert property(disable iff(!rst_n) verify_part1_stage2_p); + + +///////////////////////////////////////////////////////////////////////////////////// +// ---------------------------------BEGIN----------------------------------------- // +// Checking the counter integrity that the sequence is performed one after another // +///////////////////////////////////////////////////////////////////////////////////// + + logic [PROG_ADDR_W-1 : 0] counter_ver_p1_a; + logic [PROG_ADDR_W-1 : 0] counter_ver_p1_b; + logic trigger_counter_ver_p1_a_reg; + logic trigger_counter_ver_p1_b_reg; + logic triggered_counter_ver_p1_a; + logic triggered_counter_ver_p1_b; + + counter_nonreachable_values_in_ver_p1: assume property (disable iff(!rst_n)counter_nonreachable_values_in_ver_p1_p); + property counter_nonreachable_values_in_ver_p1_p; + counter_ver_p1_a != PM_INIT_G_E+1 && counter_ver_p1_b != PM_INIT_G_E+1 && + counter_ver_p1_a != PM_INIT_E+1 && counter_ver_p1_b != PM_INIT_E+1 && + counter_ver_p1_a != INV_E+1 && counter_ver_p1_b != INV_E+1 && + counter_ver_p1_a != PA_E+1 && counter_ver_p1_b != PA_E+1; + + endproperty + + counter_ver_p1_a_assume: assume property(disable iff(!rst_n) (counter_ver_p1_a >=PM_INIT_G_S) && (counter_ver_p1_a <=PD_E) && $stable(counter_ver_p1_a)); + counter_ver_p1_b_assume: assume property(disable iff(!rst_n) (counter_ver_p1_b <=PD_E) && (counter_ver_p1_b > counter_ver_p1_a) && $stable(counter_ver_p1_b)); + + assign trigger_counter_ver_p1_a_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p1_a); + assign trigger_counter_ver_p1_b_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p1_b); + always_ff @(posedge clk, negedge rst_n) begin + if(!rst_n) begin + triggered_counter_ver_p1_a <= '0; + triggered_counter_ver_p1_b <= '0; + end + else begin + if (ecc_pm_ctrl.ecc_cmd_reg == VER_PART1_CMD) begin + if(trigger_counter_ver_p1_a_reg) begin + triggered_counter_ver_p1_a <= 1; + end + if(trigger_counter_ver_p1_b_reg) begin + triggered_counter_ver_p1_b <= 1; + end + end + end + end + + counter_ver_p1_a_liveness_a: assert property(disable iff(!rst_n) liveness_p(VER_PART1_CMD,triggered_counter_ver_p1_a)); + + counter_ver_p1_b_liveness_a: assert property(disable iff(!rst_n) liveness_p(VER_PART1_CMD,triggered_counter_ver_p1_b)); + + counter_order_check_ver_p1_a: assert property(disable iff(!rst_n) order_check_p(triggered_counter_ver_p1_a,triggered_counter_ver_p1_b)); + + + + +///////////////////////////////////////////////////////////////////////////////////// +// ------------------------------------END---------------------------------------- // +///////////////////////////////////////////////////////////////////////////////////// + + + // validates once the verify part2 is set initally it would traverse through VER1_ST_S and PM_INIT_S + property verify_part2_stage0_p(delay1,delay2); + ecc_cmd_i == VER_PART2_CMD && + ecc_pm_ctrl.prog_cntr == NOP + |=> + ecc_pm_ctrl.prog_cntr == VER1_ST_S //store (h*s^-1)*G in P1 address + ##delay1 ecc_pm_ctrl.prog_cntr == VER1_ST_E + ##1 ecc_pm_ctrl.prog_cntr == PM_INIT_PK_S // Pubkey in R1 + ##delay2 ecc_pm_ctrl.prog_cntr == PM_INIT_PK_E + ##1 ecc_pm_ctrl.prog_cntr == PM_INIT_S; // Initialise R0 with (0:1:0) ##12 mult delay 1 + endproperty + verify_part2_stage0_a: assert property(disable iff(!rst_n) verify_part2_stage0_p(VER_ST_DLY,PM_INT_PK_DLY)); + + + //validates if verify part2 sequence is ongoing then it would traverse from PD_E to VER2_PA_S when the mont_cntr is zero + property verify_part2_stage2_p; + ecc_pm_ctrl.ecc_cmd_reg == VER_PART2_CMD && + ecc_pm_ctrl.prog_cntr == PD_E && + ecc_pm_ctrl.mont_cntr == 0 + |-> + ##1 ecc_pm_ctrl.prog_cntr == VER2_PA_S ; // add (h*s_inv)*G, (r*s_inv)*PK) + endproperty + verify_part2_stage2_a: assert property(disable iff(!rst_n) verify_part2_stage2_p); + + + + //validates if verify part2 sequence is ongoing then it would traverse from VER2_PA_S till INV_S + property verify_part2_stage3_p(delay); + ecc_pm_ctrl.ecc_cmd_reg == VER_PART2_CMD && + ecc_pm_ctrl.prog_cntr == VER2_PA_S + |-> + ##delay ecc_pm_ctrl.prog_cntr == VER2_PA_E + ##1 ecc_pm_ctrl.prog_cntr == INV_S ; // Inv z coordinate + endproperty + verify_part2_stage3_a: assert property(disable iff(!rst_n) verify_part2_stage3_p(VER_PA_DLY)); + + +///////////////////////////////////////////////////////////////////////////////////// +// ---------------------------------BEGIN----------------------------------------- // +// Checking the counter integrity that the sequence is performed one after another // +///////////////////////////////////////////////////////////////////////////////////// + + logic [PROG_ADDR_W-1 : 0] counter_ver_p2_a; + logic [PROG_ADDR_W-1 : 0] counter_ver_p2_b; + logic [PROG_ADDR_W-1 : 0] counter_ver_p2_c; + logic [PROG_ADDR_W-1 : 0] counter_ver_p2_d; + logic [PROG_ADDR_W-1 : 0] counter_ver_p2_a_1; + logic [PROG_ADDR_W-1 : 0] counter_ver_p2_b_1; + logic [PROG_ADDR_W-1 : 0] counter_ver_p2_c_1; + logic [PROG_ADDR_W-1 : 0] counter_ver_p2_d_1; + logic trigger_counter_ver_p2_a_1_reg; + logic trigger_counter_ver_p2_b_1_reg; + logic trigger_counter_ver_p2_c_1_reg; + logic trigger_counter_ver_p2_d_1_reg; + logic triggered_counter_ver_p2_a_1; + logic triggered_counter_ver_p2_b_1; + logic triggered_counter_ver_p2_c_1; + logic triggered_counter_ver_p2_d_1; + logic trigger_counter_ver_p2_a_reg; + logic trigger_counter_ver_p2_b_reg; + logic trigger_counter_ver_p2_c_reg; + logic trigger_counter_ver_p2_d_reg; + logic triggered_counter_ver_p2_a; + logic triggered_counter_ver_p2_b; + logic triggered_counter_ver_p2_c; + logic triggered_counter_ver_p2_d; + + counter_nonreachable_values_in_ver_p2: assume property (disable iff(!rst_n)counter_nonreachable_values_in_ver_p2_p); + property counter_nonreachable_values_in_ver_p2_p; + + counter_ver_p2_a != VER1_ST_E+1 && counter_ver_p2_a_1 != VER1_ST_E+1 && + counter_ver_p2_b != PM_INIT_E+1 && counter_ver_p2_b_1 != PM_INIT_E+1 && + counter_ver_p2_b != PA_E+1 && counter_ver_p2_b_1 != PA_E+1 && + counter_ver_p2_d!= INV_E+1 && counter_ver_p2_d_1!= INV_E+1 + ; + endproperty + + counter_ver_p2_a_assume: assume property(disable iff(!rst_n) (counter_ver_p2_a >=VER1_ST_S) && (counter_ver_p2_a <=PM_INIT_PK_E) && $stable(counter_ver_p2_a)); + counter_ver_p2_a_1_assume: assume property(disable iff(!rst_n) (counter_ver_p2_a_1 > counter_ver_p2_a) && (counter_ver_p2_a_1 <=PM_INIT_PK_E) && $stable(counter_ver_p2_a_1)); + + counter_ver_p2_b_assume: assume property(disable iff(!rst_n) (counter_ver_p2_b <=PD_E) && (counter_ver_p2_b >= PM_INIT_S) && $stable(counter_ver_p2_b)); + counter_ver_p2_b_1_assume: assume property(disable iff(!rst_n) (counter_ver_p2_b_1 <=PD_E) && (counter_ver_p2_b_1 > counter_ver_p2_b) && $stable(counter_ver_p2_b_1)); + + counter_ver_p2_c_assume: assume property(disable iff(!rst_n) (counter_ver_p2_c >=VER2_PA_S) && (counter_ver_p2_c <=VER2_PA_E) && $stable(counter_ver_p2_c)); + counter_ver_p2_c_1_assume: assume property(disable iff(!rst_n) (counter_ver_p2_c_1 >counter_ver_p2_c) && (counter_ver_p2_c_1 <=VER2_PA_E) && $stable(counter_ver_p2_c_1)); + + counter_ver_p2_d_assume: assume property(disable iff(!rst_n) (counter_ver_p2_d <=CONV_E) && (counter_ver_p2_d >= INV_S) && $stable(counter_ver_p2_d)); + counter_ver_p2_d_1_assume: assume property(disable iff(!rst_n) (counter_ver_p2_d_1 <=CONV_E) && (counter_ver_p2_d_1 > counter_ver_p2_d) && $stable(counter_ver_p2_d_1)); + + assign trigger_counter_ver_p2_a_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p2_a); + assign trigger_counter_ver_p2_b_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p2_b); + + assign trigger_counter_ver_p2_c_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p2_c); + assign trigger_counter_ver_p2_d_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p2_d); + + assign trigger_counter_ver_p2_a_1_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p2_a_1); + assign trigger_counter_ver_p2_b_1_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p2_b_1); + + assign trigger_counter_ver_p2_c_1_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p2_c_1); + assign trigger_counter_ver_p2_d_1_reg = (ecc_pm_ctrl.prog_cntr==counter_ver_p2_d_1); + + always_ff @(posedge clk, negedge rst_n) begin + if(!rst_n) begin + triggered_counter_ver_p2_a <= '0; + triggered_counter_ver_p2_b <= '0; + triggered_counter_ver_p2_c <= '0; + triggered_counter_ver_p2_d <= '0; + triggered_counter_ver_p2_a_1 <= '0; + triggered_counter_ver_p2_b_1 <= '0; + triggered_counter_ver_p2_c_1 <= '0; + triggered_counter_ver_p2_d_1 <= '0; + end + else begin + if(ecc_pm_ctrl.ecc_cmd_reg == VER_PART2_CMD) begin + if(trigger_counter_ver_p2_a_reg) begin + triggered_counter_ver_p2_a <= 1; + end + if(trigger_counter_ver_p2_b_reg) begin + triggered_counter_ver_p2_b <= 1; + end + if(trigger_counter_ver_p2_c_reg) begin + triggered_counter_ver_p2_c <= 1; + end + if(trigger_counter_ver_p2_d_reg) begin + triggered_counter_ver_p2_d <= 1; + end + if(trigger_counter_ver_p2_a_1_reg) begin + triggered_counter_ver_p2_a_1 <= 1; + end + if(trigger_counter_ver_p2_b_1_reg) begin + triggered_counter_ver_p2_b_1 <= 1; + end + if(trigger_counter_ver_p2_c_1_reg) begin + triggered_counter_ver_p2_c_1 <= 1; + end + if(trigger_counter_ver_p2_d_1_reg) begin + triggered_counter_ver_p2_d_1 <= 1; + end + end + end + end + + + counter_ver_p2_a_liveness_a: assert property(disable iff(!rst_n) liveness_p(VER_PART2_CMD,triggered_counter_ver_p2_a)); + + + counter_ver_p2_b_liveness_a: assert property(disable iff(!rst_n) liveness_p(VER_PART2_CMD,triggered_counter_ver_p2_b)); + + counter_ver_p2_c_liveness_a: assert property(disable iff(!rst_n) liveness_p(VER_PART2_CMD,triggered_counter_ver_p2_c)); + + counter_ver_p2_d_liveness_a: assert property(disable iff(!rst_n) liveness_p(VER_PART2_CMD,triggered_counter_ver_p2_d)); + + counter_intrnl_ver_p2_a: assert property(disable iff(!rst_n) order_check_p(triggered_counter_ver_p2_a,triggered_counter_ver_p2_a_1)); + + counter_staging0_ver_p2_a: assert property(disable iff(!rst_n) order_check_p((triggered_counter_ver_p2_a & triggered_counter_ver_p2_a_1 & triggered_counter_ver_p2_b),triggered_counter_ver_p2_b_1)); + + counter_staging1_ver_p2_a: assert property(disable iff(!rst_n) order_check_p((triggered_counter_ver_p2_a & triggered_counter_ver_p2_b & triggered_counter_ver_p2_c & triggered_counter_ver_p2_a_1 & triggered_counter_ver_p2_b_1), triggered_counter_ver_p2_c_1)); + + counter_staging2_ver_p2_a: assert property(disable iff(!rst_n) order_check_p((triggered_counter_ver_p2_a & triggered_counter_ver_p2_b & triggered_counter_ver_p2_c & triggered_counter_ver_p2_d & triggered_counter_ver_p2_a_1 & triggered_counter_ver_p2_b_1 & triggered_counter_ver_p2_c_1),triggered_counter_ver_p2_d_1)); + + + +///////////////////////////////////////////////////////////////////////////////////// +// ------------------------------------END---------------------------------------- // +///////////////////////////////////////////////////////////////////////////////////// + + + + + //If the prog_cntr is not NOP then the pm_ctrl is busy + property busy_p; + ecc_pm_ctrl.prog_cntr != NOP + |-> + busy_o; + endproperty + busy_a: assert property(disable iff(!rst_n) busy_p); + + //If the prog_cntr is NOP then the pm_ctrl is not busy + property no_busy_p; + (ecc_pm_ctrl.prog_cntr == NOP) + |-> + !busy_o; + endproperty + no_busy_a: assert property(disable iff(!rst_n) no_busy_p); + + + //req_digit_o is set only when the mont_cntr is not zero in PD_E step or the very first rotation i.e in PM_INIT_E + property req_digit_p; + (ecc_pm_ctrl.prog_cntr == PD_E && ecc_pm_ctrl.mont_cntr!=0) || + (ecc_pm_ctrl.prog_cntr == PM_INIT_E) + |=> + req_digit_o; + endproperty + req_digit_a: assert property(disable iff(!rst_n) req_digit_p); + + + //req_digit_o is zero when the mont_cntr is zero in PD_E step or it is not the very first rotation i.e in PM_INIT_E + property no_req_digit_p; + !(ecc_pm_ctrl.prog_cntr == PD_E && ecc_pm_ctrl.mont_cntr!=0) && + !(ecc_pm_ctrl.prog_cntr == PM_INIT_E) + |=> + !req_digit_o; + endproperty + no_req_digit_a: assert property(disable iff(!rst_n) no_req_digit_p); + + + //req_digit_o trigger mont_cntr times + property mont_multiples_req_digit_o_p(cmd,count); + $rose(ecc_pm_ctrl.ecc_cmd_reg == cmd) + |-> + strong((req_digit_o && (ecc_pm_ctrl.prog_cntr==PA_S))[->count] ##1( ecc_pm_ctrl.mont_cntr==0)) ; + endproperty + keygen_mont_multiples_req_digit_o_a:assert property(disable iff(!rst_n) mont_multiples_req_digit_o_p(KEYGEN_CMD,Secp384_SCA_MONT_COUNT)); + signing_mont_multiples_req_digit_o_a:assert property(disable iff(!rst_n) mont_multiples_req_digit_o_p(SIGN_CMD,Secp384_SCA_MONT_COUNT)); + ver_p1_mont_multiples_req_digit_o_a:assert property(disable iff(!rst_n) mont_multiples_req_digit_o_p(VER_PART1_CMD,Secp384_MONT_COUNT)); + ver_p2_mont_multiples_req_digit_o_a:assert property(disable iff(!rst_n) mont_multiples_req_digit_o_p(VER_PART2_CMD,Secp384_MONT_COUNT)); + + + //when output of pm_sequencer instruction is add it would be on primary output after 3 cycles and stays stable for the delay time +2 + property opcode_add_p; + ecc_pm_ctrl.prog_instr.opcode.add_en + |-> + ##PIP_DLY + instr_o.opcode == $past(ecc_pm_ctrl.prog_instr.opcode,3) + ##1 instr_o.opcode ==$past(instr_o.opcode)[*(ADD_DLY+1)]; + endproperty + opcode_add_a: assert property(disable iff(!rst_n) opcode_add_p); + + + //when output of pm_sequencer instruction is multiplication it would be on primary output after 3 cycles and stays stable for the delay time +2 + property opcode_mul_p; + ecc_pm_ctrl.prog_instr.opcode.mult_en + |-> + ##PIP_DLY + instr_o.opcode == $past(ecc_pm_ctrl.prog_instr.opcode,3) + ##1 instr_o.opcode ==$past(instr_o.opcode)[*(MULT_DLY+1)]; + endproperty + opcode_mul_a: assert property(disable iff(!rst_n) opcode_mul_p); + + + //-----------------------------------------// + // Helper logic for stall + //-----------------------------------------// + + logic fv_stall; + logic fv_stall_dly; + logic fv_stall_pulse; + logic [6:0] fv_dly_cntr; + + always_ff @(posedge clk, negedge rst_n) begin + if(!rst_n) begin + fv_stall <= 0; + fv_dly_cntr <= 0; + fv_stall_dly <= 0; + end + else begin + if(ecc_pm_ctrl.prog_instr.opcode.add_en || + ecc_pm_ctrl.prog_instr.opcode.mult_en) begin + fv_stall <= 1; + end + if(ecc_pm_ctrl.prog_instr.opcode.add_en)begin + fv_dly_cntr <= ADD_DLY+1; + end + if(ecc_pm_ctrl.prog_instr.opcode.mult_en) begin + fv_dly_cntr <= MULT_DLY+1; + end + if(fv_dly_cntr>0) begin + fv_dly_cntr <= fv_dly_cntr - 7'h1; + end + if(fv_dly_cntr == 0 && fv_stall==1) begin + fv_stall <= 0; + end + fv_stall_dly <= fv_stall; + end + end + assign fv_stall_pulse = fv_stall & ~fv_stall_dly; + +//When the add or mult are set then the next cycle output of pm_seq instruction is stored so it not lost during +//the exceution of add ormult and the next instr_o would be stored value + property opcode_no_compute_p; + logic[5:0] next_opcode; + fv_stall_pulse + ##0 (1'b1, next_opcode = ecc_pm_ctrl.prog_instr.opcode) + ##1 !fv_stall[->1] + |-> + ##2 + instr_o.opcode == next_opcode; + endproperty + + opcode_no_compute_a: assert property (disable iff(!rst_n)opcode_no_compute_p); + + + +//Helper function for choosing address +function logic[5:0] xor_choose(input logic digit, input logic[5:0] addr); + return({addr[5:3],digit^addr[2],addr[1:0]}); +endfunction + + +//Constraint on digit_i stability,proven on the top +stable_digit_during_ladder: assume property(disable iff(!rst_n) ((ecc_pm_ctrl.prog_cntr <= PD_E) && + (ecc_pm_ctrl.prog_cntr >= PA_S)) |-> $stable(digit_i)); + + +logic[5:0] fv_compute_addra; +logic[5:0] fv_compute_addrb; +//Helper logic for storing the computed address + always_comb begin:operands_addr + if((ecc_pm_ctrl.prog_cntr <= PD_E) && (ecc_pm_ctrl.prog_cntr >= PA_S) && ecc_pm_ctrl.prog_instr.opa_addr[5:3]==3'b001) + fv_compute_addra = xor_choose(digit_i,ecc_pm_ctrl.prog_instr.opa_addr); + else + fv_compute_addra = ecc_pm_ctrl.prog_instr.opa_addr; + + if((ecc_pm_ctrl.prog_cntr <= PD_E) && (ecc_pm_ctrl.prog_cntr >= PA_S) && ecc_pm_ctrl.prog_instr.opb_addr[5:3]==3'b001) + fv_compute_addrb = xor_choose(digit_i,ecc_pm_ctrl.prog_instr.opb_addr); + else + fv_compute_addrb = ecc_pm_ctrl.prog_instr.opb_addr; + end + + + +//when output of pm_sequencer instruction is add and the addresses are not R0 then +//it would be on primary output after 3 cycles and stays stable for the delay time +2 + property addr_when_add_sub_p; + logic[5:0] addra,addrb; + ecc_pm_ctrl.prog_instr.opcode.add_en + ##0 (1'b1, addra = (fv_compute_addra)) + ##0 (1'b1, addrb = (fv_compute_addrb)) + |-> + ##PIP_DLY + (instr_o.opa_addr == addra && + instr_o.opb_addr == addrb)[*(ADD_DLY+2)] + ; + endproperty + + addr_when_add_sub_a: assert property (disable iff(!rst_n)addr_when_add_sub_p); + + +//when output of pm_sequencer instruction is multiplication and the addresses it +//would be on primary output after 3 cycles and stays stable for the delay time +2 + property addr_when_mult_p; + logic[5:0] addra,addrb; + ecc_pm_ctrl.prog_instr.opcode.mult_en + ##0 (1'b1, addra = (fv_compute_addra)) + ##0 (1'b1, addrb = (fv_compute_addrb)) + |-> + ##PIP_DLY + (instr_o.opa_addr == addra && + instr_o.opb_addr == addrb)[*(MULT_DLY+2)] + ; + endproperty + + addr_when_mult_a: assert property (disable iff(!rst_n)addr_when_mult_p); + + + +//When the add or mult are set then the next cycle output of pm_seq instruction is +//stored so it not lost during the exceution of add ormult and the next instr_o would be stored value + property addr_when_no_cmd_p; + logic[5:0] addra,addrb; + + fv_stall_pulse + ##0 (1'b1, addra = (fv_compute_addra)) + ##0 (1'b1, addrb = (fv_compute_addrb)) + ##1 !fv_stall[->1] + |-> + ##2 + (instr_o.opa_addr == addra && + instr_o.opb_addr == addrb) + ; + endproperty + + addr_when_no_cmd_a: assert property (disable iff(!rst_n)addr_when_no_cmd_p); + + + + + property instr_o_when_cmds_2cycls_p; + ecc_pm_ctrl.prog_instr.opcode.add_en || + ecc_pm_ctrl.prog_instr.opcode.mult_en + |=> + (instr_o.opa_addr == $past(instr_o.opa_addr) && + instr_o.opb_addr == $past(instr_o.opb_addr)) && + instr_o.opcode == $past(instr_o.opcode); + endproperty + instr_o_when_cmds_2cycls_a: assert property(disable iff(!rst_n) instr_o_when_cmds_2cycls_p); + + + property instr_o_when_no_cmds_2cycls_p; + !fv_stall && + ecc_pm_ctrl.prog_instr.opcode!=UOP_NOP + |=> + (instr_o.opa_addr == $past(instr_o.opa_addr) && + instr_o.opb_addr == $past(instr_o.opb_addr)) && + instr_o.opcode == $past(instr_o.opcode); + endproperty + instr_o_when_no_cmds_2cycls_a: assert property(disable iff(!rst_n) instr_o_when_no_cmds_2cycls_p); + + + + property prog_cntr_stable_p; + fv_stall && + (fv_dly_cntr > 1) + |=> + ecc_pm_ctrl.prog_cntr == $past(ecc_pm_ctrl.prog_cntr); + endproperty + + prog_cntr_stable_a: assert property(disable iff(!rst_n) prog_cntr_stable_p); + + + + property prog_cntr_change_p; + (fv_stall & (fv_dly_cntr <= 1)) + |=> + ecc_pm_ctrl.prog_cntr != $past(ecc_pm_ctrl.prog_cntr); + endproperty + + prog_cntr_change_a: assert property(disable iff(!rst_n) prog_cntr_change_p); + + + property prog_cntr_change_1_p; + !fv_stall && + ecc_pm_ctrl.prog_cntr !=NOP + |=> + fv_stall || + ecc_pm_ctrl.prog_cntr != $past(ecc_pm_ctrl.prog_cntr); + endproperty + + prog_cntr_change_1_a: assert property(disable iff(!rst_n) prog_cntr_change_1_p); + + + property no_cmd_prog_nop_p; + ecc_pm_ctrl.prog_cntr == NOP && + ecc_cmd_i != KEYGEN_CMD && + ecc_cmd_i != SIGN_CMD && + ecc_cmd_i != VER_PART0_CMD && + ecc_cmd_i != VER_PART1_CMD && + ecc_cmd_i != VER_PART2_CMD && + ecc_cmd_i != CHK_PK_CMD + |=> + ecc_pm_ctrl.prog_cntr == NOP; + endproperty + + no_cmd_prog_nop_a: assert property(disable iff(!rst_n) no_cmd_prog_nop_p); + + + +endmodule + +bind ecc_pm_ctrl fv_ecc_pm_ctrl_abstract #( + .REG_SIZE(REG_SIZE), + .RND_SIZE(RND_SIZE), + .INSTR_SIZE(INSTRUCTION_LENGTH), + .MULT_DLY(ecc_pm_ctrl.MULT_DELAY), + .ADD_DLY(ecc_pm_ctrl.ADD_DELAY), + .Secp384_MONT_COUNT(ecc_pm_ctrl.Secp384_MONT_COUNT), + .Secp384_SCA_MONT_COUNT(ecc_pm_ctrl.Secp384_SCA_MONT_COUNT) + ) + fv_ecc_pm_ctrl_abstract_inst( + .clk(clk), + .rst_n(reset_n && !zeroize), + .ecc_cmd_i(ecc_cmd_i), + .sca_en_i(sca_en_i), + .digit_i(digit_i), + .instr_o(instr_o), + .req_digit_o(req_digit_o), + .busy_o(busy_o) + ); \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_ecc_pm_sequencer.sv b/src/ecc/formal/properties/fv_ecc_pm_sequencer.sv new file mode 100644 index 000000000..475393718 --- /dev/null +++ b/src/ecc/formal/properties/fv_ecc_pm_sequencer.sv @@ -0,0 +1,3065 @@ + +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_pm_sequencer + import ecc_pm_uop_pkg::*; + #( + parameter ADDR_WIDTH = 10, + parameter DATA_WIDTH = 32 + ) + ( + input wire clk, + input wire rst_n, + input wire ena, + input wire [ADDR_WIDTH-1 : 0] addra, + input logic [DATA_WIDTH-1 : 0] douta + ); + +logic [ADDR_WIDTH-1 : 0] fv_cntr_pminitg; +logic [ADDR_WIDTH-1 : 0] fv_cntr_pminit; +logic [ADDR_WIDTH-1 : 0] fv_cntr_pa; +logic [ADDR_WIDTH-1 : 0] fv_cntr_pd; +logic [ADDR_WIDTH-1 : 0] fv_cntr_inv; +logic [ADDR_WIDTH-1 : 0] fv_cntr_conv; +logic [ADDR_WIDTH-1 : 0] fv_cntr_sign0; +logic [ADDR_WIDTH-1 : 0] fv_cntr_invq; +logic [ADDR_WIDTH-1 : 0] fv_cntr_sign1; +logic [ADDR_WIDTH-1 : 0] fv_cntr_chkpk; +logic [ADDR_WIDTH-1 : 0] fv_cntr_ver0p0; +logic [ADDR_WIDTH-1 : 0] fv_cntr_ver0p1; +logic [ADDR_WIDTH-1 : 0] fv_cntr_ver1st; +logic [ADDR_WIDTH-1 : 0] fv_cntr_pminitpk; +logic [ADDR_WIDTH-1 : 0] fv_cntr_ver2pa; + +logic fv_set_pminitg; +logic fv_set_pminit; +logic fv_set_pa; +logic fv_set_pd; +logic fv_set_inv; +logic fv_set_conv; +logic fv_set_sign0; +logic fv_set_invq; +logic fv_set_sign1; +logic fv_set_chkpk; +logic fv_set_ver0p0; +logic fv_set_ver0p1; +logic fv_set_ver1st; +logic fv_set_pminitpk; +logic fv_set_ver2pa; + +always_ff @(posedge clk or negedge rst_n) begin + if(!rst_n) begin + fv_set_pminitg <= '0; + fv_set_pminit <= '0; + fv_set_pa <= '0; + fv_set_pd <= '0; + fv_set_inv <= '0; + fv_set_conv <= '0; + fv_set_sign0 <= '0; + fv_set_invq <= '0; + fv_set_sign1 <= '0; + fv_set_chkpk <= '0; + fv_set_ver0p0 <= '0; + fv_set_ver0p1 <= '0; + fv_set_ver1st <= '0; + fv_set_pminitpk <= '0; + fv_set_ver2pa <= '0; + fv_cntr_pminitg <= '0; + fv_cntr_pminit <= '0; + fv_cntr_pa <= '0; + fv_cntr_pd <= '0; + fv_cntr_inv <= '0; + fv_cntr_conv <= '0; + fv_cntr_sign0 <= '0; + fv_cntr_invq <= '0; + fv_cntr_sign1 <= '0; + fv_cntr_chkpk <= '0; + fv_cntr_ver0p0 <= '0; + fv_cntr_ver0p1 <= '0; + fv_cntr_ver1st <= '0; + fv_cntr_pminitpk <= '0; + fv_cntr_ver2pa <= '0; + end + else begin + if(addra == PM_INIT_G_S) begin + fv_set_pminitg <= 1; + fv_set_ver2pa <=0; + fv_cntr_pminitg <= addra+1; + end + else if(fv_set_pminitg) begin + fv_cntr_pminitg <= fv_cntr_pminitg+1; + end + if(addra == PM_INIT_S) begin + fv_set_pminitg <= 0; + fv_set_pminit <=1; + fv_cntr_pminit <= addra+1; + end + else if(fv_set_pminit) begin + fv_cntr_pminit <= fv_cntr_pminit+1; + end + if(addra == PA_S) begin + fv_set_pminit <= 0; + fv_set_pa <=1; + fv_cntr_pa <= addra+1; + end + else if(fv_set_pa) begin + fv_cntr_pa <= fv_cntr_pa+1; + end + if(addra == PD_S) begin + fv_set_pa <= 0; + fv_set_pd <=1; + fv_cntr_pd <= addra+1; + end + else if(fv_set_pd) begin + fv_cntr_pd <= fv_cntr_pd+1; + end + if(addra == INV_S) begin + fv_set_pd <= 0; + fv_set_inv <=1; + fv_cntr_inv <= addra+1; + end + else if(fv_set_inv) begin + fv_cntr_inv <= fv_cntr_inv+1; + end + if(addra == CONV_S) begin + fv_set_inv <= 0; + fv_set_conv <=1; + fv_cntr_conv <= addra+1; + end + else if(fv_set_conv) begin + fv_cntr_conv <= fv_cntr_conv+1; + end + if(addra == SIGN0_S) begin + fv_set_conv <= 0; + fv_set_sign0 <=1; + fv_cntr_sign0 <= addra+1; + end + else if(fv_set_sign0) begin + fv_cntr_sign0 <= fv_cntr_sign0+1; + end + if(addra == INVq_S) begin + fv_set_sign0 <= 0; + fv_set_invq <=1; + fv_cntr_invq <= addra+1; + end + else if(fv_set_invq) begin + fv_cntr_invq <= fv_cntr_invq+1; + end + if(addra == SIGN1_S) begin + fv_set_invq <= 0; + fv_set_sign1 <=1; + fv_cntr_sign1 <= addra+1; + end + else if(fv_set_sign1) begin + fv_cntr_sign1 <= fv_cntr_sign1+1; + end + if(addra == CHK_PK_S) begin + fv_set_sign1 <= 0; + fv_set_chkpk <=1; + fv_cntr_chkpk <= addra+1; + end + else if(fv_set_chkpk) begin + fv_cntr_chkpk <= fv_cntr_chkpk+1; + end + if(addra == VER0_P0_S) begin + fv_set_chkpk <= 0; + fv_set_ver0p0 <=1; + fv_cntr_ver0p0 <= addra+1; + end + else if(fv_set_ver0p0) begin + fv_cntr_ver0p0 <= fv_cntr_ver0p0+1; + end + if(addra == VER0_P1_S) begin + fv_set_ver0p0 <= 0; + fv_set_ver0p1 <=1; + fv_cntr_ver0p1 <= addra+1; + end + else if(fv_set_ver0p1) begin + fv_cntr_ver0p1 <= fv_cntr_ver0p1+1; + end + if(addra == VER1_ST_S) begin + fv_set_ver0p1 <= 0; + fv_set_ver1st <=1; + fv_cntr_ver1st <= addra+1; + end + else if(fv_set_ver1st) begin + fv_cntr_ver1st <= fv_cntr_ver1st+1; + end + if(addra == PM_INIT_PK_S) begin + fv_set_pminitpk <= 1; + fv_set_ver1st <=0; + fv_cntr_pminitpk <= addra+1; + end + else if(fv_set_pminitpk) begin + fv_cntr_pminitpk <= fv_cntr_pminitpk+1; + end + if(addra == VER2_PA_S) begin + fv_set_ver2pa <= 1; + fv_set_pminitpk <=0; + fv_cntr_ver2pa <= addra+1; + end + else if(fv_set_ver2pa) begin + fv_cntr_ver2pa <= fv_cntr_ver2pa+1; + end + end +end + +property assign_addra(set,cntr); + set + |-> + addra == cntr; +endproperty + +cntr_assume_pminitg :assume property(assign_addra(fv_set_pminitg ,fv_cntr_pminitg )); +cntr_assume_pminit :assume property(assign_addra(fv_set_pminit ,fv_cntr_pminit )); +cntr_assume_pa :assume property(assign_addra(fv_set_pa ,fv_cntr_pa )); +cntr_assume_pd :assume property(assign_addra(fv_set_pd ,fv_cntr_pd )); +cntr_assume_inv :assume property(assign_addra(fv_set_inv ,fv_cntr_inv )); +cntr_assume_conv :assume property(assign_addra(fv_set_conv ,fv_cntr_conv )); +cntr_assume_sign0 :assume property(assign_addra(fv_set_sign0 ,fv_cntr_sign0 )); +cntr_assume_invq :assume property(assign_addra(fv_set_invq ,fv_cntr_invq )); +cntr_assume_sign1 :assume property(assign_addra(fv_set_sign1 ,fv_cntr_sign1 )); +cntr_assume_chkpk :assume property(assign_addra(fv_set_chkpk ,fv_cntr_chkpk )); +cntr_assume_ver0p0 :assume property(assign_addra(fv_set_ver0p0 ,fv_cntr_ver0p0 )); +cntr_assume_ver0p1 :assume property(assign_addra(fv_set_ver0p1 ,fv_cntr_ver0p1 )); +cntr_assume_ver1st :assume property(assign_addra(fv_set_ver1st ,fv_cntr_ver1st )); +cntr_assume_pminitpk:assume property(assign_addra(fv_set_pminitpk,fv_cntr_pminitpk)); +cntr_assume_ver2pa :assume property(assign_addra(fv_set_ver2pa ,fv_cntr_ver2pa )); + +always_enable: assume property(disable iff(!rst_n) ena == 1'b1); + +default clocking default_clk @(posedge clk); endclocking + + + sequence reset_sequence; + !rst_n ##1 rst_n; + endsequence + + +//////////////////////////////////////////// +// reset property, when reset out a and b // +// are zero // +//////////////////////////////////////////// + + property reset_p; + $past(!rst_n) + |-> + + douta == '0; + endproperty + + reset_a : assert property(reset_p); + + +//////////////////////////////////////////// +// Illegal address should result in zero // +//////////////////////////////////////////// + + property illicit_addra_p; + ((addra >1) && (addra < PM_INIT_G_S))|| + ((addra >PM_INIT_G_E) && (addra < PM_INIT_S))|| + ((addra >PM_INIT_E) && (addra < PA_S))|| + ((addra >PA_E) && (addra < PD_S))|| + ((addra >PD_E) && (addra < INV_S))|| + ((addra >INV_E) && (addra < CONV_S))|| + ((addra >CONV_E) && (addra < SIGN0_S))|| + ((addra >SIGN0_E) && (addra < INVq_S))|| + ((addra >INVq_E) && (addra < SIGN1_S))|| + ((addra >SIGN1_E) && (addra < CHK_PK_S))|| + ((addra >CHK_PK_E) && (addra < VER0_P0_S))|| + ((addra >VER0_P0_E) && (addra < VER0_P1_S))|| + ((addra >VER0_P1_E) && (addra < VER1_ST_S))|| + ((addra >VER1_ST_E) && (addra < PM_INIT_PK_S))|| + ((addra >PM_INIT_PK_E) && (addra < VER2_PA_S))|| + (addra > VER2_PA_E) + |=> + douta =='0; + endproperty + + + illicit_addra_a : assert property(disable iff(!rst_n) illicit_addra_p); + + + +//////////////////////////////////////////// +// Initial two steps dout is zero // +// // +//////////////////////////////////////////// + property initial_p; + addra == NOP || + addra == 1 + |=> + + douta == '0; + endproperty + + initial_a : assert property(disable iff(!rst_n) initial_p); + +//////////////////////////////////////////// +// Base point randamization and storing // +// in R1 // +//////////////////////////////////////////// + + + property pm_init_G_p; + addra == PM_INIT_G_S + + |-> + + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_LAMBDA, UOP_OPR_CONST_R2_p} // R1_Z = mm(Lambda, R2) λ conversion to montgomery domain + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R1_Z} // storing λ in the projective coordinate R1_Z + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_GX_MONT, UOP_OPR_R1_Z} // R1_X = mm(GX_MONT, R0_Z) 𝑋=𝐺𝑥×λ + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R1_X} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_GY_MONT, UOP_OPR_R1_Z} // R1_Y = mm(GY_MONT, R0_Z) 𝑌=𝐺𝑦×λ + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R1_Y}; + endproperty + + pm_init_G_a: assert property (disable iff(!rst_n) pm_init_G_p); + + +//////////////////////////////////////////// +// Initialize R0 with Zero // +// // +//////////////////////////////////////////// + + + property pm_init_S_p; + addra == PM_INIT_S + + |-> + + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_CONST_ZERO, UOP_OPR_CONST_ZERO} // R0_X = 0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_CONST_ONE_MONT, UOP_OPR_CONST_ZERO} // initialised with one_mont R0_y = 384'h100000000ffffffffffffffff0000000100000000 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_Y, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_CONST_ZERO, UOP_OPR_CONST_ZERO} // R0_Z = 0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_Z, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE}; + endproperty + + + pm_init_S_a: assert property (disable iff(!rst_n) pm_init_S_p); + + + + + +///////////////////////////////////////////// +// t0 =A,t1 =B,t2 =C,t3 =D,t4 =E,t5 =F // +// X1 = R0_x ,X2 = R1_x, after step 15 X3 = R1_x +// Y1 = R0_y ,Y2 = R1_y, after step Y3 = R1_x +// Z1 = R0_z ,Z2 = R1_z, after step 19 Z3 = R1_z +// +//////////////////////////////////////////// + property point_add_p; + addra == PA_S + + |=> + + douta == {UOP_DO_MUL_p, UOP_OPR_R0_X, UOP_OPR_R1_X} // t0 <- X1.X2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_R0_Y, UOP_OPR_R1_Y} // t1 <- Y1.Y2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_B} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_R0_Z, UOP_OPR_R1_Z} // t2 <- Z1.Z2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_R0_Y} // t3 <- X1+Y1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_D, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R1_X, UOP_OPR_R1_Y} // t4 <- X2+Y2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_D, UOP_OPR_E} // t3 <- t3.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_D} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_A, UOP_OPR_B} //t4 <- t0+t1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_D, UOP_OPR_E} // t3 <- t3 - t4 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_D, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_R0_Z} // t4 <- X1+Z1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R1_X, UOP_OPR_R1_Z} // t5 <- X2 + Z2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_E, UOP_OPR_F} //t4 <- t4.t5 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_E} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_A, UOP_OPR_C} // t5 <- t0+t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_E, UOP_OPR_F} // t4 <- t4 - t5 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Y, UOP_OPR_R0_Z} // t5 <- Y1+Z1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R1_Y, UOP_OPR_R1_Z} // X3 <- Y2 +Z2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R1_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_F, UOP_OPR_R1_X} // t5 <- t5.X3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_F} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_C} // X3 <- t1 +t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R1_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_F, UOP_OPR_R1_X} // t5 <- t5-X3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_a, UOP_OPR_E} // Z3 <- a.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R1_Z} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_3b, UOP_OPR_C} // X3 <-3b.t2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R1_X} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R1_X, UOP_OPR_R1_Z} // Z3 <- X3 + Z3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R1_Z, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_B, UOP_OPR_R1_Z} // X3 <- t1-Z3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R1_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_R1_Z} // Z3 <- t1+Z3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R1_Z, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_R1_X, UOP_OPR_R1_Z} // Y3 <- X3.Z3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R1_Y} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_A, UOP_OPR_A} // t1 <- t0+t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_A} // t1 <- t1+t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_a, UOP_OPR_C} // t2 <- a.t2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_3b, UOP_OPR_E} // t4 <- 3b.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_E} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_C} // t1<-t1+t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_A, UOP_OPR_C} // t2<-t0-t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_C, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_a, UOP_OPR_C} // t2<- a.t2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_E, UOP_OPR_C} // t4<-t4+t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_B, UOP_OPR_E} // t0 <- t1.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R1_Y, UOP_OPR_A} // Y3 <- Y3+t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R1_Y, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_F, UOP_OPR_E} // t0<-t5.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_D, UOP_OPR_R1_X} // X3 <- t3.X3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R1_X} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_R1_X, UOP_OPR_A} // X3 <- X3-t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R1_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_D, UOP_OPR_B} // t0 <- t3.t1 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_F, UOP_OPR_R1_Z} //Z3 <- t5.Z3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R1_Z} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R1_Z, UOP_OPR_A} // Z3 <- Z3 + t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R1_Z, UOP_OPR_DONTCARE} + ##1 addra == PD_S; +endproperty + +point_add_a: assert property(disable iff(!rst_n) point_add_p); + + + + + property point_dbl_p; + + addra == PD_S + + |=> + + douta == {UOP_DO_MUL_p, UOP_OPR_R0_X, UOP_OPR_R0_X} // t0 <- X1.X2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_R0_Y, UOP_OPR_R0_Y} // t1 <- Y1.Y2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_B} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_R0_Z, UOP_OPR_R0_Z} // t2 <- Z1.Z2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_R0_Y} // t3 <- X1+Y1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_D, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_R0_Y} // t4 <- X2+Y2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_D, UOP_OPR_E} // t3 <- t3.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_D} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_A, UOP_OPR_B} //t4 <- t0+t1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_D, UOP_OPR_E} // t3 <- t3 - t4 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_D, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_R0_Z} // t4 <- X1+Z1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_R0_Z} // t5 <- X2 + Z2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_E, UOP_OPR_F} //t4 <- t4.t5 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_E} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_A, UOP_OPR_C} // t5 <- t0+t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_E, UOP_OPR_F} // t4 <- t4 - t5 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Y, UOP_OPR_R0_Z} // t5 <- Y1+Z1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Y, UOP_OPR_R0_Z} // X3 <- Y2 +Z2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_F, UOP_OPR_R0_X} // t5 <- t5.X3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_F} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_C} // X3 <- t1 +t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_F, UOP_OPR_R0_X} // t5 <- t5-X3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_a, UOP_OPR_E} // Z3 <- a.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R0_Z} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_3b, UOP_OPR_C} // X3 <-3b.t2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R0_X} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_R0_Z} // Z3 <- X3 + Z3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_Z, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_B, UOP_OPR_R0_Z} // X3 <- t1-Z3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_R0_Z} // Z3 <- t1+Z3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_Z, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_R0_X, UOP_OPR_R0_Z} // Y3 <- X3.Z3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R0_Y} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_A, UOP_OPR_A} // t1 <- t0+t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_A} // t1 <- t1+t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_a, UOP_OPR_C} // t2 <- a.t2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_3b, UOP_OPR_E} // t4 <- 3b.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_E} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_C} // t1<-t1+t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_A, UOP_OPR_C} // t2<-t0-t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_C, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_a, UOP_OPR_C} // t2<- a.t2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_E, UOP_OPR_C} // t4<-t4+t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_B, UOP_OPR_E} // t0 <- t1.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Y, UOP_OPR_A} // Y3 <- Y3+t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_Y, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_F, UOP_OPR_E} // t0<-t5.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_D, UOP_OPR_R0_X} // X3 <- t3.X3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R0_X} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_R0_X, UOP_OPR_A} // X3 <- X3-t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_D, UOP_OPR_B} // t0 <- t3.t1 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_F, UOP_OPR_R0_Z} //Z3 <- t5.Z3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R0_Z} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Z, UOP_OPR_A} // Z3 <- Z3 + t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_Z, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE}; +endproperty + +point_dbl_a: assert property(disable iff(!rst_n) point_dbl_p); + + + + + + +property conv_p; + addra == CONV_S + + |-> + + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_INV_OUT, UOP_OPR_R0_Y} // y_MONT = fp_mult(Z_inv, Y_MONT, p) . Y = Y/Z (Ref: sec 2 Montgomery curves and their arithmetic The case of large characteristic fields Craig Costello · Benjamin Smith) + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_Qy_MONT} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_INV_OUT, UOP_OPR_R0_X} // x_MONT = fp_mult(Z_inv, X_MONT, p) X = X/Z + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_Qx_MONT} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_ONE, UOP_OPR_Qy_MONT} // y_affine = fp_mult(y_MONT, 1, p) conversion from mont domain to normal + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_Qy_AFFN} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_ONE, UOP_OPR_Qx_MONT} // y_affine = fp_mult(y_MONT, 1, p) conversion from mont domain to normal + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_Qx_AFFN} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE}; +endproperty + +conv_a: assert property(disable iff(!rst_n) conv_p); + +//////////////////////////////////////////////////////////////// +// s = [k^-1((h-d) + r (privKey-d))] + [k^-1(d + r.d)] mod n // +// // +//////////////////////////////////////////////////////////////// + + +property sign0_p; + addra == SIGN0_S + + |-> + + ##1 douta == {UOP_DO_ADD_q, UOP_OPR_CONST_ZERO, UOP_OPR_Qx_AFFN} // R = Qx_AFFN + ##1 douta == {UOP_ST_ADD_q, UOP_OPR_SIGN_R, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_SIGN_R, UOP_OPR_CONST_R2_q} // E = mm(R, R2) % q r conversion to montgomery domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_E} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_SCALAR_G, UOP_OPR_CONST_R2_q} // k_MONT = mm(k, R2) % q k conversion to montgomery domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_INV_IN} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_PRIVKEY, UOP_OPR_CONST_R2_q} // A = mm(privKey, R2) % q privkey conversion to montgomery domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_HASH_MSG, UOP_OPR_CONST_R2_q} // B = mm(h, R2) % q hash msg conversion to montgomery domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_B} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_MASKING, UOP_OPR_CONST_R2_q} // D = mm(masking_d, R2) % q d conversion to montgomery domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_D} + ##1 douta == {UOP_DO_SUB_q, UOP_OPR_A, UOP_OPR_D} // A = (A - D) % q (privkey-d) + ##1 douta == {UOP_ST_ADD_q, UOP_OPR_A, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_q, UOP_OPR_B, UOP_OPR_D} // B = (B - D) % q (h-d) + ##1 douta == {UOP_ST_ADD_q, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A, UOP_OPR_E} // C = mm(A, E) % q r(privkey-d) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_D, UOP_OPR_E} // F = mm(D, E) % q r.d + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_F} + ##1 douta == {UOP_DO_ADD_q, UOP_OPR_D, UOP_OPR_C} // C = (C + D) % q (d + r (privKey-d)) + ##1 douta == {UOP_ST_ADD_q, UOP_OPR_C, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_q, UOP_OPR_B, UOP_OPR_F} // D = (B + F) % q ((h-d) + r.d) + ##1 douta == {UOP_ST_ADD_q, UOP_OPR_D, UOP_OPR_DONTCARE}; +endproperty + + + +sign0_a: assert property(disable iff(!rst_n) sign0_p); + + +property sign1_p; + addra == SIGN1_S + + |-> + + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_OUT, UOP_OPR_C} // C = fp_mult(C, k_inv, q) C = k^-1.((h-d) + r (privKey-d)) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_OUT, UOP_OPR_D} // D = fp_mult(D, k_inv, q) D = k^-1.(d + r.d) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_D} + ##1 douta == {UOP_DO_ADD_q, UOP_OPR_C, UOP_OPR_D} // B = C + D % q B = (C+D) mod n + ##1 douta == {UOP_ST_ADD_q, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_CONST_ONE, UOP_OPR_B} // B = fp_mult(B, 1, q) conversion from montgomery to normal domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_SIGN_S} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE}; +endproperty + +sign1_a: assert property(disable iff(!rst_n) sign1_p); + + +// Inputs pubKey,h(hash msg),r(respective r part in signature),s(respective s part in signature) +// s1 = s^-1 mod q +// R' = (h* s1)*G + (r*s1)*pubKey +// r' = R'x mod q +// +// Verify part0 to convert inputs to the mont domain + + + + +property verify0_p0_p; + addra == VER0_P0_S + + |-> + + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_HASH_MSG, UOP_OPR_CONST_R2_q} // A = mm(h, R2) % q conversion of hash msg to mont domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_SIGN_R, UOP_OPR_CONST_R2_q} // B = mm(R, R2) % q conversion of r to mont domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_B} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_SIGN_S, UOP_OPR_CONST_R2_q} // INV_IN = mm(S, R2) % q conversion of s to mont domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_INV_IN} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE}; +endproperty + +verify0_p0_a: assert property(disable iff(!rst_n)verify0_p0_p); + + + +// verify part1 use the generated s^-1 for the intermediate computations and convert them +// into normal domain so in next step they could be used in the point multiplication. + + +property verify0_p1_p; + addra == VER0_P1_S + + |-> + + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_OUT, UOP_OPR_A} // A = mm(h, S_INV) % q h*s^-1 mod q + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_CONST_ONE, UOP_OPR_A} // hs1 = mm(A, 1) % q conversion from mont domain to normal domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_SCALAR_G} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_OUT, UOP_OPR_B} // B = mm(r, S_INV) % q r*s^-1 mod q + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_B} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_CONST_ONE, UOP_OPR_B} // rs1 = mm(B, 1) % q conversion from mont domain to normal domain + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_SCALAR_PK} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE}; +endproperty + +verify0_p1_a: assert property(disable iff(!rst_n)verify0_p1_p); + + +//verify1 (h*s^-1)*G + +property verify1_st_p; + addra == VER1_ST_S + + |-> + + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_CONST_ZERO} // computed results stored in R0, in the previous seq + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_P1_X_MONT, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Y, UOP_OPR_CONST_ZERO} + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_P1_Y_MONT, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Z, UOP_OPR_CONST_ZERO} + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_P1_Z_MONT, UOP_OPR_DONTCARE}; + +endproperty + +verify1_st_a: assert property(disable iff(!rst_n)verify1_st_p); + + +// verify2 Initialise with PubKey(PK) for (r*s^-1)*PK computation +// It is stored R1, but R1_z is initialised with one_mont + + + +property verify2_init_pk_p; + + addra == PM_INIT_PK_S + + |-> + + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_Qx_AFFN, UOP_OPR_CONST_R2_p} //Through DSA seq pubkey is stored to QX and QY prior to start of this seq + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R1_X} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_Qy_AFFN, UOP_OPR_CONST_R2_p} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R1_Y} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_CONST_ONE_MONT, UOP_OPR_CONST_ZERO} // + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R1_Z, UOP_OPR_DONTCARE}; +endproperty + +verify2_init_pk_a: assert property (disable iff(!rst_n) verify2_init_pk_p); + + + + //VER2 point addtion of PA((h*s_inv)*G, (r*s_inv)*PK) + // t0 =A,t1 =B,t2 =C,t3 =D,t4 =E,t5 =F // + // X1 = R0_x ,X2 = P1_x, after step 15 X3 = R0_x + // Y1 = R0_y ,Y2 = P1_y, after step Y3 = R0_x + // Z1 = R0_z ,Z2 = P1_z, after step 19 Z3 = R0_z + + property verify2_pointadd_p; + + addra == VER2_PA_S + |-> + + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_R0_X, UOP_OPR_P1_X_MONT} // A = fp_mult(P0.X, P1.X, p) t0 <- X1.X2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_R0_Y, UOP_OPR_P1_Y_MONT} // B = fp_mult(P0.Y, P1.Y, p) t1 <- Y1.Y2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_B} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_R0_Z, UOP_OPR_P1_Z_MONT} // C = fp_mult(P0.Z, P1.Z, p) t2 <- Z1.Z2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_R0_Y} // D = (P0.X + P0.Y) % p t3 <- X1+Y1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_D, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_P1_X_MONT, UOP_OPR_P1_Y_MONT} // E = (P1.X + P1.Y) % p t4 <- X2+Y2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_D, UOP_OPR_E} // D = fp_mult(D, E, p) t3 <- t3.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_D} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_A, UOP_OPR_B} // E = (A + B) % p t4 <- t0+t1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_D, UOP_OPR_E} // D = (D - E) % p t3 <- t3 - t4 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_D, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_R0_Z} // E = (P0.X + P0.Z) % p t4 <- X1+Z1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_P1_X_MONT, UOP_OPR_P1_Z_MONT} // F = (P1.X + P1.Z) % p t5 <- X2 + Z2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_E, UOP_OPR_F} // E = fp_mult(E, F, p) t4 <- t4.t5 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_E} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_A, UOP_OPR_C} // F = (A + C) % p t5 <- t0+t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_E, UOP_OPR_F} // E = (E - F) % p t4 <- t4 - t5 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Y, UOP_OPR_R0_Z} // F = (P0.Y + P0.Z) % p t5 <- Y1+Z1 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_P1_Y_MONT, UOP_OPR_P1_Z_MONT} // X3 = (P1.Y + P1.Z) % p X3 <- Y2 +Z2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_F, UOP_OPR_R0_X} // F = fp_mult(F, X3, p) t5 <- t5.X3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_F} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_C} // X3 = (B + C) % p X3 <- t1 +t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_F, UOP_OPR_R0_X} // F = (F - X3) % p t5 <- t5-X3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_F, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_a, UOP_OPR_E} // Z3 = fp_mult(ECC.a, E, p) Z3 <- a.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R0_Z} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_3b, UOP_OPR_C} // X3 = fp_mult(ECC.3b, C, p) X3 <-3b.t2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R0_X} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_X, UOP_OPR_R0_Z} // Z3 = (X3 + Z3) % p Z3 <- X3 + Z3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_Z, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_B, UOP_OPR_R0_Z} // X3 = (B - Z3) % p X3 <- t1-Z3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_R0_Z} // Z3 = (B + Z3) % p Z3 <- t1+Z3 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_Z, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_R0_X, UOP_OPR_R0_Z} // Y3 = fp_mult(X3, Z3, p) Y3 <- X3.Z3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R0_Y} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_A, UOP_OPR_A} // B = (A + A) % p t1 <- t0+t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_A} // B = (B + A) % p t1 <- t1+t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_a, UOP_OPR_C} // C = fp_mult(ECC.a, C, p) t2 <- a.t2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_3b, UOP_OPR_E} // E = fp_mult(ECC.3b, E, p) t4 <- 3b.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_E} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_B, UOP_OPR_C} // B = (B + C) % p t1<-t1+t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_B, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_A, UOP_OPR_C} // C = (A - C) % p t2<-t0-t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_C, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_a, UOP_OPR_C} // C = fp_mult(ECC.a, C, p) t2<- a.t2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_E, UOP_OPR_C} // E = (E + C) % p t4<-t4+t2 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_E, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_B, UOP_OPR_E} // A = fp_mult(B, E, p) t0 <- t1.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Y, UOP_OPR_A} // Y3 = (Y3 + A) % p Y3 <- Y3+t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_Y, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_F, UOP_OPR_E} // A = fp_mult(F, E, p) t0<-t5.t4 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_D, UOP_OPR_R0_X} // X3 = fp_mult(D, X3, p) X3 <- t3.X3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R0_X} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_R0_X, UOP_OPR_A} // X3 = (X3 - A) % p X3 <- X3-t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_X, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_D, UOP_OPR_B} // A = fp_mult(D, B, p) t0 <- t3.t1 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_F, UOP_OPR_R0_Z} // Z3 = fp_mult(F, Z3, p) Z3 <- t5.Z3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_R0_Z} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Z, UOP_OPR_A} // Z3 = (Z3 + A) % p Z3 <- Z3 + t0 + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_R0_Z, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_R0_Z, UOP_OPR_CONST_ZERO} // Zinv_IN = P1_Z + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_INV_IN, UOP_OPR_DONTCARE}; +endproperty + +verify2_pointadd_a: assert property (disable iff(!rst_n) verify2_pointadd_p); + + + + + +property inv_modp_p; + addra == INV_S + + |-> + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_CONST_ZERO, UOP_OPR_CONST_ONE_MONT} // precompute[0] = UOP_OPR_CONST_ONE_MONT % p + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_INV_PRE0, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_INV_IN, UOP_OPR_INV_PRE0} // precompute[1] = fp_mult(Z, precompute[0], p) + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE1} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_INV_IN, UOP_OPR_INV_PRE1} // precompute[2] = fp_mult(Z, precompute[1], p) + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE2} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_INV_IN, UOP_OPR_INV_PRE2} // precompute[3] = fp_mult(Z, precompute[2], p) + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_INV_IN, UOP_OPR_INV_PRE3} // precompute[4] = fp_mult(Z, precompute[3], p) + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE4} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_INV_IN, UOP_OPR_INV_PRE4} // precompute[5] = fp_mult(Z, precompute[4], p) + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_INV_IN, UOP_OPR_INV_PRE5} // precompute[6] = fp_mult(Z, precompute[5], p) + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_INV_IN, UOP_OPR_INV_PRE6} // precompute[7] = fp_mult(Z, precompute[6], p) + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_INV_PRE0, UOP_OPR_INV_PRE0} // a_inv = fp_mult(precompute[0], precompute[0], p) + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} // a_inv = fp_mult(a_inv, a_inv, p) //why these two additional steps ? + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} // a_inv = fp_mult(a_inv, a_inv, p) + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A_INV, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_INV_OUT}; +endproperty + + +inv_modp_a: assert property (disable iff(!rst_n) inv_modp_p); + + + + +property inv_modq_p; + addra == INVq_S + + |-> + + ##1 douta == {UOP_DO_ADD_q, UOP_OPR_CONST_ZERO, UOP_OPR_CONST_ONE_q_MONT} // precompute[0] = UOP_OPR_CONST_ONE_q_MONT % q + ##1 douta == {UOP_ST_ADD_q, UOP_OPR_INV_PRE0, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_IN, UOP_OPR_INV_PRE0} // precompute[1] = fp_mult(Z, precompute[0], q) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE1} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_IN, UOP_OPR_INV_PRE1} // precompute[2] = fp_mult(Z, precompute[1], q) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE2} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_IN, UOP_OPR_INV_PRE2} // precompute[3] = fp_mult(Z, precompute[2], q) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_IN, UOP_OPR_INV_PRE3} // precompute[4] = fp_mult(Z, precompute[3], q) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE4} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_IN, UOP_OPR_INV_PRE4} // precompute[5] = fp_mult(Z, precompute[4], q) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_IN, UOP_OPR_INV_PRE5} // precompute[6] = fp_mult(Z, precompute[5], q) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_IN, UOP_OPR_INV_PRE6} // precompute[7] = fp_mult(Z, precompute[6], q) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_INV_PRE0, UOP_OPR_INV_PRE0} // a_inv = fp_mult(precompute[0], precompute[0], q) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} // a_inv = fp_mult(a_inv, a_inv, q) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} // a_inv = fp_mult(a_inv, a_inv, q) + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE1} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE1} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE1} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE4} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE2} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE1} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE4} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE2} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE2} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE2} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE1} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE2} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE4} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE7} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE4} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE0} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE2} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE3} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE1} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE4} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE1} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE2} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE2} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE4} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE5} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE6} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_A_INV} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_A_INV} + ##1 douta == {UOP_DO_MUL_q, UOP_OPR_A_INV, UOP_OPR_INV_PRE1} + ##1 douta == {UOP_ST_MUL_q, UOP_OPR_DONTCARE, UOP_OPR_INV_OUT}; +endproperty + +inv_modq_a: assert property(disable iff(!rst_n) inv_modq_p); + + + +//seq to check the provided pubKey is on the curve or not. +property chk_pk_p; + addra == CHK_PK_S + + |-> + + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_Qy_AFFN, UOP_OPR_CONST_R2_p} // A = mm(Qy, R2) % p conversion of pubkey y to mont domain + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_A, UOP_OPR_A} // A = A*A % p y^2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_A} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_Qx_AFFN, UOP_OPR_CONST_R2_p} // B = mm(Qx, R2) % p conversion of pubkey x to mont domain + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_B} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_B, UOP_OPR_B} // C = B*B % p x^2 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_C, UOP_OPR_B} // C = C*B % p x^3 + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_C} + ##1 douta == {UOP_DO_MUL_p, UOP_OPR_CONST_E_a, UOP_OPR_B} // D = ECC.a*B % p a.x + ##1 douta == {UOP_ST_MUL_p, UOP_OPR_DONTCARE, UOP_OPR_D} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_C, UOP_OPR_D} // C = C + D % p x^3 + a.x + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_C, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_ADD_p, UOP_OPR_C, UOP_OPR_CONST_E_b} // C = C + ECC.b % p x^3 + a.x + b + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_C, UOP_OPR_DONTCARE} + ##1 douta == {UOP_DO_SUB_p, UOP_OPR_A, UOP_OPR_C} // PK_valid = A - C % p y^2 - (x^3 + a.x + b) should be equal to zero if the key is on the curve + ##1 douta == {UOP_ST_ADD_p, UOP_OPR_PK_VALID, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE} + ##1 douta == {UOP_NOP, UOP_OPR_DONTCARE, UOP_OPR_DONTCARE}; +endproperty + +chk_pk_a: assert property(disable iff(!rst_n) chk_pk_p); + + + +// When storing both the address should not be the same +property store_not_same_addr_p; + douta[17] || + douta[16] + |-> + douta[11:6]!= douta[5:0]; +endproperty + +store_not_same_addr_a: assert property(disable iff(!rst_n) store_not_same_addr_p); + +// If it starts with UOP_NOP, the next both fields should be UOP_OPR_DONTCARE +property when_nop_both_addr_0_p; + douta[17:12] == UOP_NOP + |-> + douta[11:0]== {UOP_OPR_DONTCARE,UOP_OPR_DONTCARE}; +endproperty + +when_nop_both_addr_0_a: assert property(disable iff(!rst_n) when_nop_both_addr_0_p); + +//If it starts with UOP_ST_ADD_p/UOP_ST_ADD_q, the last field should be UOP_OPR_DONTCARE. + +property when_add_addrb_0_p; + (douta[17:12] == UOP_ST_ADD_p) || + (douta[17:12] == UOP_ST_ADD_q) + |-> + douta[5:0]== UOP_OPR_DONTCARE; +endproperty + +when_add_addrb_0_a: assert property(disable iff(!rst_n) when_add_addrb_0_p); + + +//o If it starts with UOP_ST_MUL_p/UOP_ST_MUL_q the middle field should be UOP_OPR_DONTCARE + +property when_mult_addra_0_p; + (douta[17:12] == UOP_ST_MUL_p) || + (douta[17:12] == UOP_ST_MUL_q) + |-> + douta[11:6]== UOP_OPR_DONTCARE; +endproperty + +when_mult_addra_0_a: assert property(disable iff(!rst_n) when_mult_addra_0_p); + +//If it starts with UOP_DO_MUL_p/UOP_DO_MUL_q/ UOP_DO_ADD_p/ UOP_DO_ADD_q/ UOP_DO_SUB_p/UOP_DO_SUB_q, +//the next both fields shouldn’t be UOP_OPR_DONTCARE. + + +property when_do_add_mul_sub_addr_not_zero_p; + ((douta[17:12] == UOP_DO_MUL_p) || + (douta[17:12] == UOP_DO_MUL_q) || + (douta[17:12] == UOP_DO_ADD_q) || + (douta[17:12] == UOP_DO_ADD_p) || + (douta[17:12] == UOP_DO_SUB_p) || + (douta[17:12] == UOP_DO_SUB_q)) && + $past(addra) != PM_INIT_S && + $past(addra) != PM_INIT_S+ 4 //Next field after opcode is const_zero i.e both the fields are zero so excluded + |-> + douta[11:0] != {UOP_OPR_DONTCARE,UOP_OPR_DONTCARE}; +endproperty + +when_do_add_mul_sub_addr_not_zero_a: assert property(disable iff(!rst_n) when_do_add_mul_sub_addr_not_zero_p); + + +endmodule + + + +bind ecc_pm_sequencer fv_ecc_pm_sequencer + #(.ADDR_WIDTH(ADDR_WIDTH), + .DATA_WIDTH(DATA_WIDTH) + ) + fv_ecc_pm_sequencer_inst( + .clk(clka), + .rst_n(reset_n && !zeroize), + .ena(ena), + .addra(addra), + .douta(douta) + ); diff --git a/src/ecc/formal/properties/fv_ecc_ram_tdp_file.sv b/src/ecc/formal/properties/fv_ecc_ram_tdp_file.sv new file mode 100644 index 000000000..7cad1927b --- /dev/null +++ b/src/ecc/formal/properties/fv_ecc_ram_tdp_file.sv @@ -0,0 +1,210 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_ecc_ram_tdp_file #( + parameter ADDR_WIDTH = 10, + parameter DATA_WIDTH = 32 + ) + ( + input wire clk, + input wire rst_n, + + + input wire ena, + input wire wea, + input wire [ADDR_WIDTH-1 : 0] addra, + input wire [DATA_WIDTH-1 : 0] dina, + input logic [DATA_WIDTH-1 : 0] douta, + + input wire enb, + input wire web, + input wire [ADDR_WIDTH-1 : 0] addrb, + input wire [DATA_WIDTH-1 : 0] dinb, + input logic [DATA_WIDTH-1 : 0] doutb + ); + + // Declare the RAM variable + localparam ADDR_LENGTH = 2**ADDR_WIDTH; + default clocking default_clk @(posedge clk); endclocking + + + sequence reset_sequence; + !rst_n ##1 rst_n; + endsequence + +addr_not_same_write : assume property (disable iff(!rst_n) (ena && wea && enb && web) |-> addra != addrb); + + +//////////////////////////////////////////// +// reset property, when reset out a and b // +// are zero // +//////////////////////////////////////////// + + property reset_p; + $past(!rst_n) + |-> + douta == '0 && + doutb == '0; + endproperty + + reset_a : assert property(reset_p); + + + + + +/////////////////////////////////////////////// +//Symbolic checking // +/////////////////////////////////////////////// + logic [ADDR_WIDTH-1:0] sym_addr; + + property sym_reset_mem_p; + $past(!rst_n) + |-> + ecc_ram_tdp_file.mem[sym_addr] == '0; + endproperty + sym_reset_mem_a: assert property(sym_reset_mem_p); + + + /////////////////////////////////////////////// + // write to the memory with din in the // + // address provided considering the addresses// + // a and b will not be same while writing // + /////////////////////////////////////////////// + + logic [8:0] idx_sym_data_wr_a; + logic [8:0] idx_sym_data_wr_b; + + idx_sym_wr_a_less_than_384: assume property(disable iff(!rst_n) (idx_sym_data_wr_a<9'd384) && $stable(idx_sym_data_wr_a)); + idx_sym_wr_b_less_than_384: assume property(disable iff(!rst_n) (idx_sym_data_wr_b<9'd384) && $stable(idx_sym_data_wr_b)); + + + property write_p(en,we,addr,dout,din,idx); + logic [ADDR_WIDTH-1 : 0] store_addr; + logic [DATA_WIDTH-1: 0] store_data; + en && + we + ##0 (1'b1, store_addr = addr) + ##0 (1'b1, store_data = ecc_ram_tdp_file.mem[addr]) + |=> + dout[idx] == store_data[idx] && + (ecc_ram_tdp_file.mem[store_addr][idx]) == $past(din[idx]) + ; + endproperty + write_a_a: assert property(disable iff(!rst_n)write_p(ena,wea,addra,douta,dina,idx_sym_data_wr_a)); + write_b_a: assert property(disable iff(!rst_n)write_p(enb,web,addrb,doutb,dinb,idx_sym_data_wr_b)); + + + + + /////////////////////////////////////////////// + // read to the memory with whatever the // + // address provided considering the addresses// + // a and b can be same // + /////////////////////////////////////////////// + logic [8:0] idx_sym_data_rd_a; + logic [8:0] idx_sym_data_rd_b; + + idx_sym_rd_a_less_than_384: assume property(disable iff(!rst_n) (idx_sym_data_rd_a<9'd384) && $stable(idx_sym_data_rd_a)); + idx_sym_rd_b_less_than_384:assume property(disable iff(!rst_n) (idx_sym_data_rd_b<9'd384) && $stable(idx_sym_data_rd_b)); + + + property read_p(en,we,addr,dout,idx); + logic [DATA_WIDTH-1:0] store_data; + logic [ADDR_WIDTH-1:0] store_addr; + en && + !we + ##0 (1'b1, store_data = ecc_ram_tdp_file.mem[addr] ) + |=> + dout[idx] == store_data[idx] + ; + endproperty + read_a_a: assert property(disable iff(!rst_n)read_p(ena,wea,addra,douta,idx_sym_data_rd_a)); + read_b_a: assert property(disable iff(!rst_n)read_p(enb,web,addrb,doutb,idx_sym_data_rd_b)); + + + + +/////////////////////////////////////////////// +// No enable, no read and write // +/////////////////////////////////////////////// + logic [8:0] idx_sym_nen_a; + logic [8:0] idx_sym_nen_b; + logic [8:0] idx_sym_nen_ab; + + idx_sym_nen_a_less_than_384: assume property(disable iff(!rst_n) (idx_sym_nen_a<9'd384) && $stable(idx_sym_nen_a)); + idx_sym_nen_b_less_than_384: assume property(disable iff(!rst_n) (idx_sym_nen_b<9'd384) && $stable(idx_sym_nen_b)); + idx_sym_nen_ab_less_than_384: assume property(disable iff(!rst_n) (idx_sym_nen_ab<9'd384) && $stable(idx_sym_nen_ab)); + + + property no_enable_p(en,dout,addr,idx); + logic [DATA_WIDTH-1:0] store_data; + logic [ADDR_WIDTH-1 : 0] store_addr; + !en && + addra != addrb + ##0 (1'b1, store_data = ecc_ram_tdp_file.mem[addr] ) + ##0 (1'b1, store_addr = addr) + |=> + dout[idx] == $past(dout[idx]) && + (ecc_ram_tdp_file.mem[store_addr][idx]) == store_data[idx]; + endproperty + + no_enable_a_a: assert property(disable iff(!rst_n) no_enable_p(ena,douta,addra,idx_sym_nen_a)); + no_enable_b_a: assert property(disable iff(!rst_n) no_enable_p(enb,doutb,addrb,idx_sym_nen_b)); + + + property no_enable_ab_p; + logic [DATA_WIDTH-1:0] store_datab,store_dataa; + logic [ADDR_WIDTH-1 : 0] store_addrb,store_addra; + !ena && + !enb + ##0 (1'b1, store_dataa = ecc_ram_tdp_file.mem[addra] ) + ##0 (1'b1, store_addra = addra) + ##0 (1'b1, store_datab = ecc_ram_tdp_file.mem[addrb] ) + ##0 (1'b1, store_addrb = addrb) + |=> + douta[idx_sym_nen_ab] == $past(douta[idx_sym_nen_ab]) && + (ecc_ram_tdp_file.mem[store_addra][idx_sym_nen_ab]) == store_dataa[idx_sym_nen_ab] && + doutb[idx_sym_nen_ab] == $past(doutb[idx_sym_nen_ab]) && + (ecc_ram_tdp_file.mem[store_addrb][idx_sym_nen_ab]) == store_datab[idx_sym_nen_ab]; + endproperty + + no_enable_ab_a: assert property(disable iff(!rst_n) no_enable_ab_p); + +endmodule + + + +bind ecc_ram_tdp_file fv_ecc_ram_tdp_file #( + .ADDR_WIDTH(ADDR_WIDTH), + .DATA_WIDTH(DATA_WIDTH) + ) + fv_ecc_ram_tdp_file_inst( + .clk(clk), + .rst_n(reset_n && !zeroize), + .ena(ena), + .wea(wea), + .addra(addra), + .dina(dina), + .douta(douta), + .enb(enb), + .web(web), + .addrb(addrb), + .dinb(dinb), + .doutb(doutb) + ); \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_montmultiplier.sv b/src/ecc/formal/properties/fv_montmultiplier.sv new file mode 100644 index 000000000..42011dd95 --- /dev/null +++ b/src/ecc/formal/properties/fv_montmultiplier.sv @@ -0,0 +1,269 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_montmultiplier #( + parameter REG_SIZE = 384, + parameter RADIX = 32 +) +( + // Clock and reset. + input logic clk, + input logic rst_n, + + // DATA PORT + input logic start_i, + input logic [REG_SIZE-1:0] opa_i, + input logic [REG_SIZE-1:0] opb_i, + input logic [REG_SIZE-1:0] n_i, + input logic [RADIX-1:0] n_prime_i, // only need the last few bits + input logic [REG_SIZE-1:0] p_o, + input logic ready_o +); + +default clocking default_clk @(posedge clk); endclocking + + +//-------------------------------------------------------// +//R = 2^((ceil(bits(n_i)/RADIX)+1)*RADIX) +//R^(-1) = R invmod n_i; +//localparam R = 417'h100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; +//localparam R_inv = 355'h0600000014000000140000000C00000002FFFFFFFCFFFFFFFAFFFFFFFBFFFFFFF7FFFFFFE5FFFFFFD8FFFFFFE7; +//-------------------------------------------------------// + + +localparam MULT_DLY = 40; // Defines after start how many cycles ready would stay deasserted. + + +localparam int unsigned S_NUM = ((REG_SIZE + RADIX - 1) / RADIX) + 1; +localparam int unsigned FULL_REG_SIZE = S_NUM * RADIX; + +localparam PE_UNITS = ((S_NUM - 1) / 2) - 1; + + +function logic[ REG_SIZE-1:0] montmult (logic[ REG_SIZE-1:0] a, logic[ REG_SIZE-1:0] b, logic[ REG_SIZE-1:0] c, logic[ REG_SIZE-1:0] d); + return ((1152'(768'(a*b)*c)%d)); +endfunction + + + +sequence reset_sequence; + !rst_n ##1 rst_n; +endsequence + +property reset_p; + $past(!rst_n) + |-> + p_o == 0 && + ready_o == 1; +endproperty + +reset_a: assert property(reset_p); + + +//////////////////////////////////////////// +// start_i triggers only after multi done // +/////////////////////////////////////////// +start_mult_as: assume property(disable iff(!rst_n)start_mult_as_p); + +property start_mult_as_p; + start_i + |=> + !start_i until (ready_o); +endproperty + +mult_operands_less_than_prime: assume property(disable iff(!rst_n) mult_operands_less_than_prime_p); + +property mult_operands_less_than_prime_p; + start_i + |-> + opa_i < n_i && + opb_i < n_i ; +endproperty + + + +`ifndef FOR48 + + +///////////////////////////////////////////////// +// Property for 16 bit to prove the computation// +//////////////////////////////////////////////// + +/********For inp value less than 4 bits ******/ +property multi_0_p(prime_i, mu_i,r_inv); + logic [REG_SIZE-1:0] temp; + n_i == prime_i && + n_prime_i == mu_i && + opa_i <= 4'hf && + opb_i <= 4'hf && + start_i + ##0 (1'b1, temp = (48'(32'(opa_i*opb_i)*r_inv)%n_i)) + |-> + ##16 + (p_o == temp) && + ready_o; + endproperty + + +/********For inp value less than 8 bits ******/ +property multi_1_p(prime_i, mu_i,r_inv); + logic [REG_SIZE-1:0] temp; + n_i == prime_i && + n_prime_i == mu_i && + opa_i <= 8'hff && + opb_i <= 8'hff && + opa_i > 4'hf && + opb_i > 4'hf && + start_i + ##0 (1'b1, temp = (48'(32'(opa_i*opb_i)*r_inv)%n_i)) + + |-> + ##16 + (p_o == temp) && + ready_o; + endproperty + + +/********For inp value less than 12 bits ******/ +property multi_2_p(prime_i, mu_i,r_inv); + logic [REG_SIZE-1:0] temp; + n_i == prime_i && + n_prime_i == mu_i && + opa_i <= 12'hfff && + opb_i <= 12'hfff && + opa_i > 8'hff && + opb_i > 8'hff && + start_i + ##0 (1'b1, temp = (48'(32'(opa_i*opb_i)*r_inv)%n_i)) + |-> + ##16 //for 16 bit just gave a slack + (p_o[0] == temp[0]) && + ready_o; + endproperty + +/********For inp value all bits ******/ +property multi_p(prime_i, mu_i,r_inv); + logic [REG_SIZE-1:0] temp; + n_i == prime_i && + n_prime_i == mu_i && + start_i + ##0 (1'b1, temp = (48'(32'(opa_i*opb_i)*r_inv)%n_i)) + |-> + ##16 //for 16 bit just gave a slack + p_o == temp && + ready_o; + endproperty + +logic [4:0][REG_SIZE-1:0] prime; +logic [4:0][RADIX-1:0] mu_word; +logic [4:0][REG_SIZE-1:0] rinv; +assign prime ={16'hfceb,16'hfcfb,16'hfd0d,16'hfd0f,16'hfd19}; +assign mu_word = {4'hd,4'hd,4'hb,4'h1,4'h7}; +assign rinv ={16'hc0ea,16'he269,16'hcc03,16'h1a92,16'h4e28}; + +genvar i; +for(i=0;i<5;i++) begin + multi_a: assert property(disable iff (!rst_n) multi_p(prime[i], mu_word[i],rinv[i])); + multi_2_a: assert property(disable iff (!rst_n) multi_2_p(prime[i], mu_word[i],rinv[i])); + multi_1_a: assert property(disable iff (!rst_n) multi_1_p(prime[i], mu_word[i],rinv[i])); + multi_0_a: assert property(disable iff (!rst_n) multi_0_p(prime[i], mu_word[i],rinv[i])); +end + + +///////////////////////////////////////////////// +// Property for ready deassert // +//////////////////////////////////////////////// + +property no_ready_p; + start_i + |=> + !ready_o[*15]; +endproperty + +no_ready_a: assert property(disable iff(!rst_n)no_ready_p); + + +//-------------------------------------------------------------------------------------------------// +// For 48 bit operands // +//-------------------------------------------------------------------------------------------------// + + +`else + + +/********For inp value all bits ******/ +property multi_p(prime_i, mu_i,r_inv); + logic [REG_SIZE-1:0] temp; + n_i == prime_i && + n_prime_i == mu_i && + start_i + ##0 (1'b1, temp = (144'(96'(opa_i*opb_i)*r_inv)%n_i)) + //##0 (1'b1, temp = ((1152'(768'(opa_i*opb_i)*r_inv)%n_i))) + ##1 ready_o[->1] + |-> + + p_o == temp; +endproperty + + +logic [4:0][REG_SIZE-1:0] prime; +logic [4:0][RADIX-1:0] mu_word; +logic [4:0][REG_SIZE-1:0] rinv; +assign prime ={48'hffffffffff9f,48'hffffffffffb3,48'hffffffffffbf,48'hffffffffffc9,48'hffffffffffd5}; +assign mu_word = {4'h1,4'h5,4'h1,4'h7,4'h3}; +assign rinv ={48'h1fd5c5f02a2e,48'h3ce213f2b376,48'h1fc0fc0fc0f4,48'h686fb586fb42,48'h30be82fa0be0}; + + +genvar i; +for(i=0;i<5;i++) begin + multi_a: assert property(disable iff (!rst_n) multi_p(prime[i], mu_word[i],rinv[i])); + end + +///////////////////////////////////////////////// +// Property for ready deassert // +//////////////////////////////////////////////// + +property no_ready_p; + start_i + |=> + !ready_o[*(MULT_DLY-1)]; +endproperty + +no_ready_a: assert property(disable iff(!rst_n)no_ready_p); + +`endif +endmodule + +bind ecc_montgomerymultiplier fv_montmultiplier #( + .REG_SIZE(REG_SIZE), + .RADIX(RADIX) + ) + fv_montmultiplier_inst ( + // Clock and reset. + .clk(clk), + .rst_n(reset_n && !zeroize), + + // DATA PORT + .start_i(start_i), + .opa_i(opa_i), + .opb_i(opb_i), + .n_i(n_i), + .n_prime_i(n_prime_i), // only need the last few bits + .p_o(p_o), + .ready_o(ready_o) + ); \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_montmultiplier_glue.sv b/src/ecc/formal/properties/fv_montmultiplier_glue.sv new file mode 100644 index 000000000..ad8573f5c --- /dev/null +++ b/src/ecc/formal/properties/fv_montmultiplier_glue.sv @@ -0,0 +1,252 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_montmultiplier_glue #( + parameter REG_SIZE = 384, + parameter RADIX = 32 +) +( + // Clock and reset. + input wire clk, + input wire rst_n, + + + // DATA PORT + input wire start_i, + input wire [REG_SIZE-1:0] opa_i, + input wire [REG_SIZE-1:0] opb_i, + input wire [REG_SIZE-1:0] n_i, + input wire [RADIX-1:0] n_prime_i, // only need the last few bits + input logic [REG_SIZE-1:0] p_o, + input logic ready_o +); + +localparam int unsigned S_NUM = ((REG_SIZE + RADIX - 1) / RADIX) + 1; +localparam int unsigned FULL_REG_SIZE = S_NUM * RADIX; + +localparam PE_UNITS = ((S_NUM - 1) / 2) - 1; + +localparam [(FULL_REG_SIZE-REG_SIZE)-1 : 0] fv_zero_pad = '0; + +localparam prime_p = 384'hfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff; +localparam prime_q = 384'hffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973; +localparam p_mu = 32'h00000001; +localparam q_mu = 32'he88fdc45; +localparam MULT_DLY = 40; +localparam DLY_CONCAT = MULT_DLY - (2*(PE_UNITS+1))-1; //27 + + +///////////////////////////////////////////////// +// Function for selecting o/p // +///////////////////////////////////////////////// +function logic[REG_SIZE-1:0] reduction_prime(input logic [FULL_REG_SIZE-1:0] a, input logic [REG_SIZE-1:0] b); + if(a>=b) + return(a-b); + else + return(a); +endfunction + + +default clocking default_clk @(posedge clk); endclocking + +// constraint that the multiplication is enable and doesn't trigger until the current computation done +property start_mult_as_p; + start_i + |=> + !start_i until (ready_o); +endproperty +start_mult_as: assume property(disable iff(!rst_n)start_mult_as_p); + + +// Reset property +sequence reset_sequence; + !rst_n ##1 rst_n; +endsequence + +property reset_a; + reset_sequence + |-> + p_o == 0 && + ready_o == 1; +endproperty + +reset_p: assert property(reset_a); + + + +// Bit symbolics used for proof convergence, these define the bit to be checked in proof +logic [8:0] fv_bit_idx_p; +logic [8:0] fv_bit_idx_q; +idx_384_p_assump: assume property(disable iff(!rst_n) fv_bit_idx_p < 384); +idx_384_q_assump: assume property(disable iff(!rst_n) fv_bit_idx_q < 384); + + + +////////////////////////////////////////////////// +// Once the start triggers then after a delay of 28 cycles i.e DLY_CONCAT because to push the whole +// operand a sequentially would require 26 cycles and 2 extra cycles for valid computation to receive on first box +// from next cycle on as each block of PE works parallely on 2 RADIX elements, next computed value is again on first_box +// later the sequence continues until the last block i.e the carry bits are stored and then reduced by prime +// + +property compare_p(prime,idx); +logic [REG_SIZE-1:0] fv_result; +logic [FULL_REG_SIZE-1:0] fv_reg; + ##0 n_i == prime + ##0 start_i + ##DLY_CONCAT + ##0 (1'b1, fv_reg[RADIX-1:0] = (ecc_montgomerymultiplier.gen_PE[0].box_i.s_out)) + ##1 (1'b1, fv_reg[2*RADIX-1:RADIX] = (ecc_montgomerymultiplier.gen_PE[0].box_i.s_out)) + ##1 (1'b1, fv_reg[3*RADIX-1:2*RADIX] = (ecc_montgomerymultiplier.gen_PE[1].box_i.s_out)) + ##1 (1'b1, fv_reg[4*RADIX-1:3*RADIX] = (ecc_montgomerymultiplier.gen_PE[1].box_i.s_out)) + ##1 (1'b1, fv_reg[5*RADIX-1:4*RADIX] = (ecc_montgomerymultiplier.gen_PE[2].box_i.s_out)) + ##1 (1'b1, fv_reg[6*RADIX-1:5*RADIX] = (ecc_montgomerymultiplier.gen_PE[2].box_i.s_out)) + ##1 (1'b1, fv_reg[7*RADIX-1:6*RADIX] = (ecc_montgomerymultiplier.gen_PE[3].box_i.s_out)) + ##1 (1'b1, fv_reg[8*RADIX-1:7*RADIX] = (ecc_montgomerymultiplier.gen_PE[3].box_i.s_out)) + ##1 (1'b1, fv_reg[9*RADIX-1:8*RADIX] = (ecc_montgomerymultiplier.gen_PE[4].box_i.s_out)) + ##1 (1'b1, fv_reg[10*RADIX-1:9*RADIX] = (ecc_montgomerymultiplier.gen_PE[4].box_i.s_out)) + ##1 (1'b1, fv_reg[11*RADIX-1:10*RADIX] = (ecc_montgomerymultiplier.final_box.s_out)) + ##1 (1'b1, fv_reg[12*RADIX-1:11*RADIX] = (ecc_montgomerymultiplier.final_box.s_out)) + ##0 (1'b1, fv_reg[13*RADIX-1:12*RADIX] = (ecc_montgomerymultiplier.final_box.c_out[RADIX-1:0])) + ##0 (1'b1, fv_result = reduction_prime(fv_reg, prime)) + |=> + ##1 + ready_o && + p_o[idx] == fv_result[idx]; +endproperty +compare_concat_prime_p_a : assert property ( disable iff(!rst_n) compare_p(prime_p,fv_bit_idx_p)); +compare_concat_prime_q_a : assert property ( disable iff(!rst_n) compare_p(prime_q,fv_bit_idx_q)); + + + +//a_reg shifts by RADIX, when odd and no start + +property when_odd_a_array_shifts_p; + ecc_montgomerymultiplier.odd && + !start_i + |=> + ecc_montgomerymultiplier.a_array[0] == RADIX'($past(ecc_montgomerymultiplier.a_reg)>>RADIX) && + ecc_montgomerymultiplier.a_reg == ($past(ecc_montgomerymultiplier.a_reg)>>RADIX); +endproperty +when_odd_a_array_shifts_a : assert property ( disable iff(!rst_n) when_odd_a_array_shifts_p); + +// a_reg stable if no odd +property when_even_a_array_stable_p; + !ecc_montgomerymultiplier.odd && + !start_i + |=> + ecc_montgomerymultiplier.a_array[0] == $past(ecc_montgomerymultiplier.a_array[0]) && + ecc_montgomerymultiplier.a_reg == $past(ecc_montgomerymultiplier.a_reg); +endproperty +when_even_a_array_stable_a : assert property ( disable iff(!rst_n) when_even_a_array_stable_p); + + + +// reg's set once start is triggered + + property reg_set_start_p; + start_i + |=> + ecc_montgomerymultiplier.a_reg == {fv_zero_pad, $past(opa_i)} && + ecc_montgomerymultiplier.b_reg == {fv_zero_pad, $past(opb_i)} && + ecc_montgomerymultiplier.p_reg == {fv_zero_pad, $past(n_i)} && + ecc_montgomerymultiplier.n_prime_reg == $past(n_prime_i); + endproperty + reg_set_start_a : assert property ( disable iff(!rst_n) reg_set_start_p); + +// reg's stay stable if no start cmd + property reg_no_start_p; + !start_i + |=> + ecc_montgomerymultiplier.b_reg == $past(ecc_montgomerymultiplier.b_reg) && + ecc_montgomerymultiplier.p_reg == $past(ecc_montgomerymultiplier.p_reg) && + ecc_montgomerymultiplier.n_prime_reg == $past(ecc_montgomerymultiplier.n_prime_reg); + endproperty + reg_no_start_a : assert property ( disable iff(!rst_n) reg_no_start_p); + + +//b_array and p_array in 64bit takes MSB 32 if odd if not LSB 32 + + property when_odd_b_p_array_p(idx); + ecc_montgomerymultiplier.odd + |-> + ecc_montgomerymultiplier.b_array[idx] == ecc_montgomerymultiplier.b_reg[(((2*idx)+1)*RADIX)-1 : (2*idx)*RADIX] && + ecc_montgomerymultiplier.p_array[idx] == ecc_montgomerymultiplier.p_reg[(((2*idx)+1)*RADIX)-1 : (2*idx)*RADIX]; + endproperty + + //b_array and p_array are 64bits takes LSB 32 if even from b_reg and p_reg + property when_even_b_p_array_p(idx); + !ecc_montgomerymultiplier.odd + |-> + ecc_montgomerymultiplier.b_array[idx] == ecc_montgomerymultiplier.b_reg[((2*idx)*RADIX)-1 : ((2*idx)-1)*RADIX] && + ecc_montgomerymultiplier.p_array[idx] == ecc_montgomerymultiplier.p_reg[((2*idx)*RADIX)-1 : ((2*idx)-1)*RADIX]; + endproperty + + for (genvar i=1; i < (PE_UNITS+2); i++) begin + when_odd_b_p_array_a : assert property ( disable iff(!rst_n) when_odd_b_p_array_p(i)); + when_even_b_p_array_a : assert property ( disable iff(!rst_n) when_even_b_p_array_p(i)); + end + + + // connections for the s_in's of the pe blocks + property s_in_routing_p; + ecc_montgomerymultiplier.gen_PE[0].box_i.s_in == ecc_montgomerymultiplier.gen_PE[1].box_i.s_out; + endproperty + //for (genvar i=0; i < (PE_UNITS); i++) begin + s_in_routing_a: assert property (disable iff(!rst_n) s_in_routing_p); + //end + + + // connections for the a_in's of the pe blocks + property a_in_routing_p; + ecc_montgomerymultiplier.gen_PE[0].box_i.a_in == ecc_montgomerymultiplier.first_box.a_out; + endproperty + + a_in_routing_a: assert property (disable iff(!rst_n) a_in_routing_p); + + + // connections for the m_in's,c_in's of the pe blocks + property m_c_in_routing_p; + ecc_montgomerymultiplier.gen_PE[0].box_i.m_in == ecc_montgomerymultiplier.first_box.m_out && + ecc_montgomerymultiplier.gen_PE[0].box_i.c_in == ecc_montgomerymultiplier.first_box.c_out; + + endproperty + m_c_in_routing_a: assert property (disable iff(!rst_n) m_c_in_routing_p); + + +endmodule + +bind ecc_montgomerymultiplier fv_montmultiplier_glue #( + .REG_SIZE(REG_SIZE), + .RADIX(RADIX) + ) + fv_montmultiplier_glue_inst ( + // Clock and reset. + .clk(clk), + .rst_n(reset_n && !zeroize), + + // DATA PORT + .start_i(start_i), + .opa_i(opa_i), + .opb_i(opb_i), + .n_i(n_i), + .n_prime_i(n_prime_i), // only need the last few bits + .p_o(p_o), + .ready_o(ready_o) + ); + diff --git a/src/ecc/formal/properties/fv_pe.sv b/src/ecc/formal/properties/fv_pe.sv new file mode 100644 index 000000000..9b9acbe78 --- /dev/null +++ b/src/ecc/formal/properties/fv_pe.sv @@ -0,0 +1,218 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_pe #( + parameter RADIX = 32 +) +( + // Clock and reset. + input logic clk, + input logic rst_n, + + input logic start_in, + input logic [RADIX-1:0] a_in, + input logic [RADIX-1:0] b_in, + input logic [RADIX-1:0] p_in, + input logic [RADIX-1:0] m_in, + input logic [RADIX-1:0] s_in, + input logic [RADIX :0] c_in, + input logic odd, + + input logic [RADIX-1:0] a_out, + input logic [RADIX-1:0] m_out, + input logic [RADIX-1:0] s_out, + input logic [RADIX :0] c_out +); + + + +function logic [2*RADIX :0] add_func( input logic [RADIX-1:0] a_in, + input logic [RADIX-1:0] b_in, + input logic [RADIX-1:0] p_in, + input logic [RADIX-1:0] m_in, + input logic [RADIX :0] c_in, + input logic [RADIX-1:0] s_in + ); + + return((a_in*b_in)+(p_in*m_in)+c_in+s_in); +endfunction + + + +default clocking default_clk @(posedge clk); endclocking + +//////////////////////////////////////////////////// +// reset or start_in // +//////////////////////////////////////////////////// + +sequence reset_sequence; + !rst_n || start_in ##1 rst_n; +endsequence + + +property reset_p; +$past(!rst_n || start_in) +|-> +m_out == 0 && +a_out == 0 && +s_out == 0 && +c_out == 0; +endproperty + +reset_a : assert property(reset_p); + + +//////////////////////////////////////////////////// +// aout when odd takes the previous value of ain // +//////////////////////////////////////////////////// + +property aout_p; + odd && + !start_in + |=> + a_out == $past(a_in); +endproperty + +aout_a : assert property(disable iff(!rst_n)aout_p); + + +//////////////////////////////////////////////////// +// mout when odd takes the previous value of min // +//////////////////////////////////////////////////// + +property mout_p; + odd && + !start_in + |=> + m_out == $past(m_in); +endproperty + +mout_a : assert property(disable iff(!rst_n) mout_p); + + + +//////////////////////////////////////////////////////// +// aout when even takes the previous value of itself // +//////////////////////////////////////////////////////// +property aout_even_p; + !odd && + !start_in + |=> + a_out == $past(a_out); +endproperty + +aout_even_a : assert property(disable iff(!rst_n)aout_even_p); + + + +//////////////////////////////////////////////////////// +// mout when even takes the previous value of itself // +//////////////////////////////////////////////////////// +property mout_even_p; + !odd && + !start_in + |=> + m_out == $past(m_out); +endproperty + +mout_even_a : assert property(disable iff(!rst_n) mout_even_p); + + + +//////////////////////////////////////////////////////////// +// sout when odd LSB (a_in*b_in)+(p_in*m_in)+c_out+s_in // +//////////////////////////////////////////////////////////// +property sout_odd_p; +logic [2*RADIX :0] temp; + odd && + !start_in + ##0 (1'b1, temp = add_func(a_in,b_in,p_in,m_in,c_out,s_in)) + |=> + s_out == temp[RADIX-1:0]; +endproperty + +sout_odd_a : assert property(disable iff(!rst_n) sout_odd_p); + + + +/////////////////////////////////////////////////////////// +// sout when even LSB a_in*b_in)+(p_in*m_in)+c_in+s_out // +/////////////////////////////////////////////////////////// +property sout_even_p; +logic [2*RADIX :0] temp; + !odd && + !start_in + ##0 (1'b1, temp = add_func(a_in,b_in,p_in,m_in,c_in,s_out)) + |=> + s_out == temp[RADIX-1:0]; +endproperty + +sout_even_a : assert property(disable iff(!rst_n) sout_even_p); + + +//////////////////////////////////////////////////////////// +// cout when odd MSB (a_in*b_in)+(p_in*m_in)+c_out+s_in // +//////////////////////////////////////////////////////////// +property cout_odd_p; +logic [2*RADIX :0] temp; + odd && + !start_in + ##0 (1'b1, temp = add_func(a_in,b_in,p_in,m_in,c_out,s_in)) + |=> + c_out == temp[2*RADIX:RADIX]; +endproperty + +cout_odd_a : assert property(disable iff(!rst_n) cout_odd_p); + + + +/////////////////////////////////////////////////////////// +// cout when even MSB a_in*b_in)+(p_in*m_in)+c_in+s_out // +/////////////////////////////////////////////////////////// +property cout_even_p; +logic [2*RADIX :0] temp; + !odd && + !start_in + ##0 (1'b1, temp = add_func(a_in,b_in,p_in,m_in,c_in,s_out)) + |=> + c_out == temp[2*RADIX:RADIX]; +endproperty + +cout_even_a : assert property(disable iff(!rst_n) cout_even_p); + + + +endmodule + +bind ecc_pe fv_pe #(.RADIX(RADIX))fv_pe_inst( + .clk(clk), + .rst_n(reset_n && !zeroize), + + .start_in(start_in), + .a_in(a_in), + .b_in(b_in), + .p_in(p_in), + .m_in(m_in), + .s_in(s_in), + .c_in(c_in), + .odd(odd), + .a_out(a_out), + .m_out(m_out), + .s_out(s_out), + .c_out(c_out) + ); \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_pe_final.sv b/src/ecc/formal/properties/fv_pe_final.sv new file mode 100644 index 000000000..7e739e310 --- /dev/null +++ b/src/ecc/formal/properties/fv_pe_final.sv @@ -0,0 +1,126 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_pe_final #( + parameter RADIX = 32 +) ( + input logic clk, + input logic rst_n, + + input logic start_in, + // DATA PORT + input logic [RADIX-1:0] a_in, + input logic [RADIX-1:0] b_in, + input logic [RADIX-1:0] p_in, + input logic [RADIX-1:0] m_in, + input logic [RADIX-1:0] s_in, + input logic [RADIX :0] c_in, + input logic odd, + + input logic [RADIX-1:0] s_out, + input logic [RADIX :0] c_out +); + +default clocking default_clk @(posedge clk); endclocking + + +sequence reset_sequence; + !rst_n || start_in ##1 rst_n; +endsequence + +property reset_p; +$past(!rst_n || start_in) +|-> +s_out == 0 && +c_out == 0; +endproperty + +reset_a : assert property (reset_p); + + + +property s_out_odd_p; + odd && + !start_in + |=> + s_out == $past(32'(64'(a_in * b_in) + 64'(p_in * m_in)+ c_out + s_in)); +endproperty + +s_out_odd_a : assert property (disable iff(!rst_n) s_out_odd_p); + + + + +property s_out_noodd_p; + + !odd && + !start_in + |=> + s_out == $past(32'(64'(a_in * b_in) + 64'(p_in * m_in)+ c_in + s_out)); +endproperty + +s_out_noodd_a : assert property (disable iff(!rst_n) s_out_noodd_p); + + + + +property c_out_odd_p; +logic [2*RADIX : 0] temp; + odd && + !start_in + ##0 (1'b1, temp = (64'(a_in * b_in) + 64'(p_in * m_in)+ c_out + s_in)) + |=> + //c_out == $past(33'((64'(a_in * b_in) + 64'(p_in * m_in)+ c_out + s_in)>>32)); + c_out == temp[2*RADIX:RADIX]; +endproperty + +c_out_odd_a : assert property (disable iff(!rst_n) c_out_odd_p); + + + + +property c_out_noodd_p; +logic [2*RADIX : 0] temp; + !odd && + !start_in + ##0 (1'b1, temp = (64'(a_in * b_in) + 64'(p_in * m_in)+ c_in + s_out)) + |=> + //c_out == $past(33'((64'(a_in * b_in) + 64'(p_in * m_in)+ c_in + s_out)>>32)); + c_out == temp[2*RADIX:RADIX]; +endproperty + +c_out_noodd_a : assert property (disable iff(!rst_n) c_out_noodd_p); + +endmodule + +bind ecc_pe_final fv_pe_final #(.RADIX(RADIX)) fv_pe_final_inst( + .clk(clk), + .rst_n(reset_n && !zeroize), + + .start_in(start_in), + .a_in(a_in), + .b_in(b_in), + .p_in(p_in), + .m_in(m_in), + .s_in(s_in), + .c_in(c_in), + .odd(odd), + + .s_out(s_out), + .c_out(c_out) + ); diff --git a/src/ecc/formal/properties/fv_pe_first.sv b/src/ecc/formal/properties/fv_pe_first.sv new file mode 100644 index 000000000..7fd0b5c1a --- /dev/null +++ b/src/ecc/formal/properties/fv_pe_first.sv @@ -0,0 +1,275 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_pe_first #( + parameter RADIX = 32 +) +( + // Clock and reset. + input logic clk, + input logic rst_n, + + input logic start_in, + input logic [RADIX-1:0] a_in, + input logic [RADIX-1:0] b_in, + input logic [RADIX-1:0] p_in, + input logic [RADIX-1:0] s_in, + input wire [RADIX-1:0] n_prime_in, + input logic odd, + + input logic [RADIX-1:0] a_out, + input logic [RADIX-1:0] m_out, + input logic [RADIX :0] c_out +); + + + +default clocking default_clk @(posedge clk); endclocking + + +////////////////////////////////////////// +// m_out_func where it depends on // +// (s_in+(a_in*b_in)_lsw)*n_prme_in // +////////////////////////////////////////// + +function logic[RADIX-1:0] m_out_func (input logic [RADIX-1:0] a,input logic [RADIX-1:0] b, +input logic [RADIX-1:0] c,input logic [RADIX-1:0] d); + logic [RADIX-1:0] mult_lsw; + mult_lsw = b*c; + mult_lsw = (a+mult_lsw)*d; + return (mult_lsw); +endfunction + + +///////////////////////////////////////////// +// c_out_func where it depends on // +// previous sum(s0), carry(c0) multiplied // +// with p_in and added(res=m_temp*pin_lsw // +// carry = msw + res[maxbit] + previous(c0)// +///////////////////////////////////////////// + +function logic[RADIX:0] c_out_func (input logic [RADIX-1:0] a,input logic [RADIX-1:0] b, +input logic [RADIX:0] c, input logic [RADIX-1:0] d); + + logic[(2*RADIX)-1:0] mult; + logic [RADIX:0] res; + logic [RADIX:0] c1; + mult = a * b; + res = d + mult[RADIX-1:0]; + c1 = mult[(2*RADIX)-1:RADIX] + res[RADIX]; + +return(c1+c); + +endfunction + +/////////////////////////////////////////////// +// c_0 func used for calculating the previous// +// carry used in c_out computation // +/////////////////////////////////////////////// + +function logic[RADIX:0] c_0 (input logic [RADIX-1:0] a,input logic [RADIX-1:0] b, +input logic [RADIX-1:0] c); + logic[(2*RADIX)-1:0] mult_0; + logic [RADIX:0] res_0; + mult_0 = b*c; + res_0 = a + mult_0[RADIX-1:0]; + return (mult_0[(2*RADIX)-1:RADIX]+res_0[RADIX]); +endfunction + + +/////////////////////////////////////////////// +// m_temp_reg func used for calculating the // +// previous m_out in c_out computation // +/////////////////////////////////////////////// + +function logic[RADIX-1:0] m_temp_reg (input logic [RADIX-1:0] a,input logic [RADIX-1:0] b, +input logic [RADIX-1:0] c,input logic [RADIX-1:0] d); + logic [RADIX:0] res_0; + + res_0 = s_0(a,b,c); + return ((res_0[RADIX-1:0])*d); +endfunction + + + +/////////////////////////////////////////////// +// s_0 func used for calculating the previous// +// sum used in c_out computation // +/////////////////////////////////////////////// +function logic[RADIX-1:0] s_0 (input logic [RADIX-1:0] a,input logic [RADIX-1:0] b, +input logic [RADIX-1:0] c ); + logic[(2*RADIX)-1:0] mult_0; + logic [RADIX:0] res_0; + mult_0 = b*c; + res_0 = a + mult_0[RADIX-1:0]; + return ((res_0[RADIX-1:0])); +endfunction + + + +sequence reset_sequence; + !rst_n || start_in ##1 rst_n; +endsequence + +////////////////////////////////////////// +// When in reset carry and the sum, // +// array a are zero // +////////////////////////////////////////// + +property reset_p; +$past(!rst_n || start_in) +|-> +m_out == 0 && +a_out == 0 && +c_out == 0; +endproperty + +reset_a : assert property(reset_p); + + + +////////////////////////////////////////// +// When its odd and no start then // +// a out takes the previous a_in value // +////////////////////////////////////////// +property aout_p; + odd && + !start_in + |=> + a_out == $past(a_in); +endproperty + +aout_a : assert property(disable iff(!rst_n)aout_p); + + +////////////////////////////////////////// +// When its odd and no start then // +// m out takes the computed value // +////////////////////////////////////////// + +property mout_p; + odd && + !start_in + |=> + m_out == $past(m_out_func(s_in,a_in,b_in,n_prime_in)); +endproperty + +mout_a : assert property(disable iff(!rst_n) mout_p); + + +//////////////////////////////////////////////// +// When its even and no start then // +// a out takes the 2cyc previous a_in value // +//////////////////////////////////////////////// +property aout_even_p; + !start_in +##1 + !odd && + !start_in + |=> + a_out == $past(a_in,2); +endproperty + +aout_even_a : assert property(disable iff(!rst_n)aout_even_p); + + +////////////////////////////////////////// +// When its even and no start then // +// mout takes the previous mout value // +////////////////////////////////////////// +property mout_even_p; + !start_in + ##1 + !odd && + !start_in + |=> + m_out == $past(m_out_func($past(s_in),$past(a_in),b_in,n_prime_in),1); +endproperty + +mout_even_a : assert property(disable iff(!rst_n) mout_even_p); + + + +////////////////////////////////////////// +// When its odd and no start then // +// cout takes the computed value // +// from previous carry sum and computed m // +////////////////////////////////////////// +property cout_odd_p; +logic [RADIX :0] c0; +logic [RADIX-1:0] m_temp; +logic [RADIX-1:0] s0; + + odd && + !start_in + ##0 (1'b1, c0 = c_0(s_in,a_in,b_in)) + ##0 (1'b1, s0 = s_0(s_in,a_in,b_in)) + ##0 (1'b1, m_temp = m_temp_reg(s_in,a_in,b_in,n_prime_in)) + |=> + c_out == c_out_func(m_temp,p_in,c0,s0); +endproperty + +cout_odd_a : assert property(disable iff(!rst_n) cout_odd_p); + + + + +///////////////////////////////////////////// +// When its even and no start then // +// cout takes the computed value // +// from previous carry sum and computed m // +///////////////////////////////////////////// +property cout_even_p; +logic [RADIX :0] c0; +logic [RADIX-1:0] m_temp; +logic [RADIX-1:0] s0; + !start_in + ##1 + !odd && + !start_in + ##0 (1'b1, c0 = c_0($past(s_in),$past(a_in),b_in)) + ##0 (1'b1, s0 = s_0($past(s_in),$past(a_in),b_in)) + ##0 (1'b1, m_temp = m_temp_reg($past(s_in),$past(a_in),b_in,n_prime_in)) + |=> + c_out == c_out_func(m_temp,p_in,c0,s0); + +endproperty + +cout_even_a : assert property(disable iff(!rst_n) cout_even_p); + + + +endmodule + +bind ecc_pe_first fv_pe_first #(.RADIX(RADIX)) fv_pe_inst( + .clk(clk), + .rst_n(reset_n && !zeroize), + + .start_in(start_in), + .a_in(a_in), + .b_in(b_in), + .p_in(p_in), + .s_in(s_in), + .n_prime_in(n_prime_in), + + .odd(odd), + .a_out(a_out), + .m_out(m_out), + + .c_out(c_out) + ); \ No newline at end of file diff --git a/src/ecc/formal/properties/fv_scalar_blinding.sv b/src/ecc/formal/properties/fv_scalar_blinding.sv new file mode 100644 index 000000000..389f41d14 --- /dev/null +++ b/src/ecc/formal/properties/fv_scalar_blinding.sv @@ -0,0 +1,140 @@ + +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_scalar_blind_m #( + parameter REG_SIZE = 384, + parameter RND_SIZE = 192, + parameter RADIX = 32 +)( + input bit rst_n, + input bit clk, + input bit unsigned [(RND_SIZE-1):0] rnd_i, + input bit unsigned [(REG_SIZE+RND_SIZE-1):0] data_o, + input bit unsigned [(REG_SIZE-1):0] data_i, + input logic [REG_SIZE-1:0] group_order, + input bit en_i, + input bit busy_o, + input bit input_read +); + +localparam SCA_DLY = 110; // The delay for computing the result + + + + +//Helper function for computation +function bit unsigned [(REG_SIZE+RND_SIZE-1):0] randomize(bit unsigned [(REG_SIZE-1):0] scalar, bit unsigned [(RND_SIZE-1):0] random, bit unsigned [REG_SIZE-1:0] grp_order); + return (REG_SIZE+RND_SIZE)'((scalar + (REG_SIZE+RND_SIZE)'(random * grp_order))); +endfunction + +default clocking default_clk @(posedge clk); endclocking + +sequence reset_sequence; + !rst_n ##1 rst_n; +endsequence + +//no enable until the busy stays deasserted +assume_enb: assume property (disable iff(!rst_n) + en_i + |=> + !en_i until_with (!busy_o) //check: no strong as it deasserts busy_o + ); + +//Input data is always less than group order +assume_scalr_less_group_order: assume property (disable iff(!rst_n) + data_i < group_order +); + + + + +//when reset busy_o and data_o is zero +reset_a: assert property (reset_p); +property reset_p; + $past(!rst_n) |-> + input_read && + data_o == '0 && + busy_o == 0 +;endproperty + + +//If not busy and en is set then the computation is carried out +input_read_to_input_read_a: assert property (disable iff(!rst_n) input_read_to_input_read_p); +property input_read_to_input_read_p; + logic [(REG_SIZE-1):0] scalar_store; + logic [(RND_SIZE-1):0] random_store; + logic [(REG_SIZE+RND_SIZE-1):0] temp; + + input_read && + en_i + ##0 (1'b1, scalar_store = data_i) + ##0 (1'b1, random_store = rnd_i) + ##0 (1'b1, temp = randomize(data_i,rnd_i,group_order)) +|-> + ##1 busy_o[*SCA_DLY] + ##1 (input_read && + data_o == temp && + busy_o == 0) +;endproperty + + + +// If not busy and not enabled then it stays in not busy +input_read_wait_a: assert property (disable iff(!rst_n) input_read_wait_p); +property input_read_wait_p; + input_read && + !en_i +|-> + ##1 + input_read && + busy_o == 0 +;endproperty + + +//If not busy and enabled then busy is set +input_read_next_a: assert property (disable iff(!rst_n) input_read_next_p); +property input_read_next_p; + input_read && + en_i +|-> + ##1 + !input_read && + busy_o == 1 +;endproperty + +endmodule + + + +bind ecc_scalar_blinding fv_scalar_blind_m #( + .REG_SIZE(REG_SIZE), + .RND_SIZE(RND_SIZE), + .RADIX(RADIX) + )fv_scalar_blind( + .rst_n(ecc_scalar_blinding.reset_n && !ecc_scalar_blinding.zeroize), + .clk(ecc_scalar_blinding.clk), + .rnd_i(ecc_scalar_blinding.rnd_i), + .data_o(ecc_scalar_blinding.data_o), + .data_i(ecc_scalar_blinding.data_i), + .en_i(ecc_scalar_blinding.en_i), + .busy_o(ecc_scalar_blinding.busy_o), + .input_read(!ecc_scalar_blinding.busy_o), + .group_order(ecc_scalar_blinding.GROUP_ORDER) + +); diff --git a/src/ecc/formal/readme.md b/src/ecc/formal/readme.md new file mode 100644 index 000000000..cdba90718 --- /dev/null +++ b/src/ecc/formal/readme.md @@ -0,0 +1,80 @@ +# Reproduce results + +**MACROS :** +TOP + +- Used for the submodules fv_ecc_fau.sv and fv_scalar_blinding.sv and in fv_ecc_dsa_ctrl_constraints.sv. + +- Use this macro or define this macro only when loading the design the with ecc_dsa_ctrl as top module. + +FOR48 + +- This macro is used for fv_montmultiplier.sv as the montgomery multiplier shorter version end-to-end checkers. Due to the restriction of the formal tool overmultiplication this file is used for only reduced version of the design. Further details are in the ECC_block_overview. + +## Proving the submodules + +- Load submodule as top in the formal tool. + +- Load the checker files along with the constraints and respective packages in the formal tool. + +- Run the properties. + +## Proving the top + +- Load all design files in the formal tool and set ecc_dsa_ctrl as top module, disable the proofs as mentioned in the sheet which are not for the top. + +- Load all the checker files with respective macro defined along with the constraints and respective packages in the formal tool. + +- Copy all the submodule assertions and assumptions and enable if they were disabled into seperate task and cut the signals from the top that affect the submodule verification. + + If the following modules are chossen as a task then the respective signals need to be cut. + + + # ecc_add_sub_mod_alter + + - cut the signals add_en_i, sub_i + + # ecc_pm_sequencer + + - cut the signal addra + + # ecc_dsa_sequencer + + - cut the signal addra + + # ecc_pm_sequencer + + - cut the signal addra + + # ecc_ram_tdp_file + + - cut the signals wea,web,ena,enb + + # ecc_pm_ctrl + + - cut the signal ecc_cmd_i + + # ecc_hmac_drbg_interface + + - cut the signal counter_nonce, keygen_sign, hmac_drbg_i.drbg, hmac_drbg_i.ready,hmac_drbg_i.valid, internal signal counter_nonce. Constraints do the work by reducing the timing. + + # hmac_drbg + + - cut the signals init_cmd,next_cmd,nonce, entropy,u_sha512_core_h1.digest, + u_sha512_core_h2.digest,HMAC_K.tag,hmac_drbg_lfsr.rnd + + # sha512_masked + + - cut the signals init_cmd,next_cmd,mode,block_msg,sha_masked_lfsr.rnd + + # reduced versions + - For montgomerymultiplier, scalar_blinding and ecc_pe_first modules, a reduced + version instantiations are created inside the module ecc_reduced_instatiations, these proofs could be created in a separate task as they are not part of the actual top design and these proofs should be disabled on the top. + +- On the main task, disable all submodule assumptions(convert to assertions) and just keep the assumptions on the ecc_dsa_ctrl module. + +- Run the properties on the main task . + +- Switch the tasks to one of the submodules which consists of the assumptions and assertions of that particular submodule. + +- Run the properties. diff --git a/src/hmac/config/compile.yml b/src/hmac/config/compile.yml index 181ae1ce8..480936e76 100755 --- a/src/hmac/config/compile.yml +++ b/src/hmac/config/compile.yml @@ -19,7 +19,7 @@ targets: rtl_lint: directories: [] waiver_files: - - $COMPILE_ROOT/config/design_lint/hmac_ctrl/sglint_waivers + - $MSFT_REPO_ROOT/src/hmac/config/design_lint/hmac_ctrl/sglint_waivers black_box: - hmac_reg --- diff --git a/src/hmac_drbg/formal/properties/fv_constraints_m.sv b/src/hmac_drbg/formal/properties/fv_constraints_m.sv new file mode 100644 index 000000000..c7c52fd75 --- /dev/null +++ b/src/hmac_drbg/formal/properties/fv_constraints_m.sv @@ -0,0 +1,110 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_constraints_m +#( + parameter time_window = 3) +( + input logic clk, + input logic rst_n, + input logic zeroize, + input logic next, + input logic init, + input logic hmac_valid, + input logic [383:0] hmac_tag +); + + logic fv_init_reg; + + default clocking default_clk @(posedge clk); endclocking + + + always @ (posedge clk or negedge rst_n) + begin + if (!rst_n || zeroize) + fv_init_reg <= 1'h0; + else if (init) + fv_init_reg <= 1'h1; + end + + /////////////////////////// + /// constraints + ////////////////////////// + + + /////////////////////////// + // Assumptions 1 + // input nonce and entropy + // remains stable until + // valid is high + ///// + assume_stable_entropy: assume property(disable iff(!rst_n || zeroize) + ($stable(hmac_drbg.nonce) || hmac_drbg.valid) + ); + + + assume_stable_nonce: assume property(disable iff(!rst_n || zeroize) + ($stable(hmac_drbg.entropy) || hmac_drbg.valid) + ); + + /////////////////////////// + // Assumptions 2 + // hmac_init and hmac_next + // cannot be high at same + // time + ///// + property hmac_init_and_next_not_high_same; + !(init && next); + endproperty + assume_hmac_init_and_next_not_high_same: assume property(disable iff(!rst_n)hmac_init_and_next_not_high_same); + + /////////////////////////// + // Assumptions 3 + // hmac_init should be high + // first then next + ////// + property hmac_first_init_then_next; + !fv_init_reg + |-> + !next; + endproperty + assume_hmac_first_init_then_next : assume property(disable iff(!rst_n) hmac_first_init_then_next); + + /////////////////////////////////// + // Assumptions 4 + // tag remains stable as long + // valid is high + ///// + property sha_digest_stable_when_valid(valid, tag); + valid + |-> + $stable(tag); + endproperty + assume_hmac_digest_stable_when_valid : assume property(@(posedge clk) disable iff(!rst_n || zeroize) sha_digest_stable_when_valid(hmac_valid, hmac_tag)); + + endmodule + + bind hmac_drbg fv_constraints_m fv_constraint ( + .clk (clk ), + .rst_n (reset_n ), + .zeroize (zeroize ), + .init (init_cmd ), + .next (next_cmd ), + .hmac_valid (HMAC_tag_valid ), + .hmac_tag (HMAC_tag ) + ); \ No newline at end of file diff --git a/src/hmac_drbg/formal/properties/fv_cover_points.sv b/src/hmac_drbg/formal/properties/fv_cover_points.sv new file mode 100644 index 000000000..6e0961612 --- /dev/null +++ b/src/hmac_drbg/formal/properties/fv_cover_points.sv @@ -0,0 +1,66 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +module fv_coverpoints_m( + input logic clk, + input logic reset_n, + input logic zeroize +); + + default clocking default_clk @(posedge clk); endclocking + + //Cover zeroize + cover_zeroize: cover property(disable iff(!reset_n) hmac_drbg.zeroize ); + //Assert zeroize input and check the status of all registers. All registers/internal memories should be cleared. + cover_zeroize_after_next: cover property(disable iff(!reset_n ) hmac_drbg.zeroize && hmac_drbg.ready && hmac_drbg.next_cmd ); + + cover_multiple_next: cover property(disable iff(!reset_n || zeroize) + hmac_drbg.next_cmd && hmac_drbg.ready ##1 hmac_drbg.next_cmd && hmac_drbg.ready[->1] + ); + + // Assert init_cmd or next_cmd when HMAC_ready is still low. The engine ignores the new command and continues + // to complete the previous command. + cover_init_and_next_ready_low: cover property(disable iff(!reset_n || zeroize) + (hmac_drbg.init_cmd || + hmac_drbg.next_cmd) && + !hmac_drbg.ready + ); + + //Cover transition from T to "done" and "k3" state + cover_transition_T_to_DONE: cover property (disable iff(!reset_n || zeroize) + hmac_drbg.T_ST + ##1 + !((hmac_drbg.HMAC_tag == 384'd0) || (hmac_drbg.HMAC_DRBG_PRIME <= hmac_drbg.HMAC_tag)) + ##1 + hmac_drbg.DONE_ST + ); + + cover_transition_T_to_K3: cover property (disable iff(!reset_n || zeroize) + hmac_drbg.T_ST + ##1 + ((hmac_drbg.HMAC_tag == 384'd0) || (hmac_drbg.HMAC_DRBG_PRIME <= hmac_drbg.HMAC_tag)) + ##1 + hmac_drbg.K3_ST + ); + +endmodule +bind hmac_drbg fv_coverpoints_m fv_coverpoints( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize) +); \ No newline at end of file diff --git a/src/hmac_drbg/formal/properties/fv_hmac_drbg.sv b/src/hmac_drbg/formal/properties/fv_hmac_drbg.sv new file mode 100644 index 000000000..8e0d30e5b --- /dev/null +++ b/src/hmac_drbg/formal/properties/fv_hmac_drbg.sv @@ -0,0 +1,586 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import hmac_drbg_pkg::*; + + +module fv_hmac_drbg_m( + input bit rst, + input bit clk, + + // Inputs + input bit unsigned [383:0] hmac_tag, + input st_drbg_block input_data, + + // Outputs + input bit unsigned [383:0] drbg, + input st_hmac_block hmac_msg, + + // Sync signals + input bit hmac_tag_valid, + input bit input_data_valid, + + // Notify signals + input bit drbg_valid, + input bit input_data_ready, + + // Registers + input bit unsigned [7:0] cnt, + input st_hmac_block hmac, + input st_drbg_block in_data, + input bit unsigned [383:0] key_reg, + input bit unsigned [383:0] tag_temp, + input bit unsigned [383:0] v_reg, + + // States + input bit idle, + input bit K10, + input bit K11, + input bit V1, + input bit K20, + input bit K21, + input bit V2, + input bit T, + input bit Done, + input bit K3, + input bit V3 +); + + +default clocking default_clk @(posedge clk); endclocking + + +st_hmac_block hmac_0 = '{ + key: 384'd0, + block_msg: 1024'd0, + init: 0, + next: 0 +}; + +st_drbg_block in_data_0 = '{ + entropy: 384'd0, + nonce: 384'd0, + init: 0, + next: 0 +}; + +st_hmac_block hmac_1 = '{ + key: K_INIT, + block_msg: k10_func(V_INIT, 8'd0, input_data.entropy, input_data.nonce), + init: 1, + next: 0 +}; + +st_hmac_block hmac_2 = '{ + key: key_reg, + block_msg: k10_func(v_reg, 8'((cnt + 8'd1)), input_data.entropy, input_data.nonce), + init: 1, + next: 0 +}; + +st_hmac_block hmac_3 = '{ + key: key_reg, + block_msg: k11_func(in_data.nonce), + init: 0, + next: 1 +}; + +st_hmac_block hmac_4 = '{ + key: hmac_tag, + block_msg: v1_func(v_reg), + init: 1, + next: 0 +}; + +st_hmac_block hmac_5 = '{ + key: key_reg, + block_msg: k10_func(hmac_tag, 8'((cnt + 8'd1)), in_data.entropy, in_data.nonce), + init: 1, + next: 0 +}; + +st_hmac_block hmac_6 = '{ + key: key_reg, + block_msg: v1_func(hmac_tag), + init: 1, + next: 0 +}; + +st_hmac_block hmac_7 = '{ + key: key_reg, + block_msg: 1024'd0, + init: 0, + next: 0 +}; + +st_hmac_block hmac_8 = '{ + key: key_reg, + block_msg: k3_func(v_reg), + init: 1, + next: 0 +}; + +st_hmac_block hmac_9 = '{ + key: key_reg, + block_msg: hmac.block_msg, + init: hmac.init, + next: hmac.next +}; + + +sequence reset_sequence; + rst ##1 !rst; +endsequence + + +reset_a: assert property (reset_p); +property reset_p; + reset_sequence |-> + idle && + cnt == 8'd0 && + hmac_msg == hmac_0 && + key_reg == 384'd0 && + v_reg == 384'd0 && + drbg_valid == 0 && + input_data_ready == 0; +endproperty + + +Done_to_idle_a: assert property (disable iff(rst) Done_to_idle_p); +property Done_to_idle_p; + Done +|-> + ##1 + idle && + cnt == $past(cnt, 1) && + drbg == $past(tag_temp, 1) && + hmac_msg == $past(hmac_msg, 1) && + key_reg == $past(key_reg, 1) && + v_reg == $past(tag_temp, 1) && + drbg_valid == 1 && + input_data_ready == 0; +endproperty + + +K10_to_K11_a: assert property (disable iff(rst) K10_to_K11_p); +property K10_to_K11_p; + K10 && + hmac_tag_valid +|-> + ##1 (drbg_valid == 0)[*2] and + ##1 (input_data_ready == 0)[*2] and + ##2 + K11 && + cnt == $past(cnt, 2) && + hmac_msg == $past(hmac_3, 2) && + key_reg == $past(key_reg, 2) && + v_reg == $past(v_reg, 2); +endproperty + + +K11_to_V1_a: assert property (disable iff(rst) K11_to_V1_p); +property K11_to_V1_p; + K11 && + hmac_tag_valid +|-> + ##1 (drbg_valid == 0)[*2] and + ##1 (input_data_ready == 0)[*2] and + ##2 + V1 && + cnt == $past(cnt, 2) && + hmac_msg == $past(hmac_4, 2) && + key_reg == $past(hmac_tag, 2) && + v_reg == $past(v_reg, 2); +endproperty + + +K20_to_K21_a: assert property (disable iff(rst) K20_to_K21_p); +property K20_to_K21_p; + K20 && + hmac_tag_valid +|-> + ##1 (drbg_valid == 0)[*2] and + ##1 (input_data_ready == 0)[*2] and + ##2 + K21 && + cnt == $past(cnt, 2) && + hmac_msg == $past(hmac_3, 2) && + key_reg == $past(key_reg, 2) && + v_reg == $past(v_reg, 2); +endproperty + + +K21_to_V2_a: assert property (disable iff(rst) K21_to_V2_p); +property K21_to_V2_p; + K21 && + hmac_tag_valid +|-> + ##1 (drbg_valid == 0)[*2] and + ##1 (input_data_ready == 0)[*2] and + ##2 + V2 && + cnt == $past(cnt, 2) && + hmac_msg == $past(hmac_4, 2) && + key_reg == $past(hmac_tag, 2) && + v_reg == $past(v_reg, 2); +endproperty + + +K3_to_V3_a: assert property (disable iff(rst) K3_to_V3_p); +property K3_to_V3_p; + K3 && + hmac_tag_valid +|-> + ##1 (drbg_valid == 0)[*2] and + ##1 (input_data_ready == 0)[*2] and + ##2 + V3 && + cnt == $past(cnt, 2) && + hmac_msg == $past(hmac_4, 2) && + key_reg == $past(hmac_tag, 2) && + v_reg == $past(v_reg, 2); +endproperty + + +T_to_Done_a: assert property (disable iff(rst) T_to_Done_p); +property T_to_Done_p; + T && + hmac_tag_valid && + (hmac_tag != 384'd0) && + (HMAC_DRBG_PRIME > hmac_tag) +|-> + ##1 (drbg_valid == 0)[*2] and + ##1 (input_data_ready == 0)[*2] and + ##2 + Done && + cnt == $past(cnt, 2) && + hmac_msg == $past(hmac_7, 2) && + key_reg == $past(key_reg, 2) && + v_reg == $past(v_reg, 2); +endproperty + + +T_to_K3_a: assert property (disable iff(rst) T_to_K3_p); +property T_to_K3_p; + T && + hmac_tag_valid && + ((hmac_tag == 384'd0) || (HMAC_DRBG_PRIME <= hmac_tag)) +|-> + ##1 (drbg_valid == 0)[*3] and + ##1 (input_data_ready == 0)[*3] and + ##3 + K3 && + cnt == $past(cnt, 3) && + hmac_msg == $past(hmac_8, 3) && + key_reg == $past(key_reg, 3) && + v_reg == $past(v_reg, 3); +endproperty + + +V1_to_K20_a: assert property (disable iff(rst) V1_to_K20_p); +property V1_to_K20_p; + V1 && + hmac_tag_valid +|-> + ##1 (drbg_valid == 0)[*3] and + ##1 (input_data_ready == 0)[*3] and + ##3 + K20 && + cnt == 8'((9'd1 + $past(cnt, 3))) && + hmac_msg == $past(hmac_5, 3) && + key_reg == $past(key_reg, 3) && + v_reg == $past(hmac_tag, 3); +endproperty + + +V2_to_T_a: assert property (disable iff(rst) V2_to_T_p); +property V2_to_T_p; + V2 && + hmac_tag_valid +|-> + ##1 (drbg_valid == 0)[*2] and + ##1 (input_data_ready == 0)[*2] and + ##2 + T && + cnt == $past(cnt, 2) && + hmac_msg == $past(hmac_6, 2) && + key_reg == $past(key_reg, 2) && + v_reg == $past(hmac_tag, 2); +endproperty + + +V3_to_T_a: assert property (disable iff(rst) V3_to_T_p); +property V3_to_T_p; + V3 && + hmac_tag_valid +|-> + ##1 (drbg_valid == 0)[*2] and + ##1 (input_data_ready == 0)[*2] and + ##2 + T && + cnt == $past(cnt, 2) && + hmac_msg == $past(hmac_6, 2) && + key_reg == $past(key_reg, 2) && + v_reg == $past(hmac_tag, 2); +endproperty + + +idle_to_K10_a: assert property (disable iff(rst) idle_to_K10_p); +property idle_to_K10_p; + idle && + input_data_valid && + input_data.init +|-> + ##1 (drbg_valid == 0)[*3] and + ##1 (input_data_ready == 1) and + ##2 (input_data_ready == 0) and + ##3 + K10 && + cnt == 8'd0 && + hmac_msg == $past(hmac_1, 3) && + key_reg == $past(K_INIT, 3) && + v_reg == $past(V_INIT, 3) && + input_data_ready == 0; +endproperty + + +idle_to_K10_1_a: assert property (disable iff(rst) idle_to_K10_1_p); +property idle_to_K10_1_p; + idle && + input_data_valid && + !input_data.init +|-> + ##1 (drbg_valid == 0)[*3] and + ##1 (input_data_ready == 1) and + ##2 (input_data_ready == 0) and + ##3 + K10 && + cnt == 8'((9'd1 + $past(cnt, 3))) && + hmac_msg == $past(hmac_2, 3) && + key_reg == $past(key_reg, 3) && + v_reg == $past(v_reg, 3) && + input_data_ready == 0; +endproperty + + +K10_wait_a: assert property (disable iff(rst) K10_wait_p); +property K10_wait_p; + K10 && + !hmac_tag_valid +|-> + ##1 + K10 && + cnt == $past(cnt, 1) && + key_reg == $past(key_reg, 1) && + v_reg == $past(v_reg, 1) && + drbg_valid == 0 && + input_data_ready == 0; +endproperty + + +K11_wait_a: assert property (disable iff(rst) K11_wait_p); +property K11_wait_p; + K11 && + !hmac_tag_valid +|-> + ##1 + K11 && + cnt == $past(cnt, 1) && + key_reg == $past(key_reg, 1) && + drbg_valid == 0 && + input_data_ready == 0; +endproperty + + +K20_wait_a: assert property (disable iff(rst) K20_wait_p); +property K20_wait_p; + K20 && + !hmac_tag_valid +|-> + ##1 + K20 && + cnt == $past(cnt, 1) && + key_reg == $past(key_reg, 1) && + drbg_valid == 0 && + input_data_ready == 0; +endproperty + + +K21_wait_a: assert property (disable iff(rst) K21_wait_p); +property K21_wait_p; + K21 && + !hmac_tag_valid +|-> + ##1 + K21 && + cnt == $past(cnt, 1) && + key_reg == $past(key_reg, 1) && + v_reg == $past(v_reg, 1) && + drbg_valid == 0 && + input_data_ready == 0; +endproperty + + +K3_wait_a: assert property (disable iff(rst) K3_wait_p); +property K3_wait_p; + K3 && + !hmac_tag_valid +|-> + ##1 + K3 && + cnt == $past(cnt, 1) && + key_reg == $past(key_reg, 1) && + drbg_valid == 0 && + input_data_ready == 0; +endproperty + + +T_wait_a: assert property (disable iff(rst) T_wait_p); +property T_wait_p; + T && + !hmac_tag_valid +|-> + ##1 + T && + cnt == $past(cnt, 1) && + key_reg == $past(key_reg, 1) && + drbg_valid == 0 && + input_data_ready == 0; +endproperty + + +V1_wait_a: assert property (disable iff(rst) V1_wait_p); +property V1_wait_p; + V1 && + !hmac_tag_valid +|-> + ##1 + V1 && + cnt == $past(cnt, 1) && + v_reg == $past(v_reg, 1) && + drbg_valid == 0 && + input_data_ready == 0; +endproperty + + +V2_wait_a: assert property (disable iff(rst) V2_wait_p); +property V2_wait_p; + V2 && + !hmac_tag_valid +|-> + ##1 + V2 && + cnt == $past(cnt, 1) && + v_reg == $past(v_reg, 1) && + drbg_valid == 0 && + input_data_ready == 0; +endproperty + + +V3_wait_a: assert property (disable iff(rst) V3_wait_p); +property V3_wait_p; + V3 && + !hmac_tag_valid +|-> + ##1 + V3 && + cnt == $past(cnt, 1) && + v_reg == $past(v_reg, 1) && + drbg_valid == 0 && + input_data_ready == 0; +endproperty + + +idle_wait_a: assert property (disable iff(rst) idle_wait_p); +property idle_wait_p; + idle && + !input_data_valid +|-> + ##1 + idle && + cnt == $past(cnt, 1) && + key_reg == $past(key_reg, 1) && + v_reg == $past(v_reg, 1) && + drbg_valid == $past(drbg_valid) && + input_data_ready == 1; +endproperty + + +endmodule + + +module fv_hmac_drbg_wrapper_m; + + +default clocking default_clk @(posedge (hmac_drbg.clk)); endclocking + + +st_hmac_block hmac_msg = '{ key: (hmac_drbg.HMAC_key), block_msg: (hmac_drbg.HMAC_block), init: (hmac_drbg.HMAC_init), next: (hmac_drbg.HMAC_next) }; +st_drbg_block input_data = '{ entropy: (hmac_drbg.entropy), nonce: (hmac_drbg.nonce), init: (hmac_drbg.init_cmd), next: (hmac_drbg.next_cmd) }; +st_hmac_block hmac = '{ key: (hmac_drbg.HMAC_key), block_msg: (hmac_drbg.HMAC_block), init: (hmac_drbg.HMAC_init), next: (hmac_drbg.HMAC_next) }; +st_drbg_block in_data = '{ entropy: (hmac_drbg.entropy), nonce: (hmac_drbg.nonce), init: (hmac_drbg.init_cmd), next: (hmac_drbg.next_cmd) }; + + +fv_hmac_drbg_m fv_hmac_drbg( + .rst((!hmac_drbg.reset_n||hmac_drbg.zeroize)), + .clk(hmac_drbg.clk), + + // Inputs + .hmac_tag(hmac_drbg.HMAC_tag), + .input_data(input_data), + + // Outputs + .drbg(hmac_drbg.drbg), + .hmac_msg(hmac_msg), + + // Sync signals + .hmac_tag_valid(hmac_drbg.HMAC_tag_valid && !$past(hmac_drbg.HMAC_tag_valid)), + .input_data_valid((hmac_drbg.init_cmd || hmac_drbg.next_cmd) && hmac_drbg.HMAC_ready), + + // Notify signals + .drbg_valid(hmac_drbg.valid), + .input_data_ready(hmac_drbg.ready), + + // Registers + .cnt(hmac_drbg.cnt_reg), + .hmac(hmac), + .in_data(in_data), + .key_reg(hmac_drbg.K_reg), + .tag_temp(hmac_drbg.HMAC_tag), + .v_reg(hmac_drbg.V_reg), + + // States + .idle(hmac_drbg.drbg_st_reg == 5'd00), + .K10(hmac_drbg.drbg_st_reg == 5'd03), + .K11(hmac_drbg.drbg_st_reg == 5'd04), + .V1(hmac_drbg.drbg_st_reg == 5'd05), + .K20(hmac_drbg.drbg_st_reg == 5'd07), + .K21(hmac_drbg.drbg_st_reg == 5'd08), + .V2(hmac_drbg.drbg_st_reg == 5'd09), + .T(hmac_drbg.drbg_st_reg == 5'd10), + .Done(hmac_drbg.drbg_st_reg == 5'd14), + .K3(hmac_drbg.drbg_st_reg == 5'd12), + .V3(hmac_drbg.drbg_st_reg == 5'd13) +); + + +endmodule + + +bind hmac_drbg fv_hmac_drbg_wrapper_m fv_hmac_drbg_wrapper(); diff --git a/src/hmac_drbg/formal/properties/fv_hmac_drbg_pkg.sv b/src/hmac_drbg/formal/properties/fv_hmac_drbg_pkg.sv new file mode 100644 index 000000000..ad18803e0 --- /dev/null +++ b/src/hmac_drbg/formal/properties/fv_hmac_drbg_pkg.sv @@ -0,0 +1,72 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package hmac_drbg_pkg; + + +typedef struct { + bit unsigned [383:0] entropy; + bit unsigned [383:0] nonce; + bit init; + bit next; +} st_drbg_block; + +typedef struct { + bit unsigned [383:0] key; + bit unsigned [1023:0] block_msg; + bit init; + bit next; +} st_hmac_block; + + +// Constants + +parameter bit unsigned [383:0] HMAC_DRBG_PRIME = 384'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973; + +parameter bit unsigned [383:0] K_INIT = 384'h0; + +parameter bit unsigned [383:0] MASK = 384'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + +parameter bit unsigned [383:0] V_INIT = 384'h10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101; + + +// Functions + +function bit unsigned [1023:0] k10_func(bit unsigned [383:0] V, bit unsigned [7:0] cnt, bit unsigned [383:0] entropy, bit unsigned [383:0] nonce); + return ((((((V << 384'd8) | cnt) << 392'd384) | entropy) << 776'd248) | (nonce >> 384'd136)); +endfunction + +function bit unsigned [1023:0] k11_func(bit unsigned [383:0] nonce); + return (((137'((mask_nonce(nonce) << 384'd1)) | 137'd1) << 137'd887) | 1024'd2184); +endfunction + +function bit unsigned [1023:0] k3_func(bit unsigned [383:0] V); + return ((((((((V << 384'd8) | 392'd0) << 392'd1) | 393'd1) << 393'd619) | 1012'd0) << 1012'd12) | 1024'd1400); +endfunction + +function bit unsigned [383:0] mask_nonce(bit unsigned [383:0] nonce); + return (nonce & MASK); +endfunction + +function bit unsigned [1023:0] v1_func(bit unsigned [383:0] V); + return ((((V << 384'd1) | 385'd1) << 639'd639) | unsigned'((('sd0 << 'sd11) | 'sd1408))); +endfunction + + +endpackage diff --git a/src/hmac_drbg/formal/readme.md b/src/hmac_drbg/formal/readme.md new file mode 100644 index 000000000..768d8f5db --- /dev/null +++ b/src/hmac_drbg/formal/readme.md @@ -0,0 +1,94 @@ +# HMAC DRBG + +Date: 28-08-2023 Author: LUBIS EDA + +## Folder Structure + +The following subdirectories are part of the main directory **formal** + +- model: Contains the high level abstracted model +- properties: Contains the assertion IP(AIP) named as fv_hmac_drbg.sv and the constraints in place for the respective AIP fv_constraints.sv. The folder also contains fv_cover_points.sv that cover certain conditions that are not covered by the properties. + +## DUT Overview + +The DUT hmac_drbg has the primary inputs and primary outputs as shown below. + +|S.No | Port |Direction| Description | +|---- |----------------- |-------- |-------------------------------------------------------------------------------------------| +|1 |clk | input | The positive edge of the clk is used for all the signals | +|2 |reset_n | input | The reset signal is active low and resets the core | +|3 |zeroize | input | The drbg is reseted when this signal is triggered. | +|4 |init_cmd | input | The drbg is initialised with respective register init values | +|5 |next_cmd | input | The drbg processes by increasing count_register | +|6 |entropy [383:0] | input | The input entropy | +|7 |nonce [383:0] | input | The input nonce | +|8 |lfsr_seed [147:0] | input | The input constant value that is feed to sha512_masked as an input for digest computation | +|8 |ready | output | When triggered indicates that the drbg is ready | +|9 |drbg [383:0] | output | The drbg value of the given input values | +|10 |valid | output | When triggered indicates that the computed drbg is valid | + +Drbg algorithm starts with assigning block_register and key_register to its init values. When the model receives an init_cmd, the count_register which helps in creating more randomness in generation of the drbg_tag, is assigned to zero. If the drbg_model recieves next_cmd the count_register is incremented. Initially drbg initializes HMAC by appending block_msg register with count_register and other input signals such as entropy and nonce. Using the updated tag from previous hmac is used as new hmac_key and hmac_block_msg as previous block_register for new tag computation. The updated tag computed will used as new hmac_block_msg and hmac_key remains the same. This repitation is done until we have recieved the tag value in the range of greater than 0 and less than the HMAC_TAG_PRIME value. + +## Assertion IP Overview + +The Assertion IP signals are bound with the respective signals in the dut, where for the rst is binded with the DUT (reset_n && !zeroize), which ensures the reset functionality. Assertion IP is binded with hmac_drbg and checks for the functionality of only hmac_drbg. hmac_tag from HMAC_CORE, is an open wire. This is achieved by cut open the signal from output port of HMAC_CORE, using formal tool. Since it is an open signal the complexity of tag computation is reduced and helps in converging the properties. Similarily two instantances of sha_digest from sha512_masked_core inside HMAC_CORE instantance are also cut open. + +- reset_a: Checks that all the resgiters are resetted and the state is idle, with the ready to high. + +- Done_to_idle_a: Checks if tag register outputs correct value and valid is high, when transition from done to idle states. + +- K10_to_K11_a: Checks if the state is in K11, the hmac_core is called with hmac_next_cmd is set to high and remaining nonce as the block_msg and key remains the same. + +- K11_to_V1_a: Checks if the state is in V1, the hmac_core is called with hmac_init_cmd is set to high and block_msg as the previous block_register and key as updated tag from previous hmac computation. + +- K20_to_K21_a: Checks if the state is in K21, the hmac_core is called with hmac_next_cmd is set to high and remaining nonce as the block_msg and key remains the same. + +- K21_to_V2_a: Checks if the state is in V2, the hmac_core is called with hmac_init_cmd is set to high and block_msg as the previous block_register and key as updated tag from previous hmac computation. + +- K3_to_V3_a: Checks if the state is in V3, the hmac_core is called with hmac_init_cmd is set to high and block_msg as the previous block_register and key as updated tag from previous hmac computation. + +- T_to_Done_a: Checks if the is in done state, where the computated tag from hmac_core passes the required tag condition. + +- T_to_K3_a: Checks if the state is in K3, where the computated tag from hmac_core failes the required tag condition and goes another round of randomness, by initalizing hmac_core and setting hmac_key as same and block_msg as previous tag appended with zeroes. + +- V1_to_K20_a: Checks if the state is in K20, the hmac_core is initalized with hmac_init_cmd set, hmac_key remains the same and block_msg as the newly computed hmac_tag appened with count_register incremented and inputs entropy and nonce. + +- V2_to_T_a: Checks if the state is in T, reads the computed tag from the hmac_core and appends it with previous stored tag_register in order to check if tag condition is holding or not. + +- V3_to_T_a: Checks if the state is in T, reads the computed tag from the hmac_core and appends it with previous stored tag_register in order to check if tag condition is holding or not. + +- idle_to_K10_a: Checks if the state reached is K10, checks for initalization of drbg and HMAC_CORE is ready. Count_register is set to zero, hmac_key is set with init key and hmac_block is appened with init block_register and inputs nonce and entropy. + +- idle_to_K10_1_a: Checks if the state reached is K10, checks for next_cmd and HMAC_CORE is ready. Count_register is incremented, hmac_key is set with previously computed and hmac_block is appened with previously computed hmac_tag and inputs nonce and entropy. + +- K10_wait_a: Checks if there is valid hmac_tag from hmac_core while in state K10, it remains in same state and certain registers holds past values and ready is low. + +- K20_wait_a: Checks if there is valid hmac_tag from hmac_core while in state K20, it remains in same state and certain registers holds past values and ready is low. + +- V1_wait_a: Checks if there is valid hmac_tag from hmac_core while in state V1, it remains in same state and certain registers holds past values and ready is low. + +- K11_wait_a: Checks if there is valid hmac_tag from hmac_core while in state K11, it remains in same state and certain registers holds past values and ready is low. + +- K21_wait_a: Checks if there is valid hmac_tag from hmac_core while in state K21, it remains in same state and certain registers holds past values and ready is low. + +- V2_wait_a: Checks if there is valid hmac_tag from hmac_core while in state V2, it remains in same state and certain registers holds past values and ready is low. + +- T_wait_a: Checks if there is valid hmac_tag from hmac_core while in state T, it remains in same state and certain registers holds past values and ready is low. + +- K3_wait_a: Checks if there is valid hmac_tag from hmac_core while in state K3, it remains in same state and certain registers holds past values and ready is low. + +- V3_wait_a: Checks if there is valid hmac_tag from hmac_core while in state V3, it remains in same state and certain registers holds past values and ready is low. + +- idle_wait_a: Checks if there is valid hmac_tag from hmac_core while in state idle, it remains in same state and certain registers holds past values and while ready is high and previous computed drbg is valid. + +## Reproduce results + +The AIP has been tested with two major FV tools. For both tools proves pass in less then 2 hour and coverage is at 100% . + +For reproducing the results: Load the AIP, hmac_drbg and fv_constraints together in your formal tool. To ensure converging proves cut the following signals: + +cut HMAC_K.u_sha512_core_h1.digest cut HMAC_K.u_sha512_core_h2.digest cut HMAC_K.tag + +The hmac_core and sha512_masked core had been verified separately. By cutting the signal model complexity is drastically reduced. + +Feel free to reach out to contact@lubis-eda.com to request the loadscripts. \ No newline at end of file diff --git a/src/integration/asserts/caliptra_top_sva.sv b/src/integration/asserts/caliptra_top_sva.sv index cdb92c125..619690d92 100644 --- a/src/integration/asserts/caliptra_top_sva.sv +++ b/src/integration/asserts/caliptra_top_sva.sv @@ -24,22 +24,29 @@ `else `define CPTRA_TB_TOP_NAME caliptra_top_tb `endif -`define CPTRA_TOP_PATH `CPTRA_TB_TOP_NAME.caliptra_top_dut -`define KEYVAULT_PATH `CPTRA_TOP_PATH.key_vault1 -`define DOE_INST_PATH `CPTRA_TOP_PATH.doe.doe_inst -`define DOE_PATH `DOE_INST_PATH.doe_fsm1 -`define DOE_REG_PATH `DOE_INST_PATH.i_doe_reg -`define SERVICES_PATH `CPTRA_TB_TOP_NAME.tb_services_i -`define SHA512_PATH `CPTRA_TOP_PATH.sha512.sha512_inst -`define HMAC_PATH `CPTRA_TOP_PATH.hmac.hmac_inst -`define ECC_PATH `CPTRA_TOP_PATH.ecc_top1.ecc_dsa_ctrl_i -`define ECC_REG_PATH `CPTRA_TOP_PATH.ecc_top1.ecc_reg1 -`define SHA256_PATH `CPTRA_TOP_PATH.sha256.sha256_inst -`define SHA512_MASKED_PATH `CPTRA_TOP_PATH.ecc_top1.ecc_dsa_ctrl_i.ecc_hmac_drbg_interface_i.hmac_drbg_i.HMAC_K.u_sha512_core_h1 -`define SOC_IFC_TOP_PATH `CPTRA_TOP_PATH.soc_ifc_top1 -`define WDT_PATH `SOC_IFC_TOP_PATH.i_wdt +`define CPTRA_TOP_PATH `CPTRA_TB_TOP_NAME.caliptra_top_dut +`define KEYVAULT_PATH `CPTRA_TOP_PATH.key_vault1 +`define KEYVAULT_REG_PATH `KEYVAULT_PATH.kv_reg1 +`define PCRVAULT_PATH `CPTRA_TOP_PATH.pcr_vault1 +`define PCRVAULT_REG_PATH `PCRVAULT_PATH.pv_reg1 +`define DATA_VAULT_PATH `CPTRA_TOP_PATH.data_vault1 +`define DATA_VAULT_REG_PATH `DATA_VAULT_PATH.dv_reg1 +`define DOE_INST_PATH `CPTRA_TOP_PATH.doe.doe_inst +`define DOE_PATH `DOE_INST_PATH.doe_fsm1 +`define DOE_REG_PATH `DOE_INST_PATH.i_doe_reg +`define SERVICES_PATH `CPTRA_TB_TOP_NAME.tb_services_i +`define SHA512_PATH `CPTRA_TOP_PATH.sha512.sha512_inst +`define HMAC_PATH `CPTRA_TOP_PATH.hmac.hmac_inst +`define HMAC_REG_PATH `HMAC_PATH.i_hmac_reg +`define ECC_PATH `CPTRA_TOP_PATH.ecc_top1.ecc_dsa_ctrl_i +`define ECC_REG_PATH `CPTRA_TOP_PATH.ecc_top1.ecc_reg1 +`define SHA256_PATH `CPTRA_TOP_PATH.sha256.sha256_inst +`define SHA512_MASKED_PATH `CPTRA_TOP_PATH.ecc_top1.ecc_dsa_ctrl_i.ecc_hmac_drbg_interface_i.hmac_drbg_i.HMAC_K.u_sha512_core_h1 +`define SOC_IFC_TOP_PATH `CPTRA_TOP_PATH.soc_ifc_top1 +`define WDT_PATH `SOC_IFC_TOP_PATH.i_wdt `define SVA_RDC_CLK `CPTRA_TOP_PATH.rdc_clk_cg +`define CPTRA_FW_UPD_RST_WINDOW `SOC_IFC_TOP_PATH.i_soc_ifc_boot_fsm.fw_update_rst_window `ifdef UVMF_CALIPTRA_TOP `define SVA_CLK `CPTRA_TB_TOP_NAME.clk `define SVA_RST `CPTRA_TB_TOP_NAME.soc_ifc_subenv_soc_ifc_ctrl_agent_bus.cptra_rst_b @@ -552,5 +559,25 @@ module caliptra_top_sva `ECC_PATH.ecc_arith_unit_i.ecc_instr_s.opcode.mult_we |-> (`ECC_PATH.ecc_arith_unit_i.mult_res_s < `ECC_PATH.ecc_arith_unit_i.adder_prime) ) else $display("SVA ERROR: ECC multiplier result is not valid!"); -endmodule + // Bus IDLE on Firmware Update Reset + fw_upd_rst_doe_idle: assert property (@(posedge `SVA_RDC_CLK) `CPTRA_FW_UPD_RST_WINDOW |-> !`DOE_REG_PATH.s_cpuif_req) + else $display("SVA ERROR: DOE bus not idle after Firmware Update Reset!"); + fw_upd_rst_ecc_idle: assert property (@(posedge `SVA_RDC_CLK) `CPTRA_FW_UPD_RST_WINDOW |-> !`ECC_REG_PATH.s_cpuif_req) + else $display("SVA ERROR: ECC bus not idle after Firmware Update Reset!"); + fw_upd_rst_hmac_idle: assert property (@(posedge `SVA_RDC_CLK) `CPTRA_FW_UPD_RST_WINDOW |-> !`HMAC_REG_PATH.s_cpuif_req) + else $display("SVA ERROR: HMAC bus not idle after Firmware Update Reset!"); + fw_upd_rst_kv_idle: assert property (@(posedge `SVA_RDC_CLK) `CPTRA_FW_UPD_RST_WINDOW |-> !`KEYVAULT_REG_PATH.s_cpuif_req) + else $display("SVA ERROR: Key Vault bus not idle after Firmware Update Reset!"); + fw_upd_rst_pv_idle: assert property (@(posedge `SVA_RDC_CLK) `CPTRA_FW_UPD_RST_WINDOW |-> !`PCRVAULT_REG_PATH.s_cpuif_req) + else $display("SVA ERROR: PCR Vault bus not idle after Firmware Update Reset!"); + fw_upd_rst_dv_idle: assert property (@(posedge `SVA_RDC_CLK) `CPTRA_FW_UPD_RST_WINDOW |-> !`DATA_VAULT_REG_PATH.s_cpuif_req) + else $display("SVA ERROR: Data Vault bus not idle after Firmware Update Reset!"); + fw_upd_rst_sha256_idle: assert property (@(posedge `SVA_RDC_CLK) `CPTRA_FW_UPD_RST_WINDOW |-> !`SHA256_PATH.i_sha256_reg.s_cpuif_req) + else $display("SVA ERROR: SHA256 bus not idle after Firmware Update Reset!"); + fw_upd_rst_sha512_idle: assert property (@(posedge `SVA_RDC_CLK) `CPTRA_FW_UPD_RST_WINDOW |-> !`SHA512_PATH.i_sha512_reg.s_cpuif_req) + else $display("SVA ERROR: SHA512 bus not idle after Firmware Update Reset!"); + fw_upd_rst_soc_ifc_idle: assert property (@(posedge `SVA_RDC_CLK) `CPTRA_FW_UPD_RST_WINDOW |-> !`SOC_IFC_TOP_PATH.i_ahb_slv_sif_soc_ifc.dv) + else $display("SVA ERROR: SOC_IFC bus not idle after Firmware Update Reset!"); + +endmodule diff --git a/src/integration/config/compile.yml b/src/integration/config/compile.yml index ef8f9ca6f..841335776 100644 --- a/src/integration/config/compile.yml +++ b/src/integration/config/compile.yml @@ -45,7 +45,7 @@ targets: tops: [caliptra_top] rtl_lint: waiver_files: - - $COMPILE_ROOT/config/design_lint/sglint_waivers + - $MSFT_REPO_ROOT/src/integration/config/design_lint/sglint_waivers black_box: - el2_veer_wrapper cdc: @@ -109,7 +109,7 @@ targets: - $COMPILE_ROOT/tb/caliptra_top_tb.sv tops: [caliptra_top_tb] sim: - pre_exec: '$MSFT_TOOLS/scripts/run_test_makefile && echo "[PRE-EXEC] Copying ECC vector generator to ${pwd}" && cp $COMPILE_ROOT/../ecc/tb/ecdsa_secp384r1.exe . + pre_exec: '$MSFT_SCRIPTS_DIR/run_test_makefile && echo "[PRE-EXEC] Copying ECC vector generator to ${pwd}" && cp $COMPILE_ROOT/../ecc/tb/ecdsa_secp384r1.exe . && echo "[PRE-EXEC] Copying DOE vector generator to ${pwd}" && cp $COMPILE_ROOT/../doe/tb/doe_test_gen.py .' global: tool: diff --git a/src/integration/stimulus/L0_regression.yml b/src/integration/stimulus/L0_regression.yml index 2614e6710..c8b240084 100644 --- a/src/integration/stimulus/L0_regression.yml +++ b/src/integration/stimulus/L0_regression.yml @@ -9,7 +9,7 @@ contents: #add back for aes #- ../test_suites/smoke_test_aes/smoke_test_aes.yml - ../test_suites/smoke_test_mbox/smoke_test_mbox.yml - #- ../test_suites/smoke_test_mbox_cg/smoke_test_mbox_cg.yml + - ../test_suites/smoke_test_mbox_cg/smoke_test_mbox_cg.yml - ../test_suites/smoke_test_sha512/smoke_test_sha512.yml - ../test_suites/smoke_test_sha256/smoke_test_sha256.yml - ../test_suites/smoke_test_sha_accel/smoke_test_sha_accel.yml @@ -37,7 +37,7 @@ contents: - ../test_suites/smoke_test_kv_hmac_flow/smoke_test_kv_hmac_flow.yml - ../test_suites/smoke_test_kv_sha512_flow/smoke_test_kv_sha512_flow.yml - ../test_suites/smoke_test_kv_crypto_flow/smoke_test_kv_crypto_flow.yml - #- ../test_suites/smoke_test_kv_cg/smoke_test_kv_cg.yml + - ../test_suites/smoke_test_kv_cg/smoke_test_kv_cg.yml - ../test_suites/pv_hash_and_sign/pv_hash_and_sign.yml - ../test_suites/smoke_test_pcr_signing/smoke_test_pcr_signing.yml - ../test_suites/smoke_test_fw_kv_backtoback_hmac/smoke_test_fw_kv_backtoback_hmac.yml @@ -47,7 +47,7 @@ contents: - ../test_suites/smoke_test_doe_rand/smoke_test_doe_rand.yml - ../test_suites/smoke_test_doe_scan/smoke_test_doe_scan.yml - ../test_suites/smoke_test_zeroize_crypto/smoke_test_zeroize_crypto.yml - #- ../test_suites/smoke_test_doe_cg/smoke_test_doe_cg.yml + - ../test_suites/smoke_test_doe_cg/smoke_test_doe_cg.yml # data vault tests - ../test_suites/smoke_test_datavault_basic/smoke_test_datavault_basic.yml - ../test_suites/smoke_test_datavault_reset/smoke_test_datavault_reset.yml diff --git a/src/integration/stimulus/testsuites/uvmf_caliptra_top_nightly_directed_regression.yml b/src/integration/stimulus/testsuites/uvmf_caliptra_top_nightly_directed_regression.yml index 5baa312a8..dd668520b 100644 --- a/src/integration/stimulus/testsuites/uvmf_caliptra_top_nightly_directed_regression.yml +++ b/src/integration/stimulus/testsuites/uvmf_caliptra_top_nightly_directed_regression.yml @@ -7,8 +7,8 @@ contents: path: "" config: params: - # 12 hours - timeout: 720 + # 24 hours + timeout: 1440 weight: 100 generations: 1 formats: diff --git a/src/integration/tb/caliptra_top_tb_services.sv b/src/integration/tb/caliptra_top_tb_services.sv index 8d167d0e7..400aa8c85 100644 --- a/src/integration/tb/caliptra_top_tb_services.sv +++ b/src/integration/tb/caliptra_top_tb_services.sv @@ -1059,7 +1059,7 @@ endgenerate //IV_NO wb_valid <= `DEC.dec_i0_wen_r; wb_dest <= `DEC.dec_i0_waddr_r; wb_data <= `DEC.dec_i0_wdata_r; - if (caliptra_top_dut.trace_rv_i_valid_ip && !$test$plusargs("CLP_REGRESSION")) begin + if (caliptra_top_dut.trace_rv_i_valid_ip && $test$plusargs("CLP_BUS_LOGS")) begin $fwrite(tp,"%b,%h,%h,%0h,%0h,3,%b,%h,%h,%b\n", caliptra_top_dut.trace_rv_i_valid_ip, 0, caliptra_top_dut.trace_rv_i_address_ip, 0, caliptra_top_dut.trace_rv_i_insn_ip,caliptra_top_dut.trace_rv_i_exception_ip,caliptra_top_dut.trace_rv_i_ecause_ip, @@ -1074,18 +1074,18 @@ endgenerate //IV_NO ); end if(`DEC.dec_nonblock_load_wen) begin - if (!$test$plusargs("CLP_REGRESSION")) $fwrite (el, "%10d : %32s=%h ; nbL\n", cycleCnt, abi_reg[`DEC.dec_nonblock_load_waddr], `DEC.lsu_nonblock_load_data); + if ($test$plusargs("CLP_BUS_LOGS")) $fwrite (el, "%10d : %32s=%h ; nbL\n", cycleCnt, abi_reg[`DEC.dec_nonblock_load_waddr], `DEC.lsu_nonblock_load_data); caliptra_top_tb_services.gpr[0][`DEC.dec_nonblock_load_waddr] = `DEC.lsu_nonblock_load_data; end if(`DEC.exu_div_wren) begin - if (!$test$plusargs("CLP_REGRESSION")) $fwrite (el, "%10d : %32s=%h ; nbD\n", cycleCnt, abi_reg[`DEC.div_waddr_wb], `DEC.exu_div_result); + if ($test$plusargs("CLP_BUS_LOGS")) $fwrite (el, "%10d : %32s=%h ; nbD\n", cycleCnt, abi_reg[`DEC.div_waddr_wb], `DEC.exu_div_result); caliptra_top_tb_services.gpr[0][`DEC.div_waddr_wb] = `DEC.exu_div_result; end end // IFU Initiator monitor always @(posedge clk) begin - if (!$test$plusargs("CLP_REGRESSION")) + if (!$test$plusargs("CLP_BUS_LOGS")) $fstrobe(ifu_p, "%10d : 0x%0h %h %b %h %h %h %b 0x%08h_%08h %b %b\n", cycleCnt, caliptra_top_dut.ic_haddr, caliptra_top_dut.ic_hburst, caliptra_top_dut.ic_hmastlock, caliptra_top_dut.ic_hprot, caliptra_top_dut.ic_hsize, caliptra_top_dut.ic_htrans, @@ -1095,7 +1095,7 @@ endgenerate //IV_NO // LSU Initiator monitor always @(posedge clk) begin - if (!$test$plusargs("CLP_REGRESSION")) + if ($test$plusargs("CLP_BUS_LOGS")) $fstrobe(lsu_p, "%10d : 0x%0h %h %h %b 0x%08h_%08h 0x%08h_%08h %b %b\n", cycleCnt, caliptra_top_dut.initiator_inst.haddr, caliptra_top_dut.initiator_inst.hsize, caliptra_top_dut.initiator_inst.htrans, caliptra_top_dut.initiator_inst.hwrite, caliptra_top_dut.initiator_inst.hrdata[63:32], caliptra_top_dut.initiator_inst.hrdata[31:0], @@ -1108,7 +1108,7 @@ endgenerate //IV_NO generate for (sl_i = 0; sl_i < `CALIPTRA_AHB_SLAVES_NUM; sl_i = sl_i + 1) begin: gen_responder_inf_monitor always @(posedge clk) begin - if (!$test$plusargs("CLP_REGRESSION")) + if ($test$plusargs("CLP_BUS_LOGS")) $fstrobe(sl_p[sl_i], "%10d : 0x%0h %h %h %b 0x%08h_%08h 0x%08h_%08h %b %b %b %b\n", cycleCnt, caliptra_top_dut.responder_inst[sl_i].haddr, caliptra_top_dut.responder_inst[sl_i].hsize, caliptra_top_dut.responder_inst[sl_i].htrans, caliptra_top_dut.responder_inst[sl_i].hwrite, caliptra_top_dut.responder_inst[sl_i].hrdata[63:32], caliptra_top_dut.responder_inst[sl_i].hrdata[31:0], @@ -1167,13 +1167,13 @@ endgenerate //IV_NO if (!hex_file_is_empty) $readmemh("dccm.hex", dummy_dccm_preloader.ram,0,32'h0001_FFFF); hex_file_is_empty = $system("test -s iccm.hex"); if (!hex_file_is_empty) $readmemh("iccm.hex", dummy_iccm_preloader.ram,0,32'h0001_FFFF); - if (!$test$plusargs("CLP_REGRESSION")) begin + if ($test$plusargs("CLP_BUS_LOGS")) begin tp = $fopen("trace_port.csv","w"); el = $fopen("exec.log","w"); ifu_p = $fopen("ifu_master_ahb_trace.log", "w"); lsu_p = $fopen("lsu_master_ahb_trace.log", "w"); end - if (!$test$plusargs("CLP_REGRESSION")) begin + if ($test$plusargs("CLP_BUS_LOGS")) begin $fwrite (el, "// Cycle : #inst 0 pc opcode reg=value ; mnemonic\n"); $fwrite(ifu_p, "// Cycle: ic_haddr ic_hburst ic_hmastlock ic_hprot ic_hsize ic_htrans ic_hwrite ic_hrdata ic_hwdata ic_hready ic_hresp\n"); $fwrite(lsu_p, "// Cycle: lsu_haddr lsu_hsize lsu_htrans lsu_hwrite lsu_hrdata lsu_hwdata lsu_hready lsu_hresp\n"); diff --git a/src/integration/test_suites/infinite_loop/dump_and_compare.sh b/src/integration/test_suites/infinite_loop/dump_and_compare.sh index 594703ba0..1e6c6a0d3 100755 --- a/src/integration/test_suites/infinite_loop/dump_and_compare.sh +++ b/src/integration/test_suites/infinite_loop/dump_and_compare.sh @@ -16,7 +16,7 @@ set -ex # Invoke GDB and dump core registers -riscv64-unknown-elf-gdb -n --batch -x dump_registers.gdb >gdb.log +${GCC_PREFIX}-gdb -n --batch -x dump_registers.gdb >gdb.log # Parse the log, extract register values. Skip those which change as the # program executes since we don't know at which point we tap in. cat gdb.log | grep -E '^ra |^sp |^gp |^tp |^t[01256] |^s[0-9]+ |^a[0-9]+ |^\$[0-9]+' >regdump.txt diff --git a/src/integration/test_suites/infinite_loop/mem_access.sh b/src/integration/test_suites/infinite_loop/mem_access.sh index d800cc099..fb4a7e670 100755 --- a/src/integration/test_suites/infinite_loop/mem_access.sh +++ b/src/integration/test_suites/infinite_loop/mem_access.sh @@ -16,7 +16,7 @@ set -ex # Invoke GDB -riscv64-unknown-elf-gdb -n --batch -x mem_access.gdb >gdb.log +${GCC_PREFIX}-gdb -n --batch -x mem_access.gdb >gdb.log # Parse the log cat gdb.log | grep -E '^\$[0-9]+' >out.txt diff --git a/src/integration/test_suites/infinite_loop/peripheral_access.sh b/src/integration/test_suites/infinite_loop/peripheral_access.sh index 1f9d83cf5..e9d195662 100755 --- a/src/integration/test_suites/infinite_loop/peripheral_access.sh +++ b/src/integration/test_suites/infinite_loop/peripheral_access.sh @@ -16,7 +16,7 @@ set -ex # Invoke GDB -riscv64-unknown-elf-gdb -n --batch -x peripheral_access.gdb >gdb.log +${GCC_PREFIX}-gdb -n --batch -x peripheral_access.gdb >gdb.log # Parse the log cat gdb.log | grep -E '^\$[0-9]+' >out.txt diff --git a/src/integration/test_suites/smoke_test_clk_gating/smoke_test_clk_gating.yml b/src/integration/test_suites/smoke_test_clk_gating/smoke_test_clk_gating.yml new file mode 100644 index 000000000..d919ef2e9 --- /dev/null +++ b/src/integration/test_suites/smoke_test_clk_gating/smoke_test_clk_gating.yml @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +seed: 1 +testname: smoke_test_clk_gating \ No newline at end of file diff --git a/src/integration/test_suites/smoke_test_clk_gating/smoke_test_clk_gating_asm.s b/src/integration/test_suites/smoke_test_clk_gating/smoke_test_clk_gating_asm.s new file mode 100644 index 000000000..29fdaecfc --- /dev/null +++ b/src/integration/test_suites/smoke_test_clk_gating/smoke_test_clk_gating_asm.s @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2019 Western Digital Corporation or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Assembly code for Hello World +// Not using only ALU ops for creating the string + + +#include "../includes/caliptra_defines.h" +//#include "../smoke_test_sha512/smoke_test_sha512_vectors.s" + + +// Code to execute +.section .text +.global _start +_start: + + // Clear minstret + csrw minstret, zero + csrw minstreth, zero + + // Set up MTVEC - not expecting to use it though + li x1, RV_ICCM_SADR + csrw mtvec, x1 + + la sp, STACK + + call init_interrupts + + // Enable Caches in MRAC + li x1, 0xaaaaaaaa + csrw 0x7c0, x1 + + + + + +//---------------------------------------------------- +//Wake up using internal timer0 +//---------------------------------------------------- + //Internal timer 0 counter + li x1, 0x00000000 + csrw 0x7d2,x1 + + //Internal timer 0 upper bound + li x1, 0x00000020 + csrw 0x7d3,x1 + + //Internal timer 0 control (halt_en = 1, enable = 1) + li x1, 0x00000003 + csrw 0x7d4, x1 + + //Machine intr enable reg (mie) - enable internal timer 0 intr + li x1, 0x20000000 + csrw 0x304, x1 + + //mstatus - mie enable + li x1, 0x00000008 + csrw 0x300, x1 + + //FW halt (mpmc) - halt, haltie + li x1,0x00000003 + csrw 0x7c6,x1 + +//------------------------------------------------------ +//Set STDOUT to F8 until all cases below finish running +//------------------------------------------------------ + li x3, STDOUT + li x5, 0xf8 + sb x5, 0(x3) //write F8 to STDOUT to cause NMI event +//------------------------------------------------------ +//Wake up using software int +//------------------------------------------------------ + //Machine intr enable reg (mie) - enable software int + li x1, 0x00000008 + csrw 0x304, x1 + + //FW halt (mpmc) - halt, haltie + li x1,0x00000003 + csrw 0x7c6,x1 +//------------------------------------------------------ +//Wake up using timer int +//------------------------------------------------------ + //Machine intr enable reg (mie) - enable timer int + li x1, 0x00000080 + csrw 0x304, x1 + + //FW halt (mpmc) - halt, haltie + li x1,0x00000003 + csrw 0x7c6,x1 +//------------------------------------------------------ +//Wake up using external int - TODO +//------------------------------------------------------ + //Machine intr enable reg (mie) - enable timer int + //li x1, 0x00000800 + //csrw 0x304, x1 + + + //FW halt (mpmc) - halt, haltie + //li x1,0x00000003 + //csrw 0x7c6,x1 +//------------------------------------------------------ +//Wake up using generic input wires +//------------------------------------------------------ + //FW halt (mpmc) - halt, haltie + li x1,0x00000003 + csrw 0x7c6,x1 +//------------------------------------------------------ +//Wake up using APB tx int and exit halt using NMI - TODO +//------------------------------------------------------ + + //TODO: how to write a dword in asm + //Trigger APB tx + li x3, CLP_SOC_IFC_REG_CPTRA_FLOW_STATUS + li x4, SOC_IFC_REG_CPTRA_FLOW_STATUS_READY_FOR_FW_MASK + //sb x5, 0(x3) + + loop1: + lw x5, 0(x4) + sw x5, 0(x3) + addi x4, x4, 4 + bnez x5, loop1 + + //FW halt (mpmc) - halt, haltie + li x1,0x00000003 + csrw 0x7c6,x1 + + +//------------------------------------------------------ +//End test +//------------------------------------------------------ + // Load string from hw_data + // and write to stdout address + + li x3, STDOUT + la x4, hw_data_out + +loop: + lb x5, 0(x4) + sb x5, 0(x3) + addi x4, x4, 1 + bnez x5, loop + +// Write 0xff to STDOUT for TB to termiate test. +_finish: + li x3, STDOUT + addi x5, x0, 0xff + sb x5, 0(x3) + beq x0, x0, _finish +.rept 100 + nop +.endr + +.section .dccm +hw_data_out: +.ascii "----------------------------------\n" +.ascii "Running clk gating test\n" +.ascii "----------------------------------\n" +.byte 0 + +//.data +//key_data: +////this is the key 384-bit +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//.word 0x0b0b0b0b +//block_data: +//.word 0x48692054 +//.word 0x68657265 +//.word 0x80000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000000 +//.word 0x00000440 +//expected_data: +//.word 0xb6a8d563 +//.word 0x6f5c6a72 +//.word 0x24f9977d +//.word 0xcf7ee6c7 +//.word 0xfb6d0c48 +//.word 0xcbdee973 +//.word 0x7a959796 +//.word 0x489bddbc +//.word 0x4c5df61d +//.word 0x5b3297b4 +//.word 0xfb68dab9 +//.word 0xf1b582c2 + +.align 4 +.global stdout +stdout: .word STDOUT +.global verbosity_g +verbosity_g: .word 2 + +.global intr_count +intr_count: .word 0 diff --git a/src/integration/test_suites/smoke_test_doe_cg/smoke_test_doe_cg.c b/src/integration/test_suites/smoke_test_doe_cg/smoke_test_doe_cg.c index abab48c5c..04ab79691 100644 --- a/src/integration/test_suites/smoke_test_doe_cg/smoke_test_doe_cg.c +++ b/src/integration/test_suites/smoke_test_doe_cg/smoke_test_doe_cg.c @@ -94,7 +94,6 @@ void main() { //Call interrupt init init_interrupts(); - if (rst_count == 1) { //Enable clk gating and halt core SEND_STDOUT_CTRL(0xf2); set_mit0(mitb0, mie_timer0_en); @@ -106,7 +105,31 @@ void main() { SEND_STDOUT_CTRL(0xec); *doe_ctrl = 0x0000000D; - printf("Dummy\n"); + __asm__ volatile ("csrwi %0, %1" \ + : /* output: none */ \ + : "i" (0x7c6), "i" (0x03) /* input : immediate */ \ + : /* clobbers: none */); + + // //Poll for DOE status + while(doe_status_int != (DOE_REG_DOE_STATUS_VALID_MASK | DOE_REG_DOE_STATUS_READY_MASK)) { + doe_status_int = *doe_status; + doe_status_int = doe_status_int & (DOE_REG_DOE_STATUS_VALID_MASK | DOE_REG_DOE_STATUS_READY_MASK) ; + } + + //Clear doe_status_int + doe_status_int = 0; + + //-------------------------------------------------------------------- + //Enable clk gating and halt core + SEND_STDOUT_CTRL(0xf2); + set_mit0(mitb0, mie_timer0_en); + + printf("Rand FE\n"); + + //Start FE and store in KV7 + SEND_STDOUT_CTRL(0xed); + *doe_ctrl = 0x0000001E; + __asm__ volatile ("csrwi %0, %1" \ : /* output: none */ \ : "i" (0x7c6), "i" (0x03) /* input : immediate */ \ diff --git a/src/integration/test_suites/smoke_test_kv_cg/smoke_test_kv_cg.c b/src/integration/test_suites/smoke_test_kv_cg/smoke_test_kv_cg.c index c90f3fcf6..6929ed929 100644 --- a/src/integration/test_suites/smoke_test_kv_cg/smoke_test_kv_cg.c +++ b/src/integration/test_suites/smoke_test_kv_cg/smoke_test_kv_cg.c @@ -140,6 +140,11 @@ void main() { VPRINTF(LOW, "Starting UDS again\n"); *doe_ctrl = 0x00000001; + //Enable clk gating and halt core + // SEND_STDOUT_CTRL(0xf2); + set_mit0(mitb0, mie_timer0_en); + halt_core(); + // //Poll for DOE status doe_status_int = 0x00000000; while(doe_status_int != (DOE_REG_DOE_STATUS_VALID_MASK | DOE_REG_DOE_STATUS_READY_MASK)) { diff --git a/src/integration/uvmf_caliptra_top/config/compile.yml b/src/integration/uvmf_caliptra_top/config/compile.yml index a2f5c1c7e..1029c8669 100644 --- a/src/integration/uvmf_caliptra_top/config/compile.yml +++ b/src/integration/uvmf_caliptra_top/config/compile.yml @@ -51,7 +51,7 @@ targets: pre_exec: | echo "[PRE-EXEC] Copying SHA512 Vectors to $(pwd)" cp ${COMPILE_ROOT}/../tb/vectors/SHA*.rsp . - $TOOLS/scripts/run_test_makefile + $MSFT_SCRIPTS_DIR/run_test_makefile global: tool: vcs: @@ -97,7 +97,7 @@ targets: pre_exec: | echo "[PRE-EXEC] Copying SHA512 Vectors to $(pwd)" cp ${COMPILE_ROOT}/../tb/vectors/SHA*.rsp . - $TOOLS/scripts/run_test_makefile + $MSFT_SCRIPTS_DIR/run_test_makefile global: tool: vcs: diff --git a/src/keyvault/config/compile.yml b/src/keyvault/config/compile.yml index e0d516e0e..6bebe194c 100644 --- a/src/keyvault/config/compile.yml +++ b/src/keyvault/config/compile.yml @@ -52,7 +52,7 @@ targets: rtl_lint: directories: [] waiver_files: - - $COMPILE_ROOT/config/design_lint/keyvault/sglint_waivers + - $MSFT_REPO_ROOT/src/keyvault/config/design_lint/keyvault/sglint_waivers black_box: - kv_reg global: diff --git a/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/environment_packages/kv_env_pkg/src/kv_predictor.svh b/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/environment_packages/kv_env_pkg/src/kv_predictor.svh index d17b1a2ac..2dc9b85d7 100644 --- a/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/environment_packages/kv_env_pkg/src/kv_predictor.svh +++ b/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/environment_packages/kv_env_pkg/src/kv_predictor.svh @@ -210,6 +210,8 @@ class kv_predictor #( // int unsigned job_end_count[time]; // bit write_entry_pending = 0; // bit send_hmac_write_txn = 0; + logic [KV_NUM_KEYS-1:0] clear_secrets_debug0 = 0; + logic [KV_NUM_KEYS-1:0] clear_secrets_debug1 = 0; bit set_val_ctrl_derived = 0; logic [KV_NUM_KEYS-1:0] val_ctrl_derived_data = 0; logic [KV_NUM_KEYS-1:0] key_entry_ctrl_we = 0; @@ -221,6 +223,7 @@ class kv_predictor #( extern function void populate_expected_kv_read_txn(ref kv_sb_ap_output_transaction_t t_expected, kv_read_transaction t_received, string client); extern function void populate_expected_kv_write_txn(ref kv_sb_ap_output_transaction_write_t t_expected, kv_write_transaction t_received); extern task poll_and_run_delay_jobs(); + extern task poll_and_run_clr_secrets_delay_job(); // extern function send_delayed_expected_transactions_hmac_write(kv_write_transaction t); // extern function send_delayed_expected_transactions_sha512_write(kv_write_transaction t); // extern function send_delayed_expected_transactions_ecc_write(kv_write_transaction t); @@ -292,6 +295,7 @@ class kv_predictor #( task run_phase (uvm_phase phase); fork poll_and_run_delay_jobs(); + poll_and_run_clr_secrets_delay_job(); join_none super.run_phase(phase); endtask @@ -323,6 +327,8 @@ class kv_predictor #( p_kv_rm.reset(); //all regs cleared on hard rst for(entry = 0; entry < KV_NUM_KEYS; entry++) begin last_dword_written[entry] = 'h0; //Clear last dword on hard rst + // clear_secrets_debug0[entry] = 'h0; + // clear_secrets_debug1[entry] = 'h0; end key_ctrl_lock_wr = 'h0; key_ctrl_lock_use = 'h0; @@ -332,22 +338,18 @@ class kv_predictor #( p_kv_rm.val_reg.debug_mode_unlocked.set(1'b1); p_kv_rm.val_reg.cptra_in_debug_scan_mode.set(1'b1); - `uvm_info("PRED", "Clear_secrets reg is set in debug/scan mode. Flushing KV", UVM_MEDIUM) + `uvm_info("PRED", "Debug mode switch, KV will be flushed", UVM_MEDIUM) if (clear_secrets_data[p_kv_rm.kv_reg_rm.CLEAR_SECRETS.sel_debug_value.get_lsb_pos()] == 'h1) begin for(entry = 0; entry < KV_NUM_KEYS; entry++) begin //Debug mode should flush all regs inspite of locks - for(offset = 0; offset < KV_NUM_DWORDS; offset++) begin - p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].predict(CLP_DEBUG_MODE_KV_1); - p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].set(CLP_DEBUG_MODE_KV_1); - end + clear_secrets_debug0[entry] = 'h0; + clear_secrets_debug1[entry] = 'h1; end end else begin for(entry = 0; entry < KV_NUM_KEYS; entry++) begin - for(offset = 0; offset < KV_NUM_DWORDS; offset++) begin - p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].predict(CLP_DEBUG_MODE_KV_0); - p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].set(CLP_DEBUG_MODE_KV_0); - end + clear_secrets_debug0[entry] = 'h1; + clear_secrets_debug1[entry] = 'h0; end end end @@ -655,31 +657,27 @@ class kv_predictor #( //Only allow clear operation if in debug mode //if (data_active[1:0] == 'h1) begin if (data_active [p_kv_rm.kv_reg_rm.CLEAR_SECRETS.wr_debug_values.get_lsb_pos()] && !data_active[p_kv_rm.kv_reg_rm.CLEAR_SECRETS.sel_debug_value.get_lsb_pos()]) begin - `uvm_info("PRED", "Clear_secrets reg is set in debug/scan mode. Flushing KV with DEBUG0 values", UVM_MEDIUM) + `uvm_info("PRED", "Clear_secrets reg is set in debug/scan mode", UVM_MEDIUM) for(entry = 0; entry < KV_NUM_KEYS; entry++) begin //Read locks before clearing - do not clear if locked kv_reg = p_kv_rm.get_reg_by_name($sformatf("KEY_CTRL[%0d]",entry)); kv_reg_data = kv_reg.get_mirrored_value(); if(kv_reg_data[1:0] == 2'b00) begin - for(offset = 0; offset < KV_NUM_DWORDS; offset++) begin - p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].predict(CLP_DEBUG_MODE_KV_0); - p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].set(CLP_DEBUG_MODE_KV_0); - end + clear_secrets_debug0[entry] = 'h1; + clear_secrets_debug1[entry] = 'h0; end end end //else if(data_active[1:0] == 'h3) begin else if (data_active [p_kv_rm.kv_reg_rm.CLEAR_SECRETS.wr_debug_values.get_lsb_pos()] && data_active[p_kv_rm.kv_reg_rm.CLEAR_SECRETS.sel_debug_value.get_lsb_pos()]) begin - `uvm_info("PRED", "Clear_secrets reg is set in debug/scan mode. Flushing KV with DEBUG1 values", UVM_MEDIUM) + `uvm_info("PRED", "Clear_secrets reg is set in debug/scan mode", UVM_MEDIUM) for(entry = 0; entry < KV_NUM_KEYS; entry++) begin //Read locks before clearing kv_reg = p_kv_rm.get_reg_by_name($sformatf("KEY_CTRL[%0d]",entry)); kv_reg_data = kv_reg.get_mirrored_value(); if(kv_reg_data[1:0] == 2'b00) begin - for(offset = 0; offset < KV_NUM_DWORDS; offset++) begin - p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].predict(CLP_DEBUG_MODE_KV_1); - p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].set(CLP_DEBUG_MODE_KV_1); - end + clear_secrets_debug0[entry] = 'h0; + clear_secrets_debug1[entry] = 'h1; end end end @@ -967,5 +965,38 @@ endclass configuration.kv_hmac_write_agent_config.wait_for_num_clocks(1); end endtask + + task kv_predictor::poll_and_run_clr_secrets_delay_job(); + int entry, offset; + forever begin + fork + begin + //CLEAR SECRETS: + configuration.kv_hmac_write_agent_config.wait_for_num_clocks(1); + `uvm_info("Delay Jobs",$sformatf(" |clear_secrets_debug0 = %b, |debug1 = %b\n", |clear_secrets_debug0, |clear_secrets_debug1), UVM_DEBUG) + if (|clear_secrets_debug0 || |clear_secrets_debug1) begin + `uvm_info("Delay Jobs", "Flushing key vault", UVM_MEDIUM) + for(entry = 0; entry < KV_NUM_KEYS; entry++) begin + if(clear_secrets_debug0[entry] == 'h1) begin + for(offset = 0; offset < KV_NUM_DWORDS; offset++) begin + p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].predict(CLP_DEBUG_MODE_KV_0); + p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].set(CLP_DEBUG_MODE_KV_0); + end + clear_secrets_debug0[entry] = 'h0; + end + else if (clear_secrets_debug1[entry]== 'h1) begin + for(offset = 0; offset < KV_NUM_DWORDS; offset++) begin + p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].predict(CLP_DEBUG_MODE_KV_1); + p_kv_rm.kv_reg_rm.KEY_ENTRY[entry][offset].set(CLP_DEBUG_MODE_KV_1); + end + clear_secrets_debug1[entry] = 'h0; + end + end //for loop + end //if block + end //begin + join_none + configuration.kv_hmac_write_agent_config.wait_for_num_clocks(1); + end + endtask // pragma uvmf custom external end diff --git a/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/environment_packages/kv_env_pkg/src/kv_wr_rd_debug_sequence.svh b/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/environment_packages/kv_env_pkg/src/kv_wr_rd_debug_sequence.svh index 319fb1c02..f8138067d 100644 --- a/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/environment_packages/kv_env_pkg/src/kv_wr_rd_debug_sequence.svh +++ b/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/environment_packages/kv_env_pkg/src/kv_wr_rd_debug_sequence.svh @@ -167,7 +167,7 @@ class kv_wr_rd_debug_sequence #( end join - `uvm_info("DEBUG_WR_RD", "Waiting for sha512 write/read to finish", UVM_FULL) + `uvm_info("DEBUG_WR_RD", "Waiting for sha512 write/read to finish", UVM_MEDIUM) configuration.kv_rst_agent_config.wait_for_num_clocks(1000); configuration.kv_hmac_write_agent_config.wait_for_num_clocks(1000); configuration.kv_sha512_write_agent_config.wait_for_num_clocks(1000); @@ -179,34 +179,40 @@ class kv_wr_rd_debug_sequence #( configuration.kv_ecc_privkey_read_agent_config.wait_for_num_clocks(1000); configuration.kv_ecc_seed_read_agent_config.wait_for_num_clocks(1000); - `uvm_info("DEBUG_WR_RD", "Scan mode and queue writes", UVM_FULL) - fork //debug mode - begin - kv_rst_agent_scan_on_seq.start(configuration.kv_rst_agent_config.sequencer); - end - begin - queue_writes(); - //Wait for these writes to finish before setting next CTRL reg to avoid collision (test trying to write to CTRL and predictor trying to read from CTRL) - configuration.kv_hmac_write_agent_config.wait_for_num_clocks(100); - configuration.kv_sha512_write_agent_config.wait_for_num_clocks(100); - configuration.kv_ecc_write_agent_config.wait_for_num_clocks(100); - configuration.kv_doe_write_agent_config.wait_for_num_clocks(100); - end - join - - `uvm_info("DEBUG_WR_RD", "clear_secrets and queue writes", UVM_FULL) + `uvm_info("DEBUG_WR_RD", "Scan mode and queue writes", UVM_MEDIUM) + `uvm_info("DEBUG_WR_RD", "Turning on scan mode", UVM_MEDIUM) + + kv_rst_agent_scan_on_seq.start(configuration.kv_rst_agent_config.sequencer); + + `uvm_info("DEBUG_WR_RD", "Queuing writes", UVM_MEDIUM) + queue_writes(); + //Wait for these writes to finish before setting next CTRL reg to avoid collision (test trying to write to CTRL and predictor trying to read from CTRL) + configuration.kv_hmac_write_agent_config.wait_for_num_clocks(100); + configuration.kv_sha512_write_agent_config.wait_for_num_clocks(100); + configuration.kv_ecc_write_agent_config.wait_for_num_clocks(100); + configuration.kv_doe_write_agent_config.wait_for_num_clocks(100); + + `uvm_info("DEBUG_WR_RD", "Turning off scan mode", UVM_MEDIUM) + kv_rst_agent_scan_off_seq.start(configuration.kv_rst_agent_config.sequencer); + + `uvm_info("DEBUG_WR_RD", "clear_secrets and queue writes", UVM_MEDIUM) fork //clear secrets begin repeat(20) begin + configuration.kv_hmac_write_agent_config.wait_for_num_clocks(5); + configuration.kv_sha512_write_agent_config.wait_for_num_clocks(5); + configuration.kv_ecc_write_agent_config.wait_for_num_clocks(5); + configuration.kv_doe_write_agent_config.wait_for_num_clocks(5); + std::randomize(clear_secrets_data); //wren, debug_value0/1 reg_model.kv_reg_rm.CLEAR_SECRETS.write(sts, clear_secrets_data, UVM_FRONTDOOR, reg_model.kv_AHB_map, this); assert(sts == UVM_IS_OK) else `uvm_error("AHB_CLEAR_SECRETS_SET", "Failed when writing to CLEAR_SECRETS reg!") - - configuration.kv_hmac_write_agent_config.wait_for_num_clocks(2); - configuration.kv_sha512_write_agent_config.wait_for_num_clocks(2); - configuration.kv_ecc_write_agent_config.wait_for_num_clocks(2); - configuration.kv_doe_write_agent_config.wait_for_num_clocks(2); + + configuration.kv_hmac_write_agent_config.wait_for_num_clocks(5); + configuration.kv_sha512_write_agent_config.wait_for_num_clocks(5); + configuration.kv_ecc_write_agent_config.wait_for_num_clocks(5); + configuration.kv_doe_write_agent_config.wait_for_num_clocks(5); end //repeat end begin diff --git a/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/interface_packages/kv_rst_pkg/src/kv_rst_scan_on_sequence.svh b/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/interface_packages/kv_rst_pkg/src/kv_rst_scan_on_sequence.svh index 960931259..97c66f90d 100644 --- a/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/interface_packages/kv_rst_pkg/src/kv_rst_scan_on_sequence.svh +++ b/src/keyvault/uvmf_kv/uvmf_template_output/verification_ip/interface_packages/kv_rst_pkg/src/kv_rst_scan_on_sequence.svh @@ -57,6 +57,7 @@ class kv_rst_scan_on_sequence extends kv_rst_sequence_base; req.assert_core_rst = 1'b0; req.debug_mode = 1'b1; req.scan_mode = 1'b1; + req.wait_cycles = 'h0; finish_item(req); `uvm_info("KV_RST_SCAN_ON", {"Response:",req.convert2string()},UVM_MEDIUM) diff --git a/src/libs/uvmf/qvip_ahb_lite_slave_dir/config_policies/ahb_lite_slave_0_config_policy.svh b/src/libs/uvmf/qvip_ahb_lite_slave_dir/config_policies/ahb_lite_slave_0_config_policy.svh index 1057eb119..55943973e 100644 --- a/src/libs/uvmf/qvip_ahb_lite_slave_dir/config_policies/ahb_lite_slave_0_config_policy.svh +++ b/src/libs/uvmf/qvip_ahb_lite_slave_dir/config_policies/ahb_lite_slave_0_config_policy.svh @@ -121,7 +121,7 @@ class ahb_lite_slave_0_config_policy; // // If true, drives previous address when bus is IDLE // cfg.m_bfm.config_address_on_idle = 1'b0; // // Maximum number of successive wait states - cfg.m_bfm.config_max_wait_states_count = 34; + cfg.m_bfm.config_max_wait_states_count = 67; // // Data endianness // cfg.m_bfm.config_endianness = AHB_LITTLE_ENDIAN; // // Sets the domain diff --git a/src/pcrvault/config/compile.yml b/src/pcrvault/config/compile.yml index 8e17ba963..b52d4c33e 100644 --- a/src/pcrvault/config/compile.yml +++ b/src/pcrvault/config/compile.yml @@ -52,7 +52,7 @@ targets: rtl_lint: directories: [] waiver_files: - - $COMPILE_ROOT/config/design_lint/pcrvault/sglint_waivers + - $MSFT_REPO_ROOT/src/pcrvault/config/design_lint/pcrvault/sglint_waivers black_box: - pv_reg global: diff --git a/src/riscv_core/veer_el2/config/compile.yml b/src/riscv_core/veer_el2/config/compile.yml index dad981819..883ece5df 100755 --- a/src/riscv_core/veer_el2/config/compile.yml +++ b/src/riscv_core/veer_el2/config/compile.yml @@ -71,7 +71,7 @@ targets: rtl_lint: directories: [] waiver_files: - - $COMPILE_ROOT/config/design_lint/el2_veer_wrapper/sglint_waivers + - $MSFT_REPO_ROOT/src/riscv_core/veer_el2/config/design_lint/el2_veer_wrapper/sglint_waivers global: tool: vcs: diff --git a/src/sha256/config/compile.yml b/src/sha256/config/compile.yml index 03ecae0e0..15af97656 100755 --- a/src/sha256/config/compile.yml +++ b/src/sha256/config/compile.yml @@ -20,7 +20,7 @@ targets: directories: [] waiver_files: #- $COMPILE_ROOT/config/rtl_lint/sha256.waiver - - $COMPILE_ROOT/config/design_lint/sha256_ctrl/sglint_waivers + - $MSFT_REPO_ROOT/src/sha256/config/design_lint/sha256_ctrl/sglint_waivers black_box: - sha256_reg --- diff --git a/src/sha512/config/compile.yml b/src/sha512/config/compile.yml index 690ae1c4a..f7c6f56f6 100755 --- a/src/sha512/config/compile.yml +++ b/src/sha512/config/compile.yml @@ -23,7 +23,7 @@ targets: directories: [] waiver_files: #- $COMPILE_ROOT/config/rtl_lint/sha512.waiver - - $COMPILE_ROOT/config/design_lint/sha512_ctrl/sglint_waivers + - $MSFT_REPO_ROOT/src/sha512/config/design_lint/sha512_ctrl/sglint_waivers black_box: - sha512_reg --- diff --git a/src/sha512/formal/model/tb/sc_main.cpp b/src/sha512/formal/model/tb/sc_main.cpp index 7bf012fe0..665c4db06 100644 --- a/src/sha512/formal/model/tb/sc_main.cpp +++ b/src/sha512/formal/model/tb/sc_main.cpp @@ -1,3 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + #include "systemc.h" #include "../Interfaces/Interfaces.h" #include "../sha512.h" diff --git a/src/sha512/formal/model/tb/tb.cpp b/src/sha512/formal/model/tb/tb.cpp index a4202ddf2..92efdec46 100644 --- a/src/sha512/formal/model/tb/tb.cpp +++ b/src/sha512/formal/model/tb/tb.cpp @@ -1,3 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + using namespace std; #include #include "systemc.h" diff --git a/src/sha512/formal/model/tb/tb.h b/src/sha512/formal/model/tb/tb.h index 14218adcd..83a443291 100644 --- a/src/sha512/formal/model/tb/tb.h +++ b/src/sha512/formal/model/tb/tb.h @@ -1,3 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + #ifndef TB_H #define TB_H diff --git a/src/sha512_masked/formal/properties/fv_constraints.sv b/src/sha512_masked/formal/properties/fv_constraints.sv new file mode 100644 index 000000000..f3534f5ef --- /dev/null +++ b/src/sha512_masked/formal/properties/fv_constraints.sv @@ -0,0 +1,85 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +module fv_constraints_m( + input logic init_cmd, + input logic next_cmd, + input logic reset_n, + input logic clk, + input logic zeroize, + input logic ready, + input logic digest_valid, + input logic [1023 : 0] block_msg, + input logic [73 : 0] lfsr_seed, + input logic [511 : 0] digest, + input logic [1 : 0] mode + ); + + default clocking default_clk @(posedge clk); endclocking + + logic fv_init_reg; + + always @ (posedge clk or negedge reset_n) + begin : init_reg_order + if (!reset_n || zeroize) + fv_init_reg <= 1'b0; + else if (init_cmd) + fv_init_reg <= 1'b1; + end + + + property mode_values; + (sha512_masked_core.mode == 0) || + (sha512_masked_core.mode == 1) || + (sha512_masked_core.mode == 2) || + (sha512_masked_core.mode == 3); + endproperty + assume_mode_values: assume property (disable iff(!reset_n || zeroize) mode_values); + + property inputs_stay_stable; + !(sha512_masked_core.ready) |-> $stable(block_msg) && $stable(sha512_masked_core.mode); + endproperty + assume_inputs_stay_stable: assume property (disable iff(!reset_n || zeroize) inputs_stay_stable); + + property remove_init_next_together; + !(init_cmd && next_cmd); + endproperty + assume_remove_init_next_together: assume property (disable iff(!reset_n || zeroize) remove_init_next_together); + + property init_next_order; + !fv_init_reg |-> !next_cmd; + endproperty + assume_init_next_order: assume property (disable iff(!reset_n || zeroize) init_next_order); + + +endmodule + +bind sha512_masked_core fv_constraints_m fv_constraints( + .init_cmd(init_cmd), + .next_cmd(next_cmd), + .reset_n(reset_n), + .ready(ready), + .digest_valid(digest_valid), + .clk(clk), + .mode(mode), + .block_msg(block_msg), + .zeroize(zeroize), + .lfsr_seed(lfsr_seed), + .digest(digest) +); diff --git a/src/sha512_masked/formal/properties/fv_coverpoints.sv b/src/sha512_masked/formal/properties/fv_coverpoints.sv new file mode 100644 index 000000000..99fc818e4 --- /dev/null +++ b/src/sha512_masked/formal/properties/fv_coverpoints.sv @@ -0,0 +1,50 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +module fv_coverpoints_m( + input logic clk, + input logic reset_n, + input logic zeroize +); + + default clocking default_clk @(posedge clk); endclocking + + //Cover zeroize: + //Assert zeroize input and check the status of all registers. All registers/internal memories should be cleared. + cover_zeroize: cover property(disable iff(!reset_n) sha512_masked_core.zeroize ); + cover_zeroize_after_next: cover property(disable iff(!reset_n) sha512_masked_core.zeroize && sha512_masked_core.next_cmd ); + + cover_multiple_next: cover property(disable iff(!reset_n || zeroize) + sha512_masked_core.next_cmd && sha512_masked_core.ready ##1 (sha512_masked_core.next_cmd && sha512_masked_core.ready)[->1] + ); + + //Cover modes: + //Cover all 4 different modes for SHA512 + cover_mode_224: cover property(disable iff(!reset_n) sha512_masked_core.mode == 0 && sha512_masked_core.init_cmd ); + cover_mode_256: cover property(disable iff(!reset_n) sha512_masked_core.mode == 1 && sha512_masked_core.init_cmd ); + cover_mode_384: cover property(disable iff(!reset_n) sha512_masked_core.mode == 2 && sha512_masked_core.init_cmd ); + cover_mode_512: cover property(disable iff(!reset_n) sha512_masked_core.mode == 3 && sha512_masked_core.init_cmd ); + + +endmodule +bind sha512_masked_core fv_coverpoints_m fv_coverpoints( + .clk(clk), + .reset_n(reset_n), + .zeroize(zeroize) +); \ No newline at end of file diff --git a/src/sha512_masked/formal/properties/fv_sha512_masked.sv b/src/sha512_masked/formal/properties/fv_sha512_masked.sv new file mode 100644 index 000000000..a7b0ef598 --- /dev/null +++ b/src/sha512_masked/formal/properties/fv_sha512_masked.sv @@ -0,0 +1,919 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import sha512_masked_pkg::*; + + +module fv_sha512_masked_m( + input bit rst, + input bit clk, + + // Inputs + input st_SHA_Args sha_in_struct, + input bit unsigned [73:0] lfsr_in, + + // Outputs + input bit unsigned [511:0] digest_out, + + // Valid signals + input bit block_in_valid, + input bit digest_valid, + + // Ready signals + input bit block_in_ready, + + // Registers + input a_sc_big_unsigned_64_8 H, + input bit signed [31:0] block_sha_mode, + input a_sc_big_unsigned_64_16 W, + input st_masked_reg_t a, + input st_masked_reg_t b, + input bit unsigned [1023:0] block_in, + input st_masked_reg_t c, + input st_masked_reg_t d, + input st_masked_reg_t e, + input st_masked_reg_t f, + input st_masked_reg_t g, + input st_masked_reg_t h, + input bit signed [31:0] i, + input bit block_init, + input bit unsigned [73:0] lfsr_rnd, + input bit signed [31:0] rnd_cnt_reg, + input a_sc_big_unsigned_64_8 rh_masking_rnd, + + // States + input bit IDLE, + input bit CTRL_RND, + input bit SHA_Rounds, + input bit DONE +); + + +default clocking default_clk @(posedge clk); endclocking + + +a_sc_big_unsigned_64_8 H_0 = '{ + 0: 64'd0, + 1: 64'd0, + 2: 64'd0, + 3: 64'd0, + 4: 64'd0, + 5: 64'd0, + 6: 64'd0, + 7: 64'd0 +}; + +a_sc_big_unsigned_64_16 W_0 = '{ + 0: 64'd0, + 1: 64'd0, + 2: 64'd0, + 3: 64'd0, + 4: 64'd0, + 5: 64'd0, + 6: 64'd0, + 7: 64'd0, + 8: 64'd0, + 9: 64'd0, + 10: 64'd0, + 11: 64'd0, + 12: 64'd0, + 13: 64'd0, + 14: 64'd0, + 15: 64'd0 +}; + +st_masked_reg_t a_0 = '{ + masked: 64'd0, + random: 64'd0 +}; + +a_sc_big_unsigned_64_8 rh_masking_rnd_0 = '{ + 0: ((rnd_cnt_reg == 'sd0) ? lfsr_in : rh_masking_rnd['sd0]), + 1: ((rnd_cnt_reg == 'sd1) ? lfsr_in : rh_masking_rnd['sd1]), + 2: ((rnd_cnt_reg == 'sd2) ? lfsr_in : rh_masking_rnd['sd2]), + 3: ((rnd_cnt_reg == 'sd3) ? lfsr_in : rh_masking_rnd['sd3]), + 4: ((rnd_cnt_reg == 'sd4) ? lfsr_in : rh_masking_rnd['sd4]), + 5: ((rnd_cnt_reg == 'sd5) ? lfsr_in : rh_masking_rnd['sd5]), + 6: ((rnd_cnt_reg == 'sd6) ? lfsr_in : rh_masking_rnd['sd6]), + 7: ((rnd_cnt_reg == 'sd7) ? lfsr_in : rh_masking_rnd['sd7]) +}; + +a_sc_big_unsigned_64_8 H_1 = '{ + 0: 64'h8C3D37C819544DA2, + 1: 64'h73E1996689DCD4D6, + 2: 64'h1DFAB7AE32FF9C82, + 3: 64'h679DD514582F9FCF, + 4: 64'hF6D2B697BD44DA8, + 5: 64'h77E36F7304C48942, + 6: 64'h3F9D85A86A1D36C8, + 7: 64'h1112E6AD91D692A1 +}; + +a_sc_big_unsigned_64_16 W_1 = '{ + 0: slicer(block_in, 'sd15), + 1: slicer(block_in, 'sd14), + 2: slicer(block_in, 'sd13), + 3: slicer(block_in, 'sd12), + 4: slicer(block_in, 'sd11), + 5: slicer(block_in, 'sd10), + 6: slicer(block_in, 'sd9), + 7: slicer(block_in, 'sd8), + 8: slicer(block_in, 'sd7), + 9: slicer(block_in, 'sd6), + 10: slicer(block_in, 'sd5), + 11: slicer(block_in, 'sd4), + 12: slicer(block_in, 'sd3), + 13: slicer(block_in, 'sd2), + 14: slicer(block_in, 'sd1), + 15: slicer(block_in, 'sd0) +}; + +st_masked_reg_t a_1 = '{ + masked: (64'h8C3D37C819544DA2 ^ (0 ? lfsr_in : rh_masking_rnd['sd0])), + random: (0 ? lfsr_in : rh_masking_rnd['sd0]) +}; + +st_masked_reg_t b_0 = '{ + masked: (64'h73E1996689DCD4D6 ^ (0 ? lfsr_in : rh_masking_rnd['sd1])), + random: (0 ? lfsr_in : rh_masking_rnd['sd1]) +}; + +st_masked_reg_t c_0 = '{ + masked: (64'h1DFAB7AE32FF9C82 ^ (0 ? lfsr_in : rh_masking_rnd['sd2])), + random: (0 ? lfsr_in : rh_masking_rnd['sd2]) +}; + +st_masked_reg_t d_0 = '{ + masked: (64'h679DD514582F9FCF ^ (0 ? lfsr_in : rh_masking_rnd['sd3])), + random: (0 ? lfsr_in : rh_masking_rnd['sd3]) +}; + +st_masked_reg_t e_0 = '{ + masked: (64'hF6D2B697BD44DA8 ^ (0 ? lfsr_in : rh_masking_rnd['sd4])), + random: (0 ? lfsr_in : rh_masking_rnd['sd4]) +}; + +st_masked_reg_t f_0 = '{ + masked: (64'h77E36F7304C48942 ^ (0 ? lfsr_in : rh_masking_rnd['sd5])), + random: (0 ? lfsr_in : rh_masking_rnd['sd5]) +}; + +st_masked_reg_t g_0 = '{ + masked: (64'h3F9D85A86A1D36C8 ^ (0 ? lfsr_in : rh_masking_rnd['sd6])), + random: (0 ? lfsr_in : rh_masking_rnd['sd6]) +}; + +st_masked_reg_t h_0 = '{ + masked: (64'h1112E6AD91D692A1 ^ (0 ? lfsr_in : rh_masking_rnd['sd7])), + random: (0 ? lfsr_in : rh_masking_rnd['sd7]) +}; + +a_sc_big_unsigned_64_8 rh_masking_rnd_1 = '{ + 0: lfsr_in, + 1: rh_masking_rnd['sd1], + 2: rh_masking_rnd['sd2], + 3: rh_masking_rnd['sd3], + 4: rh_masking_rnd['sd4], + 5: rh_masking_rnd['sd5], + 6: rh_masking_rnd['sd6], + 7: rh_masking_rnd['sd7] +}; + +a_sc_big_unsigned_64_8 H_2 = '{ + 0: 64'h22312194FC2BF72C, + 1: 64'h9F555FA3C84C64C2, + 2: 64'h2393B86B6F53B151, + 3: 64'h963877195940EABD, + 4: 64'h96283EE2A88EFFE3, + 5: 64'hBE5E1E2553863992, + 6: 64'h2B0199FC2C85B8AA, + 7: 64'hEB72DDC81C52CA2 +}; + +st_masked_reg_t a_2 = '{ + masked: (64'h22312194FC2BF72C ^ (0 ? lfsr_in : rh_masking_rnd['sd0])), + random: (0 ? lfsr_in : rh_masking_rnd['sd0]) +}; + +st_masked_reg_t b_1 = '{ + masked: (64'h9F555FA3C84C64C2 ^ (0 ? lfsr_in : rh_masking_rnd['sd1])), + random: (0 ? lfsr_in : rh_masking_rnd['sd1]) +}; + +st_masked_reg_t c_1 = '{ + masked: (64'h2393B86B6F53B151 ^ (0 ? lfsr_in : rh_masking_rnd['sd2])), + random: (0 ? lfsr_in : rh_masking_rnd['sd2]) +}; + +st_masked_reg_t d_1 = '{ + masked: (64'h963877195940EABD ^ (0 ? lfsr_in : rh_masking_rnd['sd3])), + random: (0 ? lfsr_in : rh_masking_rnd['sd3]) +}; + +st_masked_reg_t e_1 = '{ + masked: (64'h96283EE2A88EFFE3 ^ (0 ? lfsr_in : rh_masking_rnd['sd4])), + random: (0 ? lfsr_in : rh_masking_rnd['sd4]) +}; + +st_masked_reg_t f_1 = '{ + masked: (64'hBE5E1E2553863992 ^ (0 ? lfsr_in : rh_masking_rnd['sd5])), + random: (0 ? lfsr_in : rh_masking_rnd['sd5]) +}; + +st_masked_reg_t g_1 = '{ + masked: (64'h2B0199FC2C85B8AA ^ (0 ? lfsr_in : rh_masking_rnd['sd6])), + random: (0 ? lfsr_in : rh_masking_rnd['sd6]) +}; + +st_masked_reg_t h_1 = '{ + masked: (64'hEB72DDC81C52CA2 ^ (0 ? lfsr_in : rh_masking_rnd['sd7])), + random: (0 ? lfsr_in : rh_masking_rnd['sd7]) +}; + +a_sc_big_unsigned_64_8 H_3 = '{ + 0: 64'h6A09E667F3BCC908, + 1: 64'hBB67AE8584CAA73B, + 2: 64'h3C6EF372FE94F82B, + 3: 64'hA54FF53A5F1D36F1, + 4: 64'h510E527FADE682D1, + 5: 64'h9B05688C2B3E6C1F, + 6: 64'h1F83D9ABFB41BD6B, + 7: 64'h5BE0CD19137E2179 +}; + +st_masked_reg_t a_3 = '{ + masked: (64'h6A09E667F3BCC908 ^ (0 ? lfsr_in : rh_masking_rnd['sd0])), + random: (0 ? lfsr_in : rh_masking_rnd['sd0]) +}; + +st_masked_reg_t b_2 = '{ + masked: (64'hBB67AE8584CAA73B ^ (0 ? lfsr_in : rh_masking_rnd['sd1])), + random: (0 ? lfsr_in : rh_masking_rnd['sd1]) +}; + +st_masked_reg_t c_2 = '{ + masked: (64'h3C6EF372FE94F82B ^ (0 ? lfsr_in : rh_masking_rnd['sd2])), + random: (0 ? lfsr_in : rh_masking_rnd['sd2]) +}; + +st_masked_reg_t d_2 = '{ + masked: (64'hA54FF53A5F1D36F1 ^ (0 ? lfsr_in : rh_masking_rnd['sd3])), + random: (0 ? lfsr_in : rh_masking_rnd['sd3]) +}; + +st_masked_reg_t e_2 = '{ + masked: (64'h510E527FADE682D1 ^ (0 ? lfsr_in : rh_masking_rnd['sd4])), + random: (0 ? lfsr_in : rh_masking_rnd['sd4]) +}; + +st_masked_reg_t f_2 = '{ + masked: (64'h9B05688C2B3E6C1F ^ (0 ? lfsr_in : rh_masking_rnd['sd5])), + random: (0 ? lfsr_in : rh_masking_rnd['sd5]) +}; + +st_masked_reg_t g_2 = '{ + masked: (64'h1F83D9ABFB41BD6B ^ (0 ? lfsr_in : rh_masking_rnd['sd6])), + random: (0 ? lfsr_in : rh_masking_rnd['sd6]) +}; + +st_masked_reg_t h_2 = '{ + masked: (64'h5BE0CD19137E2179 ^ (0 ? lfsr_in : rh_masking_rnd['sd7])), + random: (0 ? lfsr_in : rh_masking_rnd['sd7]) +}; + +a_sc_big_unsigned_64_8 H_4 = '{ + 0: 64'hCBBB9D5DC1059ED8, + 1: 64'h629A292A367CD507, + 2: 64'h9159015A3070DD17, + 3: 64'h152FECD8F70E5939, + 4: 64'h67332667FFC00B31, + 5: 64'h8EB44A8768581511, + 6: 64'hDB0C2E0D64F98FA7, + 7: 64'h47B5481DBEFA4FA4 +}; + +st_masked_reg_t a_4 = '{ + masked: (64'hCBBB9D5DC1059ED8 ^ (0 ? lfsr_in : rh_masking_rnd['sd0])), + random: (0 ? lfsr_in : rh_masking_rnd['sd0]) +}; + +st_masked_reg_t b_3 = '{ + masked: (64'h629A292A367CD507 ^ (0 ? lfsr_in : rh_masking_rnd['sd1])), + random: (0 ? lfsr_in : rh_masking_rnd['sd1]) +}; + +st_masked_reg_t c_3 = '{ + masked: (64'h9159015A3070DD17 ^ (0 ? lfsr_in : rh_masking_rnd['sd2])), + random: (0 ? lfsr_in : rh_masking_rnd['sd2]) +}; + +st_masked_reg_t d_3 = '{ + masked: (64'h152FECD8F70E5939 ^ (0 ? lfsr_in : rh_masking_rnd['sd3])), + random: (0 ? lfsr_in : rh_masking_rnd['sd3]) +}; + +st_masked_reg_t e_3 = '{ + masked: (64'h67332667FFC00B31 ^ (0 ? lfsr_in : rh_masking_rnd['sd4])), + random: (0 ? lfsr_in : rh_masking_rnd['sd4]) +}; + +st_masked_reg_t f_3 = '{ + masked: (64'h8EB44A8768581511 ^ (0 ? lfsr_in : rh_masking_rnd['sd5])), + random: (0 ? lfsr_in : rh_masking_rnd['sd5]) +}; + +st_masked_reg_t g_3 = '{ + masked: (64'hDB0C2E0D64F98FA7 ^ (0 ? lfsr_in : rh_masking_rnd['sd6])), + random: (0 ? lfsr_in : rh_masking_rnd['sd6]) +}; + +st_masked_reg_t h_3 = '{ + masked: (64'h47B5481DBEFA4FA4 ^ (0 ? lfsr_in : rh_masking_rnd['sd7])), + random: (0 ? lfsr_in : rh_masking_rnd['sd7]) +}; + +st_masked_reg_t a_5 = '{ + masked: (H[64'd0] ^ (0 ? lfsr_in : rh_masking_rnd['sd0])), + random: (0 ? lfsr_in : rh_masking_rnd['sd0]) +}; + +st_masked_reg_t b_4 = '{ + masked: (H[64'd1] ^ (0 ? lfsr_in : rh_masking_rnd['sd1])), + random: (0 ? lfsr_in : rh_masking_rnd['sd1]) +}; + +st_masked_reg_t c_4 = '{ + masked: (H[64'd2] ^ (0 ? lfsr_in : rh_masking_rnd['sd2])), + random: (0 ? lfsr_in : rh_masking_rnd['sd2]) +}; + +st_masked_reg_t d_4 = '{ + masked: (H[64'd3] ^ (0 ? lfsr_in : rh_masking_rnd['sd3])), + random: (0 ? lfsr_in : rh_masking_rnd['sd3]) +}; + +st_masked_reg_t e_4 = '{ + masked: (H[64'd4] ^ (0 ? lfsr_in : rh_masking_rnd['sd4])), + random: (0 ? lfsr_in : rh_masking_rnd['sd4]) +}; + +st_masked_reg_t f_4 = '{ + masked: (H[64'd5] ^ (0 ? lfsr_in : rh_masking_rnd['sd5])), + random: (0 ? lfsr_in : rh_masking_rnd['sd5]) +}; + +st_masked_reg_t g_4 = '{ + masked: (H[64'd6] ^ (0 ? lfsr_in : rh_masking_rnd['sd6])), + random: (0 ? lfsr_in : rh_masking_rnd['sd6]) +}; + +st_masked_reg_t h_4 = '{ + masked: (H[64'd7] ^ (0 ? lfsr_in : rh_masking_rnd['sd7])), + random: (0 ? lfsr_in : rh_masking_rnd['sd7]) +}; + +st_masked_reg_t a_6 = '{ + masked: A2B_conv(64'((T1_m(e.masked, e.random, f.masked, f.random, g.masked, g.random, h.masked, h.random, K[i], (W[i] ^ 64'(lfsr_rnd)), 64'(lfsr_rnd), 0, 128'd0, 64'd0, (((lfsr_rnd >> 74'd64) & 74'h1) == 74'd1), ((((lfsr_rnd >> 74'd64) >> 74'd1) & 74'h1) == 74'd1), (((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), ((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), (((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 'sd10) + T2_m(a.masked, a.random, b.masked, b.random, c.masked, c.random, 0, 128'd0, 64'd0, ((((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), (((((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 'sd10))), 64'((T1_r(e.random, g.random, h.random, 64'(lfsr_rnd)) + T2_r(a.random, b.random))), (((((((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 0, 128'd0, 64'd0, 'sd10), + random: (T1_r(e.random, g.random, h.random, 64'(lfsr_rnd)) + T2_r(a.random, b.random)) +}; + +st_masked_reg_t e_5 = '{ + masked: A2B_conv(64'((B2A_conv(d.masked, d.random, ((((((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 0, 128'd0, 64'd0, 'sd10) + T1_m(e.masked, e.random, f.masked, f.random, g.masked, g.random, h.masked, h.random, K[i], (W[i] ^ 64'(lfsr_rnd)), 64'(lfsr_rnd), 0, 128'd0, 64'd0, (((lfsr_rnd >> 74'd64) & 74'h1) == 74'd1), ((((lfsr_rnd >> 74'd64) >> 74'd1) & 74'h1) == 74'd1), (((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), ((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), (((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 'sd10))), 64'((d.random + T1_r(e.random, g.random, h.random, 64'(lfsr_rnd)))), ((((((((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 0, 128'd0, 64'd0, 'sd10), + random: (d.random + T1_r(e.random, g.random, h.random, 64'(lfsr_rnd))) +}; + +a_sc_big_unsigned_64_16 W_2 = '{ + 0: W['sd1], + 1: W['sd2], + 2: W['sd3], + 3: W['sd4], + 4: W['sd5], + 5: W['sd6], + 6: W['sd7], + 7: W['sd8], + 8: W['sd9], + 9: W['sd10], + 10: W['sd11], + 11: W['sd12], + 12: W['sd13], + 13: W['sd14], + 14: W['sd15], + 15: compute_w(W[64'd14], W[64'd9], W[64'd1], W[64'd0]) +}; + +st_masked_reg_t a_7 = '{ + masked: A2B_conv(64'((T1_m(e.masked, e.random, f.masked, f.random, g.masked, g.random, h.masked, h.random, K[i], (compute_w(W[64'd14], W[64'd9], W[64'd1], W[64'd0]) ^ 64'(lfsr_rnd)), 64'(lfsr_rnd), 0, 128'd0, 64'd0, (((lfsr_rnd >> 74'd64) & 74'h1) == 74'd1), ((((lfsr_rnd >> 74'd64) >> 74'd1) & 74'h1) == 74'd1), (((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), ((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), (((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 'sd10) + T2_m(a.masked, a.random, b.masked, b.random, c.masked, c.random, 0, 128'd0, 64'd0, ((((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), (((((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 'sd10))), 64'((T1_r(e.random, g.random, h.random, 64'(lfsr_rnd)) + T2_r(a.random, b.random))), (((((((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 0, 128'd0, 64'd0, 'sd10), + random: (T1_r(e.random, g.random, h.random, 64'(lfsr_rnd)) + T2_r(a.random, b.random)) +}; + +st_masked_reg_t e_6 = '{ + masked: A2B_conv(64'((B2A_conv(d.masked, d.random, ((((((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 0, 128'd0, 64'd0, 'sd10) + T1_m(e.masked, e.random, f.masked, f.random, g.masked, g.random, h.masked, h.random, K[i], (compute_w(W[64'd14], W[64'd9], W[64'd1], W[64'd0]) ^ 64'(lfsr_rnd)), 64'(lfsr_rnd), 0, 128'd0, 64'd0, (((lfsr_rnd >> 74'd64) & 74'h1) == 74'd1), ((((lfsr_rnd >> 74'd64) >> 74'd1) & 74'h1) == 74'd1), (((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), ((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), (((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 'sd10))), 64'((d.random + T1_r(e.random, g.random, h.random, 64'(lfsr_rnd)))), ((((((((((((lfsr_rnd >> 74'd64) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) >> 74'd1) & 74'h1) == 74'd1), 0, 128'd0, 64'd0, 'sd10), + random: (d.random + T1_r(e.random, g.random, h.random, 64'(lfsr_rnd))) +}; + +a_sc_big_unsigned_64_8 H_5 = '{ + 0: (H[64'd0] + (a.masked ^ a.random)), + 1: (H['sd1] + (b.masked ^ b.random)), + 2: (H['sd2] + (c.masked ^ c.random)), + 3: (H['sd3] + (d.masked ^ d.random)), + 4: (H['sd4] + (e.masked ^ e.random)), + 5: (H['sd5] + (f.masked ^ f.random)), + 6: (H['sd6] + (g.masked ^ g.random)), + 7: (H['sd7] + (h.masked ^ h.random)) +}; + + +sequence reset_sequence; + !rst ##1 rst; +endsequence + + +reset_a: assert property (reset_p); +property reset_p; + $past(!rst) && rst |-> + IDLE && + H == H_0 && + W == W_0 && + a == a_0 && + b == a_0 && + c == a_0 && + d == a_0 && + e == a_0 && + f == a_0 && + g == a_0 && + h == a_0 && + i == 'sd0 && + rnd_cnt_reg == 'sd0 && + rh_masking_rnd == H_0 && + block_in_ready == 1 && + digest_valid == 0; +endproperty + + +CTRL_RND_to_CTRL_RND_a: assert property (disable iff(!rst) CTRL_RND_to_CTRL_RND_p); +property CTRL_RND_to_CTRL_RND_p; + CTRL_RND && + (('sd1 + rnd_cnt_reg) < 'sd9) +|-> + ##1 (block_in_ready == 0) and + ##1 (digest_valid == 0) and + ##1 + CTRL_RND && + H == $past(H, 1) && + W == $past(W, 1) && + a == $past(a, 1) && + b == $past(b, 1) && + c == $past(c, 1) && + d == $past(d, 1) && + e == $past(e, 1) && + f == $past(f, 1) && + g == $past(g, 1) && + h == $past(h, 1) && + i == $past(i, 1) && + rnd_cnt_reg == ('sd1 + $past(rnd_cnt_reg, 1)) && + rh_masking_rnd == $past(rh_masking_rnd_0, 1); +endproperty + + +CTRL_RND_to_SHA_Rounds_224_a: assert property (disable iff(!rst) CTRL_RND_to_SHA_Rounds_224_p); +property CTRL_RND_to_SHA_Rounds_224_p; + CTRL_RND && + (('sd1 + rnd_cnt_reg) >= 'sd9) && + block_init && + (block_sha_mode == 'sd0) +|-> + ##1 (block_in_ready == 0) and + ##1 (digest_valid == 0) and + ##1 + SHA_Rounds && + H == $past(H_1, 1) && + W == $past(W_1, 1) && + a == $past(a_1, 1) && + b == $past(b_0, 1) && + c == $past(c_0, 1) && + d == $past(d_0, 1) && + e == $past(e_0, 1) && + f == $past(f_0, 1) && + g == $past(g_0, 1) && + h == $past(h_0, 1) && + i == 'sd0 && + rnd_cnt_reg == ('sd1 + $past(rnd_cnt_reg, 1)) && + rh_masking_rnd == $past(rh_masking_rnd_1, 1); +endproperty + + +CTRL_RND_to_SHA_Rounds_256_a: assert property (disable iff(!rst) CTRL_RND_to_SHA_Rounds_256_p); +property CTRL_RND_to_SHA_Rounds_256_p; + CTRL_RND && + (('sd1 + rnd_cnt_reg) >= 'sd9) && + block_init && + (block_sha_mode == 'sd1) +|-> + ##1 (block_in_ready == 0) and + ##1 (digest_valid == 0) and + ##1 + SHA_Rounds && + H == $past(H_2, 1) && + W == $past(W_1, 1) && + a == $past(a_2, 1) && + b == $past(b_1, 1) && + c == $past(c_1, 1) && + d == $past(d_1, 1) && + e == $past(e_1, 1) && + f == $past(f_1, 1) && + g == $past(g_1, 1) && + h == $past(h_1, 1) && + i == 'sd0 && + rnd_cnt_reg == ('sd1 + $past(rnd_cnt_reg, 1)) && + rh_masking_rnd == $past(rh_masking_rnd_1, 1); +endproperty + + +CTRL_RND_to_SHA_Rounds_512_a: assert property (disable iff(!rst) CTRL_RND_to_SHA_Rounds_512_p); +property CTRL_RND_to_SHA_Rounds_512_p; + CTRL_RND && + (('sd1 + rnd_cnt_reg) >= 'sd9) && + block_init && + (block_sha_mode == 'sd3) +|-> + ##1 (block_in_ready == 0) and + ##1 (digest_valid == 0) and + ##1 + SHA_Rounds && + H == $past(H_3, 1) && + W == $past(W_1, 1) && + a == $past(a_3, 1) && + b == $past(b_2, 1) && + c == $past(c_2, 1) && + d == $past(d_2, 1) && + e == $past(e_2, 1) && + f == $past(f_2, 1) && + g == $past(g_2, 1) && + h == $past(h_2, 1) && + i == 'sd0 && + rnd_cnt_reg == ('sd1 + $past(rnd_cnt_reg, 1)) && + rh_masking_rnd == $past(rh_masking_rnd_1, 1); +endproperty + + +CTRL_RND_to_SHA_Rounds_384_a: assert property (disable iff(!rst) CTRL_RND_to_SHA_Rounds_384_p); +property CTRL_RND_to_SHA_Rounds_384_p; + CTRL_RND && + (('sd1 + rnd_cnt_reg) >= 'sd9) && + block_init && + (block_sha_mode != 'sd0) && + (block_sha_mode != 'sd1) && + (block_sha_mode != 'sd3) +|-> + ##1 (block_in_ready == 0) and + ##1 (digest_valid == 0) and + ##1 + SHA_Rounds && + H == $past(H_4, 1) && + W == $past(W_1, 1) && + a == $past(a_4, 1) && + b == $past(b_3, 1) && + c == $past(c_3, 1) && + d == $past(d_3, 1) && + e == $past(e_3, 1) && + f == $past(f_3, 1) && + g == $past(g_3, 1) && + h == $past(h_3, 1) && + i == 'sd0 && + rnd_cnt_reg == ('sd1 + $past(rnd_cnt_reg, 1)) && + rh_masking_rnd == $past(rh_masking_rnd_1, 1); +endproperty + + +CTRL_RND_to_SHA_Rounds_next_a: assert property (disable iff(!rst) CTRL_RND_to_SHA_Rounds_next_p); +property CTRL_RND_to_SHA_Rounds_next_p; + CTRL_RND && + (('sd1 + rnd_cnt_reg) >= 'sd9) && + !block_init +|-> + ##1 (block_in_ready == 0) and + ##1 (digest_valid == 0) and + ##1 + SHA_Rounds && + H == $past(H, 1) && + W == $past(W_1, 1) && + a == $past(a_5, 1) && + b == $past(b_4, 1) && + c == $past(c_4, 1) && + d == $past(d_4, 1) && + e == $past(e_4, 1) && + f == $past(f_4, 1) && + g == $past(g_4, 1) && + h == $past(h_4, 1) && + i == 'sd0 && + rnd_cnt_reg == ('sd1 + $past(rnd_cnt_reg, 1)) && + rh_masking_rnd == $past(rh_masking_rnd_1, 1); +endproperty + + +DONE_to_IDLE_a: assert property (disable iff(!rst) DONE_to_IDLE_p); +property DONE_to_IDLE_p; + DONE +|-> + ##1 + IDLE && + H == $past(H_5, 1) && + W == $past(W, 1) && + a == $past(a, 1) && + b == $past(b, 1) && + c == $past(c, 1) && + d == $past(d, 1) && + e == $past(e, 1) && + f == $past(f, 1) && + g == $past(g, 1) && + h == $past(h, 1) && + i == $past(i, 1) && + digest_out == $past(compute_digest(H[64'd7], h.masked, h.random, H[64'd6], g.masked, g.random, H[64'd5], f.masked, f.random, H[64'd4], e.masked, e.random, H[64'd3], d.masked, d.random, H[64'd2], c.masked, c.random, H[64'd1], b.masked, b.random, H[64'd0], a.masked, a.random)) && + rnd_cnt_reg == $past(rnd_cnt_reg, 1) && + rh_masking_rnd == $past(rh_masking_rnd, 1) && + block_in_ready == 1 && + digest_valid == 1; +endproperty + + +IDLE_to_CTRL_RND_a: assert property (disable iff(!rst) IDLE_to_CTRL_RND_p); +property IDLE_to_CTRL_RND_p; + IDLE && + block_in_valid +|-> + ##1 (block_in_ready == 0) and + ##1 (digest_valid == 0) and + ##1 + CTRL_RND && + H == $past(H, 1) && + W == $past(W, 1) && + a == $past(a, 1) && + b == $past(b, 1) && + c == $past(c, 1) && + d == $past(d, 1) && + e == $past(e, 1) && + f == $past(f, 1) && + g == $past(g, 1) && + h == $past(h, 1) && + i == $past(i, 1) && + rnd_cnt_reg == 'sd0 && + rh_masking_rnd == $past(rh_masking_rnd, 1); +endproperty + + +SHA_Rounds_to_DONE_a: assert property (disable iff(!rst) SHA_Rounds_to_DONE_p); +property SHA_Rounds_to_DONE_p; + SHA_Rounds && + (i >= 'sd16) && + (('sd1 + i) >= 'sd80) +|-> + ##1 (block_in_ready == 0) and + ##1 (digest_valid == 0) and + ##1 + DONE && + H == $past(H, 1) && + W == $past(W_2, 1) && + a == $past(a_7, 1) && + b == $past(a, 1) && + c == $past(b, 1) && + d == $past(c, 1) && + e == $past(e_6, 1) && + f == $past(e, 1) && + g == $past(f, 1) && + h == $past(g, 1) && + i == ('sd1 + $past(i, 1)) && + rnd_cnt_reg == $past(rnd_cnt_reg, 1) && + rh_masking_rnd == $past(rh_masking_rnd, 1); +endproperty + + +SHA_Rounds_to_SHA_Rounds_before_16_a: assert property (disable iff(!rst) SHA_Rounds_to_SHA_Rounds_before_16_p); +property SHA_Rounds_to_SHA_Rounds_before_16_p; + SHA_Rounds && + (i < 'sd16) && + (('sd1 + i) < 'sd80) +|-> + ##1 (block_in_ready == 0) and + ##1 (digest_valid == 0) and + ##1 + SHA_Rounds && + H == $past(H, 1) && + W == $past(W, 1) && + a == $past(a_6, 1) && + b == $past(a, 1) && + c == $past(b, 1) && + d == $past(c, 1) && + e == $past(e_5, 1) && + f == $past(e, 1) && + g == $past(f, 1) && + h == $past(g, 1) && + i == ('sd1 + $past(i, 1)) && + rnd_cnt_reg == $past(rnd_cnt_reg, 1) && + rh_masking_rnd == $past(rh_masking_rnd, 1); +endproperty + + +SHA_Rounds_to_SHA_Rounds_after_16_a: assert property (disable iff(!rst) SHA_Rounds_to_SHA_Rounds_after_16_p); +property SHA_Rounds_to_SHA_Rounds_after_16_p; + SHA_Rounds && + (i >= 'sd16) && + (('sd1 + i) < 'sd80) +|-> + ##1 (block_in_ready == 0) and + ##1 (digest_valid == 0) and + ##1 + SHA_Rounds && + H == $past(H, 1) && + W == $past(W_2, 1) && + a == $past(a_7, 1) && + b == $past(a, 1) && + c == $past(b, 1) && + d == $past(c, 1) && + e == $past(e_6, 1) && + f == $past(e, 1) && + g == $past(f, 1) && + h == $past(g, 1) && + i == ('sd1 + $past(i, 1)) && + rnd_cnt_reg == $past(rnd_cnt_reg, 1) && + rh_masking_rnd == $past(rh_masking_rnd, 1); +endproperty + + +IDLE_wait_a: assert property (disable iff(!rst) IDLE_wait_p); +property IDLE_wait_p; + IDLE && + !block_in_valid +|-> + ##1 + IDLE && + H == $past(H, 1) && + W == $past(W, 1) && + a == $past(a, 1) && + b == $past(b, 1) && + c == $past(c, 1) && + d == $past(d, 1) && + e == $past(e, 1) && + f == $past(f, 1) && + g == $past(g, 1) && + h == $past(h, 1) && + i == $past(i, 1) && + rnd_cnt_reg == $past(rnd_cnt_reg, 1) && + rh_masking_rnd == $past(rh_masking_rnd, 1) && + block_in_ready == 1 && + digest_valid == $past(digest_valid); +endproperty + + +endmodule + + +module fv_SHA512_masked_wrapper_m; + + +default clocking default_clk @(posedge (sha512_masked_core.clk)); endclocking + + +st_SHA_Args sha_in_struct = '{ + in: (sha512_masked_core.block_msg), + SHA_Mode: (sha512_masked_core.mode), + init_cmd: (sha512_masked_core.init_cmd), + next_cmd: (sha512_masked_core.next_cmd), + zeroize: (sha512_masked_core.zeroize) +}; +a_sc_big_unsigned_64_8 H = '{ + 0: (sha512_masked_core.H0_reg), + 1: (sha512_masked_core.H1_reg), + 2: (sha512_masked_core.H2_reg), + 3: (sha512_masked_core.H3_reg), + 4: (sha512_masked_core.H4_reg), + 5: (sha512_masked_core.H5_reg), + 6: (sha512_masked_core.H6_reg), + 7: (sha512_masked_core.H7_reg) +}; +a_sc_big_unsigned_64_16 W = '{ + 0: (sha512_masked_core.w_mem_inst.w_mem[00]), + 1: (sha512_masked_core.w_mem_inst.w_mem[01]), + 2: (sha512_masked_core.w_mem_inst.w_mem[02]), + 3: (sha512_masked_core.w_mem_inst.w_mem[03]), + 4: (sha512_masked_core.w_mem_inst.w_mem[04]), + 5: (sha512_masked_core.w_mem_inst.w_mem[05]), + 6: (sha512_masked_core.w_mem_inst.w_mem[06]), + 7: (sha512_masked_core.w_mem_inst.w_mem[07]), + 8: (sha512_masked_core.w_mem_inst.w_mem[08]), + 9: (sha512_masked_core.w_mem_inst.w_mem[09]), + 10: (sha512_masked_core.w_mem_inst.w_mem[10]), + 11: (sha512_masked_core.w_mem_inst.w_mem[11]), + 12: (sha512_masked_core.w_mem_inst.w_mem[12]), + 13: (sha512_masked_core.w_mem_inst.w_mem[13]), + 14: (sha512_masked_core.w_mem_inst.w_mem[14]), + 15: (sha512_masked_core.w_mem_inst.w_mem[15]) +}; +st_masked_reg_t a = '{ + masked: (sha512_masked_core.a_reg.masked), + random: (sha512_masked_core.a_reg.random) +}; +st_masked_reg_t b = '{ + masked: (sha512_masked_core.b_reg.masked), + random: (sha512_masked_core.b_reg.random) +}; +st_masked_reg_t c = '{ + masked: (sha512_masked_core.c_reg.masked), + random: (sha512_masked_core.c_reg.random) +}; +st_masked_reg_t d = '{ + masked: (sha512_masked_core.d_reg.masked), + random: (sha512_masked_core.d_reg.random) +}; +st_masked_reg_t e = '{ + masked: (sha512_masked_core.e_reg.masked), + random: (sha512_masked_core.e_reg.random) +}; +st_masked_reg_t f = '{ + masked: (sha512_masked_core.f_reg.masked), + random: (sha512_masked_core.f_reg.random) +}; +st_masked_reg_t g = '{ + masked: (sha512_masked_core.g_reg.masked), + random: (sha512_masked_core.g_reg.random) +}; +st_masked_reg_t h = '{ + masked: (sha512_masked_core.h_reg.masked), + random: (sha512_masked_core.h_reg.random) +}; +a_sc_big_unsigned_64_8 rh_masking_rnd = '{ + 0: (sha512_masked_core.rh_masking_rnd[0]), + 1: (sha512_masked_core.rh_masking_rnd[1]), + 2: (sha512_masked_core.rh_masking_rnd[2]), + 3: (sha512_masked_core.rh_masking_rnd[3]), + 4: (sha512_masked_core.rh_masking_rnd[4]), + 5: (sha512_masked_core.rh_masking_rnd[5]), + 6: (sha512_masked_core.rh_masking_rnd[6]), + 7: (sha512_masked_core.rh_masking_rnd[7]) +}; + + +fv_sha512_masked_m fv_sha512_masked( + .rst((sha512_masked_core.reset_n) && !(sha512_masked_core.zeroize)), + .clk(sha512_masked_core.clk), + + // Inputs + .sha_in_struct(sha_in_struct), + .lfsr_in(sha512_masked_core.lfsr_inst.rnd), + + // Outputs + .digest_out(sha512_masked_core.digest), + + // Valid signals + .block_in_valid(((sha512_masked_core.init_cmd) || (sha512_masked_core.next_cmd))), + .digest_valid(sha512_masked_core.digest_valid), + + // Ready signals + .block_in_ready(sha512_masked_core.ready), + + // Registers + .H(H), + .block_sha_mode(sha512_masked_core.mode), + .W(W), + .a(a), + .b(b), + .block_in(sha512_masked_core.block_msg), + .c(c), + .d(d), + .e(e), + .f(f), + .g(g), + .h(h), + .i(sha512_masked_core.round_ctr_reg), + .block_init(sha512_masked_core.init_reg), + .lfsr_rnd(sha512_masked_core.lfsr_rnd), + .rnd_cnt_reg(sha512_masked_core.rnd_ctr_reg), + .rh_masking_rnd(rh_masking_rnd), + + // States + .IDLE(sha512_masked_core.sha512_ctrl_reg==2'h0), + .CTRL_RND(sha512_masked_core.sha512_ctrl_reg==2'h1), + .SHA_Rounds(sha512_masked_core.sha512_ctrl_reg==2'h2), + .DONE(sha512_masked_core.sha512_ctrl_reg==2'h3) +); + + +endmodule + + +bind sha512_masked_core fv_SHA512_masked_wrapper_m fv_SHA512_masked_wrapper(); diff --git a/src/sha512_masked/formal/properties/fv_sha512_masked_pkg.sv b/src/sha512_masked/formal/properties/fv_sha512_masked_pkg.sv new file mode 100644 index 000000000..9479c5ebc --- /dev/null +++ b/src/sha512_masked/formal/properties/fv_sha512_masked_pkg.sv @@ -0,0 +1,197 @@ +// ------------------------------------------------- +// Contact: contact@lubis-eda.com +// Author: Tobias Ludwig, Michael Schwarz +// ------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package sha512_masked_pkg; + + +typedef struct { + bit unsigned [1023:0] in; + bit signed [31:0] SHA_Mode; + bit init_cmd; + bit next_cmd; + bit zeroize; +} st_SHA_Args; + +typedef struct { + bit unsigned [63:0] masked; + bit unsigned [63:0] random; +} st_masked_reg_t; + +typedef bit a_bool_10 [9:0]; + +typedef bit unsigned [63:0] a_sc_big_unsigned_64_16 [15:0]; + +typedef bit unsigned [63:0] a_sc_big_unsigned_64_8 [7:0]; + +typedef bit unsigned [63:0] a_sc_big_unsigned_64_80 [79:0]; + + +// Constants + +parameter a_sc_big_unsigned_64_80 K = '{ 0: 64'h428A2F98D728AE22, 1: 64'h7137449123EF65CD, 2: 64'hB5C0FBCFEC4D3B2F, 3: 64'hE9B5DBA58189DBBC, 4: 64'h3956C25BF348B538, 5: 64'h59F111F1B605D019, 6: 64'h923F82A4AF194F9B, 7: 64'hAB1C5ED5DA6D8118, 8: 64'hD807AA98A3030242, 9: 64'h12835B0145706FBE, 10: 64'h243185BE4EE4B28C, 11: 64'h550C7DC3D5FFB4E2, 12: 64'h72BE5D74F27B896F, 13: 64'h80DEB1FE3B1696B1, 14: 64'h9BDC06A725C71235, 15: 64'hC19BF174CF692694, 16: 64'hE49B69C19EF14AD2, 17: 64'hEFBE4786384F25E3, 18: 64'hFC19DC68B8CD5B5, 19: 64'h240CA1CC77AC9C65, 20: 64'h2DE92C6F592B0275, 21: 64'h4A7484AA6EA6E483, 22: 64'h5CB0A9DCBD41FBD4, 23: 64'h76F988DA831153B5, 24: 64'h983E5152EE66DFAB, 25: 64'hA831C66D2DB43210, 26: 64'hB00327C898FB213F, 27: 64'hBF597FC7BEEF0EE4, 28: 64'hC6E00BF33DA88FC2, 29: 64'hD5A79147930AA725, 30: 64'h6CA6351E003826F, 31: 64'h142929670A0E6E70, 32: 64'h27B70A8546D22FFC, 33: 64'h2E1B21385C26C926, 34: 64'h4D2C6DFC5AC42AED, 35: 64'h53380D139D95B3DF, 36: 64'h650A73548BAF63DE, 37: 64'h766A0ABB3C77B2A8, 38: 64'h81C2C92E47EDAEE6, 39: 64'h92722C851482353B, 40: 64'hA2BFE8A14CF10364, 41: 64'hA81A664BBC423001, 42: 64'hC24B8B70D0F89791, 43: 64'hC76C51A30654BE30, 44: 64'hD192E819D6EF5218, 45: 64'hD69906245565A910, 46: 64'hF40E35855771202A, 47: 64'h106AA07032BBD1B8, 48: 64'h19A4C116B8D2D0C8, 49: 64'h1E376C085141AB53, 50: 64'h2748774CDF8EEB99, 51: 64'h34B0BCB5E19B48A8, 52: 64'h391C0CB3C5C95A63, 53: 64'h4ED8AA4AE3418ACB, 54: 64'h5B9CCA4F7763E373, 55: 64'h682E6FF3D6B2B8A3, 56: 64'h748F82EE5DEFB2FC, 57: 64'h78A5636F43172F60, 58: 64'h84C87814A1F0AB72, 59: 64'h8CC702081A6439EC, 60: 64'h90BEFFFA23631E28, 61: 64'hA4506CEBDE82BDE9, 62: 64'hBEF9A3F7B2C67915, 63: 64'hC67178F2E372532B, 64: 64'hCA273ECEEA26619C, 65: 64'hD186B8C721C0C207, 66: 64'hEADA7DD6CDE0EB1E, 67: 64'hF57D4F7FEE6ED178, 68: 64'h6F067AA72176FBA, 69: 64'hA637DC5A2C898A6, 70: 64'h113F9804BEF90DAE, 71: 64'h1B710B35131C471B, 72: 64'h28DB77F523047D84, 73: 64'h32CAAB7B40C72493, 74: 64'h3C9EBE0A15C9BEBC, 75: 64'h431D67C49C100D4C, 76: 64'h4CC5D4BECB3E42B6, 77: 64'h597F299CFC657E2A, 78: 64'h5FCB6FAB3AD6FAEC, 79: 64'h6C44198C4A475817 }; + + +// Functions + +function bit unsigned [63:0] A2B_conv(bit unsigned [63:0] x_masked, bit unsigned [63:0] x_random, bit q, bit masked_carr, bit unsigned [127:0] x_m, bit unsigned [63:0] mask, bit signed [31:0] j); + + reg [63 : 0] masked_carry; + for (int j = 0; j < 64 ; j++) begin + if (j == 0) begin + masked_carry[j] = (~x_masked[0] & x_random[0]) ^ q; + x_masked[j] = x_masked[j]; + end + else begin + masked_carry[j] = (x_masked[j] ^ x_random[j]) & (x_random[j] ^ q) | (~x_masked[j] ^ x_random[j]) & masked_carry[j-1]; + x_masked[j] = (x_masked[j] ^ masked_carry[j-1]) ^ q; + + end + end + return x_masked; +endfunction + +function bit unsigned [63:0] B2A_conv(bit unsigned [63:0] x_masked, bit unsigned [63:0] x_random, bit q, bit masked_carr, bit unsigned [127:0] x_prime, bit unsigned [63:0] mask, bit signed [31:0] j); +reg [63 : 0] masked_carry; + for (int j = 0; j < 64 ; j++) begin + if (j == 0) begin + masked_carry[j] = ~x_masked[j] & (x_random[j] ^ q) | (x_masked[j] & q); + x_prime[j] = x_masked[j]; + end + else begin + x_prime[j] = (x_masked[j] ^ masked_carry[j-1]) ^ q; + masked_carry[j] = ~x_masked[j] & (x_random[j] ^ q) | x_masked[j] & masked_carry[j-1]; + end + end + return x_prime; +endfunction + +function bit unsigned [63:0] T1_m(bit unsigned [63:0] e_masked, bit unsigned [63:0] e_random, bit unsigned [63:0] f_masked, bit unsigned [63:0] f_random, bit unsigned [63:0] g_masked, bit unsigned [63:0] g_random, bit unsigned [63:0] h_masked, bit unsigned [63:0] h_random, bit unsigned [63:0] k, bit unsigned [63:0] w_masked, bit unsigned [63:0] w_random, bit masked_carry, bit unsigned [127:0] x_prime, bit unsigned [63:0] mask, bit q_masking_rnd_0, bit q_masking_rnd_1, bit q_masking_rnd_2, bit q_masking_rnd_3, bit q_masking_rnd_4, bit signed [31:0] j); + return 64'(((((B2A_conv(h_masked, h_random, q_masking_rnd_0, masked_carry, x_prime, mask, j) + B2A_conv(sigma1(e_masked), sigma1(e_random), q_masking_rnd_1, masked_carry, x_prime, mask, j)) + B2A_conv(masked_Ch_m(e_masked, e_random, f_masked, f_random, g_masked, g_random), (e_random ^ g_random), q_masking_rnd_2, masked_carry, x_prime, mask, j)) + B2A_conv(k, 64'h0, q_masking_rnd_3, masked_carry, x_prime, mask, j)) + B2A_conv(w_masked, w_random, q_masking_rnd_4, masked_carry, x_prime, mask, j))); +endfunction + +function bit unsigned [63:0] T1_r(bit unsigned [63:0] e_random, bit unsigned [63:0] g_random, bit unsigned [63:0] h_random, bit unsigned [63:0] w_random); + return 64'((((h_random + sigma1(e_random)) + (e_random ^ g_random)) + w_random)); +endfunction + +function bit unsigned [63:0] T2_m(bit unsigned [63:0] a_masked, bit unsigned [63:0] a_random, bit unsigned [63:0] b_masked, bit unsigned [63:0] b_random, bit unsigned [63:0] c_masked, bit unsigned [63:0] c_random, bit masked_carry, bit unsigned [127:0] x_prime, bit unsigned [63:0] mask, bit q_masking_rnd_5, bit q_masking_rnd_6, bit signed [31:0] j); + return 64'((B2A_conv(sigma0(a_masked), sigma0(a_random), q_masking_rnd_5, masked_carry, x_prime, mask, j) + B2A_conv(masked_Maj(a_masked, a_random, b_masked, b_random, c_masked, c_random), b_random, q_masking_rnd_6, masked_carry, x_prime, mask, j))); +endfunction + +function bit unsigned [63:0] T2_r(bit unsigned [63:0] a_random, bit unsigned [63:0] b_random); + return 64'((sigma0(a_random) + b_random)); +endfunction + +function bit unsigned [63:0] compute_w(bit unsigned [63:0] w14, bit unsigned [63:0] w9, bit unsigned [63:0] w1, bit unsigned [63:0] w0); + return 64'((((delta1(w14) + w9) + delta0(w1)) + w0)); +endfunction + +function bit unsigned [63:0] delta0(bit unsigned [63:0] x); + return ((rotr1(x) ^ rotr8(x)) ^ shr7(x)); +endfunction + +function bit unsigned [63:0] delta1(bit unsigned [63:0] x); + return ((rotr19(x) ^ rotr61(x)) ^ shr6(x)); +endfunction + +function bit unsigned [63:0] masked_Ch_m(bit unsigned [63:0] e_masked, bit unsigned [63:0] e_random, bit unsigned [63:0] f_masked, bit unsigned [63:0] f_random, bit unsigned [63:0] g_masked, bit unsigned [63:0] g_random); + return (masked_and(e_masked, e_random, f_masked, f_random) ^ masked_and(g_masked, g_random, ~e_masked, e_random)); +endfunction + +function bit unsigned [63:0] masked_Maj(bit unsigned [63:0] a_masked, bit unsigned [63:0] a_random, bit unsigned [63:0] b_masked, bit unsigned [63:0] b_random, bit unsigned [63:0] c_masked, bit unsigned [63:0] c_random); + return ((masked_and(a_masked, a_random, b_masked, b_random) ^ masked_and(a_masked, a_random, c_masked, c_random)) ^ masked_and(b_masked, b_random, c_masked, c_random)); +endfunction + +function bit unsigned [63:0] masked_and(bit unsigned [63:0] x_masked, bit unsigned [63:0] x_random, bit unsigned [63:0] y_masked, bit unsigned [63:0] y_random); + return ((~y_masked & ((~y_random & x_random) | (y_random & x_masked))) | (y_masked & ((y_random & x_random) | (~y_random & x_masked)))); +endfunction + +function bit unsigned [63:0] rotr1(bit unsigned [63:0] n); + return 64'(((n >> 64'd1) | (n << 64'd63))); +endfunction + +function bit unsigned [63:0] rotr14(bit unsigned [63:0] n); + return 64'(((n >> 64'd14) | (n << 64'd50))); +endfunction + +function bit unsigned [63:0] rotr18(bit unsigned [63:0] n); + return 64'(((n >> 64'd18) | (n << 64'd46))); +endfunction + +function bit unsigned [63:0] rotr19(bit unsigned [63:0] n); + return 64'(((n >> 64'd19) | (n << 64'd45))); +endfunction + +function bit unsigned [63:0] rotr28(bit unsigned [63:0] n); + return 64'(((n >> 64'd28) | (n << 64'd36))); +endfunction + +function bit unsigned [63:0] rotr34(bit unsigned [63:0] n); + return 64'(((n >> 64'd34) | (n << 64'd30))); +endfunction + +function bit unsigned [63:0] rotr39(bit unsigned [63:0] n); + return 64'(((n >> 64'd39) | (n << 64'd25))); +endfunction + +function bit unsigned [63:0] rotr41(bit unsigned [63:0] n); + return 64'(((n >> 64'd41) | (n << 64'd23))); +endfunction + +function bit unsigned [63:0] rotr61(bit unsigned [63:0] n); + return 64'(((n >> 64'd61) | (n << 64'd3))); +endfunction + +function bit unsigned [63:0] rotr8(bit unsigned [63:0] n); + return 64'(((n >> 64'd8) | (n << 64'd56))); +endfunction + +function bit unsigned [63:0] shr6(bit unsigned [63:0] n); + return (n >> 64'd6); +endfunction + +function bit unsigned [63:0] shr7(bit unsigned [63:0] n); + return (n >> 64'd7); +endfunction + +function bit unsigned [63:0] sigma0(bit unsigned [63:0] x); + return ((rotr28(x) ^ rotr34(x)) ^ rotr39(x)); +endfunction + +function bit unsigned [63:0] sigma1(bit unsigned [63:0] x); + return ((rotr14(x) ^ rotr18(x)) ^ rotr41(x)); +endfunction + +function bit unsigned [63:0] slicer(bit unsigned [1023:0] block, bit signed [31:0] index); + return(block[(64*index)+:64]); +endfunction + +function bit unsigned [511:0] compute_digest(bit unsigned [63:0] H_7, bit unsigned [63:0] h_random , bit unsigned [63:0] h_masked, bit unsigned [63:0] H_6, bit unsigned [63:0] g_random , bit unsigned [63:0] g_masked, bit unsigned [63:0] H_5, bit unsigned [63:0] f_random , bit unsigned [63:0] f_masked, bit unsigned [63:0] H_4, bit unsigned [63:0] e_random , bit unsigned [63:0] e_masked, bit unsigned [63:0] H_3, bit unsigned [63:0] d_random , bit unsigned [63:0] d_masked, bit unsigned [63:0] H_2, bit unsigned [63:0] c_random , bit unsigned [63:0] c_masked, bit unsigned [63:0] H_1, bit unsigned [63:0] b_random , bit unsigned [63:0] b_masked, bit unsigned [63:0] H_0, bit unsigned [63:0] a_random , bit unsigned [63:0] a_masked); + bit unsigned [511:0] temp; + temp[63:0] = 64'(H_7 + (h_masked ^ h_random)); + temp[127:64] = 64'(H_6 + (g_masked ^ g_random)); + temp[191:128] = 64'(H_5 + (f_masked ^ f_random)); + temp[255:192] = 64'(H_4 + (e_masked ^ e_random)); + temp[319:256] = 64'(H_3 + (d_masked ^ d_random)); + temp[383:320] = 64'(H_2 + (c_masked ^ c_random)); + temp[447:384] = 64'(H_1 + (b_masked ^ b_random)); + temp[511:448] = 64'(H_0 + (a_masked ^ a_random)); + return temp; + endfunction + +endpackage diff --git a/src/sha512_masked/formal/readme.md b/src/sha512_masked/formal/readme.md new file mode 100644 index 000000000..0a23239e2 --- /dev/null +++ b/src/sha512_masked/formal/readme.md @@ -0,0 +1,64 @@ +# SHA512_MASKED +Date: 28-06-2023 +Author: LUBIS EDA + +## Folder Structure +The following subdirectories are part of the main directory **formal** + +- properties: Contains the assertion IP(AIP) named as **fv_sha512_masked.sv** and the constraints in place for the respective AIP **fv_constraints.sv** + + +## DUT Overview + +The DUT sha512_core has the primary inputs and primary outputs as shown below. + +| S.No | Port | Direction | Description | +| ---- | -------------------| --------- | --------------------------------------------------------------------------------- | +| 1 | clk | input | The positive edge of the clk is used for all the signals | +| 2 | reset_n | input | The reset signal is active low and resets the core | +| 3 | zeroize | input | The core is reseted when this signal is triggered. | +| 4 | init_cmd | input | The core is initialised with respective mode constants and processes the message. | +| 5 | next_cmd | input | The core processes the message block with the previously computed results | +| 6 | mode[1:0] | input | Define which hash function: SHA512,SHA384,SHA224,SHA256 | +| 7 | block_msg[1023:0] | input | The padded block message | +| 8 | lfsr_seed[73:0] | input | random bit vectors that are left shifted and rotated | +| 9 | ready | output | When triggered indicates that the core is ready | +| 10 | digest[511:0] | output | The hashed value of the given message block | +| 11 | digest_valid | output | When triggered indicates that the computed digest is ready | + +When the respective mode is selected and initalised the core iterates for 80 rounds to process the hash value with random lfsr seed value so as a countermeasure for single channel side-attacks. if the next is triggered then the previous values of the **H** registers are in place for processing the hash value. The digest is always generated of 512 bits, in which if the mode changes to 384 then from MSB 384 bits is a valid output and rest is garbage value. +## Assertion IP Overview + +The Assertion IP signals are bound with the respective signals in the dut, where for the **rst** in binded with the DUT (reset_n && !zeroize), which ensures the reset functionality. And another AIP signal block_in_valid is triggered whenever the init or next is high. + +- reset_a: Checks that all the resgiters are resetted and the state is idle, with the ready to high. + +- DONE_to_IDLE_a: Checks the necessary registers, outputs holds the values when state transits from Done to idle. + +- IDLE_to_CTRL_RND_a: Checks if the state is in idle, if there is an init_cmd or next_cmd, state transists to CTRL_RND and checks if the state registers are unchanged and round counter remains zero. + +- CTRL_RND_TO_CTRL_RND: State transition remains CTRL_RND as long as the round_counter values is less than 9 and checks the necessary registers, masking register holds corrcet value. + +- CTRL_RND_to_SHA_Rounds_224_a: Checks if the state is in ctrl_rnd ,the mode choosen as 224,the init is triggered then the registers should be initialised with the respective constants of 224. + +- CTRL_RND_to_SHA_Rounds_256_a: Checks if the state is in ctrl_rnd ,the mode choosen as 256,the init is triggered then the registers should be initialised with the respective constants of 256. + +- CTRL_RND_to_SHA_Rounds_512_a: Checks if the state is in ctrl_rnd ,the mode choosen as 512,the init is triggered then the registers should be initialised with the respective constants of 512. + +- CTRL_RND_to_SHA_Rounds_384_a: Checks if the state is in ctrl_rnd ,the mode choosen is neither 512,256 nor 224,the init is triggered then the registers should be initialised with the respective constants of default, which covers 384 mode also. + +- CTRL_RND_to_SHA_Rounds_next_a: Checks if the state is in ctrl_rnd and there is no init signal and the next signal asserts then the register holds the past values. + +- SHA_Rounds_to_DONE_a: Checks if the rounds are done then the registers are updated correctly. + +- SHA_Rounds_to_SHA_Rounds_before_16_a: Checks if the the rounds less than 16 then the necessary registers are updated correctly and the round increments. + +- SHA_Rounds_to_SHA_Rounds_after_16_a: Checks if the rounds are greater than 16 and less than 80 then the respective registers are updated correctly and the round increments. + +- IDLE_wait_a: Checks if there isn't either init or next signal triggered in idle state then the state stays in idle and holds the past values and the core is ready. + + +## Reproduce results +For reproducing the results: Load the AIP, sha512_masked_core and fv_constraints together in your formal tool. + +Feel free to reach out to contact@lubis-eda.com to request the loadscripts. diff --git a/src/soc_ifc/config/compile.yml b/src/soc_ifc/config/compile.yml index 203ddb636..85cdd473b 100644 --- a/src/soc_ifc/config/compile.yml +++ b/src/soc_ifc/config/compile.yml @@ -74,7 +74,7 @@ targets: - soc_ifc_reg - soc_ifc_reg_pkg waiver_files: - - $COMPILE_ROOT/config/design_lint/soc_ifc/sglint_waivers + - $MSFT_REPO_ROOT/src/soc_ifc/config/design_lint/soc_ifc/sglint_waivers black_box: - sha512_acc_csr - mbox_csr diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/bringup/cptra/soc_ifc_env_cptra_rst_wait_sequence.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/bringup/cptra/soc_ifc_env_cptra_rst_wait_sequence.svh index b2efda83d..118ff593d 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/bringup/cptra/soc_ifc_env_cptra_rst_wait_sequence.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/bringup/cptra/soc_ifc_env_cptra_rst_wait_sequence.svh @@ -76,7 +76,12 @@ class soc_ifc_env_cptra_rst_wait_sequence extends soc_ifc_env_sequence_base #(.C core_rst_asserted = cptra_status_agent_rsp_seq.rsp.uc_rst_asserted; sts_rsp_count--; if (!noncore_rst_asserted || !core_rst_asserted) - `uvm_error("CPTRA_RESET_WAIT", "Unexpected status transition, with noncore/core resets deasserted, while waiting for noncore reset to assert") + // This might be an error, but the delay from cptra_rst_b -> cptra_noncore_rst_b + // means that some additional activity might complete before the noncore rst asserts. + // That activity might be legal, so this is an INFO and not an ERROR. + // soc_ifc_predictor is responsible for detecting invalid activity during a + // reset condition. + `uvm_info("CPTRA_RESET_WAIT", "Unexpected status transition, with noncore/core resets deasserted, while waiting for noncore reset to assert!", UVM_LOW) else `uvm_info("CPTRA_RESET_WAIT", "Detected Caliptra noncore reset assertion", UVM_LOW) end diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/cptra/soc_ifc_env_cptra_mbox_handler_sequence.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/cptra/soc_ifc_env_cptra_mbox_handler_sequence.svh index 028f82379..40a8ca6c3 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/cptra/soc_ifc_env_cptra_mbox_handler_sequence.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/cptra/soc_ifc_env_cptra_mbox_handler_sequence.svh @@ -370,6 +370,7 @@ task soc_ifc_env_cptra_mbox_handler_sequence::mbox_wait_and_force_unlock(); // unlock causes this routine to break while(!inject_force_unlock) begin if (err_rsp_count > 0 && cptra_status_agent_rsp_seq.rsp.soc_ifc_err_intr_pending) begin + unlock_proc_active = 1'b1; `uvm_info("CPTRA_MBOX_HANDLER", "Received soc_ifc_err_intr, clearing and (if needed) proceeding to mbox_unlock", UVM_MEDIUM) // Read and clear any error interrupts reg_model.soc_ifc_reg_rm.intr_block_rf_ext.error_internal_intr_r.read(reg_sts, data, UVM_FRONTDOOR, reg_model.soc_ifc_AHB_map, this); @@ -380,6 +381,7 @@ task soc_ifc_env_cptra_mbox_handler_sequence::mbox_wait_and_force_unlock(); err_rsp_count = 0; // Next, check if we need to proceed to mbox_unlock step if (!data[reg_model.soc_ifc_reg_rm.intr_block_rf_ext.error_internal_intr_r.error_cmd_fail_sts.get_lsb_pos()]) begin + unlock_proc_active = 1'b0; continue; end reg_model.mbox_csr_rm.mbox_status.read(reg_sts, data, UVM_FRONTDOOR, reg_model.soc_ifc_AHB_map, this); @@ -390,6 +392,7 @@ task soc_ifc_env_cptra_mbox_handler_sequence::mbox_wait_and_force_unlock(); `uvm_info("CPTRA_MBOX_HANDLER", "After servicing soc_ifc_err_intr, proceeding with mbox_unlock", UVM_MEDIUM) break; end + unlock_proc_active = 1'b0; end configuration.soc_ifc_ctrl_agent_config.wait_for_num_clocks(10/*TODO rand delays*/); end diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_rand_medium_interference_sequence.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_rand_medium_interference_sequence.svh index 058454ca9..0f3f699fe 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_rand_medium_interference_sequence.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_rand_medium_interference_sequence.svh @@ -94,7 +94,7 @@ task soc_ifc_env_mbox_rand_medium_interference_sequence::mbox_poll_status(); end end else if (sts == CMD_FAILURE) begin - `uvm_error("MBOX_SEQ", $sformatf("Received unexpected mailbox status %p", sts)) + `uvm_error("MBOX_SEQ", $sformatf("Received mailbox status %p unexpectedly, since no error is anticipated for this sequence", sts)) end else if (sts == CMD_COMPLETE) begin if (mbox_resp_expected_dlen != 0) diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_rand_pauser_sequence.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_rand_pauser_sequence.svh index e1bbe05c9..496b74b1c 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_rand_pauser_sequence.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_rand_pauser_sequence.svh @@ -38,6 +38,7 @@ class soc_ifc_env_mbox_rand_pauser_sequence extends soc_ifc_env_mbox_sequence_ba function new(string name = "" ); super.new(name); + this.mbox_sts_exp_error = 1; endfunction endclass diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_reg_axs_invalid_sequence.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_reg_axs_invalid_sequence.svh index 2cde1d81f..0a99d3eeb 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_reg_axs_invalid_sequence.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_reg_axs_invalid_sequence.svh @@ -37,6 +37,7 @@ class soc_ifc_env_mbox_reg_axs_invalid_sequence extends soc_ifc_env_mbox_sequenc function new(string name = "" ); super.new(name); + this.mbox_sts_exp_error = 1; endfunction //========================================== diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_sequence_base.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_sequence_base.svh index ceaee7f2a..acc5f8bce 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_sequence_base.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_sequence_base.svh @@ -41,6 +41,8 @@ class soc_ifc_env_mbox_sequence_base extends soc_ifc_env_sequence_base #(.CONFIG uvm_event in_report_reg_sts; rand bit do_apb_lock_check; rand bit retry_failed_reg_axs; + bit mbox_sts_exp_error = 0; // Indicates this sequence will inject an error, which should manifest as a CMD_FAILURE response status + // TODO make this more comprehensive/intelligent about randomized error injection typedef enum byte { DLY_ZERO, @@ -563,11 +565,11 @@ task soc_ifc_env_mbox_sequence_base::mbox_poll_status(); end end else if (data == CMD_FAILURE) begin - if (sts_rsp_count > 0 && soc_ifc_status_agent_rsp_seq.rsp.cptra_error_non_fatal_intr_pending) begin + if (sts_rsp_count > 0 && soc_ifc_status_agent_rsp_seq.rsp.cptra_error_non_fatal_intr_pending && mbox_sts_exp_error) begin `uvm_info("MBOX_SEQ", $sformatf("Unexpected mailbox status [%p] likely is the result of a spurious reg access injection specifically intended to cause a protocol violation or a mailbox SRAM double bit flip", data), UVM_HIGH) end else begin - `uvm_error("MBOX_SEQ", $sformatf("Received mailbox status %p unexpectedly, since there is no pending non_fatal error interrupt", data)) + `uvm_error("MBOX_SEQ", $sformatf("Received mailbox status %p unexpectedly, since there is no pending non_fatal error interrupt (or error injection was unexpected)", data)) end end else if (data == CMD_COMPLETE) begin @@ -610,6 +612,8 @@ task soc_ifc_env_mbox_sequence_base::mbox_clr_execute(); `uvm_error("MBOX_SEQ", "Unexpected error on read from CPTRA_HW_ERROR_NON_FATAL") end if (|err) begin + if (!mbox_sts_exp_error) + `uvm_error("MBOX_SEQ", "Observed error in CPTRA_HW_ERROR_NON_FATAL unexpectedly, since sequence was not anticipating mailbox ECC errors or protocol violations") `uvm_info("MBOX_SEQ", "Detected non-fatal errors at end of mailbox flow. Clearing.", UVM_LOW) reg_model.soc_ifc_reg_rm.CPTRA_HW_ERROR_NON_FATAL.write(reg_sts, err, UVM_FRONTDOOR, reg_model.soc_ifc_APB_map, this, .extension(get_rand_user(500))); if (reg_sts != UVM_IS_OK) begin @@ -686,6 +690,13 @@ endfunction // A legal addr_user is defined as: // - A random selection from valid_users if the mbox_lock has yet to be acquired // - The value in mbox_user if mbox_lock has been acquired already +// NOTE: In the context of this function, the term 'valid' is overloaded. +// mbox_valid_users contains the list of 'allowed' agent PAUSER values +// that have access to issue commands to the mailbox. +// Once the mailbox is locked, the only PAUSER value that is actually +// considered "valid" is the value that was locked - other entries from +// mbox_valid_users are not legal and will trigger protocol violations. +// This function uses the more restrictive definition to evaluate constraints. //========================================== function caliptra_apb_user soc_ifc_env_mbox_sequence_base::get_rand_user(int unsigned invalid_prob = FORCE_VALID_PAUSER); apb_user_obj = new(); @@ -699,7 +710,15 @@ function caliptra_apb_user soc_ifc_env_mbox_sequence_base::get_rand_user(int uns else (addr_user inside {mbox_valid_users}) dist {1 :/ 1000, - 0 :/ invalid_prob}; }) + 0 :/ invalid_prob}; + // When randomizing to a non-valid USER value after + // PAUSER has been locked, make the assigned USER value + // equally likely to be from the allowed agents as it is + // to be some totally random (non-allowed) value + if (pauser_locked.locked) + (addr_user inside {mbox_valid_users}) dist + {1 :/ 1, + 0 :/ 1}; }) `uvm_error("MBOX_SEQ", "Failed to randomize APB PAUSER override value") else `uvm_info("MBOX_SEQ", $sformatf("Randomized APB PAUSER override value to 0x%x", this.apb_user_obj.addr_user), UVM_HIGH) diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_sram_double_bit_flip_sequence.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_sram_double_bit_flip_sequence.svh index 22f0a3134..e9e9f013e 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_sram_double_bit_flip_sequence.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc/soc_ifc_env_mbox_sram_double_bit_flip_sequence.svh @@ -45,6 +45,7 @@ class soc_ifc_env_mbox_sram_double_bit_flip_sequence extends soc_ifc_env_mbox_se function new(string name = "" ); super.new(name); + this.mbox_sts_exp_error = 1; endfunction //========================================== diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc_env_top_mbox_rand_medium_unlock_sequence.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc_env_top_mbox_rand_medium_unlock_sequence.svh index 299e1d929..10ec8b8a7 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc_env_top_mbox_rand_medium_unlock_sequence.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/sequences/mbox/soc_ifc_env_top_mbox_rand_medium_unlock_sequence.svh @@ -46,6 +46,7 @@ endfunction function soc_ifc_env_top_mbox_rand_medium_unlock_sequence::randomize_seqs(); if(!soc_ifc_env_mbox_seq.randomize()) `uvm_fatal("SOC_IFC_MBOX_TOP", $sformatf("soc_ifc_env_top_mbox_rand_medium_unlock_sequence::body() - %s randomization failed", soc_ifc_env_mbox_seq.get_type_name())); + soc_ifc_env_mbox_seq.mbox_sts_exp_error = 1'b1; if(!soc_ifc_env_cptra_handler_seq.randomize() with { inject_force_unlock == 1'b1; }) `uvm_fatal("SOC_IFC_MBOX_TOP", $sformatf("soc_ifc_env_top_mbox_rand_medium_unlock_sequence::body() - %s randomization failed", soc_ifc_env_cptra_handler_seq.get_type_name())); endfunction diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/src/soc_ifc_predictor.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/src/soc_ifc_predictor.svh index 8ea5ce3e5..426b8eeac 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/src/soc_ifc_predictor.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/src/soc_ifc_predictor.svh @@ -3345,7 +3345,7 @@ function void soc_ifc_predictor::predict_reset(input string kind = "HARD"); begin: DELAY_INTERNAL_RESET_ASSERTION cptra_sb_ap_output_transaction_t local_cptra_sb_ap_txn; soc_ifc_sb_ap_output_transaction_t local_soc_ifc_sb_ap_txn; - bit send_soc_ifc_sts_txn = soc_ifc_status_txn_expected_after_noncore_reset(); + bit send_soc_ifc_sts_txn; // Do the noncore reset `uvm_info("PRED_RESET", $sformatf("Reset prediction of kind: %p results in assertion of internal resets after a delay", kind), UVM_MEDIUM) @@ -3361,6 +3361,7 @@ function void soc_ifc_predictor::predict_reset(input string kind = "HARD"); end configuration.soc_ifc_ctrl_agent_config.wait_for_num_clocks(SOC_IFC_CPTRA_RST_NONCORE_RST_DELAY); join + send_soc_ifc_sts_txn = soc_ifc_status_txn_expected_after_noncore_reset(); // Synchronize the noncore reset with the reset of the environment and allow other // components to reset before proceeding with predicted activity reset_handled.trigger(noncore_reset_flag); diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/interface_packages/cptra_ctrl_pkg/src/cptra_ctrl_transaction_coverage.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/interface_packages/cptra_ctrl_pkg/src/cptra_ctrl_transaction_coverage.svh index 8a1d6e013..4945067b0 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/interface_packages/cptra_ctrl_pkg/src/cptra_ctrl_transaction_coverage.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/interface_packages/cptra_ctrl_pkg/src/cptra_ctrl_transaction_coverage.svh @@ -45,7 +45,10 @@ class cptra_ctrl_transaction_coverage extends uvm_subscriber #(.T(cptra_ctrl_tr option.per_instance=1; assert_clear_secrets: coverpoint coverage_trans.assert_clear_secrets; iccm_axs_blocked: coverpoint coverage_trans.iccm_axs_blocked; - pulse_rv_ecc_error: coverpoint coverage_trans.pulse_rv_ecc_error; + pulse_rv_ic_single_ecc_error: coverpoint coverage_trans.pulse_rv_ecc_error.cptra_iccm_ecc_single_error; + pulse_rv_ic_double_ecc_error: coverpoint coverage_trans.pulse_rv_ecc_error.cptra_iccm_ecc_double_error; + pulse_rv_dc_single_ecc_error: coverpoint coverage_trans.pulse_rv_ecc_error.cptra_dccm_ecc_single_error; + pulse_rv_dc_double_ecc_error: coverpoint coverage_trans.pulse_rv_ecc_error.cptra_dccm_ecc_double_error; // pragma uvmf custom covergroup end endgroup diff --git a/tools/scripts/Makefile b/tools/scripts/Makefile index 03c9b10c5..65bc2941e 100644 --- a/tools/scripts/Makefile +++ b/tools/scripts/Makefile @@ -20,9 +20,14 @@ VERILATOR = verilator GCC_PREFIX = riscv64-unknown-elf BUILD_DIR = $(CURDIR) -rv_gcc_version = $(strip $(shell $(GCC_PREFIX)-gcc --version | head -1 | sed "s/$(GCC_PREFIX)-gcc (\w\+) //")) +# Ensure that RISC-V toolchain is installed +ifeq ($(shell which $(GCC_PREFIX)-gcc 2> /dev/null),) +$(error RISC-V toolchain not found, please refer to https://github.com/chipsalliance/caliptra-rtl?tab=readme-ov-file#riscv-toolchain-installation for more details) +endif + +rv_gcc_version = $(strip $(shell $(GCC_PREFIX)-gcc --version | head -1 | sed "s/$(GCC_PREFIX)-gcc (.*) //")) $(info rv_gcc_version is $(rv_gcc_version)) -ifeq (12.2.0, $(rv_gcc_version)) +ifeq "12.2.0" "$(word 1, $(sort 12.2.0 $(rv_gcc_version)))" ABI = -mabi=ilp32 -march=rv32imc_zicsr_zifencei else ABI = -mabi=ilp32 -march=rv32imc diff --git a/tools/scripts/run_verilator_l0_regression.py b/tools/scripts/run_verilator_l0_regression.py index a4cbbd2ee..05a1f5c84 100644 --- a/tools/scripts/run_verilator_l0_regression.py +++ b/tools/scripts/run_verilator_l0_regression.py @@ -123,7 +123,7 @@ def getTestNames(): # Skip clk gating tests in Verilator until PC issue is resolved # https://github.com/chipsalliance/Cores-VeeR-EL2/issues/88 # https://github.com/chipsalliance/caliptra-rtl/issues/126 - if (re.search(r'(smoke_test_clk_gating|smoke_test_cg_wdt)',x.groups()[0])) : + if (re.search(r'(smoke_test_clk_gating|smoke_test_cg_wdt|smoke_test_mbox_cg|smoke_test_kv_cg|smoke_test_doe_cg)',x.groups()[0])) : continue integrationTestSuiteList.append(x.groups()[0])