org.bouncycastle.pqc.crypto.lms.LMS Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-jdk15on Show documentation
Show all versions of bcprov-jdk15on Show documentation
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.5 and up.
package org.bouncycastle.pqc.crypto.lms;
import org.bouncycastle.crypto.Digest;
class LMS
{
static final short D_LEAF = (short)0x8282;
static final short D_INTR = (short)0x8383;
public static LMSPrivateKeyParameters generateKeys(LMSigParameters parameterSet, LMOtsParameters lmOtsParameters, int q, byte[] I, byte[] rootSeed)
throws IllegalArgumentException
{
//
// RFC 8554 recommends that digest used in LMS and LMOTS be of the same strength to protect against
// attackers going after the weaker of the two digests. This is not enforced here!
//
// Algorithm 5, Compute LMS private key.
// Step 1
// -- Parameters passed in as arguments.
// Step 2
if (rootSeed == null || rootSeed.length < parameterSet.getM())
{
throw new IllegalArgumentException("root seed is less than " + parameterSet.getM());
}
int twoToH = 1 << parameterSet.getH();
return new LMSPrivateKeyParameters(parameterSet, lmOtsParameters, q, I, twoToH, rootSeed);
}
public static LMSSignature generateSign(LMSPrivateKeyParameters privateKey, byte[] message)
{
//
// Get T from the public key.
// This may cause the public key to be generated.
//
// byte[][] T = new byte[privateKey.getMaxQ()][];
// Step 1.
LMSigParameters lmsParameter = privateKey.getSigParameters();
// Step 2
int h = lmsParameter.getH();
int q = privateKey.getIndex();
LMOtsPrivateKey otsPk = privateKey.getNextOtsPrivateKey();
// LmsPrivateKey.KeyWithQ keyWithQ = privateKey.getNextOtsPrivateKey();
LMOtsSignature ots_signature = LM_OTS.lm_ots_generate_signature(otsPk, message, false);
int i = 0;
int r = (1 << h) + q;
byte[][] path = new byte[h][];
while (i < h)
{
int tmp = (r / (1 << i)) ^ 1;
path[i] = privateKey.findT(tmp);
i++;
}
return new LMSSignature(q, ots_signature, lmsParameter, path);
}
public static boolean verifySignature(LMSPublicKeyParameters publicKey, LMSSignature S, byte[] message)
{
byte[] Tc = algorithm6a(S, publicKey.refI(), publicKey.getOtsParameters().getType(), message);
return publicKey.matchesT1(Tc);
}
public static byte[] algorithm6a(LMSSignature S, byte[] I, int ots_typecode, byte[] message)
{
// Step 1.
// if (S.length < 8)
// {
// throw new IllegalArgumentException("signature must be at least eight bytes");
// }
// Step 2a
int q = S.getQ(); // Pack.bigEndianToInt(S, 0);
// // Step 2b
// int otssigtype = S. Pack.bigEndianToInt(S, 4);
// Step 2c
if (S.getOtsSignature().getType().getType() != ots_typecode)
{
throw new IllegalArgumentException("ots type from lsm signature does not match ots" +
" signature type from embedded ots signature");
}
// Step 2d
// LmOtsParameter otsParameter = LmOtsParameters.getOtsParameter(otssigtype);
// int n = otsParameter.getN();
// int p = otsParameter.getP();
// if (S.length < 12 + n * (p + 1))
// {
// throw new IllegalArgumentException("S must be at least " + (12 + n * (p + 1)) + " bytes");
// }
// Step 2e
// byte[] lmots_signature = new byte[(((7 + n * (p + 1))) - 4) + 1];
// System.arraycopy(S, 4, lmots_signature, 0, lmots_signature.length);
//
// // Step 2f
// int sigType = Pack.bigEndianToInt(S, (8 + n * (p + 1)));
//
// // Step 2g
// if (sigType != lMpubType)
// {
// throw new IllegalArgumentException("lm ");
// }
//
// // Step 2h
LMSigParameters lmsParameter = S.getParameter();
int m = lmsParameter.getM();
int h = lmsParameter.getH();
//
//
// // Step 2i
// if (q > (1 << h) || S.length != 12 + n * (p + 1) + m * h)
// {
// throw new IllegalArgumentException("S has incorrect length.");
// }
//
//
// // Step 2j
// int pos = (8 + n * (p + 1)) + 4;
byte[][] path = S.getY();
// for (int i = 0; i < h; i++)
// {
// path[i] = new byte[m];
// System.arraycopy(S, pos, path[i], 0, m);
// pos += m;
// }
// Step 3
byte[] Kc = LM_OTS.lm_ots_validate_signature_calculate(
LMOtsParameters.getParametersForType(ots_typecode),
I,
q,
S.getOtsSignature(),
message, false);
// Step 4
// node_num = 2^h + q
int node_num = (1 << h) + q;
// tmp = H(I || u32str(node_num) || u16str(D_LEAF) || Kc)
Digest H = DigestUtil.getDigest(lmsParameter.getDigestOID());
byte[] tmp = new byte[H.getDigestSize()];
H.update(I, 0, I.length);
LmsUtils.u32str(node_num, H);
LmsUtils.u16str(D_LEAF, H);
H.update(Kc, 0, Kc.length);
H.doFinal(tmp, 0);
int i = 0;
while (node_num > 1)
{
if ((node_num & 1) == 1)
{
// is odd
H.update(I, 0, I.length);
LmsUtils.u32str(node_num / 2, H);
LmsUtils.u16str(D_INTR, H);
H.update(path[i], 0, path[i].length);
H.update(tmp, 0, tmp.length);
H.doFinal(tmp, 0);
}
else
{
H.update(I, 0, I.length);
LmsUtils.u32str(node_num / 2, H);
LmsUtils.u16str(D_INTR, H);
H.update(tmp, 0, tmp.length);
H.update(path[i], 0, path[i].length);
H.doFinal(tmp, 0);
}
node_num = node_num / 2;
i++;
}
return tmp;
}
}