| 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; |
| } |
| } |