| package org.bouncycastle.pqc.crypto.xmss; |
| |
| import java.text.ParseException; |
| |
| import org.bouncycastle.util.Pack; |
| |
| /** |
| * XMSS Signature. |
| */ |
| public final class XMSSSignature |
| extends XMSSReducedSignature |
| implements XMSSStoreableObjectInterface |
| { |
| |
| private final int index; |
| private final byte[] random; |
| |
| private XMSSSignature(Builder builder) |
| throws ParseException |
| { |
| super(builder); |
| index = builder.index; |
| int n = getParams().getDigestSize(); |
| 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]; |
| } |
| } |
| |
| public static class Builder |
| extends XMSSReducedSignature.Builder |
| { |
| |
| private final XMSSParameters params; |
| /* optional */ |
| private int index = 0; |
| private byte[] random = null; |
| |
| public Builder(XMSSParameters params) |
| { |
| super(params); |
| this.params = params; |
| } |
| |
| public Builder withIndex(int val) |
| { |
| index = val; |
| return this; |
| } |
| |
| public Builder withRandom(byte[] val) |
| { |
| random = XMSSUtil.cloneArray(val); |
| return this; |
| } |
| |
| public Builder withSignature(byte[] val) |
| { |
| if (val == null) |
| { |
| throw new NullPointerException("signature == null"); |
| } |
| int n = params.getDigestSize(); |
| int len = params.getWOTSPlus().getParams().getLen(); |
| int height = params.getHeight(); |
| int indexSize = 4; |
| int randomSize = n; |
| int signatureSize = len * n; |
| int authPathSize = height * n; |
| int position = 0; |
| /* extract index */ |
| index = Pack.bigEndianToInt(val, position); |
| position += indexSize; |
| /* extract random */ |
| random = XMSSUtil.extractBytesAtOffset(val, position, randomSize); |
| position += randomSize; |
| withReducedSignature(XMSSUtil.extractBytesAtOffset(val, position, signatureSize + authPathSize)); |
| return this; |
| } |
| |
| public XMSSSignature build() |
| throws ParseException |
| { |
| return new XMSSSignature(this); |
| } |
| } |
| |
| public byte[] toByteArray() |
| { |
| /* index || random || signature || authentication path */ |
| int n = getParams().getDigestSize(); |
| int indexSize = 4; |
| int randomSize = n; |
| int signatureSize = getParams().getWOTSPlus().getParams().getLen() * n; |
| int authPathSize = getParams().getHeight() * n; |
| int totalSize = indexSize + randomSize + signatureSize + authPathSize; |
| byte[] out = new byte[totalSize]; |
| int position = 0; |
| /* copy index */ |
| XMSSUtil.intToBytesBigEndianOffset(out, index, position); |
| position += indexSize; |
| /* copy random */ |
| XMSSUtil.copyBytesAtOffset(out, random, position); |
| position += randomSize; |
| /* copy signature */ |
| byte[][] signature = getWOTSPlusSignature().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 < getAuthPath().size(); i++) |
| { |
| byte[] value = getAuthPath().get(i).getValue(); |
| XMSSUtil.copyBytesAtOffset(out, value, position); |
| position += n; |
| } |
| return out; |
| } |
| |
| public int getIndex() |
| { |
| return index; |
| } |
| |
| public byte[] getRandom() |
| { |
| return XMSSUtil.cloneArray(random); |
| } |
| } |