Skip to content

Commit eddde1f

Browse files
[crypto] ML-DSA-87: Encoding of S polynomials
This commit introduces a routine that facilitates the encoding of S{1,2} polynomials of the secret key. Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
1 parent b8b5106 commit eddde1f

4 files changed

Lines changed: 196 additions & 0 deletions

File tree

sw/otbn/crypto/mldsa87/keygen/mldsa87_keygen_encoding.s

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
.globl encode_t0
88
.globl encode_t1
9+
.globl encode_s
910

1011
.text
1112

@@ -144,3 +145,118 @@ encode_t1:
144145
.endr
145146

146147
ret
148+
149+
/**
150+
* Encode a S{1, 2} polynomial to a dense representation.
151+
*
152+
* A S{1, 2} polynomial of the secret key consists of 256 3-bit coefficients in
153+
* the range [-ETA, ETA] for ETA = 2, hence its encoded representation has a
154+
* size of 256 * 3 = 768 bits or 96 bytes. This routine is a part of the
155+
* `skEncode` function (Algorithm 24) of FIPS-204.
156+
*
157+
* The S polynomial is assumed to be passed as two arithmetic shares. The
158+
* encoded polynomial is returned as two Boolean shares.
159+
*
160+
* @param[in] x2: DMEM address of the first arithmetic share of S.
161+
* @param[in] x3: DMEM address of the second arithmetic share of S.
162+
* @param[in] x4: DMEM address of the first Boolean share of the encoded S.
163+
* @param[in] x5: DMEM address of the second Boolean share of the encoded S.
164+
*/
165+
encode_s:
166+
/* Push clobbered registers onto the stack. */
167+
.irp reg, x2, x3, x6, x7
168+
sw \reg, 0(x31)
169+
addi x31, x31, 4
170+
.endr
171+
172+
/* Set up subtraction vector w2 = [ETA, ETA, ..., ETA]. */
173+
bn.not w2, w31
174+
bn.shv.8s w2, w2 >> 31
175+
bn.shv.8s w2, w2 << 1
176+
177+
/* WDR pointers. */
178+
addi x6, x0, 0
179+
addi x7, x0, 1
180+
181+
/* Initialize the registers that hold the compressed polynomial shares with
182+
randomness. This avoids isolating secrets bits in an all-zero register
183+
during the shifting operations. */
184+
185+
/* Share 0. */
186+
bn.wsrr w3, URND
187+
bn.wsrr w4, URND
188+
bn.wsrr w5, URND
189+
/* Share 1. */
190+
bn.wsrr w6, URND
191+
bn.wsrr w7, URND
192+
bn.wsrr w8, URND
193+
194+
/* Encode the polynomial in chunks of 8 coefficients at a time. */
195+
loopi 32, 19
196+
/* Load the two arithmetically shared vectors of 8 coefficients
197+
x = (x0, x1) and compute ETA - x mod Q. This is the centering step of
198+
the `BitPack` function (Algorithm 17) of FIPS-204. */
199+
200+
/* Share 0. */
201+
bn.lid x6, 0(x2++)
202+
bn.subvm.8S w0, w2, w0
203+
204+
bn.xor w31, w31, w31 /* dummy */
205+
206+
/* Share 1. */
207+
bn.lid x7, 0(x3++)
208+
bn.subvm.8S w1, w31, w1
209+
210+
/* Convert the two arithmetically shared vectors to Boolean shares. */
211+
jal x1, sec_a2b_8x32
212+
213+
loopi 8, 11
214+
/* Randomness to shift into registers when a coefficient is extracted.
215+
This avoids that few secrets bits are isolated in an all-zero WDR. */
216+
bn.wsrr w9, URND
217+
bn.wsrr w10, URND
218+
219+
/* Share 0: */
220+
221+
/* Shift a 3-bit coefficient into w3-w5. */
222+
bn.rshi w3, w4, w3 >> 3
223+
bn.rshi w4, w5, w4 >> 3
224+
bn.rshi w5, w0, w5 >> 3
225+
bn.rshi w0, w9, w0 >> 32
226+
227+
/* Share 1. */
228+
229+
bn.xor w31, w31, w31 /* dummy */
230+
231+
/* Shift a 3-bit coefficient into w6-w8. */
232+
bn.rshi w6, w7, w6 >> 3
233+
bn.rshi w7, w8, w7 >> 3
234+
bn.rshi w8, w1, w8 >> 3
235+
bn.rshi w1, w10, w1 >> 32
236+
/* End of loop */
237+
238+
nop
239+
/* End of loop */
240+
241+
/* Store the encoded polynomial shares to DMEM. */
242+
243+
/* Share 0. */
244+
addi x6, x0, 3
245+
bn.sid x6++, 0(x4)
246+
bn.sid x6++, 32(x4)
247+
bn.sid x6++, 64(x4)
248+
249+
bn.xor w31, w31, w31 /* dummy */
250+
251+
/* Share 1. */
252+
bn.sid x6++, 0(x5)
253+
bn.sid x6++, 32(x5)
254+
bn.sid x6++, 64(x5)
255+
256+
/* Restore clobbered general-purpose registers. */
257+
.irp reg, x7, x6, x3, x2
258+
addi x31, x31, -4
259+
lw \reg, 0(x31)
260+
.endr
261+
262+
ret

