Skip to content

Commit

Permalink
fixed slh-dsa: message_to_indexes replaced with base2b in for.sign()
Browse files Browse the repository at this point in the history
added internal functions
added context to SLHDSAKeyParameters
  • Loading branch information
royb committed Aug 23, 2024
1 parent 455ca61 commit cf9877b
Show file tree
Hide file tree
Showing 5 changed files with 514 additions and 381 deletions.
36 changes: 20 additions & 16 deletions core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/Fors.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.bouncycastle.pqc.crypto.slhdsa;

import java.math.BigInteger;
import java.util.LinkedList;

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

int[] idxs = message_to_idxs(md, engine.K, engine.A);
// int[] idxs = message_to_idxs(md, engine.K, engine.A);
int[] idxs = base2B(md, engine.A, engine.K);
SIG_FORS[] sig_fors = new SIG_FORS[engine.K];
// compute signature elements
int t = engine.T;
Expand Down Expand Up @@ -99,7 +101,8 @@ public byte[] pkFromSig(SIG_FORS[] sig_fors, byte[] message, byte[] pkSeed, ADRS
byte[][] root = new byte[engine.K][];
int t = engine.T;

int[] idxs = message_to_idxs(message, engine.K, engine.A);
// int[] idxs = message_to_idxs(message, engine.K, engine.A);
int[] idxs = base2B(message, engine.A, engine.K);
// compute roots
for (int i = 0; i < engine.K; i++)
{
Expand Down Expand Up @@ -137,24 +140,25 @@ public byte[] pkFromSig(SIG_FORS[] sig_fors, byte[] message, byte[] pkSeed, ADRS
return engine.T_l(pkSeed, forspkADRS, Arrays.concatenate(root));
}

/**
* Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
* Assumes indices has space for SPX_FORS_TREES integers.
*/
static int[] message_to_idxs(byte[] msg, int fors_trees, int fors_height)
static int[] base2B(byte[] msg, int b, int outLen)
{
int offset = 0;
int[] idxs = new int[fors_trees];
for (int i = 0; i < fors_trees; i++)
int[] baseB = new int[outLen];
int i = 0;
int bits = 0;
BigInteger total = BigInteger.ZERO;

for (int o = 0; o < outLen; o++)
{
idxs[i] = 0;
for (int j = 0; j < fors_height; j++)
while (bits < b)
{
idxs[i] ^= ((msg[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
offset++;
total = total.shiftLeft(8).add(BigInteger.valueOf(msg[i] & 0xff));
i+= 1;
bits += 8;
}
bits -= b;
baseB[o] = (total.shiftRight(bits).mod(BigInteger.valueOf(2).pow(b))).intValue();
}
return idxs;

return baseB;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,32 @@ public void init(KeyGenerationParameters param)
parameters = ((SLHDSAKeyGenerationParameters)param).getParameters();
}

public AsymmetricCipherKeyPair generateKeyPair()
public AsymmetricCipherKeyPair internalGenerateKeyPair(byte[] skSeed, byte[] skPrf, byte[] pkSeed)
{
SLHDSAEngine engine = parameters.getEngine();
byte[] pkSeed;
SK sk;

sk = new SK(sec_rand(engine.N), sec_rand(engine.N));
pkSeed = sec_rand(engine.N);
SK sk = new SK(skSeed, skPrf);

engine.init(pkSeed);

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

return new AsymmetricCipherKeyPair(new SLHDSAPublicKeyParameters(parameters, pk),
new SLHDSAPrivateKeyParameters(parameters, sk, pk));
new SLHDSAPrivateKeyParameters(parameters, sk, pk));
}

public AsymmetricCipherKeyPair generateKeyPair()
{
SLHDSAEngine engine = parameters.getEngine();
byte[] pkSeed;
byte[] skSeed;
byte[] skPrf;


skSeed = sec_rand(engine.N);
skPrf = sec_rand(engine.N);
pkSeed = sec_rand(engine.N);
return internalGenerateKeyPair(skSeed, skPrf, pkSeed);
}

private byte[] sec_rand(int n)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,27 @@ public class SLHDSAKeyParameters
extends AsymmetricKeyParameter
{
final SLHDSAParameters parameters;
final byte[] context;

protected SLHDSAKeyParameters(boolean isPrivate, SLHDSAParameters parameters, byte[] context)
{
super(isPrivate);
this.parameters = parameters;
this.context = context;
}
protected SLHDSAKeyParameters(boolean isPrivate, SLHDSAParameters parameters)
{
super(isPrivate);
this.parameters = parameters;
this.context = new byte[0];
}

public SLHDSAParameters getParameters()
{
return parameters;
}
public byte[] getContext()
{
return context.clone();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,68 +52,52 @@ public void init(boolean forSigning, CipherParameters param)
}
}

//TODO: make Hash_slh_sign

public byte[] generateSignature(byte[] message)
{
// # Input: Message M, private key SK = (SK.seed, SK.prf, PK.seed, PK.root)
// # Output: SLH-DSA signature SIG
// init

SLHDSAEngine engine = privKey.getParameters().getEngine();

engine.init(privKey.pk.seed);
byte[] ctx = privKey.getContext();

// generate randomizer
byte[] optRand = new byte[engine.N];
if (random != null)
if (ctx.length > 255)
{
random.nextBytes(optRand);
throw new RuntimeException("Context too long");
}
else
{
System.arraycopy(privKey.pk.seed, 0, optRand, 0, optRand.length);
}

Fors fors = new Fors(engine);
byte[] R = engine.PRF_msg(privKey.sk.prf, optRand, message);

// compute message digest and index
IndexedDigest idxDigest = engine.H_msg(R, privKey.pk.seed, privKey.pk.root, message);
byte[] mHash = idxDigest.digest;
long idx_tree = idxDigest.idx_tree;
int idx_leaf = idxDigest.idx_leaf;
// FORS sign
ADRS adrs = new ADRS();
adrs.setType(ADRS.FORS_TREE);
adrs.setTreeAddress(idx_tree);
adrs.setKeyPairAddress(idx_leaf);
SIG_FORS[] sig_fors = fors.sign(mHash, privKey.sk.seed, privKey.pk.seed, adrs);
// get FORS public key - spec shows M?
adrs = new ADRS();
adrs.setType(ADRS.FORS_TREE);
adrs.setTreeAddress(idx_tree);
adrs.setKeyPairAddress(idx_leaf);
byte[] PK_FORS = fors.pkFromSig(sig_fors, mHash, privKey.pk.seed, adrs);
byte[] ds_message = new byte[1 + 1 + ctx.length + message.length];
ds_message[0] = 0;
ds_message[1] = (byte)ctx.length;
System.arraycopy(ctx, 0, ds_message, 2, ctx.length);
System.arraycopy(message, 0, ds_message, 2 + ctx.length, message.length);

// sign FORS public key with HT
ADRS treeAdrs = new ADRS();
treeAdrs.setType(ADRS.TREE);
// generate randomizer
byte[] optRand = new byte[engine.N];
return internalGenerateSignature(ds_message, optRand);
}

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

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

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

return Arrays.concatenate(sigComponents);
}
byte[] ds_message = new byte[1 + 1 + ctx.length + message.length];
ds_message[0] = 0;
ds_message[1] = (byte)ctx.length;
System.arraycopy(ctx, 0, ds_message, 2, ctx.length);
System.arraycopy(message, 0, ds_message, 2 + ctx.length, message.length);

public boolean verifySignature(byte[] message, byte[] signature)
return internalVerifySignature(ds_message, signature);
}
public boolean internalVerifySignature(byte[] message, byte[] signature)
{
//# Input: Message M, signature SIG, public key PK
//# Output: Boolean
Expand All @@ -124,6 +108,12 @@ public boolean verifySignature(byte[] message, byte[] signature)
engine.init(pubKey.getSeed());

ADRS adrs = new ADRS();

if (((1 + engine.K * (1 + engine.A) + engine.H + engine.D *engine.WOTS_LEN)* engine.N) != signature.length)
{
return false;
}

SIG sig = new SIG(engine.N, engine.K, engine.A, engine.D, engine.H_PRIME, engine.WOTS_LEN, signature);

byte[] R = sig.getR();
Expand All @@ -150,5 +140,55 @@ public boolean verifySignature(byte[] message, byte[] signature)
HT ht = new HT(engine, null, pubKey.getSeed());
return ht.verify(PK_FORS, SIG_HT, pubKey.getSeed(), idx_tree, idx_leaf, pubKey.getRoot());
}

public byte[] internalGenerateSignature(byte[] message, byte[] optRand)
{
SLHDSAEngine engine = privKey.getParameters().getEngine();
engine.init(privKey.pk.seed);

if (optRand == null)
{
optRand = new byte[engine.N];
System.arraycopy(privKey.pk.seed, 0, optRand, 0, optRand.length);
}

Fors fors = new Fors(engine);
byte[] R = engine.PRF_msg(privKey.sk.prf, optRand, message);

IndexedDigest idxDigest = engine.H_msg(R, privKey.pk.seed, privKey.pk.root, message);
byte[] mHash = idxDigest.digest;
long idx_tree = idxDigest.idx_tree;
int idx_leaf = idxDigest.idx_leaf;
// FORS sign
ADRS adrs = new ADRS();
adrs.setType(ADRS.FORS_TREE);
adrs.setTreeAddress(idx_tree);
adrs.setKeyPairAddress(idx_leaf);
SIG_FORS[] sig_fors = fors.sign(mHash, privKey.sk.seed, privKey.pk.seed, adrs);
// get FORS public key - spec shows M?
adrs = new ADRS();
adrs.setType(ADRS.FORS_TREE);
adrs.setTreeAddress(idx_tree);
adrs.setKeyPairAddress(idx_leaf);
byte[] PK_FORS = fors.pkFromSig(sig_fors, mHash, privKey.pk.seed, adrs);

// sign FORS public key with HT
ADRS treeAdrs = new ADRS();
treeAdrs.setType(ADRS.TREE);

HT ht = new HT(engine, privKey.getSeed(), privKey.getPublicSeed());
byte[] SIG_HT = ht.sign(PK_FORS, idx_tree, idx_leaf);

byte[][] sigComponents = new byte[sig_fors.length + 2][];
sigComponents[0] = R;

for (int i = 0; i != sig_fors.length; i++)
{
sigComponents[1 + i] = Arrays.concatenate(sig_fors[i].sk, Arrays.concatenate(sig_fors[i].authPath));
}
sigComponents[sigComponents.length - 1] = SIG_HT;

return Arrays.concatenate(sigComponents);
}
}

Loading

0 comments on commit cf9877b

Please sign in to comment.