blob: 70df495189e8fbfdb5d584f492ae7c631a5822d0 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{
name: "otbn",
human_name: "OpenTitan Big Number Accelerator",
one_line_desc: "Programmable coprocessor for asymmetric cryptography with SCA and FI countermeasures",
one_paragraph_desc: '''
OpenTitan Big Number Accelerator (OTBN) is a programmable coprocessor for asymmetric cryptographic algorithms such as RSA or elliptic curve cryptography (ECC).
Such algorithms are dominated by wide integer arithmetic, which are executed on OTBN's 256-bit-wide data path.
The data OTBN processes is often security sensitive, and OTBN is designed to reduce the attack surface by
(1) keeping the instruction set and the processor design as simple as possible to aid verification,
(2) minimizing control flow and clearly separating it from data flow,
(3) limiting OTBN's instruction fetch and data memory accesses to separate, dedicated on-chip memories,
(4) giving OTBN software direct access to cryptographically secure random numbers,
and (5) implementing various hardware countermeasures to deter side-channel analysis (SCA) and fault injection (FI) attacks.
'''
design_spec: "../doc",
dv_doc: "../doc/dv",
hw_checklist: "../doc/checklist",
sw_checklist: "/sw/device/lib/dif/dif_otbn"
revisions: [
{
version: "0.1",
life_stage: "L1",
design_stage: "D1",
verification_stage: "V1",
dif_stage: "S1",
commit_id: "a46be154ebbcb7b0d5e310b5510a4ac700adc9df",
notes: ""
},
{
version: "1.0",
life_stage: "L1",
design_stage: "D2S",
verification_stage: "V2S",
dif_stage: "S2",
commit_id: "a6b908283fccba3f8b6b44052c6ad87276dc21e8",
notes: ""
},
]
clocking: [
{clock: "clk_i", reset: "rst_ni", idle: "idle_o", primary: true},
{clock: "clk_edn_i", reset: "rst_edn_ni", idle: "idle_o"},
{clock: "clk_otp_i", reset: "rst_otp_ni", idle: "idle_otp_o"}
]
bus_interfaces: [
{ protocol: "tlul", direction: "device" }
],
param_list: [
{ name: "Stub",
type: "bit",
default: "0",
desc: "Stub out the core of Otbn logic"
local: "false",
expose: "true"
},
{ name: "RegFile",
type: "otbn_pkg::regfile_e",
default: "otbn_pkg::RegFileFF",
desc: "Selection of the register file implementation. See otbn_pkg.sv."
local: "false",
expose: "true"
},
{ name: "RndCnstUrndPrngSeed",
type: "otbn_pkg::urnd_prng_seed_t",
desc: '''
Default seed of the PRNG used for URND.
'''
randcount: "256",
randtype: "data"
},
{ name: "SecMuteUrnd"
type: "bit"
default: "0"
desc: '''
If enabled (1), URND is advanced only when data is needed.
Disabled (0) by default.
Useful for SCA measurements only.
'''
local: "false"
expose: "true"
}
{ name: "SecSkipUrndReseedAtStart"
type: "bit"
default: "0"
desc: '''
If enabled (1), URND reseed is skipped at the start of an operation.
Disabled (0) by default.
Useful for SCA measurements only.
'''
local: "false"
expose: "true"
}
{ name: "RndCnstOtbnKey",
type: "otp_ctrl_pkg::otbn_key_t",
desc: '''
Compile-time random reset value for IMem/DMem scrambling key.
'''
randcount: "128",
randtype: "data"
},
{ name: "RndCnstOtbnNonce",
type: "otp_ctrl_pkg::otbn_nonce_t",
desc: '''
Compile-time random reset value for IMem/DMem scrambling nonce.
'''
randcount: "64",
randtype: "data"
},
]
interrupt_list: [
{ name: "done"
desc: "OTBN has completed the operation."
}
]
alert_list: [
{ name: "fatal"
desc: "A fatal error. Fatal alerts are non-recoverable and will be asserted until a hard reset."
}
{ name: "recov"
desc: "A recoverable error. Just sent once (as the processor stops)."
}
]
inter_signal_list: [
// Key request to OTP
{ struct: "otbn_otp_key"
type: "req_rsp"
name: "otbn_otp_key"
act: "req"
default: "'0"
package: "otp_ctrl_pkg"
},
// EDN interface for RND
{ struct: "edn"
type: "req_rsp"
name: "edn_rnd"
act: "req"
package: "edn_pkg"
},
// EDN interface for URND
{ struct: "edn"
type: "req_rsp"
name: "edn_urnd"
act: "req"
package: "edn_pkg"
},
// OTBN is not performing any operation and can be clock/power-gated.
{ name: "idle",
type: "uni",
struct: "mubi4",
width: "1",
act: "req",
package: "prim_mubi_pkg"
},
// ram configuration
{ struct: "ram_1p_cfg",
package: "prim_ram_1p_pkg",
type: "uni",
name: "ram_cfg",
act: "rcv"
},
// Lifecycle escalation
{ struct: "lc_tx"
type: "uni"
name: "lc_escalate_en"
act: "rcv"
default: "lc_ctrl_pkg::Off"
package: "lc_ctrl_pkg"
},
// Lifecycle RMA request and acknowledge
{ struct: "lc_tx"
type: "uni"
name: "lc_rma_req"
act: "rcv"
default: "lc_ctrl_pkg::Off"
package: "lc_ctrl_pkg"
},
{ struct: "lc_tx"
type: "uni"
name: "lc_rma_ack"
act: "req"
default: "lc_ctrl_pkg::Off"
package: "lc_ctrl_pkg"
},
// Key sideload
{ struct: "otbn_key_req"
type: "uni"
name: "keymgr_key"
act: "rcv"
package: "keymgr_pkg"
},
],
countermeasures: [
{ name: "MEM.SCRAMBLE",
desc: "Both the imem and dmem are scrambled by using prim_ram_1p_scr."
}
{ name: "DATA.MEM.INTEGRITY",
desc: '''
Dmem is protected with ECC integrity.
This is carried through to OTBN's register file.
'''
}
{ name: "INSTRUCTION.MEM.INTEGRITY",
desc: '''
Imem is protected with ECC integrity.
This is carried through into OTBN's execute stage.
'''
}
{ name: "BUS.INTEGRITY",
desc: "End-to-end bus integrity scheme."
}
{ name: "CONTROLLER.FSM.GLOBAL_ESC",
desc: "The controller FSM moves to a terminal error state upon global escalation."
}
{ name: "CONTROLLER.FSM.LOCAL_ESC",
desc: '''
The controller FSM moves to a terminal error state upon local escalation.
Can be triggered by CONTROLLER.FSM.SPARSE, SCRAMBLE_CTRL.FSM.SPARSE, and START_STOP_CTRL.FSM.SPARSE.
'''
}
{ name: "CONTROLLER.FSM.SPARSE",
desc: "The controller FSM uses a sparse state encoding."
}
{ name: "SCRAMBLE.KEY.SIDELOAD",
desc: "The scrambling key is sideloaded from OTP and thus unreadable by SW."
}
{ name: "SCRAMBLE_CTRL.FSM.LOCAL_ESC",
desc: '''
The scramble control FSM moves to a terminal error state upon local escalation.
Can be triggered by SCRAMBLE_CTRL.FSM.SPARSE.
'''
}
{ name: "SCRAMBLE_CTRL.FSM.SPARSE",
desc: "The scramble control FSM uses a sparse state encoding."
}
{ name: "START_STOP_CTRL.FSM.GLOBAL_ESC",
desc: "The start-stop control FSM moves to a terminal error state upon global escalation."
}
{ name: "START_STOP_CTRL.FSM.LOCAL_ESC",
desc: '''
The start-stop control FSM moves to a terminal error state upon local escalation.
Can be triggered by START_STOP_CTRL.FSM.SPARSE.
'''
}
{ name: "START_STOP_CTRL.FSM.SPARSE",
desc: "The start-stop control FSM uses a sparse state encoding."
}
{ name: "DATA_REG_SW.SCA",
desc: "Blanking of bignum data paths when unused by the executing instruction."
}
{ name: "CTRL.REDUN",
desc: '''
Check pre-decoded control matches separately decoded control from main decoder.
This includes control signals used for blanking, pushing/popping the call stack, controlling loop and branch/jump instructions, as well as the actual branch target.
'''
}
{ name: "PC.CTRL_FLOW.REDUN",
desc: '''
Check prefetch stage PC and execute stage PC match.
The prefetch stage and execute stage store their PC's separately and have separate increment calculations.
'''
}
{ name: "RND.BUS.CONSISTENCY",
desc: "Comparison on successive bus values received over the EDN RND interface."
}
{ name: "RND.RNG.DIGEST",
desc: "Checking that the random numbers received over the EDN RND interface have not been generated from entropy that failed the FIPS health checks in the entropy source."
}
{ name: "RF_BASE.DATA_REG_SW.INTEGRITY"
desc: "Register file is protected with ECC integrity."
}
{ name: "RF_BASE.DATA_REG_SW.GLITCH_DETECT"
desc: '''
This countermeasure checks for spurious write-enable signals on the register file by monitoring the one-hot0 property of the individual write-enable strobes.
'''
}
{ name: "STACK_WR_PTR.CTR.REDUN"
desc: '''
The write pointer of the stack (used for calls and loops) is redundant.
If the two instances of the counter mismatch, an error is emitted.
'''
}
{ name: "RF_BIGNUM.DATA_REG_SW.INTEGRITY"
desc: "Register file is protected with ECC integrity."
}
{ name: "RF_BIGNUM.DATA_REG_SW.GLITCH_DETECT"
desc: "This countermeasure checks for spurious write-enable signals on the register file by monitoring the one-hot0 property of the individual write-enable strobes."
}
{ name: "LOOP_STACK.CTR.REDUN"
desc: "The iteration counter of each entry in the loop step uses cross counts via prim_count."
}
{ name: "LOOP_STACK.ADDR.INTEGRITY"
desc: "Loop start and end address on the loop stack are protected with ECC integrity."
}
{ name: "CALL_STACK.ADDR.INTEGRITY"
desc: "Call stack entries are protected with ECC integrity."
}
{ name: "START_STOP_CTRL.STATE.CONSISTENCY"
desc: '''
The secure wipe handshake between otbn_controller and
otbn_start_stop_control uses a level-based req/ack interface. At the
otbn_controller end, there is a check for unexpected acks. In
otbn_start_stop_control, there is a check for secure wipe requests when
we aren't in a state that allows it, and also a check for if the
request drops at an unexpected time.
'''
}
{ name: "DATA.MEM.SEC_WIPE"
desc: '''
Rotate the scrambling key, effectively wiping the dmem.
Initiated on command, upon fatal errors and before RMA entry.
'''
}
{ name: "INSTRUCTION.MEM.SEC_WIPE"
desc: '''
Rotate the scrambling key, effectively wiping the imem.
Initiated on command, upon fatal errors and before RMA entry.
'''
}
{ name: "DATA_REG_SW.SEC_WIPE"
desc: '''
Securely wipe programmer visible OTBN register (GPRs, WDRs, CSRs, WSRs) state with random data.
Initiated after reset, at the end of any OTBN operation, upon recoverable and fatal errors, and before RMA entry.
'''
}
{ name: "WRITE.MEM.INTEGRITY"
desc: '''
A software visible checksum is calculated for all dmem and imem writes
'''
}
{ name: "CTRL_FLOW.COUNT"
desc: "A software visible count of instructions executed"
}
{ name: "CTRL_FLOW.SCA"
desc: '''
OTBN architecture does not have any data dependent timing behaviour
'''
}
{ name: "DATA.MEM.SW_NOACCESS"
desc: "A portion of DMEM is invisible to CPU software"
}
{ name: "KEY.SIDELOAD"
desc: "Keys can be sideloaded without exposing them to the CPU"
}
{ name: "TLUL_FIFO.CTR.REDUN",
desc: "The TL-UL response FIFO pointers are implemented with duplicate counters."
}
]
regwidth: "32"
registers: [
// The magic values for EXECUTE, SEC_WIPE_DMEM and SEC_WIPE_IMEM in the CMD
// register below were generated with the sparse-fsm-encode.py script:
//
// util/design/sparse-fsm-encode.py -d 4 -m 3 -n 8 --avoid-zero -s 1
//
// and have a hamming distance of at least 4 from one another and the zero
// word.
{ name: "CMD"
desc: '''
Command Register
A command initiates an OTBN operation. While performing the operation,
OTBN is busy; the !!STATUS register reflects that.
All operations signal their completion by raising the done
interrupt; alternatively, software may poll the !!STATUS register.
Writes are ignored if OTBN is not idle.
Unrecognized commands are ignored.
''',
swaccess: "wo",
hwaccess: "hro",
hwext: "true",
hwqe: "true",
fields: [
{ bits: "7:0"
name: "cmd"
resval: 0,
desc: '''
The operation to perform.
<table>
<thead>
<tr>
<th>Value</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0xd8</td>
<td>EXECUTE</td>
<td>
Starts the execution of the program stored in the
instruction memory, starting at address zero.
</td>
</tr>
<tr>
<td>0xc3</td>
<td>SEC_WIPE_DMEM</td>
<td>Securely removes all contents from the data memory.</td>
</tr>
<tr>
<td>0x1e</td>
<td>SEC_WIPE_IMEM</td>
<td>
Securely removes all contents from the instruction memory.
</td>
</tr>
</tbody>
</table>
'''
tags: [
// Don't write this field in the automated CSR tests: it would
// start an operation!
"excl:CsrAllTests:CsrExclWrite"
]
}
],
}
{ name: "CTRL",
desc: "Control Register",
hwext: "true",
swaccess: "rw",
hwaccess: "hrw",
hwqe: "true",
fields: [
{ bits: "0",
name: "software_errs_fatal",
resval: 0,
desc: '''
Controls the reaction to software errors.
When set software errors produce fatal errors, rather than
recoverable errors.
Writes are ignored if OTBN is not idle.
'''
}
],
tags: [
// Don't write this register in the automated CSR tests, because those
// tests are not aware whether OTBN is idle or not. If OTBN is not idle,
// it ignores the write and the test would fail.
"excl:CsrAllTests:CsrExclWrite"
]
}
{ name: "STATUS",
desc: "Status Register",
swaccess: "ro",
hwaccess: "hwo",
fields: [
{ bits: "7:0",
name: "status",
resval: "0x04",
// Note: Keep the list of status codes in sync with status_e in
// otbn_pkg.sv.
desc: '''
Indicates the current operational state OTBN is in.
All BUSY values represent an operation started by a write to the
!!CMD register.
<table>
<thead>
<tr>
<th>Value</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x00</td>
<td>IDLE</td>
<td>OTBN is idle: it is not performing any action.</td>
</tr>
<tr>
<td>0x01</td>
<td>BUSY_EXECUTE</td>
<td>OTBN is busy executing software.</td>
</tr>
<tr>
<td>0x02</td>
<td>BUSY_SEC_WIPE_DMEM</td>
<td>OTBN is busy securely wiping the data memory.</td>
</tr>
<tr>
<td>0x03</td>
<td>BUSY_SEC_WIPE_IMEM</td>
<td>OTBN is busy securely wiping the instruction memory.</td>
</tr>
<tr>
<td>0x04</td>
<td>BUSY_SEC_WIPE_INT</td>
<td>OTBN is busy securely wiping the internal state.</td>
</tr>
<tr>
<td>0xFF</td>
<td>LOCKED</td>
<td>
OTBN is locked as reaction to a fatal error, and must be
reset to unlock it again. See also the section
"Reaction to Fatal Errors".
</td>
</tr>
</tbody>
</table>
'''
tags: [
// Exclude this field from the automated CSR tests. The register model does not know
// OTBN automatically transitions from the reset state to `IDLE` as it completes the
// initial secure wipe of the internal state.
"excl:CsrAllTests:CsrExclAll"
]
}
]
}
{ name: "ERR_BITS",
desc: '''
Operation Result Register
Describes the errors detected during an operation.
Refer to the "List of Errors" section for a detailed description of the
errors.
The host CPU can clear this register when OTBN is not running,
by writing any value. Write attempts while OTBN is running are ignored.
''',
swaccess: "rw",
hwaccess: "hrw",
hwext: "true",
hwqe: "true",
tags: [
// Don't use this register in the automated CSR tests. Its behaviour is
// "write any value to clear", which we don't model in those tests.
"excl:CsrAllTests:CsrExclWrite"
],
fields: [
// Software errors
{ bits: "0",
name: "bad_data_addr"
resval: 0,
desc: "A `BAD_DATA_ADDR` error was observed."
}
{ bits: "1",
name: "bad_insn_addr"
resval: 0,
desc: "A `BAD_INSN_ADDR` error was observed."
}
{ bits: "2",
resval: 0,
name: "call_stack"
desc: "A `CALL_STACK` error was observed."
}
{ bits: "3",
resval: 0,
name: "illegal_insn"
desc: "An `ILLEGAL_INSN` error was observed."
}
{ bits: "4",
name: "loop"
resval: 0,
desc: "A `LOOP` error was observed."
}
{ bits: "5",
name: "key_invalid"
resval: 0,
desc: "A `KEY_INVALID` error was observed."
}
// Recoverable errors
{ bits: "6",
name: "rnd_rep_chk_fail"
resval: 0,
desc: "An `RND_REP_CHK_FAIL` error was observed."
}
{ bits: "7",
name: "rnd_fips_chk_fail"
resval: 0,
desc: "An `RND_FIPS_CHK_FAIL` error was observed."
}
// Fatal errors. Keep in sync with list in FATAL_ALERT_CAUSE.
{ bits: "16",
name: "imem_intg_violation"
resval: 0,
desc: "A `IMEM_INTG_VIOLATION` error was observed."
}
{ bits: "17",
name: "dmem_intg_violation"
resval: 0,
desc: "A `DMEM_INTG_VIOLATION` error was observed."
}
{ bits: "18",
name: "reg_intg_violation"
resval: 0,
desc: "A `REG_INTG_VIOLATION` error was observed."
}
{ bits: "19",
name: "bus_intg_violation"
resval: 0,
desc: "A `BUS_INTG_VIOLATION` error was observed."
}
{ bits: "20",
name: "bad_internal_state",
resval: 0,
desc: "A `BAD_INTERNAL_STATE` error was observed."
}
{ bits: "21",
name: "illegal_bus_access"
resval: 0,
desc: "An `ILLEGAL_BUS_ACCESS` error was observed."
}
{ bits: "22",
name: "lifecycle_escalation"
resval: 0,
desc: "A `LIFECYCLE_ESCALATION` error was observed."
}
{ bits: "23",
name: "fatal_software"
resval: 0,
desc: "A `FATAL_SOFTWARE` error was observed."
}
]
}
{ name: "FATAL_ALERT_CAUSE",
desc: '''
Fatal Alert Cause Register
Describes any errors that led to a fatal alert.
A fatal error puts OTBN in locked state; the value of this register
does not change until OTBN is reset.
Refer to the "List of Errors" section for a detailed description of the
errors.
'''
swaccess: "ro",
hwaccess: "hwo",
fields: [
// Keep the list in sync with the fatal errors in ERR_BITS.
{ bits: "0",
name: "imem_intg_violation",
resval: 0,
desc: "A `IMEM_INTG_VIOLATION` error was observed."
}
{ bits: "1",
name: "dmem_intg_violation",
resval: 0,
desc: "A `DMEM_INTG_VIOLATION` error was observed."
}
{ bits: "2",
name: "reg_intg_violation",
resval: 0,
desc: "A `REG_INTG_VIOLATION` error was observed."
}
{ bits: "3",
name: "bus_intg_violation",
resval: 0,
desc: "A `BUS_INTG_VIOLATION` error was observed."
}
{ bits: "4",
name: "bad_internal_state",
resval: 0,
desc: "A `BAD_INTERNAL_STATE` error was observed."
}
{ bits: "5",
name: "illegal_bus_access"
resval: 0,
desc: "A `ILLEGAL_BUS_ACCESS` error was observed."
}
{ bits: "6",
name: "lifecycle_escalation"
resval: 0,
desc: "A `LIFECYCLE_ESCALATION` error was observed."
}
{ bits: "7",
name: "fatal_software"
resval: 0,
desc: "A `FATAL_SOFTWARE` error was observed."
}
]
}
{ name: "INSN_CNT",
desc: '''
Instruction Count Register
Returns the number of instructions executed in the current or last
operation. The counter saturates at 2^32-1 and is reset to 0 at the
start of a new operation.
Only the EXECUTE operation counts instructions; for all other operations
this register remains at 0. Instructions triggering an error do not
count towards the total.
Always reads as 0 if OTBN is locked.
The host CPU can clear this register when OTBN is not running,
by writing any value. Write attempts while OTBN is running are ignored.
''',
swaccess: "rw",
hwaccess: "hrw",
hwext: "true",
hwqe: "true",
fields: [
{ bits: "31:0",
name: "insn_cnt",
resval: 0,
desc: '''
The number of executed instructions.
'''
tags: [
// Don't write this field in the automated CSR tests. Like
// ERR_BITS, its behaviour is "write any value to clear", which we
// don't model in those tests.
"excl:CsrAllTests:CsrExclWrite"
]
}
]
}
{ name: "LOAD_CHECKSUM",
desc: '''
A 32-bit CRC checksum of data written to memory
See the "Memory Load Integrity" section of the manual for full details.
'''
hwext: "true",
hwqe: "true",
swaccess: "rw",
hwaccess: "hrw",
fields: [
{ bits: "31:0",
name: "checksum",
resval: 0,
desc: "Checksum accumulator"
}
]
tags: [
// Don't read this field in any of the automated CSR tests (they
// will predict the value wrongly because they don't know that it
// updates on memory writes).
"excl:CsrAllTests:CsrExclAll"
]
}
// Give IMEM and DMEM 16 KiB address space, each, to allow for easy expansion
// of the actual IMEM and DMEM sizes without changing the address map.
{ skipto: "0x4000" }
// Imem size (given as `items` below) must be a power of two.
{ window: {
name: "IMEM",
items: "1024", // 4 kB
swaccess: "rw",
data-intg-passthru: "true",
byte-write: "false",
desc: '''
Instruction Memory Access
The instruction memory may only be accessed through this window
while OTBN is idle.
If OTBN is busy or locked, read accesses return 0 and write accesses
are ignored.
If OTBN is busy, any access additionally triggers an
ILLEGAL_BUS_ACCESS fatal error.
'''
}
}
{ skipto: "0x8000" }
// Dmem size (given as `items` below) must be a power of two.
{ window: {
name: "DMEM",
items: "768", // 3 kB visible over the bus (1 kB scratch)
unusual: "true", // Needed to avoid an error because of the non-power-of-two size
swaccess: "rw",
data-intg-passthru: "true",
byte-write: "false",
desc: '''
Data Memory Access
The data memory may only be accessed through this window while OTBN
is idle.
If OTBN is busy or locked, read accesses return 0 and write accesses
are ignored.
If OTBN is busy, any access additionally triggers an
ILLEGAL_BUS_ACCESS fatal error.
Note that DMEM is actually 4kiB in size, but only the first 3kiB of
the memory is visible through this register interface.
'''
}
}
]
}