#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.
Download the target
Create the AXI IP core
Build the AXI IP core
Package the AXI IP core
Build the Vivado Project
Integrate the IP to the C program
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¶
Launch Vivado
Open the SCABox project created in the previous tutorial
Click on Tools > Create and Package New IP
Hit next and select Create AXI4 Peripheral
- 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
In the next window, increase the register number to 16, you can also modify AXI name to S_AXI, then hit next.
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¶
Enter the IP catalog
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.
Click on File > Add Sources
Select “Add or create design sources” then hit next
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.
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.
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
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,
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
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
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;
--------------------------------------------------
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;
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;
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;
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¶
Click run synthesis to verify that the IP has been properly created.
If no error or critical warning appear click Package IP else correct the errors.
In the package IP identification window enter your ID
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.
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
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
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))
Package the IP and click on close project.
Build the vivado project¶
In the SCABox Vivado project open the block design
Then, click on the IP catalog and right click on AXI Peripheral to hit refresh all repositories
The CRYPTON block cipher should appear.
Double click on CRYPTON IP and select Add IP to Block Design
Remove the previously used AES IP and replace its connections by those of the CRYPTON IP
Now the design is ready, you can click on generate bitstream
On success, select File > Export > Export Hardware, (check include Bitstream)
Launch the SDK by selecting File > Launch SDK
Integrate the IP to the C program¶
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.
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
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.
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
Then you will have to add the crypton commands in main.c and main.h files.
The procedure takes some time
Once done, build the project and conenct through JTAG to the Zybo board.
Capture target side-channel leakage¶
Open a serial tool, connect to the Zybo at 921600 baudrate.
Test the crypton module with the following command:
> crypton -m hw -k ffff -d ffff
The result should be