Skip to content

Commit cf9877b

Browse files
author
royb
committed
fixed slh-dsa: message_to_indexes replaced with base2b in for.sign()
added internal functions added context to SLHDSAKeyParameters
1 parent 455ca61 commit cf9877b

File tree

5 files changed

+514
-381
lines changed

5 files changed

+514
-381
lines changed

core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/Fors.java

+20-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.bouncycastle.pqc.crypto.slhdsa;
22

3+
import java.math.BigInteger;
34
import java.util.LinkedList;
45

56
import org.bouncycastle.util.Arrays;
@@ -63,7 +64,8 @@ public SIG_FORS[] sign(byte[] md, byte[] skSeed, byte[] pkSeed, ADRS paramAdrs)
6364
{
6465
ADRS adrs = new ADRS(paramAdrs);
6566

66-
int[] idxs = message_to_idxs(md, engine.K, engine.A);
67+
// int[] idxs = message_to_idxs(md, engine.K, engine.A);
68+
int[] idxs = base2B(md, engine.A, engine.K);
6769
SIG_FORS[] sig_fors = new SIG_FORS[engine.K];
6870
// compute signature elements
6971
int t = engine.T;
@@ -99,7 +101,8 @@ public byte[] pkFromSig(SIG_FORS[] sig_fors, byte[] message, byte[] pkSeed, ADRS
99101
byte[][] root = new byte[engine.K][];
100102
int t = engine.T;
101103

102-
int[] idxs = message_to_idxs(message, engine.K, engine.A);
104+
// int[] idxs = message_to_idxs(message, engine.K, engine.A);
105+
int[] idxs = base2B(message, engine.A, engine.K);
103106
// compute roots
104107
for (int i = 0; i < engine.K; i++)
105108
{
@@ -137,24 +140,25 @@ public byte[] pkFromSig(SIG_FORS[] sig_fors, byte[] message, byte[] pkSeed, ADRS
137140
return engine.T_l(pkSeed, forspkADRS, Arrays.concatenate(root));
138141
}
139142

140-
/**
141-
* Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
142-
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
143-
* Assumes indices has space for SPX_FORS_TREES integers.
144-
*/
145-
static int[] message_to_idxs(byte[] msg, int fors_trees, int fors_height)
143+
static int[] base2B(byte[] msg, int b, int outLen)
146144
{
147-
int offset = 0;
148-
int[] idxs = new int[fors_trees];
149-
for (int i = 0; i < fors_trees; i++)
145+
int[] baseB = new int[outLen];
146+
int i = 0;
147+
int bits = 0;
148+
BigInteger total = BigInteger.ZERO;
149+
150+
for (int o = 0; o < outLen; o++)
150151
{
151-
idxs[i] = 0;
152-
for (int j = 0; j < fors_height; j++)
152+
while (bits < b)
153153
{
154-
idxs[i] ^= ((msg[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
155-
offset++;
154+
total = total.shiftLeft(8).add(BigInteger.valueOf(msg[i] & 0xff));
155+
i+= 1;
156+
bits += 8;
156157
}
158+
bits -= b;
159+
baseB[o] = (total.shiftRight(bits).mod(BigInteger.valueOf(2).pow(b))).intValue();
157160
}
158-
return idxs;
161+
162+
return baseB;
159163
}
160164
}

core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSAKeyPairGenerator.java

+17-7
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,32 @@ public void init(KeyGenerationParameters param)
1818
parameters = ((SLHDSAKeyGenerationParameters)param).getParameters();
1919
}
2020

21-
public AsymmetricCipherKeyPair generateKeyPair()
21+
public AsymmetricCipherKeyPair internalGenerateKeyPair(byte[] skSeed, byte[] skPrf, byte[] pkSeed)
2222
{
2323
SLHDSAEngine engine = parameters.getEngine();
24-
byte[] pkSeed;
25-
SK sk;
26-
27-
sk = new SK(sec_rand(engine.N), sec_rand(engine.N));
28-
pkSeed = sec_rand(engine.N);
24+
SK sk = new SK(skSeed, skPrf);
2925

3026
engine.init(pkSeed);
3127

3228
// TODO
3329
PK pk = new PK(pkSeed, new HT(engine, sk.seed, pkSeed).htPubKey);
3430

3531
return new AsymmetricCipherKeyPair(new SLHDSAPublicKeyParameters(parameters, pk),
36-
new SLHDSAPrivateKeyParameters(parameters, sk, pk));
32+
new SLHDSAPrivateKeyParameters(parameters, sk, pk));
33+
}
34+
35+
public AsymmetricCipherKeyPair generateKeyPair()
36+
{
37+
SLHDSAEngine engine = parameters.getEngine();
38+
byte[] pkSeed;
39+
byte[] skSeed;
40+
byte[] skPrf;
41+
42+
43+
skSeed = sec_rand(engine.N);
44+
skPrf = sec_rand(engine.N);
45+
pkSeed = sec_rand(engine.N);
46+
return internalGenerateKeyPair(skSeed, skPrf, pkSeed);
3747
}
3848

3949
private byte[] sec_rand(int n)

core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSAKeyParameters.java

+12
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,27 @@ public class SLHDSAKeyParameters
66
extends AsymmetricKeyParameter
77
{
88
final SLHDSAParameters parameters;
9+
final byte[] context;
910

11+
protected SLHDSAKeyParameters(boolean isPrivate, SLHDSAParameters parameters, byte[] context)
12+
{
13+
super(isPrivate);
14+
this.parameters = parameters;
15+
this.context = context;
16+
}
1017
protected SLHDSAKeyParameters(boolean isPrivate, SLHDSAParameters parameters)
1118
{
1219
super(isPrivate);
1320
this.parameters = parameters;
21+
this.context = new byte[0];
1422
}
1523

1624
public SLHDSAParameters getParameters()
1725
{
1826
return parameters;
1927
}
28+
public byte[] getContext()
29+
{
30+
return context.clone();
31+
}
2032
}

core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSASigner.java

+85-45
Original file line numberDiff line numberDiff line change
@@ -52,68 +52,52 @@ public void init(boolean forSigning, CipherParameters param)
5252
}
5353
}
5454

55+
//TODO: make Hash_slh_sign
56+
5557
public byte[] generateSignature(byte[] message)
5658
{
57-
// # Input: Message M, private key SK = (SK.seed, SK.prf, PK.seed, PK.root)
58-
// # Output: SLH-DSA signature SIG
59-
// init
60-
6159
SLHDSAEngine engine = privKey.getParameters().getEngine();
6260

6361
engine.init(privKey.pk.seed);
62+
byte[] ctx = privKey.getContext();
6463

65-
// generate randomizer
66-
byte[] optRand = new byte[engine.N];
67-
if (random != null)
64+
if (ctx.length > 255)
6865
{
69-
random.nextBytes(optRand);
66+
throw new RuntimeException("Context too long");
7067
}
71-
else
72-
{
73-
System.arraycopy(privKey.pk.seed, 0, optRand, 0, optRand.length);
74-
}
75-
76-
Fors fors = new Fors(engine);
77-
byte[] R = engine.PRF_msg(privKey.sk.prf, optRand, message);
7868

79-
// compute message digest and index
80-
IndexedDigest idxDigest = engine.H_msg(R, privKey.pk.seed, privKey.pk.root, message);
81-
byte[] mHash = idxDigest.digest;
82-
long idx_tree = idxDigest.idx_tree;
83-
int idx_leaf = idxDigest.idx_leaf;
84-
// FORS sign
85-
ADRS adrs = new ADRS();
86-
adrs.setType(ADRS.FORS_TREE);
87-
adrs.setTreeAddress(idx_tree);
88-
adrs.setKeyPairAddress(idx_leaf);
89-
SIG_FORS[] sig_fors = fors.sign(mHash, privKey.sk.seed, privKey.pk.seed, adrs);
90-
// get FORS public key - spec shows M?
91-
adrs = new ADRS();
92-
adrs.setType(ADRS.FORS_TREE);
93-
adrs.setTreeAddress(idx_tree);
94-
adrs.setKeyPairAddress(idx_leaf);
95-
byte[] PK_FORS = fors.pkFromSig(sig_fors, mHash, privKey.pk.seed, adrs);
69+
byte[] ds_message = new byte[1 + 1 + ctx.length + message.length];
70+
ds_message[0] = 0;
71+
ds_message[1] = (byte)ctx.length;
72+
System.arraycopy(ctx, 0, ds_message, 2, ctx.length);
73+
System.arraycopy(message, 0, ds_message, 2 + ctx.length, message.length);
9674

97-
// sign FORS public key with HT
98-
ADRS treeAdrs = new ADRS();
99-
treeAdrs.setType(ADRS.TREE);
75+
// generate randomizer
76+
byte[] optRand = new byte[engine.N];
77+
return internalGenerateSignature(ds_message, optRand);
78+
}
10079

101-
HT ht = new HT(engine, privKey.getSeed(), privKey.getPublicSeed());
102-
byte[] SIG_HT = ht.sign(PK_FORS, idx_tree, idx_leaf);
80+
//TODO: make Hash_slh_verify
10381

104-
byte[][] sigComponents = new byte[sig_fors.length + 2][];
105-
sigComponents[0] = R;
82+
// Equivalent to slh_verify_internal from specs
83+
public boolean verifySignature(byte[] message, byte[] signature)
84+
{
85+
byte[] ctx = pubKey.getContext();
10686

107-
for (int i = 0; i != sig_fors.length; i++)
87+
if (ctx.length > 255)
10888
{
109-
sigComponents[1 + i] = Arrays.concatenate(sig_fors[i].sk, Arrays.concatenate(sig_fors[i].authPath));
89+
throw new RuntimeException("Context too long");
11090
}
111-
sigComponents[sigComponents.length - 1] = SIG_HT;
11291

113-
return Arrays.concatenate(sigComponents);
114-
}
92+
byte[] ds_message = new byte[1 + 1 + ctx.length + message.length];
93+
ds_message[0] = 0;
94+
ds_message[1] = (byte)ctx.length;
95+
System.arraycopy(ctx, 0, ds_message, 2, ctx.length);
96+
System.arraycopy(message, 0, ds_message, 2 + ctx.length, message.length);
11597

116-
public boolean verifySignature(byte[] message, byte[] signature)
98+
return internalVerifySignature(ds_message, signature);
99+
}
100+
public boolean internalVerifySignature(byte[] message, byte[] signature)
117101
{
118102
//# Input: Message M, signature SIG, public key PK
119103
//# Output: Boolean
@@ -124,6 +108,12 @@ public boolean verifySignature(byte[] message, byte[] signature)
124108
engine.init(pubKey.getSeed());
125109

126110
ADRS adrs = new ADRS();
111+
112+
if (((1 + engine.K * (1 + engine.A) + engine.H + engine.D *engine.WOTS_LEN)* engine.N) != signature.length)
113+
{
114+
return false;
115+
}
116+
127117
SIG sig = new SIG(engine.N, engine.K, engine.A, engine.D, engine.H_PRIME, engine.WOTS_LEN, signature);
128118

129119
byte[] R = sig.getR();
@@ -150,5 +140,55 @@ public boolean verifySignature(byte[] message, byte[] signature)
150140
HT ht = new HT(engine, null, pubKey.getSeed());
151141
return ht.verify(PK_FORS, SIG_HT, pubKey.getSeed(), idx_tree, idx_leaf, pubKey.getRoot());
152142
}
143+
144+
public byte[] internalGenerateSignature(byte[] message, byte[] optRand)
145+
{
146+
SLHDSAEngine engine = privKey.getParameters().getEngine();
147+
engine.init(privKey.pk.seed);
148+
149+
if (optRand == null)
150+
{
151+
optRand = new byte[engine.N];
152+
System.arraycopy(privKey.pk.seed, 0, optRand, 0, optRand.length);
153+
}
154+
155+
Fors fors = new Fors(engine);
156+
byte[] R = engine.PRF_msg(privKey.sk.prf, optRand, message);
157+
158+
IndexedDigest idxDigest = engine.H_msg(R, privKey.pk.seed, privKey.pk.root, message);
159+
byte[] mHash = idxDigest.digest;
160+
long idx_tree = idxDigest.idx_tree;
161+
int idx_leaf = idxDigest.idx_leaf;
162+
// FORS sign
163+
ADRS adrs = new ADRS();
164+
adrs.setType(ADRS.FORS_TREE);
165+
adrs.setTreeAddress(idx_tree);
166+
adrs.setKeyPairAddress(idx_leaf);
167+
SIG_FORS[] sig_fors = fors.sign(mHash, privKey.sk.seed, privKey.pk.seed, adrs);
168+
// get FORS public key - spec shows M?
169+
adrs = new ADRS();
170+
adrs.setType(ADRS.FORS_TREE);
171+
adrs.setTreeAddress(idx_tree);
172+
adrs.setKeyPairAddress(idx_leaf);
173+
byte[] PK_FORS = fors.pkFromSig(sig_fors, mHash, privKey.pk.seed, adrs);
174+
175+
// sign FORS public key with HT
176+
ADRS treeAdrs = new ADRS();
177+
treeAdrs.setType(ADRS.TREE);
178+
179+
HT ht = new HT(engine, privKey.getSeed(), privKey.getPublicSeed());
180+
byte[] SIG_HT = ht.sign(PK_FORS, idx_tree, idx_leaf);
181+
182+
byte[][] sigComponents = new byte[sig_fors.length + 2][];
183+
sigComponents[0] = R;
184+
185+
for (int i = 0; i != sig_fors.length; i++)
186+
{
187+
sigComponents[1 + i] = Arrays.concatenate(sig_fors[i].sk, Arrays.concatenate(sig_fors[i].authPath));
188+
}
189+
sigComponents[sigComponents.length - 1] = SIG_HT;
190+
191+
return Arrays.concatenate(sigComponents);
192+
}
153193
}
154194

0 commit comments

Comments
 (0)