ibex/vendor/lowrisc_ip/prim/doc/prim_present.md
Philipp Wagner 8b42024cd5 Use vendored-in primitives from OpenTitan
Instead of using copies of primitives from OpenTitan, vendor the files
in directly from OpenTitan, and use them.

Benefits:

- Less potential for diverging code between OpenTitan and Ibex, causing
  problems when importing Ibex into OT.

- Use of the abstract primitives instead of the generic ones. The
  abstract primitives are replaced during synthesis time with
  target-dependent implementations. For simulation, nothing changes. For
  synthesis for a given target technology (e.g. a specific ASIC or FPGA
  technology), the primitives system can be instructed to choose
  optimized versions (if available).

  This is most relevant for the icache, which hard-coded the generic
  SRAM primitive before. This primitive is always implemented as
  registers. By using the abstract primitive (prim_ram_1p) instead, the
  RAMs can be replaced with memory-compiler-generated ones if necessary.

There are no real draw-backs, but a couple points to be aware of:

- Our ram_1p and ram_2p implementations are kept as wrapper around the
  primitives, since their interface deviates slightly from the one in
  prim_ram*. This also includes a rather unfortunate naming confusion
  around rvalid, which means "read data valid" in the OpenTitan advanced
  RAM primitives (prim_ram_1p_adv for example), but means "ack" in
  PULP-derived IP and in our bus implementation.

- The core_ibex UVM DV doesn't use FuseSoC to generate its file list,
  but uses a hard-coded list in `ibex_files.f` instead. Since the
  dynamic primitives system requires the use of FuseSoC we need to
  provide a stop-gap until this file is removed. Issue #893 tracks
  progress on that.

- Dynamic primitives depend no a not-yet-merged feature of FuseSoC
  (https://github.com/olofk/fusesoc/pull/391). We depend on the same
  functionality in OpenTitan and have instructed users to use a patched
  branch of FuseSoC for a long time through `python-requirements.txt`,
  so no action is needed for users which are either successfully
  interacting with the OpenTitan source code, or have followed our
  instructions. All other users will see a reasonably descriptive error
  message during a FuseSoC run.

- This commit is massive, but there are no good ways to split it into
  bisectable, yet small, chunks. I'm sorry. Reviewers can safely ignore
  all code in `vendor/lowrisc_ip`, it's an import from OpenTitan.

- The check_tool_requirements tooling isn't easily vendor-able from
  OpenTitan at the moment. I've filed
  https://github.com/lowRISC/opentitan/issues/2309 to get that sorted.

- The LFSR primitive doesn't have a own core file, forcing us to include
  the catch-all `lowrisc:prim:all` core. I've filed
  https://github.com/lowRISC/opentitan/issues/2310 to get that sorted.
2020-05-27 10:23:15 +01:00

2.9 KiB

title
Primitive Component: PRESENT Scrambler

Overview

prim_present is an (unhardened) implementation of the encryption pass of the 64bit PRESENT block cipher. It is a fully unrolled combinational implementation that supports both key lengths specified in the paper (80bit and 128bit). Further, the number of rounds is fully configurable, and the primitive supports a 32bit block cipher flavor which is not specified in the original paper.

It should be noted, however, that reduced-round and/or 32bit versions are not secure and must not be used in a setting where cryptographic cipher strength is required. I.e., this primitive is only intended to be used as a lightweight data scrambling device.

Parameters

Name type Description
DataWidth int Block size, can be 32 or 64
KeyWidth int Key size, can be 64, 80 or 128
NumRounds int Number of PRESENT rounds, has to be greater than 0

Signal Interfaces

Name In/Out Description
data_i input Plaintext input
key_i input Key input
data_o output Output of the ciphertext

Theory of Operations

             /---------------\
             |               |
             |    PRESENT    |
key_i        |               |
=====/======>|   DataWidth   |
 [KeyWidth]  |   KeyWidth    |
             |   NumRounds   |
data_i       |               |  data_o
=====/======>|               |=====/=======>
 [DataWidth] |               |  [DataWidth]
             |               |
             \---------------/

The PRESENT module is fully unrolled and combinational, meaning that it does not have any clock, reset or handshaking inputs. The only inputs are the key and the plaintext, and the only output is the ciphertext.

The internal construction follows the the algorithm described in the original paper. The block size is 64bit and the key size can be either 80bit or 128bit, depending on the security requirements. In its original formulation, this cipher has 31 rounds comprised of an XOR operation with a round key, followed by the application of an s-box and a permutation layer:


round_keys = key_derivation(key_i);

state = data_i;

for (int i=1; i < 32; i++) {
	state = state ^ round_keys[i];
	state = sbox4_layer(state);
	state = perm_layer(state);
}

data_o = state ^ round_keys[32];

The reduced 32bit block-size variant implemented is non-standard and should only be used for scrambling purposes, since it is not secure. It leverages the same crypto primitives and key derivation functions as the 64bit variant, with the difference that the permutation layer is formulated for 32 instead of 64 elements.