Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions sw/otbn/crypto/mldsa87/mldsa87_gadgets.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/* Copyright lowRISC contributors (OpenTitan project). */
/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
/* SPDX-License-Identifier: Apache-2.0 */

/* Secure masked gadgets. */

.globl sec_a2b_8x32
.globl sec_b2a_8x32
.globl sec_add_8x32
.globl sec_unmask_8x32

/*

The masking accelerator supports three functions that operate in a vectroized
fashion on 8 coefficients in a single WDR. The interface consists of four input
WSRs to pass two shared vectors to the accelerator, MAI_IN0_S0 and MAI_IN0_S1
for the first input and MAI_IN1_S0 and MAI_IN1_S1 for the second input which is
only used for the second summand in the secure addition. The shared result of
the operation can be read in the MAI_RES_S0 and MAI_RES_S1 WSRs. The interface
has a single control register MAI_CTRL that instruments the accelerator and
immediately triggers a computation upon seeing a valid configuration value.

Note that some routines of this modules draw randomness from URND for masking
purposes, hence while an MAI operation is ongoing, URND bits shall not be
shared between different routines.

Most routines of this module are a direct implementation of the gadgets in the
work of Azouaoui et al. [1].

[1] https://tches.iacr.org/index.php/TCHES/article/view/11158/10597

*/

/*
* Configuration values for the MAI_CTRL register.
*/
.set MAI_CTRL_A2B, 0x1
.set MAI_CTRL_B2A, 0x3
.set MAI_CTRL_ADD, 0x5

.text

/* MAI interface polling routine. */
_mai_poll:
csrrs x20, MAI_STATUS, x0
andi x20, x20, 0x1
bne x20, x0, _mai_poll
ret

/**
* Convert the arithmetic sharing of a vector of 8 coefficients (x0_A, x1_A) to
* a Boolean sharing (x0_B, x1_B).
*
* @param[in] w0: x0_A, first arithmetic share.
* @param[in] w1: x1_A, second arithmetic share.
* @param[out] w0: x0_B, first Boolean share.
* @param[out] w1: x1_B, second Boolean share
*/
sec_a2b_8x32:
/* Write the two shares to the input WSRs (intersperse with configuration of
MAI_CTRL to not access both shares in subsequent instructions). */
bn.wsrw MAI_IN0_S0, w0
addi x20, x0, MAI_CTRL_A2B
bn.wsrw MAI_IN0_S1, w1

/* Trigger the conversion. */
csrrw x0, MAI_CTRL, x20

/* TODO: Replace with deterministic wait, once exact latency is known. */
jal x1, _mai_poll

/* Read back the result. */
bn.wsrr w0, MAI_RES_S0
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it save to overwrite x0_A with x0_B? It should because the conversion is performs also a re-masking?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is okay. There shouldn't be any leakage.

bn.xor w31, w31, w31 /* dummy */
bn.wsrr w1, MAI_RES_S1

ret

/**
* Convert the Boolean sharing of a vector of 8 coefficients (x0_B, x1_B) to a
* arithmetic sharing (x0_A, x1_A).
*
* @param[in] w0: x0_B, first arithmetic share.
* @param[in] w1: x1_B, second arithmetic share.
* @param[out] w0: x0_A, first Boolean share.
* @param[out] w1: x1_A, second Boolean share
*/
sec_b2a_8x32:
/* Write the two shares to the input WSRs (intersperse with configuration of
MAI_CTRL to not access both shares in subsequent instructions). */
bn.wsrw MAI_IN0_S0, w0
addi x20, x0, MAI_CTRL_B2A
bn.wsrw MAI_IN0_S1, w1

/* Trigger the conversion. */
csrrw x0, MAI_CTRL, x20

/* TODO: Replace with deterministic wait, once latency is known. */
jal x1, _mai_poll

/* Read back the result. */
bn.wsrr w0, MAI_RES_S0
bn.xor w31, w31, w31 /* dummy */
bn.wsrr w1, MAI_RES_S1

ret

/**
* Calculate a vectorized addition modulo 2^32 of 8 Boolean-shared coefficients.
*
* @param[in] w0: x0_B, first Boolean share of x
* @param[in] w1: x1_B, second Boolean share of x.
* @param[in] w2: y0_B, first Boolean share of y
* @param[in] w3: y1_B, second Boolean share of y.
* @param[out] w0: z0_B, first Boolean share of the result z = x + y.
* @param[out] w1: z1_B, second Boolean share of the result z = x + y.
*/
sec_add_8x32:
/* Write the two summands to the input WSRs (intersperse with configuration of
MAI_CTRL to not access both shares in subsequent instructions). */
bn.wsrw MAI_IN0_S0, w0
bn.wsrw MAI_IN1_S0, w2

addi x20, x0, MAI_CTRL_ADD

bn.wsrw MAI_IN0_S1, w1
bn.wsrw MAI_IN1_S1, w3

/* Trigger the conversion. */
csrrw x0, MAI_CTRL, x20

/* TODO: Replace with deterministic wait, once latency is known. */
jal x1, _mai_poll

/* Read back the result. */
bn.wsrr w0, MAI_RES_S0
bn.xor w31, w31, w31 /* dummy */
bn.wsrr w1, MAI_RES_S1

ret

