blob: f587cc7c1b1dde48eee32824cd98dae62f6c3738 [file] [log] [blame]
package org.bouncycastle.pqc.crypto.xmss;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
/**
* Reduced XMSS Signature.
*
*/
public class XMSSReducedSignature implements XMSSStoreableObjectInterface {
private final XMSSParameters params;
private final WOTSPlusSignature wotsPlusSignature;
private final List<XMSSNode> authPath;
protected XMSSReducedSignature(Builder builder) throws ParseException {
super();
params = builder.params;
if (params == null) {
throw new NullPointerException("params == null");
}
int n = params.getDigestSize();
int len = params.getWOTSPlus().getParams().getLen();
int height = params.getHeight();
byte[] reducedSignature = builder.reducedSignature;
if (reducedSignature != null) {
/* import */
int signatureSize = len * n;
int authPathSize = height * n;
int totalSize = signatureSize + authPathSize;
if (reducedSignature.length != totalSize) {
throw new ParseException("signature has wrong size", 0);
}
int position = 0;
byte[][] wotsPlusSignature = new byte[len][];
for (int i = 0; i < wotsPlusSignature.length; i++) {
wotsPlusSignature[i] = XMSSUtil.extractBytesAtOffset(reducedSignature, position, n);
position += n;
}
this.wotsPlusSignature = new WOTSPlusSignature(params.getWOTSPlus().getParams(), wotsPlusSignature);
List<XMSSNode> nodeList = new ArrayList<XMSSNode>();
for (int i = 0; i < height; i++) {
nodeList.add(new XMSSNode(i, XMSSUtil.extractBytesAtOffset(reducedSignature, position, n)));
position += n;
}
authPath = nodeList;
} else {
/* set */
WOTSPlusSignature tmpSignature = builder.wotsPlusSignature;
if (tmpSignature != null) {
wotsPlusSignature = tmpSignature;
} else {
wotsPlusSignature = new WOTSPlusSignature(params.getWOTSPlus().getParams(), new byte[len][n]);
}
List<XMSSNode> tmpAuthPath = builder.authPath;
if (tmpAuthPath != null) {
if (tmpAuthPath.size() != height) {
throw new IllegalArgumentException("size of authPath needs to be equal to height of tree");
}
authPath = tmpAuthPath;
} else {
authPath = new ArrayList<XMSSNode>();
}
}
}
public static class Builder {
/* mandatory */
private final XMSSParameters params;
/* optional */
private WOTSPlusSignature wotsPlusSignature = null;
private List<XMSSNode> authPath = null;
private byte[] reducedSignature = null;
public Builder(XMSSParameters params) {
super();
this.params = params;
}
public Builder withWOTSPlusSignature(WOTSPlusSignature val) {
wotsPlusSignature = val;
return this;
}
public Builder withAuthPath(List<XMSSNode> val) {
authPath = val;
return this;
}
public Builder withReducedSignature(byte[] val) {
reducedSignature = XMSSUtil.cloneArray(val);
return this;
}
public XMSSReducedSignature build() throws ParseException {
return new XMSSReducedSignature(this);
}
}
public byte[] toByteArray() {
/* signature || authentication path */
int n = params.getDigestSize();
int signatureSize = params.getWOTSPlus().getParams().getLen() * n;
int authPathSize = params.getHeight() * n;
int totalSize = signatureSize + authPathSize;
byte[] out = new byte[totalSize];
int position = 0;
/* copy signature */
byte[][] signature = this.wotsPlusSignature.toByteArray();
for (int i = 0; i < signature.length; i++) {
XMSSUtil.copyBytesAtOffset(out, signature[i], position);
position += n;
}
/* copy authentication path */
for (int i = 0; i < authPath.size(); i++) {
byte[] value = authPath.get(i).getValue();
XMSSUtil.copyBytesAtOffset(out, value, position);
position += n;
}
return out;
}
public XMSSParameters getParams() {
return params;
}
public WOTSPlusSignature getWOTSPlusSignature() {
return wotsPlusSignature;
}
public List<XMSSNode> getAuthPath() {
return authPath;
}
}