#4 - Build your Own Designs

Goals

In this tutorial you will learn how to add a custom target IP to the SCABox framework. Based on an example, you will learn how to build an AXI wrapper on top of your design to integrate it on SCABox.

  1. Download the target

  2. Create the AXI IP core

  3. Build the AXI IP core

  4. Package the AXI IP core

  5. Build the Vivado Project

  6. Integrate the IP to the C program

  7. Capture target side-channel leakage

Requirements

You must have a complete the installation tutorial before starting this tutorial. It is recommended to have an understanding of our hardware setup before starting the tutorial.

  • Any terminal emulator such as PuTTY, TeraTerm or picocom

  • Have a completed the installation tutorial

  • Have an understanding of our hardware setup

Download the target

For this tutorial uses a publicly available FPGA implementation of the CRYPTON block cipher. The CRYPTON lightweight block cipher encrypts individual blocks of 64 bit length with a 64, 96, or 128 bit key. 1. Clone the CRYPTON algorithm from this address: https://github.com/huljar/mcrypton-vhdl.

Create the AXI IP core

  1. Launch Vivado

  2. Open the SCABox project created in the previous tutorial

  3. Click on Tools > Create and Package New IP

  4. Hit next and select Create AXI4 Peripheral

  5. The peripheral must be configured with the following details then hit next:
    • Name: CRYPTON

    • Version: 1.0

    • Display name: CRYPTON_1.0

    • Description: CRYPTON Block cipher

    • IP location: your_path/SCAbox/sca-ip/ip_repo

  6. In the next window, increase the register number to 16, you can also modify AXI name to S_AXI, then hit next.

  7. Finally, select add IP to the repository and hit Finish

The AXI IP Core has been created and you should be able to see it in the IP catalog. If not please add the your_path/SCAbox/sca-ip/ip_repo path to your IP repository path.

Build the AXI IP core

  1. Enter the IP catalog

  2. Right click on the newly created CRYPTON_1.0 IP and select Edit in IP Packager. Hit OK. A new project window should open

In the new project you should see two VHDL source appear. The top one is will be the interface with the outside world. It also contains the AXI component that will handle the communication with the zynq processor. Now, we need to add the CRYPTON sources to the project.

  1. Click on File > Add Sources

  2. Select “Add or create design sources” then hit next

  3. On the next window hit + and add all the CRYPTON sources except “axi_stream_wrapper.vhd” from the CRYPTON project hdl folder downloaded on github.

  4. Hit Finish, the mycrypton_top module should appear on the Vivado Sources window.

Now we have to interface the CRYPTON module with AXI peripheral. First, we need clock, done and start signals for SCAbox to operate properly.

  1. Modify the Crypton_v1_0 vhdl source file by adding keysize parameter and clock, done and start signals