/**
* Securely unmask a vector of 8 Boolean-shared coefficients.
*
* This is an implementation of the `SecUnMask` function (Algorithm 3 in [1]).
*
* @param[in] w0: x0_B, first Boolean share of x
* @param[in] w1: x1_B, second Boolean share of x.
* @param[out] w0: x, unmasked value x.
*/
sec_unmask_8x32:
/* Sample a fresh random mask and XOR it to the shares before unmasking. */
bn.wsrr w20, URND

bn.xor w0, w0, w20
bn.xor w31, w31, w31 /* dummy */
bn.xor w1, w1, w20

bn.xor w0, w0, w1

ret
5 changes: 5 additions & 0 deletions sw/otbn/crypto/mldsa87/tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ srcs = [
"//sw/otbn/crypto/mldsa87:mldsa87_ntt.s",
"//sw/otbn/crypto/mldsa87:mldsa87_sample.s",
"//sw/otbn/crypto/mldsa87:mldsa87_encoding.s",
"//sw/otbn/crypto/mldsa87:mldsa87_gadgets.s",
"//sw/otbn/crypto/mldsa87:mldsa87_xof.s",
"//sw/otbn/crypto/mldsa87:mldsa87_expand.s",
]
Expand All @@ -32,6 +33,10 @@ unit_tests = [
"mldsa87_encode_w1_test",
"mldsa87_xof_shake128_test",
"mldsa87_xof_shake256_test",
"mldsa87_sec_a2b_test",
"mldsa87_sec_b2a_test",
"mldsa87_sec_add_test",
"mldsa87_sec_unmask_test",
]

[
Expand Down
12 changes: 12 additions & 0 deletions sw/otbn/crypto/mldsa87/tests/mldsa87_sec_a2b_test.hjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

{
"entrypoint": "main",
"output": {
"regs": {
"w2": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
}
}
60 changes: 60 additions & 0 deletions sw/otbn/crypto/mldsa87/tests/mldsa87_sec_a2b_test.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* Copyright lowRISC contributors (OpenTitan project). */
/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
/* SPDX-License-Identifier: Apache-2.0 */

/* Randomized test to verify the A2B conversion. */

.section .text.start

main:
la x31, _stack
bn.xor w31, w31, w31

la x2, _params
bn.lid x0, 0(x2)
bn.wsrw MOD, w0

bn.not w2, w31 /* flag */
bn.shv.8s w3, w2 >> 10 /* mask */

/* Generate 100 random arithmetically shared vectors and verify that they can
be correctly converted to Boolean shares. */
loopi 100, 10
/* Random vector of coefficients < q. */
bn.wsrr w4, URND
bn.and w4, w4, w3

/* Random coefficient masks < q. */
bn.wsrr w5, URND
bn.and w5, w5, w3

/* Create the two arithmetic shares and trigger the conversion. */
bn.subvm.8s w0, w4, w5
bn.mov w1, w5
jal x1, sec_a2b_8x32

/* Unmask the result. */
bn.xor w0, w0, w1

/* Check that the unmask result is equal to the initial vector. */
bn.cmp w0, w4, FG0
bn.sel w2, w2, w31, FG0.Z
/* End of loop */

ecall

.data
.balign 32

_params:
.word 0x007fe001 /* q */
.word 0xfc7fdfff /* mu */
.word 0x0000a3fa /* n^-1 * R^3 mod q */
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000

_stack:
.zero 4
12 changes: 12 additions & 0 deletions sw/otbn/crypto/mldsa87/tests/mldsa87_sec_add_test.hjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

{
"entrypoint": "main",
"output": {
"regs": {
"w4": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
}
}
64 changes: 64 additions & 0 deletions sw/otbn/crypto/mldsa87/tests/mldsa87_sec_add_test.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* Copyright lowRISC contributors (OpenTitan project). */
/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
/* SPDX-License-Identifier: Apache-2.0 */

/* Randomized test to verify the secure addition. */

.section .text.start

main:
la x31, _stack
bn.xor w31, w31, w31

la x2, _params
bn.lid x0, 0(x2)
bn.wsrw MOD, w0

bn.not w4, w31 /* flag */

/* Generate 100 random Boolean-shared summands and verify that they can be
correctly added together. */
loopi 100, 13
/* Random vectors x and y < 2^32. */
bn.wsrr w5, URND
bn.wsrr w6, URND

/* Expected result x + y mod 2^32. */
bn.addv.8s w7, w5, w6

/* Random masks */
bn.wsrr w8, URND
bn.wsrr w9, URND

/* Create the two Boolean shares and trigger the conversion. */
bn.xor w0, w5, w8
bn.mov w1, w8
bn.xor w2, w6, w9
bn.mov w3, w9
jal x1, sec_add_8x32

/* Unmask the result. */
bn.xor w0, w0, w1

/* Check that the unmask result is equal to the initial vector. */
bn.cmp w0, w7, FG0
bn.sel w4, w4, w31, FG0.Z
/* End of loop */

ecall

.data
.balign 32

_params:
.word 0x007fe001 /* q */
.word 0xfc7fdfff /* mu */
.word 0x0000a3fa /* n^-1 * R^3 mod q */
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000

_stack:
.zero 4
12 changes: 12 additions & 0 deletions sw/otbn/crypto/mldsa87/tests/mldsa87_sec_b2a_test.hjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

{
"entrypoint": "main",
"output": {
"regs": {
"w2": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
}
}
Loading
Loading