blob: 38fc208f383074060d28a03f5c49c928580b7fc1 [file] [log] [blame]
package org.bouncycastle.pqc.crypto.xmss;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
/**
* XMSSMT Signature.
*
*/
public final class XMSSMTSignature implements XMSSStoreableObjectInterface {
private final XMSSMTParameters params;
private final long index;
private final byte[] random;
private final List<XMSSReducedSignature> reducedSignatures;
private XMSSMTSignature(Builder builder) throws ParseException {
super();
params = builder.params;
if (params == null) {
throw new NullPointerException("params == null");
}
int n = params.getDigestSize();
byte[] signature = builder.signature;
if (signature != null) {
/* import */
int len = params.getWOTSPlus().getParams().getLen();
int indexSize = (int) Math.ceil(params.getHeight() / (double) 8);
int randomSize = n;
int reducedSignatureSizeSingle = ((params.getHeight() / params.getLayers()) + len) * n;
int reducedSignaturesSizeTotal = reducedSignatureSizeSingle * params.getLayers();
int totalSize = indexSize + randomSize + reducedSignaturesSizeTotal;
if (signature.length != totalSize) {
throw new ParseException("signature has wrong size", 0);
}
int position = 0;
index = XMSSUtil.bytesToXBigEndian(signature, position, indexSize);
if (!XMSSUtil.isIndexValid(params.getHeight(), index)) {
throw new ParseException("index out of bounds", 0);
}
position += indexSize;
random = XMSSUtil.extractBytesAtOffset(signature, position, randomSize);
position += randomSize;
reducedSignatures = new ArrayList<XMSSReducedSignature>();
while (position < signature.length) {
XMSSReducedSignature xmssSig = new XMSSReducedSignature.Builder(params.getXMSS().getParams())
.withReducedSignature(XMSSUtil.extractBytesAtOffset(signature, position, reducedSignatureSizeSingle))
.build();
reducedSignatures.add(xmssSig);
position += reducedSignatureSizeSingle;
}
} else {
/* set */
index = builder.index;
byte[] tmpRandom = builder.random;
if (tmpRandom != null) {
if (tmpRandom.length != n) {
throw new IllegalArgumentException("size of random needs to be equal to size of digest");
}
random = tmpRandom;
} else {
random = new byte[n];
}
List<XMSSReducedSignature> tmpReducedSignatures = builder.reducedSignatures;
if (tmpReducedSignatures != null) {
reducedSignatures = tmpReducedSignatures;
} else {
reducedSignatures = new ArrayList<XMSSReducedSignature>();
}
}
}
public static class Builder {
/* mandatory */
private final XMSSMTParameters params;
/* optional */
private long index = 0L;
private byte[] random = null;
private List<XMSSReducedSignature> reducedSignatures = null;
private byte[] signature = null;
public Builder(XMSSMTParameters params) {
super();
this.params = params;
}
public Builder withIndex(long val) {
index = val;
return this;
}
public Builder withRandom(byte[] val) {
random = XMSSUtil.cloneArray(val);
return this;
}
public Builder withReducedSignatures(List<XMSSReducedSignature> val) {
reducedSignatures = val;
return this;
}
public Builder withSignature(byte[] val) {
signature = val;
return this;
}
public XMSSMTSignature build() throws ParseException {
return new XMSSMTSignature(this);
}
}
public byte[] toByteArray() {
/* index || random || reduced signatures */
int n = params.getDigestSize();
int len = params.getWOTSPlus().getParams().getLen();
int indexSize = (int) Math.ceil(params.getHeight() / (double) 8);
int randomSize = n;
int reducedSignatureSizeSingle = ((params.getHeight() / params.getLayers()) + len) * n;
int reducedSignaturesSizeTotal = reducedSignatureSizeSingle * params.getLayers();
int totalSize = indexSize + randomSize + reducedSignaturesSizeTotal;
byte[] out = new byte[totalSize];
int position = 0;
/* copy index */
byte[] indexBytes = XMSSUtil.toBytesBigEndian(index, indexSize);
XMSSUtil.copyBytesAtOffset(out, indexBytes, position);
position += indexSize;
/* copy random */
XMSSUtil.copyBytesAtOffset(out, random, position);
position += randomSize;
/* copy reduced signatures */
for (XMSSReducedSignature reducedSignature : reducedSignatures) {
byte[] signature = reducedSignature.toByteArray();
XMSSUtil.copyBytesAtOffset(out, signature, position);
position += reducedSignatureSizeSingle;
}
return out;
}
public long getIndex() {
return index;
}
public byte[] getRandom() {
return XMSSUtil.cloneArray(random);
}
public List<XMSSReducedSignature> getReducedSignatures() {
return reducedSignatures;
}
}