entity CRYPTON_v1_0 is
	generic (
		-- Users to add parameters here
		-- User parameters ends
		-- Do not modify the parameters beyond this line
		-- Parameters of Axi Slave Bus Interface S00_AXI
		C_S00_AXI_DATA_WIDTH	: integer	:= 32;
		C_S00_AXI_ADDR_WIDTH	: integer	:= 6
	);
	port (
		-- Users to add ports here
		clock_i : in std_logic;
		start_o : out std_logic;
		done_o  : out std_logic;
		-- User ports ends
		-- Do not modify the ports beyond this line
		
  1. On the same file, Add the parameters to the AXI component and port map.

	component CRYPTON_v1_0_S00_AXI is
		generic (
            C_S_AXI_DATA_WIDTH	: integer	:= 32;
            C_S_AXI_ADDR_WIDTH	: integer	:= 6
		);
		port (
            clock_i       : in std_logic;
            start_o       : out std_logic;
            done_o        : out std_logic;
            -- ETC
            S_AXI_ACLK	: in std_logic;
            S_AXI_ARESETN	: in std_logic;
	generic map (
        C_S_AXI_DATA_WIDTH	=> C_S00_AXI_DATA_WIDTH,
        C_S_AXI_ADDR_WIDTH	=> C_S00_AXI_ADDR_WIDTH
	)
	port map (
        clock_i       => clock_i,
        start_o       => start_o,
        done_o        => done_o,
        --ETC
        S_AXI_ACLK	=> s00_axi_aclk,
        S_AXI_ARESETN	=> s00_axi_aresetn,
        S_AXI_AWADDR	=> s00_axi_awaddr,
  1. Now, on the CRYPTON_v1_0_S00_AXI vhdl source file, we need to modify the entity according to the new IOs.

entity CRYPTON_v1_0_S00_AXI is
	generic (
        -- Users to add parameters here
        -- User parameters ends
        -- Do not modify the parameters beyond this line
        
        -- Width of S_AXI data bus
        C_S_AXI_DATA_WIDTH	: integer	:= 32;
        -- Width of S_AXI address bus
        C_S_AXI_ADDR_WIDTH	: integer	:= 6
	);
	port (
        -- Users to add ports here
        clock_i : in std_logic;
        start_o : out std_logic;
        done_o  : out std_logic;
        -- User ports ends            
        -- Do not modify the ports beyond this line
  1. Then we add the crypton module to our AXI peripheral

        generic(k: key_enum := K_128);
        port(
             plaintext:  in std_logic_vector(63 downto 0);
             key:        in std_logic_vector(key_bits(k)-1 downto 0);
             clk:        in std_logic;
             reset:      in std_logic;
             ciphertext: out std_logic_vector(63 downto 0)
        );
    end component;
    

Plaintext, ciphertext, key, done, start and reset signals are read or written by the processor. We need to interface them using AXI registers

  1. First we need to create the signals that will serve as interface.

	---- Signals for user logic register space example
    constant active_cycles: natural := 14;
    signal data_is : std_logic_vector(63 downto 0);
    signal data_os : std_logic_vector(63 downto 0);
    signal ip_ciphertext : std_logic_vector(63 downto 0);
    signal key_s : std_logic_vector(127 downto 0);
    signal reset_s : std_logic;
    signal start_s : std_logic;
    signal done_s : std_logic;
    signal counter: natural range 0 to 64;
	--------------------------------------------------
  1. The signals flowing from the FPGA to the CPU are done and ciphertext. We connect them to any AXI register that is not use for reads.

	variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0);
	begin
	    -- Address decoding for reading registers
	    loc_addr := axi_araddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB);
	    case loc_addr is
	      when b"0000" =>
	        reg_data_out <= slv_reg0;
	      when b"0001" =>
	        reg_data_out <= slv_reg1;
	      when b"0010" =>
	        reg_data_out <= slv_reg2;
	      when b"0011" =>
	        reg_data_out <= slv_reg3;
	      when b"0100" =>
	        reg_data_out <= slv_reg4;
	      when b"0101" =>
	        reg_data_out <= slv_reg5;
	      when b"0110" =>
	           reg_data_out <= data_os(63 downto 32);
	      when b"0111" =>
	           reg_data_out <= data_os(31 downto 0);
	      when b"1000" =>
	        reg_data_out <= slv_reg8;
	      when b"1001" =>
	        reg_data_out <= slv_reg9;
	      when b"1010" =>
	        reg_data_out <= slv_reg10;
	      when b"1011" =>
	        reg_data_out <= slv_reg11;
	      when b"1100" =>
	        reg_data_out <= slv_reg12;
	      when b"1101" =>
              reg_data_out(0) <= done_s;
              reg_data_out(C_S_AXI_DATA_WIDTH - 1 downto 1) <= (others => '0');
	      when b"1110" =>
	        reg_data_out <= slv_reg14;
	      when b"1111" =>
	        reg_data_out <= slv_reg15;
	      when others =>
	        reg_data_out  <= (others => '0');
	    end case;
	end process; 
  1. The signals flowing from the CPU to the FPGA are key, plaintext and start. We connect them to any AXI register that is not use for writes.

    data_is <= slv_reg0 & slv_reg1;
    key_s <=  slv_reg8 & slv_reg9 & slv_reg10 & slv_reg11;
    reset_s <= not start_s;
    start_o <= start_s;
    
  1. To detect the end of the encryption we use a process that generates the done signal when the number of encryption clock cycle is reached

    process(clock_i,S_AXI_ARESETN) is
    begin
        if(S_AXI_ARESETN = '0') then    
           data_os <= (others=>'0');
           done_s <= '0';
           counter <= 0;
        else   
            if (rising_edge (clock_i)) then
                
                if ( start_s = '1' and done_s = '0' ) then 
                
                    if (counter = active_cycles-1) then
                        done_s <= '1';
                        data_os(63 downto 32) <= ip_ciphertext(63 downto 32);
                        data_os(31 downto 0) <= ip_ciphertext(31 downto 0); 
                        counter <= 0;
                    else
                        counter <= counter+1;
                    end if;
                    
                elsif(start_s = '1' and done_s='1') then
                
                --do nothing  
                               
                else
                
                done_s <= '0';
                
                end if;
                   
            end if;
        end if;
       
    end process;
    
    done_o <= done_s;
    
  1. Finally, we add the port map of the CRYPTON module to establish the final connection

     generic map(k => K_128)
        port map(
            plaintext  => data_is,
            key   => key_s,
            clk => clock_i,
            reset => reset_s,
            ciphertext  => ip_ciphertext
        );
    -- User logic ends

The IP is ready to be synthetized and packaged.

Package the AXI IP core

  1. Click run synthesis to verify that the IP has been properly created.

  2. If no error or critical warning appear click Package IP else correct the errors.

  3. In the package IP identification window enter your ID

  4. In the file group window enter software drivers.

You should see 6 files appear: Makefile, CRYPTON_selftest.c, CRYPTON.h, CRYPTON.c, CRYPTON.tcl, CRYPTON.mdd These files will be used as software driver to control the CRYPTON IP from the processor. We need to modify them accordingly to the methodology adopted for the other SCAbox IPs.

  1. In the yourpath/SCAbox/sca-ip/ip_repo/crypton_1.0/drivers/crypton_v1_0 folder, delete the data and hdl folders and replace then by the data and hdl folders used in yourpath/SCAbox/sca-ip/ip_repo/aes_1.0/drivers/aes_1.0

we are importing the base AES drivers in order to modify them and fit with the CRYPTON implementation

  1. Replace “aes” with “crypton” in each file names and import them as software drivers: Right click on software driver > Add Files (use view all files)

You should have Makefile, xcrypton.c, xcrypton.h, xcrypton_hw.h, crypton.tcl, crypton.mdd

  1. Now, open each file and replace AES and aes occurence with CRYPTON and crypton occurences. (you can use ctrl+r on vivado to replace words, use match case for caps lock)

#define XCRYPTON_WORDS_SIZE 4
#define XCRYPTON_BYTES_SIZE 16

#define XCRYPTON_DATA_IN0_OFFSET 0x00
#define XCRYPTON_DATA_IN1_OFFSET 0x04
#define XCRYPTON_DATA_IN2_OFFSET 0x08
#define XCRYPTON_DATA_IN3_OFFSET 0x0C

#define XCRYPTON_DATA_OUT0_OFFSET 0x10
#define XCRYPTON_DATA_OUT1_OFFSET 0x14
#define XCRYPTON_DATA_OUT2_OFFSET 0x18
#define XCRYPTON_DATA_OUT3_OFFSET 0x1C

#define XCRYPTON_DATA_KEY0_OFFSET 0x20
#define XCRYPTON_DATA_KEY1_OFFSET 0x24
#define XCRYPTON_DATA_KEY2_OFFSET 0x28
#define XCRYPTON_DATA_KEY3_OFFSET 0x2c

#define XCRYPTON_STATUS_WR_OFFSET 0x30
#define XCRYPTON_STATUS_RD_OFFSET 0x34

#define XCRYPTON_STATUS_NULL_MASK 0x0
#define XCRYPTON_STATUS_RESET_MASK 0x1
#define XCRYPTON_STATUS_START_MASK 0x2
#define XCRYPTON_STATUS_INV_MASK 0x4
#define XCRYPTON_STATUS_DONE_MASK 0x1

#define XCRYPTON_SetStatus1(status, reg) \
    (reg | status)
#define XCRYPTON_SetStatus0(status, reg) \
    (reg & ~status)
#define XCRYPTON_GetStatus(status, reg) \
    (reg & status)

#define XCRYPTON_ReadReg(addr, offset) \
    Xil_In32((addr) + (offset))
#define XCRYPTON_WriteReg(addr, offset, data) \
    Xil_Out32((addr) + (offset), (data))
  1. Package the IP and click on close project.

Build the vivado project

  1. In the SCABox Vivado project open the block design

  2. Then, click on the IP catalog and right click on AXI Peripheral to hit refresh all repositories

    The CRYPTON block cipher should appear.

  3. Double click on CRYPTON IP and select Add IP to Block Design

  4. Remove the previously used AES IP and replace its connections by those of the CRYPTON IP

  5. Now the design is ready, you can click on generate bitstream

  6. On success, select File > Export > Export Hardware, (check include Bitstream)

  7. Launch the SDK by selecting File > Launch SDK

Integrate the IP to the C program

  1. On Xilinx SDK or Vitis, open the hw_platform project arborescence and open the drivers folder arborescence.

You should see the crypton software driver appear.

  1. Now right click on the BSP project and select Re-generate BSP Sources

You should see crypton_v1_0 folder appear in yourBSP/ps7_cortexa9_0/libsrc

  1. Now you can rebuild the C/C++ index Project > C/C++index > Rebuild and build all the projects Project > Build All

The project is now ready and will be modified to add CRYPTON ip core support.

  1. Open the main.c file contained in SCABox/src/main.c and create the CRYPTON definition

#define SCABOX_TDC
//#define SCABOX_RO
//#define SCABOX_AES
//#define SCABOX_PRESENT
//#define SCABOX_KLEIN
#define SCABOX_CRYPTON
  1. Then you will have to add the crypton commands in main.c and main.h files.

The procedure takes some time

  1. Once done, build the project and conenct through JTAG to the Zybo board.

Capture target side-channel leakage

  1. Open a serial tool, connect to the Zybo at 921600 baudrate.

  2. Test the crypton module with the following command: > crypton -m hw -k ffff -d ffff

The result should be