sw/otbn/crypto/mldsa87/keygen/tests/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ srcs = [
1212
"//sw/otbn/crypto/mldsa87:mldsa87_ntt.s",
1313
"//sw/otbn/crypto/mldsa87:mldsa87_sample.s",
1414
"//sw/otbn/crypto/mldsa87:mldsa87_encoding.s",
15+
"//sw/otbn/crypto/mldsa87:mldsa87_decoding.s",
1516
"//sw/otbn/crypto/mldsa87:mldsa87_xof.s",
1617
"//sw/otbn/crypto/mldsa87:mldsa87_expand.s",
1718
"//sw/otbn/crypto/mldsa87:mldsa87_gadgets.s",
@@ -28,6 +29,7 @@ unit_tests = [
2829
"mldsa87_keygen_encode_t0_test",
2930
"mldsa87_keygen_encode_t1_test",
3031
"mldsa87_keygen_power2round_test",
32+
"mldsa87_keygen_encode_s_test",
3133
]
3234

3335
[
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright lowRISC contributors (OpenTitan project).
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
// NIST ACVP ML-DSA-87 keygen vector #51 (first ML-DSA-87 vector):
6+
// https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/ML-DSA-keyGen-FIPS204
7+
8+
{
9+
"entrypoint": "main",
10+
"input": {
11+
"dmem": {
12+
// Decoded S1[0] (share 0)
13+
"_encode_s_s_dec_share0": "0x0023f4de006832d70003a05f0004dcee0066f7a4007d1b0400325ed6007b37820071056700025e700015249900507f42007428b2004dccdb00708dd40036272c00159fbc003243800067be91002e9853006ff23b007c7535007667480028c2760032cc16003b7f6800080021000b6499002eb25600366b8e0017489a007a15c50063df3c002692bc001264cc006d2420001ba2c50072ff4c0077ea130017702a0049548c00554f77006a0da7001a2b1b005040570063a7f3002597a60070e1bf005d2ea400223e90007dccdd0060c438006781ab0013b4810054f5db002f37570034babe00419c3600711c3c0031705300565c89007554cf005221c8001a545200021ebd000a81ae00263f0500005a9f002dcd46002b5d150040d0ad004633f5005ca5e60035ac8d004a305a00064e1a00163dc6003461680028e6ff000d4f5e0064544a0013240f0061bb150017fc90003d15fc005c9809003cbac3002599480014a0d9004dca0300286322003aada30015b7830009b86f00265c99000ce8ac00759a7000140a46007aedcd0009aea7006cbb89000fa601006f34d0001ee6d90028ff94007460a3007708360042e10b005e967d002bd296000244c6003170a8007ba78f0067f9430016ba2b0067a207006856fe005ab67d0060e2a20036311500574b04004e9b910019bd4600338ce1007425660046ea9a005b0e0d0034a8f90039d4610032aad100198c63000480f40065dd7e003ab7fd0009d3b900179f8f005548720039cd77006fe63300256f68005a9d8e0039501300594a340071ea6800413f0f000878e900002279003edbce000fdd240056e8760000be1d007593f60074330b004688ef003a5f520019116c006da2bf000407a400190c010061550c00637f3600373bd2000a7f2200676b200077d021001074680025cf0d00563fb50022663e0060a78a00553bd70010d2660015e2050040b27100318d5f007fba8f002fd74c002a59f8001b639100164b7c0024f66c004cd35b001457e80023c0b90073efad007e13e1000aa0b30039a43b000a4fc20018d4dc0077e73b005e8834003d244800111d89004735d30042d159003926e9000426420065b3ac000b0277002de69b0031ae77005766e100484d0f005296f70072fc390038380a004370d700559c1900285336001303ac000cd2e100766f9f002274df00733bbd00582d15006d105f000c65d30032d4e100182ace00259cee00021418003bb4f4000b6d6f0001817d005fcf6c00198d2f0030b94c0073bc97001f21ce006dfcd0005bccbf006e0c4b003f466d0063ea13000ba2f8000dbe13003533be00520b710042dee00003ff2500590d100015a762001b8c7e000a5750004c0b1f0041ad1f003e6e8d00044ba9005ebbd0007ab168004a0ab5000dec7e001edb5a004e904b0013ca00",
14+
// Decoded S1[0] (share 1)
15+
"_encode_s_s_dec_share1": "0x005beb230017ad29007c3fa1007b03120018e85b0002c4fc004d81290004a87e000eda99007d8191006abb6a002f60be000bb75000321326000f522e0049b8d3006a4043004d9c7f00182171005147ad000fedc500036acc000978ba00571d8b004d13ec004460990077dfe000747b6700512dac00497471006897650005ca3a001c00c500594d45006d7b360012bbdf00643d3a000ce0b50007f5ec00686fd700368b77002a908b0015d2580065b4e5002f9fab001c380d005a485b000efe410022b15f005da17000021323001f1bca00185e55006c2b80002aea240050a8ab004b2543003e43cd000ec3c7004e6fad00298379000a8b32002dbe3800658bad007dc14300755e540059a0fd007f8560005212bc005482eb003f0f540039ac0d00233a1b004a33720035afa9007991e50069a23a004b7e9a0056f904007290a3001b8bb7006cbbf4001e24eb0067e3730042ca04002347fa0043253d005a46b9006b3f2a003215fd00577ce000453260006a287f00762790005983680072f756000a4593006bd5bc0004f234007631590013247700703a020010ab310060f92a0056e06d000b7f5d0008d7c9003cfef70021498500540d6a007d9b3a004e6f59000438700017e6c0006925d600183df90017890200252984001efd5e0049aeee002894fd00314470006622bc004c5320000bba990038f5660024d1f4004b370900460ba2004d352f006653a0007b5f0f001a02840045280300760c4700684073002a97910046128b000ff9cc005a709a0025427500468fec002695ce000df59b003ea0f300776719007fbd8800410432007002dc0028f78c007f21e2000a4c0c000bacf600395711004580b10066ce9500123d41007bd85b0066d402001e8af7001c60cb0048a431007560e0001874e200080fde006f6b99005a10f50029a04b005d79c4001f3878002aa42c006f0d9b0069fdfa003f2d8f004e52a400002572005008b50055860b00647c7100699485005ae99500330ca6006b881b005c1f48000bf0550001cc1e00753f4e00463bc70075904100670b260007f8c7002157cf0042bbb7006ec2790038aa2d003d0ea80046b918007bb9c1001a2c530074dd8b0051f964004e318b00287922003792f1002d4908000ce3c60047a7f9003c6f2c002a43e700578cc9006cdc5300730d2200097064005d6b20000ca4460027b2ea0012cfa100737a2c004d0b200067b532005a4315007dcbea00442b0b00747290007e5e8200201097006652d2004f26b7000c236a0060be310011e330002413430011d3b800409994001bf5ee00743d0b007221ef004aac43002dd48f003d0121007be0de0026d2f3006a389e00645383007588b30033d4e1003e32e000417173007b945a0021242f00052e970035d54a0071f383006104a600314fb7006c1603",
16+
}
17+
},
18+
"output": {
19+
"dmem": {
20+
// Encoded S1[0]
21+
"_encode_s_s_enc_share0": "0x4db8e368328c90b68a29332448c8a20632d30d96a140329c64c2d150464241861a0c83110536104e12da81369848a8d10c02d90611082536614c270040988b2428c240a48231104885a42184390072010471306481051909029a01a0e31244c8",
22+
}
23+
},
24+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* Copyright lowRISC contributors (OpenTitan project). */
2+
/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
3+
/* SPDX-License-Identifier: Apache-2.0 */
4+
5+
/* Verify that the we can correctly encode a S{1, 2} polynomial. */
6+
7+
.section .text.start
8+
9+
main:
10+
la x31, _stack
11+
bn.xor w31, w31, w31
12+
13+
la x2, _params
14+
bn.lid x0, 0(x2)
15+
bn.wsrw MOD, w0
16+
17+
la x2, _encode_s_s_dec_share0
18+
la x3, _encode_s_s_dec_share1
19+
la x4, _encode_s_s_enc_share0
20+
la x5, _encode_s_s_enc_share1
21+
jal x1, encode_s
22+
23+
la x20, _encode_s_s_enc_share0
24+
la x21, _encode_s_s_enc_share1
25+
addi x22, x0, 3
26+
jal x1, unmask_boolean
27+
28+
ecall
29+
30+
.data
31+
.balign 32
32+
33+
_encode_s_s_dec_share0:
34+
.zero 1024
35+
_encode_s_s_dec_share1:
36+
.zero 1024
37+
38+
_encode_s_s_enc_share0:
39+
.zero 96
40+
_encode_s_s_enc_share1:
41+
.zero 96
42+
43+
_params:
44+
.word 0x007fe001 /* q */
45+
.word 0xfc7fdfff /* mu */
46+
.word 0x0000a3fa /* n^-1 * R^3 mod q */
47+
.word 0x00000000
48+
.word 0x00000000
49+
.word 0x00000000
50+
.word 0x00000000
51+
.word 0x00000000
52+
53+
_stack:
54+
.zero 256

0 commit comments

Comments
 (0)