org.bouncycastle.pqc.crypto.xmss.XMSS Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-debug-jdk18on Show documentation
Show all versions of bcprov-ext-debug-jdk18on 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 Java 1.8 and later with debug enabled.
The newest version!
package org.bouncycastle.pqc.crypto.xmss;
import java.security.SecureRandom;
import java.text.ParseException;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.util.Arrays;
/**
* XMSS.
*/
public class XMSS
{
/**
* XMSS parameters.
*/
private final XMSSParameters params;
/**
* WOTS+ instance.
*/
private WOTSPlus wotsPlus;
/**
* PRNG.
*/
private SecureRandom prng;
/**
* XMSS private key.
*/
private XMSSPrivateKeyParameters privateKey;
/**
* XMSS public key.
*/
private XMSSPublicKeyParameters publicKey;
/**
* XMSS constructor...
*
* @param params XMSSParameters.
*/
public XMSS(XMSSParameters params, SecureRandom prng)
{
super();
if (params == null)
{
throw new NullPointerException("params == null");
}
this.params = params;
wotsPlus = params.getWOTSPlus();
this.prng = prng;
}
// public void generateKeys()
// {
// /* generate private key */
// privateKey = generatePrivateKey(params, prng);
// XMSSNode root = privateKey.getBDSState().initialize(privateKey, (OTSHashAddress)new OTSHashAddress.Builder().build());
//
// privateKey = new XMSSPrivateKeyParameters.Builder(params).withIndex(privateKey.getIndex())
// .withSecretKeySeed(privateKey.getSecretKeySeed()).withSecretKeyPRF(privateKey.getSecretKeyPRF())
// .withPublicSeed(privateKey.getPublicSeed()).withRoot(root.getValue())
// .withBDSState(privateKey.getBDSState()).build();
// publicKey = new XMSSPublicKeyParameters.Builder(params).withRoot(root.getValue())
// .withPublicSeed(getPublicSeed()).build();
//
// }
//
// /**
// * Generate an XMSS private key.
// *
// * @return XMSS private key.
// */
// private XMSSPrivateKeyParameters generatePrivateKey(XMSSParameters params, SecureRandom prng)
// {
// int n = params.getDigestSize();
// byte[] secretKeySeed = new byte[n];
// prng.nextBytes(secretKeySeed);
// byte[] secretKeyPRF = new byte[n];
// prng.nextBytes(secretKeyPRF);
// byte[] publicSeed = new byte[n];
// prng.nextBytes(publicSeed);
//
// XMSS xmss = new XMSS(params, prng);
//
//// this.privateKey = xmss.privateKey;
//// this.publicKey = xmss.publicKey;
//// this.wotsPlus = xmss.wotsPlus;
//// this.khf = xmss.khf;
//
// XMSSPrivateKeyParameters privateKey = new XMSSPrivateKeyParameters.Builder(params).withSecretKeySeed(secretKeySeed)
// .withSecretKeyPRF(secretKeyPRF).withPublicSeed(publicSeed)
// .withBDSState(new BDS(xmss)).build();
//
// return privateKey;
// }
/**
* Generate a new XMSS private key / public key pair.
*/
public void generateKeys()
{
XMSSKeyPairGenerator kpGen = new XMSSKeyPairGenerator();
kpGen.init(new XMSSKeyGenerationParameters(getParams(), prng));
AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
privateKey = (XMSSPrivateKeyParameters)kp.getPrivate();
publicKey = (XMSSPublicKeyParameters)kp.getPublic();
wotsPlus.importKeys(new byte[params.getTreeDigestSize()], this.privateKey.getPublicSeed());
}
public void importState(XMSSPrivateKeyParameters privateKey, XMSSPublicKeyParameters publicKey)
{
if (!Arrays.areEqual(privateKey.getRoot(), publicKey.getRoot()))
{
throw new IllegalStateException("root of private key and public key do not match");
}
if (!Arrays.areEqual(privateKey.getPublicSeed(), publicKey.getPublicSeed()))
{
throw new IllegalStateException("public seed of private key and public key do not match");
}
/* import */
this.privateKey = privateKey;
this.publicKey = publicKey;
wotsPlus.importKeys(new byte[params.getTreeDigestSize()], this.privateKey.getPublicSeed());
}
/**
* Import XMSS private key / public key pair.
*
* @param privateKey XMSS private key.
* @param publicKey XMSS public key.
*/
public void importState(byte[] privateKey, byte[] publicKey)
{
if (privateKey == null)
{
throw new NullPointerException("privateKey == null");
}
if (publicKey == null)
{
throw new NullPointerException("publicKey == null");
}
/* import keys */
XMSSPrivateKeyParameters tmpPrivateKey = new XMSSPrivateKeyParameters.Builder(params)
.withPrivateKey(privateKey).build();
XMSSPublicKeyParameters tmpPublicKey = new XMSSPublicKeyParameters.Builder(params).withPublicKey(publicKey)
.build();
if (!Arrays.areEqual(tmpPrivateKey.getRoot(), tmpPublicKey.getRoot()))
{
throw new IllegalStateException("root of private key and public key do not match");
}
if (!Arrays.areEqual(tmpPrivateKey.getPublicSeed(), tmpPublicKey.getPublicSeed()))
{
throw new IllegalStateException("public seed of private key and public key do not match");
}
/* import */
this.privateKey = tmpPrivateKey;
this.publicKey = tmpPublicKey;
wotsPlus.importKeys(new byte[params.getTreeDigestSize()], this.privateKey.getPublicSeed());
}
/**
* Sign message.
*
* @param message Message to sign.
* @return XMSS signature on digest of message.
*/
public byte[] sign(byte[] message)
{
if (message == null)
{
throw new NullPointerException("message == null");
}
XMSSSigner signer = new XMSSSigner();
signer.init(true, privateKey);
byte[] signature = signer.generateSignature(message);
privateKey = (XMSSPrivateKeyParameters)signer.getUpdatedPrivateKey();
importState(privateKey, publicKey);
return signature;
}
/**
* Verify an XMSS signature.
*
* @param message Message.
* @param signature XMSS signature.
* @param publicKey XMSS public key.
* @return true if signature is valid false else.
* @throws ParseException
*/
public boolean verifySignature(byte[] message, byte[] signature, byte[] publicKey)
throws ParseException
{
if (message == null)
{
throw new NullPointerException("message == null");
}
if (signature == null)
{
throw new NullPointerException("signature == null");
}
if (publicKey == null)
{
throw new NullPointerException("publicKey == null");
}
XMSSSigner signer = new XMSSSigner();
signer.init(false, new XMSSPublicKeyParameters.Builder(getParams()).withPublicKey(publicKey).build());
return signer.verifySignature(message, signature);
}
/**
* Export XMSS private key.
*
* @return XMSS private key.
*/
public XMSSPrivateKeyParameters exportPrivateKey()
{
return privateKey;
}
/**
* Export XMSS public key.
*
* @return XMSS public key.
*/
public XMSSPublicKeyParameters exportPublicKey()
{
return publicKey;
}
/**
* Generate a WOTS+ signature on a message without the corresponding
* authentication path
*
* @param messageDigest Message digest of length n.
* @param otsHashAddress OTS hash address.
* @return XMSS signature.
*/
protected WOTSPlusSignature wotsSign(byte[] messageDigest, OTSHashAddress otsHashAddress)
{
if (messageDigest.length != params.getTreeDigestSize())
{
throw new IllegalArgumentException("size of messageDigest needs to be equal to size of digest");
}
if (otsHashAddress == null)
{
throw new NullPointerException("otsHashAddress == null");
}
/* (re)initialize WOTS+ instance */
wotsPlus.importKeys(wotsPlus.getWOTSPlusSecretKey(privateKey.getSecretKeySeed(), otsHashAddress), getPublicSeed());
/* create WOTS+ signature */
return wotsPlus.sign(messageDigest, otsHashAddress);
}
/**
* Getter XMSS params.
*
* @return XMSS params.
*/
public XMSSParameters getParams()
{
return params;
}
/**
* Getter WOTS+.
*
* @return WOTS+ instance.
*/
protected WOTSPlus getWOTSPlus()
{
return wotsPlus;
}
/**
* Getter XMSS root.
*
* @return Root of binary tree.
*/
public byte[] getRoot()
{
return privateKey.getRoot();
}
protected void setRoot(byte[] root)
{
privateKey = new XMSSPrivateKeyParameters.Builder(params)
.withSecretKeySeed(privateKey.getSecretKeySeed()).withSecretKeyPRF(privateKey.getSecretKeyPRF())
.withPublicSeed(getPublicSeed()).withRoot(root).withBDSState(privateKey.getBDSState()).build();
publicKey = new XMSSPublicKeyParameters.Builder(params).withRoot(root).withPublicSeed(getPublicSeed())
.build();
}
/**
* Getter XMSS index.
*
* @return Index.
*/
public int getIndex()
{
return privateKey.getIndex();
}
protected void setIndex(int index)
{
privateKey = new XMSSPrivateKeyParameters.Builder(params)
.withSecretKeySeed(privateKey.getSecretKeySeed()).withSecretKeyPRF(privateKey.getSecretKeyPRF())
.withPublicSeed(privateKey.getPublicSeed()).withRoot(privateKey.getRoot())
.withBDSState(privateKey.getBDSState()).build();
}
/**
* Getter XMSS public seed.
*
* @return Public seed.
*/
public byte[] getPublicSeed()
{
return privateKey.getPublicSeed();
}
protected void setPublicSeed(byte[] publicSeed)
{
privateKey = new XMSSPrivateKeyParameters.Builder(params)
.withSecretKeySeed(privateKey.getSecretKeySeed()).withSecretKeyPRF(privateKey.getSecretKeyPRF())
.withPublicSeed(publicSeed).withRoot(getRoot()).withBDSState(privateKey.getBDSState()).build();
publicKey = new XMSSPublicKeyParameters.Builder(params).withRoot(getRoot()).withPublicSeed(publicSeed)
.build();
wotsPlus.importKeys(new byte[params.getTreeDigestSize()], publicSeed);
}
public XMSSPrivateKeyParameters getPrivateKey()
{
return privateKey;
}
}