diff options
Diffstat (limited to 'core/src/main/java/org/spongycastle/pqc/asn1')
10 files changed, 2658 insertions, 0 deletions
diff --git a/core/src/main/java/org/spongycastle/pqc/asn1/GMSSPrivateKey.java b/core/src/main/java/org/spongycastle/pqc/asn1/GMSSPrivateKey.java new file mode 100644 index 00000000..b56974ad --- /dev/null +++ b/core/src/main/java/org/spongycastle/pqc/asn1/GMSSPrivateKey.java @@ -0,0 +1,1312 @@ +package org.spongycastle.pqc.asn1; + +import java.math.BigInteger; +import java.util.Vector; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.pqc.crypto.gmss.GMSSLeaf; +import org.spongycastle.pqc.crypto.gmss.GMSSParameters; +import org.spongycastle.pqc.crypto.gmss.GMSSRootCalc; +import org.spongycastle.pqc.crypto.gmss.GMSSRootSig; +import org.spongycastle.pqc.crypto.gmss.Treehash; + +public class GMSSPrivateKey + extends ASN1Object +{ + private ASN1Primitive primitive; + + private GMSSPrivateKey(ASN1Sequence mtsPrivateKey) + { + // --- Decode <index>. + ASN1Sequence indexPart = (ASN1Sequence)mtsPrivateKey.getObjectAt(0); + int[] index = new int[indexPart.size()]; + for (int i = 0; i < indexPart.size(); i++) + { + index[i] = checkBigIntegerInIntRange(indexPart.getObjectAt(i)); + } + + // --- Decode <curSeeds>. + ASN1Sequence curSeedsPart = (ASN1Sequence)mtsPrivateKey.getObjectAt(1); + byte[][] curSeeds = new byte[curSeedsPart.size()][]; + for (int i = 0; i < curSeeds.length; i++) + { + curSeeds[i] = ((DEROctetString)curSeedsPart.getObjectAt(i)).getOctets(); + } + + // --- Decode <nextNextSeeds>. + ASN1Sequence nextNextSeedsPart = (ASN1Sequence)mtsPrivateKey.getObjectAt(2); + byte[][] nextNextSeeds = new byte[nextNextSeedsPart.size()][]; + for (int i = 0; i < nextNextSeeds.length; i++) + { + nextNextSeeds[i] = ((DEROctetString)nextNextSeedsPart.getObjectAt(i)).getOctets(); + } + + // --- Decode <curAuth>. + ASN1Sequence curAuthPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(3); + ASN1Sequence curAuthPart1; + + byte[][][] curAuth = new byte[curAuthPart0.size()][][]; + for (int i = 0; i < curAuth.length; i++) + { + curAuthPart1 = (ASN1Sequence)curAuthPart0.getObjectAt(i); + curAuth[i] = new byte[curAuthPart1.size()][]; + for (int j = 0; j < curAuth[i].length; j++) + { + curAuth[i][j] = ((DEROctetString)curAuthPart1.getObjectAt(j)).getOctets(); + } + } + + // --- Decode <nextAuth>. + ASN1Sequence nextAuthPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(4); + ASN1Sequence nextAuthPart1; + + byte[][][] nextAuth = new byte[nextAuthPart0.size()][][]; + for (int i = 0; i < nextAuth.length; i++) + { + nextAuthPart1 = (ASN1Sequence)nextAuthPart0.getObjectAt(i); + nextAuth[i] = new byte[nextAuthPart1.size()][]; + for (int j = 0; j < nextAuth[i].length; j++) + { + nextAuth[i][j] = ((DEROctetString)nextAuthPart1.getObjectAt(j)).getOctets(); + } + } + + // --- Decode <curTreehash>. + ASN1Sequence seqOfcurTreehash0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(5); + ASN1Sequence seqOfcurTreehash1; + ASN1Sequence seqOfcurTreehashStat; + ASN1Sequence seqOfcurTreehashBytes; + ASN1Sequence seqOfcurTreehashInts; + ASN1Sequence seqOfcurTreehashString; + + Treehash[][] curTreehash = new Treehash[seqOfcurTreehash0.size()][]; + /* + for (int i = 0; i < curTreehash.length; i++) + { + seqOfcurTreehash1 = (ASN1Sequence)seqOfcurTreehash0.getObjectAt(i); + curTreehash[i] = new Treehash[seqOfcurTreehash1.size()]; + for (int j = 0; j < curTreehash[i].length; j++) + { + seqOfcurTreehashStat = (ASN1Sequence)seqOfcurTreehash1.getObjectAt(j); + seqOfcurTreehashString = (ASN1Sequence)seqOfcurTreehashStat + .getObjectAt(0); + seqOfcurTreehashBytes = (ASN1Sequence)seqOfcurTreehashStat + .getObjectAt(1); + seqOfcurTreehashInts = (ASN1Sequence)seqOfcurTreehashStat + .getObjectAt(2); + + String[] name = new String[2]; + name[0] = ((DERIA5String)seqOfcurTreehashString.getObjectAt(0)).getString(); + name[1] = ((DERIA5String)seqOfcurTreehashString.getObjectAt(1)).getString(); + + int tailLength = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(1)); + byte[][] statByte = new byte[3 + tailLength][]; + statByte[0] = ((DEROctetString)seqOfcurTreehashBytes.getObjectAt(0)).getOctets(); + + if (statByte[0].length == 0) + { // if null was encoded + statByte[0] = null; + } + + statByte[1] = ((DEROctetString)seqOfcurTreehashBytes.getObjectAt(1)).getOctets(); + statByte[2] = ((DEROctetString)seqOfcurTreehashBytes.getObjectAt(2)).getOctets(); + for (int k = 0; k < tailLength; k++) + { + statByte[3 + k] = ((DEROctetString)seqOfcurTreehashBytes + .getObjectAt(3 + k)).getOctets(); + } + int[] statInt = new int[6 + tailLength]; + statInt[0] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(0)); + statInt[1] = tailLength; + statInt[2] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(2)); + statInt[3] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(3)); + statInt[4] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(4)); + statInt[5] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(5)); + for (int k = 0; k < tailLength; k++) + { + statInt[6 + k] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(6 + k)); + } + + // TODO: Check if we can do better than throwing away name[1] !!! + curTreehash[i][j] = new Treehash(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); + } + } + + + // --- Decode <nextTreehash>. + ASN1Sequence seqOfNextTreehash0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(6); + ASN1Sequence seqOfNextTreehash1; + ASN1Sequence seqOfNextTreehashStat; + ASN1Sequence seqOfNextTreehashBytes; + ASN1Sequence seqOfNextTreehashInts; + ASN1Sequence seqOfNextTreehashString; + + Treehash[][] nextTreehash = new Treehash[seqOfNextTreehash0.size()][]; + + for (int i = 0; i < nextTreehash.length; i++) + { + seqOfNextTreehash1 = (ASN1Sequence)seqOfNextTreehash0.getObjectAt(i); + nextTreehash[i] = new Treehash[seqOfNextTreehash1.size()]; + for (int j = 0; j < nextTreehash[i].length; j++) + { + seqOfNextTreehashStat = (ASN1Sequence)seqOfNextTreehash1 + .getObjectAt(j); + seqOfNextTreehashString = (ASN1Sequence)seqOfNextTreehashStat + .getObjectAt(0); + seqOfNextTreehashBytes = (ASN1Sequence)seqOfNextTreehashStat + .getObjectAt(1); + seqOfNextTreehashInts = (ASN1Sequence)seqOfNextTreehashStat + .getObjectAt(2); + + String[] name = new String[2]; + name[0] = ((DERIA5String)seqOfNextTreehashString.getObjectAt(0)) + .getString(); + name[1] = ((DERIA5String)seqOfNextTreehashString.getObjectAt(1)) + .getString(); + + int tailLength = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(1)); + + byte[][] statByte = new byte[3 + tailLength][]; + statByte[0] = ((DEROctetString)seqOfNextTreehashBytes.getObjectAt(0)).getOctets(); + if (statByte[0].length == 0) + { // if null was encoded + statByte[0] = null; + } + + statByte[1] = ((DEROctetString)seqOfNextTreehashBytes.getObjectAt(1)).getOctets(); + statByte[2] = ((DEROctetString)seqOfNextTreehashBytes.getObjectAt(2)).getOctets(); + for (int k = 0; k < tailLength; k++) + { + statByte[3 + k] = ((DEROctetString)seqOfNextTreehashBytes + .getObjectAt(3 + k)).getOctets(); + } + int[] statInt = new int[6 + tailLength]; + statInt[0] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(0)); + + statInt[1] = tailLength; + statInt[2] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(2)); + + statInt[3] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(3)); + + statInt[4] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(4)); + + statInt[5] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(5)); + + for (int k = 0; k < tailLength; k++) + { + statInt[6 + k] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(6 + k)); + + } + nextTreehash[i][j] = new Treehash(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); + } + } + + + // --- Decode <keep>. + ASN1Sequence keepPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(7); + ASN1Sequence keepPart1; + + byte[][][] keep = new byte[keepPart0.size()][][]; + for (int i = 0; i < keep.length; i++) + { + keepPart1 = (ASN1Sequence)keepPart0.getObjectAt(i); + keep[i] = new byte[keepPart1.size()][]; + for (int j = 0; j < keep[i].length; j++) + { + keep[i][j] = ((DEROctetString)keepPart1.getObjectAt(j)).getOctets(); + } + } + + // --- Decode <curStack>. + ASN1Sequence curStackPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(8); + ASN1Sequence curStackPart1; + + Vector[] curStack = new Vector[curStackPart0.size()]; + for (int i = 0; i < curStack.length; i++) + { + curStackPart1 = (ASN1Sequence)curStackPart0.getObjectAt(i); + curStack[i] = new Vector(); + for (int j = 0; j < curStackPart1.size(); j++) + { + curStack[i].addElement(((DEROctetString)curStackPart1.getObjectAt(j)).getOctets()); + } + } + + // --- Decode <nextStack>. + ASN1Sequence nextStackPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(9); + ASN1Sequence nextStackPart1; + + Vector[] nextStack = new Vector[nextStackPart0.size()]; + for (int i = 0; i < nextStack.length; i++) + { + nextStackPart1 = (ASN1Sequence)nextStackPart0.getObjectAt(i); + nextStack[i] = new Vector(); + for (int j = 0; j < nextStackPart1.size(); j++) + { + nextStack[i].addElement(((DEROctetString)nextStackPart1 + .getObjectAt(j)).getOctets()); + } + } + + // --- Decode <curRetain>. + ASN1Sequence curRetainPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(10); + ASN1Sequence curRetainPart1; + ASN1Sequence curRetainPart2; + + Vector[][] curRetain = new Vector[curRetainPart0.size()][]; + for (int i = 0; i < curRetain.length; i++) + { + curRetainPart1 = (ASN1Sequence)curRetainPart0.getObjectAt(i); + curRetain[i] = new Vector[curRetainPart1.size()]; + for (int j = 0; j < curRetain[i].length; j++) + { + curRetainPart2 = (ASN1Sequence)curRetainPart1.getObjectAt(j); + curRetain[i][j] = new Vector(); + for (int k = 0; k < curRetainPart2.size(); k++) + { + curRetain[i][j] + .addElement(((DEROctetString)curRetainPart2 + .getObjectAt(k)).getOctets()); + } + } + } + + // --- Decode <nextRetain>. + ASN1Sequence nextRetainPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(11); + ASN1Sequence nextRetainPart1; + ASN1Sequence nextRetainPart2; + + Vector[][] nextRetain = new Vector[nextRetainPart0.size()][]; + for (int i = 0; i < nextRetain.length; i++) + { + nextRetainPart1 = (ASN1Sequence)nextRetainPart0.getObjectAt(i); + nextRetain[i] = new Vector[nextRetainPart1.size()]; + for (int j = 0; j < nextRetain[i].length; j++) + { + nextRetainPart2 = (ASN1Sequence)nextRetainPart1.getObjectAt(j); + nextRetain[i][j] = new Vector(); + for (int k = 0; k < nextRetainPart2.size(); k++) + { + nextRetain[i][j] + .addElement(((DEROctetString)nextRetainPart2 + .getObjectAt(k)).getOctets()); + } + } + } + + // --- Decode <nextNextLeaf>. + ASN1Sequence seqOfLeafs = (ASN1Sequence)mtsPrivateKey.getObjectAt(12); + ASN1Sequence seqOfLeafStat; + ASN1Sequence seqOfLeafBytes; + ASN1Sequence seqOfLeafInts; + ASN1Sequence seqOfLeafString; + + GMSSLeaf[] nextNextLeaf = new GMSSLeaf[seqOfLeafs.size()]; + + for (int i = 0; i < nextNextLeaf.length; i++) + { + seqOfLeafStat = (ASN1Sequence)seqOfLeafs.getObjectAt(i); + // nextNextAuth[i]= new byte[nextNextAuthPart1.size()][]; + seqOfLeafString = (ASN1Sequence)seqOfLeafStat.getObjectAt(0); + seqOfLeafBytes = (ASN1Sequence)seqOfLeafStat.getObjectAt(1); + seqOfLeafInts = (ASN1Sequence)seqOfLeafStat.getObjectAt(2); + + String[] name = new String[2]; + name[0] = ((DERIA5String)seqOfLeafString.getObjectAt(0)).getString(); + name[1] = ((DERIA5String)seqOfLeafString.getObjectAt(1)).getString(); + byte[][] statByte = new byte[4][]; + statByte[0] = ((DEROctetString)seqOfLeafBytes.getObjectAt(0)) + .getOctets(); + statByte[1] = ((DEROctetString)seqOfLeafBytes.getObjectAt(1)) + .getOctets(); + statByte[2] = ((DEROctetString)seqOfLeafBytes.getObjectAt(2)) + .getOctets(); + statByte[3] = ((DEROctetString)seqOfLeafBytes.getObjectAt(3)) + .getOctets(); + int[] statInt = new int[4]; + statInt[0] = checkBigIntegerInIntRange(seqOfLeafInts.getObjectAt(0)); + statInt[1] = checkBigIntegerInIntRange(seqOfLeafInts.getObjectAt(1)); + statInt[2] = checkBigIntegerInIntRange(seqOfLeafInts.getObjectAt(2)); + statInt[3] = checkBigIntegerInIntRange(seqOfLeafInts.getObjectAt(3)); + nextNextLeaf[i] = new GMSSLeaf(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); + } + + // --- Decode <upperLeaf>. + ASN1Sequence seqOfUpperLeafs = (ASN1Sequence)mtsPrivateKey.getObjectAt(13); + ASN1Sequence seqOfUpperLeafStat; + ASN1Sequence seqOfUpperLeafBytes; + ASN1Sequence seqOfUpperLeafInts; + ASN1Sequence seqOfUpperLeafString; + + GMSSLeaf[] upperLeaf = new GMSSLeaf[seqOfUpperLeafs.size()]; + + for (int i = 0; i < upperLeaf.length; i++) + { + seqOfUpperLeafStat = (ASN1Sequence)seqOfUpperLeafs.getObjectAt(i); + seqOfUpperLeafString = (ASN1Sequence)seqOfUpperLeafStat.getObjectAt(0); + seqOfUpperLeafBytes = (ASN1Sequence)seqOfUpperLeafStat.getObjectAt(1); + seqOfUpperLeafInts = (ASN1Sequence)seqOfUpperLeafStat.getObjectAt(2); + + String[] name = new String[2]; + name[0] = ((DERIA5String)seqOfUpperLeafString.getObjectAt(0)).getString(); + name[1] = ((DERIA5String)seqOfUpperLeafString.getObjectAt(1)).getString(); + byte[][] statByte = new byte[4][]; + statByte[0] = ((DEROctetString)seqOfUpperLeafBytes.getObjectAt(0)) + .getOctets(); + statByte[1] = ((DEROctetString)seqOfUpperLeafBytes.getObjectAt(1)) + .getOctets(); + statByte[2] = ((DEROctetString)seqOfUpperLeafBytes.getObjectAt(2)) + .getOctets(); + statByte[3] = ((DEROctetString)seqOfUpperLeafBytes.getObjectAt(3)) + .getOctets(); + int[] statInt = new int[4]; + statInt[0] = checkBigIntegerInIntRange(seqOfUpperLeafInts.getObjectAt(0)); + statInt[1] = checkBigIntegerInIntRange(seqOfUpperLeafInts.getObjectAt(1)); + statInt[2] = checkBigIntegerInIntRange(seqOfUpperLeafInts.getObjectAt(2)); + statInt[3] = checkBigIntegerInIntRange(seqOfUpperLeafInts.getObjectAt(3)); + upperLeaf[i] = new GMSSLeaf(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); + } + + // --- Decode <upperTreehashLeaf>. + ASN1Sequence seqOfUpperTHLeafs = (ASN1Sequence)mtsPrivateKey.getObjectAt(14); + ASN1Sequence seqOfUpperTHLeafStat; + ASN1Sequence seqOfUpperTHLeafBytes; + ASN1Sequence seqOfUpperTHLeafInts; + ASN1Sequence seqOfUpperTHLeafString; + + GMSSLeaf[] upperTHLeaf = new GMSSLeaf[seqOfUpperTHLeafs.size()]; + + for (int i = 0; i < upperTHLeaf.length; i++) + { + seqOfUpperTHLeafStat = (ASN1Sequence)seqOfUpperTHLeafs.getObjectAt(i); + seqOfUpperTHLeafString = (ASN1Sequence)seqOfUpperTHLeafStat.getObjectAt(0); + seqOfUpperTHLeafBytes = (ASN1Sequence)seqOfUpperTHLeafStat.getObjectAt(1); + seqOfUpperTHLeafInts = (ASN1Sequence)seqOfUpperTHLeafStat.getObjectAt(2); + + String[] name = new String[2]; + name[0] = ((DERIA5String)seqOfUpperTHLeafString.getObjectAt(0)) + .getString(); + name[1] = ((DERIA5String)seqOfUpperTHLeafString.getObjectAt(1)) + .getString(); + byte[][] statByte = new byte[4][]; + statByte[0] = ((DEROctetString)seqOfUpperTHLeafBytes.getObjectAt(0)) + .getOctets(); + statByte[1] = ((DEROctetString)seqOfUpperTHLeafBytes.getObjectAt(1)) + .getOctets(); + statByte[2] = ((DEROctetString)seqOfUpperTHLeafBytes.getObjectAt(2)) + .getOctets(); + statByte[3] = ((DEROctetString)seqOfUpperTHLeafBytes.getObjectAt(3)) + .getOctets(); + int[] statInt = new int[4]; + statInt[0] = checkBigIntegerInIntRange(seqOfUpperTHLeafInts.getObjectAt(0)); + statInt[1] = checkBigIntegerInIntRange(seqOfUpperTHLeafInts.getObjectAt(1)); + statInt[2] = checkBigIntegerInIntRange(seqOfUpperTHLeafInts.getObjectAt(2)); + statInt[3] = checkBigIntegerInIntRange(seqOfUpperTHLeafInts.getObjectAt(3)); + upperTHLeaf[i] = new GMSSLeaf(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); + } + + // --- Decode <minTreehash>. + ASN1Sequence minTreehashPart = (ASN1Sequence)mtsPrivateKey.getObjectAt(15); + int[] minTreehash = new int[minTreehashPart.size()]; + for (int i = 0; i < minTreehashPart.size(); i++) + { + minTreehash[i] = checkBigIntegerInIntRange(minTreehashPart.getObjectAt(i)); + } + + // --- Decode <nextRoot>. + ASN1Sequence seqOfnextRoots = (ASN1Sequence)mtsPrivateKey.getObjectAt(16); + byte[][] nextRoot = new byte[seqOfnextRoots.size()][]; + for (int i = 0; i < nextRoot.length; i++) + { + nextRoot[i] = ((DEROctetString)seqOfnextRoots.getObjectAt(i)) + .getOctets(); + } + + // --- Decode <nextNextRoot>. + ASN1Sequence seqOfnextNextRoot = (ASN1Sequence)mtsPrivateKey.getObjectAt(17); + ASN1Sequence seqOfnextNextRootStat; + ASN1Sequence seqOfnextNextRootBytes; + ASN1Sequence seqOfnextNextRootInts; + ASN1Sequence seqOfnextNextRootString; + ASN1Sequence seqOfnextNextRootTreeH; + ASN1Sequence seqOfnextNextRootRetain; + + GMSSRootCalc[] nextNextRoot = new GMSSRootCalc[seqOfnextNextRoot.size()]; + + for (int i = 0; i < nextNextRoot.length; i++) + { + seqOfnextNextRootStat = (ASN1Sequence)seqOfnextNextRoot.getObjectAt(i); + seqOfnextNextRootString = (ASN1Sequence)seqOfnextNextRootStat + .getObjectAt(0); + seqOfnextNextRootBytes = (ASN1Sequence)seqOfnextNextRootStat + .getObjectAt(1); + seqOfnextNextRootInts = (ASN1Sequence)seqOfnextNextRootStat.getObjectAt(2); + seqOfnextNextRootTreeH = (ASN1Sequence)seqOfnextNextRootStat + .getObjectAt(3); + seqOfnextNextRootRetain = (ASN1Sequence)seqOfnextNextRootStat + .getObjectAt(4); + + // decode treehash of nextNextRoot + // --------------------------------- + ASN1Sequence seqOfnextNextRootTreeHStat; + ASN1Sequence seqOfnextNextRootTreeHBytes; + ASN1Sequence seqOfnextNextRootTreeHInts; + ASN1Sequence seqOfnextNextRootTreeHString; + + Treehash[] nnRTreehash = new Treehash[seqOfnextNextRootTreeH.size()]; + + for (int k = 0; k < nnRTreehash.length; k++) + { + seqOfnextNextRootTreeHStat = (ASN1Sequence)seqOfnextNextRootTreeH + .getObjectAt(k); + seqOfnextNextRootTreeHString = (ASN1Sequence)seqOfnextNextRootTreeHStat + .getObjectAt(0); + seqOfnextNextRootTreeHBytes = (ASN1Sequence)seqOfnextNextRootTreeHStat + .getObjectAt(1); + seqOfnextNextRootTreeHInts = (ASN1Sequence)seqOfnextNextRootTreeHStat + .getObjectAt(2); + + String[] name = new String[2]; + name[0] = ((DERIA5String)seqOfnextNextRootTreeHString.getObjectAt(0)) + .getString(); + name[1] = ((DERIA5String)seqOfnextNextRootTreeHString.getObjectAt(1)) + .getString(); + + int tailLength = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(1)); + + byte[][] statByte = new byte[3 + tailLength][]; + statByte[0] = ((DEROctetString)seqOfnextNextRootTreeHBytes + .getObjectAt(0)).getOctets(); + if (statByte[0].length == 0) + { // if null was encoded + statByte[0] = null; + } + + statByte[1] = ((DEROctetString)seqOfnextNextRootTreeHBytes + .getObjectAt(1)).getOctets(); + statByte[2] = ((DEROctetString)seqOfnextNextRootTreeHBytes + .getObjectAt(2)).getOctets(); + for (int j = 0; j < tailLength; j++) + { + statByte[3 + j] = ((DEROctetString)seqOfnextNextRootTreeHBytes + .getObjectAt(3 + j)).getOctets(); + } + int[] statInt = new int[6 + tailLength]; + statInt[0] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(0)); + + statInt[1] = tailLength; + statInt[2] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(2)); + + statInt[3] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(3)); + + statInt[4] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(4)); + + statInt[5] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(5)); + + for (int j = 0; j < tailLength; j++) + { + statInt[6 + j] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts + .getObjectAt(6 + j)); + } + nnRTreehash[k] = new Treehash(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); + } + // --------------------------------- + + // decode retain of nextNextRoot + // --------------------------------- + // ASN1Sequence seqOfnextNextRootRetainPart0 = + // (ASN1Sequence)seqOfnextNextRootRetain.get(0); + ASN1Sequence seqOfnextNextRootRetainPart1; + + Vector[] nnRRetain = new Vector[seqOfnextNextRootRetain.size()]; + for (int j = 0; j < nnRRetain.length; j++) + { + seqOfnextNextRootRetainPart1 = (ASN1Sequence)seqOfnextNextRootRetain + .getObjectAt(j); + nnRRetain[j] = new Vector(); + for (int k = 0; k < seqOfnextNextRootRetainPart1.size(); k++) + { + nnRRetain[j] + .addElement(((DEROctetString)seqOfnextNextRootRetainPart1 + .getObjectAt(k)).getOctets()); + } + } + // --------------------------------- + + String[] name = new String[2]; + name[0] = ((DERIA5String)seqOfnextNextRootString.getObjectAt(0)) + .getString(); + name[1] = ((DERIA5String)seqOfnextNextRootString.getObjectAt(1)) + .getString(); + + int heightOfTree = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(0)); + int tailLength = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(7)); + byte[][] statByte = new byte[1 + heightOfTree + tailLength][]; + statByte[0] = ((DEROctetString)seqOfnextNextRootBytes.getObjectAt(0)) + .getOctets(); + for (int j = 0; j < heightOfTree; j++) + { + statByte[1 + j] = ((DEROctetString)seqOfnextNextRootBytes + .getObjectAt(1 + j)).getOctets(); + } + for (int j = 0; j < tailLength; j++) + { + statByte[1 + heightOfTree + j] = ((DEROctetString)seqOfnextNextRootBytes + .getObjectAt(1 + heightOfTree + j)).getOctets(); + } + int[] statInt = new int[8 + heightOfTree + tailLength]; + statInt[0] = heightOfTree; + statInt[1] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(1)); + statInt[2] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(2)); + statInt[3] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(3)); + statInt[4] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(4)); + statInt[5] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(5)); + statInt[6] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(6)); + statInt[7] = tailLength; + for (int j = 0; j < heightOfTree; j++) + { + statInt[8 + j] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(8 + j)); + } + for (int j = 0; j < tailLength; j++) + { + statInt[8 + heightOfTree + j] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(8 + + heightOfTree + j)); + } + nextNextRoot[i] = new GMSSRootCalc(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt, + nnRTreehash, nnRRetain); + } + + // --- Decode <curRootSig>. + ASN1Sequence seqOfcurRootSig = (ASN1Sequence)mtsPrivateKey.getObjectAt(18); + byte[][] curRootSig = new byte[seqOfcurRootSig.size()][]; + for (int i = 0; i < curRootSig.length; i++) + { + curRootSig[i] = ((DEROctetString)seqOfcurRootSig.getObjectAt(i)) + .getOctets(); + } + + // --- Decode <nextRootSig>. + ASN1Sequence seqOfnextRootSigs = (ASN1Sequence)mtsPrivateKey.getObjectAt(19); + ASN1Sequence seqOfnRSStats; + ASN1Sequence seqOfnRSStrings; + ASN1Sequence seqOfnRSInts; + ASN1Sequence seqOfnRSBytes; + + GMSSRootSig[] nextRootSig = new GMSSRootSig[seqOfnextRootSigs.size()]; + + for (int i = 0; i < nextRootSig.length; i++) + { + seqOfnRSStats = (ASN1Sequence)seqOfnextRootSigs.getObjectAt(i); + // nextNextAuth[i]= new byte[nextNextAuthPart1.size()][]; + seqOfnRSStrings = (ASN1Sequence)seqOfnRSStats.getObjectAt(0); + seqOfnRSBytes = (ASN1Sequence)seqOfnRSStats.getObjectAt(1); + seqOfnRSInts = (ASN1Sequence)seqOfnRSStats.getObjectAt(2); + + String[] name = new String[2]; + name[0] = ((DERIA5String)seqOfnRSStrings.getObjectAt(0)).getString(); + name[1] = ((DERIA5String)seqOfnRSStrings.getObjectAt(1)).getString(); + byte[][] statByte = new byte[5][]; + statByte[0] = ((DEROctetString)seqOfnRSBytes.getObjectAt(0)) + .getOctets(); + statByte[1] = ((DEROctetString)seqOfnRSBytes.getObjectAt(1)) + .getOctets(); + statByte[2] = ((DEROctetString)seqOfnRSBytes.getObjectAt(2)) + .getOctets(); + statByte[3] = ((DEROctetString)seqOfnRSBytes.getObjectAt(3)) + .getOctets(); + statByte[4] = ((DEROctetString)seqOfnRSBytes.getObjectAt(4)) + .getOctets(); + int[] statInt = new int[9]; + statInt[0] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(0)); + statInt[1] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(1)); + statInt[2] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(2)); + statInt[3] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(3)); + statInt[4] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(4)); + statInt[5] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(5)); + statInt[6] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(6)); + statInt[7] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(7)); + statInt[8] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(8)); + nextRootSig[i] = new GMSSRootSig(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); + } + + // --- Decode <name>. + + // TODO: Really check, why there are multiple algorithms, we only + // use the first one!!! + ASN1Sequence namePart = (ASN1Sequence)mtsPrivateKey.getObjectAt(20); + String[] name = new String[namePart.size()]; + for (int i = 0; i < name.length; i++) + { + name[i] = ((DERIA5String)namePart.getObjectAt(i)).getString(); + } + */ + } + + public GMSSPrivateKey(int[] index, byte[][] currentSeed, + byte[][] nextNextSeed, byte[][][] currentAuthPath, + byte[][][] nextAuthPath, Treehash[][] currentTreehash, + Treehash[][] nextTreehash, Vector[] currentStack, + Vector[] nextStack, Vector[][] currentRetain, + Vector[][] nextRetain, byte[][][] keep, GMSSLeaf[] nextNextLeaf, + GMSSLeaf[] upperLeaf, GMSSLeaf[] upperTreehashLeaf, + int[] minTreehash, byte[][] nextRoot, GMSSRootCalc[] nextNextRoot, + byte[][] currentRootSig, GMSSRootSig[] nextRootSig, + GMSSParameters gmssParameterset, AlgorithmIdentifier digestAlg) + { + AlgorithmIdentifier[] names = new AlgorithmIdentifier[] { digestAlg }; + this.primitive = encode(index, currentSeed, nextNextSeed, currentAuthPath, nextAuthPath, keep, currentTreehash, nextTreehash, currentStack, nextStack, currentRetain, nextRetain, nextNextLeaf, upperLeaf, upperTreehashLeaf, minTreehash, nextRoot, nextNextRoot, currentRootSig, nextRootSig, gmssParameterset, names); + } + + + // TODO: change method signature to something more integrated into BouncyCastle + + /** + * @param index tree indices + * @param currentSeeds seed for the generation of private OTS keys for the + * current subtrees (TREE) + * @param nextNextSeeds seed for the generation of private OTS keys for the + * subtrees after next (TREE++) + * @param currentAuthPaths array of current authentication paths (AUTHPATH) + * @param nextAuthPaths array of next authentication paths (AUTHPATH+) + * @param keep keep array for the authPath algorithm + * @param currentTreehash treehash for authPath algorithm of current tree + * @param nextTreehash treehash for authPath algorithm of next tree (TREE+) + * @param currentStack shared stack for authPath algorithm of current tree + * @param nextStack shared stack for authPath algorithm of next tree (TREE+) + * @param currentRetain retain stack for authPath algorithm of current tree + * @param nextRetain retain stack for authPath algorithm of next tree (TREE+) + * @param nextNextLeaf array of upcoming leafs of the tree after next (LEAF++) of + * each layer + * @param upperLeaf needed for precomputation of upper nodes + * @param upperTreehashLeaf needed for precomputation of upper treehash nodes + * @param minTreehash index of next treehash instance to receive an update + * @param nextRoot the roots of the next trees (ROOT+) + * @param nextNextRoot the roots of the tree after next (ROOT++) + * @param currentRootSig array of signatures of the roots of the current subtrees + * (SIG) + * @param nextRootSig array of signatures of the roots of the next subtree + * (SIG+) + * @param gmssParameterset the GMSS Parameterset + * @param algorithms An array of algorithm identifiers, containing the hash function details + */ + private ASN1Primitive encode(int[] index, byte[][] currentSeeds, + byte[][] nextNextSeeds, byte[][][] currentAuthPaths, + byte[][][] nextAuthPaths, byte[][][] keep, + Treehash[][] currentTreehash, Treehash[][] nextTreehash, + Vector[] currentStack, Vector[] nextStack, + Vector[][] currentRetain, Vector[][] nextRetain, + GMSSLeaf[] nextNextLeaf, GMSSLeaf[] upperLeaf, + GMSSLeaf[] upperTreehashLeaf, int[] minTreehash, byte[][] nextRoot, + GMSSRootCalc[] nextNextRoot, byte[][] currentRootSig, + GMSSRootSig[] nextRootSig, GMSSParameters gmssParameterset, + AlgorithmIdentifier[] algorithms) + { + + ASN1EncodableVector result = new ASN1EncodableVector(); + + // --- Encode <index>. + ASN1EncodableVector indexPart = new ASN1EncodableVector(); + for (int i = 0; i < index.length; i++) + { + indexPart.add(new ASN1Integer(index[i])); + } + result.add(new DERSequence(indexPart)); + + // --- Encode <curSeeds>. + ASN1EncodableVector curSeedsPart = new ASN1EncodableVector(); + for (int i = 0; i < currentSeeds.length; i++) + { + curSeedsPart.add(new DEROctetString(currentSeeds[i])); + } + result.add(new DERSequence(curSeedsPart)); + + // --- Encode <nextNextSeeds>. + ASN1EncodableVector nextNextSeedsPart = new ASN1EncodableVector(); + for (int i = 0; i < nextNextSeeds.length; i++) + { + nextNextSeedsPart.add(new DEROctetString(nextNextSeeds[i])); + } + result.add(new DERSequence(nextNextSeedsPart)); + + // --- Encode <curAuth>. + ASN1EncodableVector curAuthPart0 = new ASN1EncodableVector(); + ASN1EncodableVector curAuthPart1 = new ASN1EncodableVector(); + for (int i = 0; i < currentAuthPaths.length; i++) + { + for (int j = 0; j < currentAuthPaths[i].length; j++) + { + curAuthPart0.add(new DEROctetString(currentAuthPaths[i][j])); + } + curAuthPart1.add(new DERSequence(curAuthPart0)); + curAuthPart0 = new ASN1EncodableVector(); + } + result.add(new DERSequence(curAuthPart1)); + + // --- Encode <nextAuth>. + ASN1EncodableVector nextAuthPart0 = new ASN1EncodableVector(); + ASN1EncodableVector nextAuthPart1 = new ASN1EncodableVector(); + for (int i = 0; i < nextAuthPaths.length; i++) + { + for (int j = 0; j < nextAuthPaths[i].length; j++) + { + nextAuthPart0.add(new DEROctetString(nextAuthPaths[i][j])); + } + nextAuthPart1.add(new DERSequence(nextAuthPart0)); + nextAuthPart0 = new ASN1EncodableVector(); + } + result.add(new DERSequence(nextAuthPart1)); + + // --- Encode <curTreehash>. + ASN1EncodableVector seqOfTreehash0 = new ASN1EncodableVector(); + ASN1EncodableVector seqOfTreehash1 = new ASN1EncodableVector(); + ASN1EncodableVector seqOfStat = new ASN1EncodableVector(); + ASN1EncodableVector seqOfByte = new ASN1EncodableVector(); + ASN1EncodableVector seqOfInt = new ASN1EncodableVector(); + + for (int i = 0; i < currentTreehash.length; i++) + { + for (int j = 0; j < currentTreehash[i].length; j++) + { + seqOfStat.add(new DERSequence(algorithms[0])); + + int tailLength = currentTreehash[i][j].getStatInt()[1]; + + seqOfByte.add(new DEROctetString(currentTreehash[i][j] + .getStatByte()[0])); + seqOfByte.add(new DEROctetString(currentTreehash[i][j] + .getStatByte()[1])); + seqOfByte.add(new DEROctetString(currentTreehash[i][j] + .getStatByte()[2])); + for (int k = 0; k < tailLength; k++) + { + seqOfByte.add(new DEROctetString(currentTreehash[i][j] + .getStatByte()[3 + k])); + } + seqOfStat.add(new DERSequence(seqOfByte)); + seqOfByte = new ASN1EncodableVector(); + + seqOfInt.add(new ASN1Integer( + currentTreehash[i][j].getStatInt()[0])); + seqOfInt.add(new ASN1Integer(tailLength)); + seqOfInt.add(new ASN1Integer( + currentTreehash[i][j].getStatInt()[2])); + seqOfInt.add(new ASN1Integer( + currentTreehash[i][j].getStatInt()[3])); + seqOfInt.add(new ASN1Integer( + currentTreehash[i][j].getStatInt()[4])); + seqOfInt.add(new ASN1Integer( + currentTreehash[i][j].getStatInt()[5])); + for (int k = 0; k < tailLength; k++) + { + seqOfInt.add(new ASN1Integer(currentTreehash[i][j] + .getStatInt()[6 + k])); + } + seqOfStat.add(new DERSequence(seqOfInt)); + seqOfInt = new ASN1EncodableVector(); + + seqOfTreehash1.add(new DERSequence(seqOfStat)); + seqOfStat = new ASN1EncodableVector(); + } + seqOfTreehash0.add(new DERSequence(seqOfTreehash1)); + seqOfTreehash1 = new ASN1EncodableVector(); + } + result.add(new DERSequence(seqOfTreehash0)); + + // --- Encode <nextTreehash>. + seqOfTreehash0 = new ASN1EncodableVector(); + seqOfTreehash1 = new ASN1EncodableVector(); + seqOfStat = new ASN1EncodableVector(); + seqOfByte = new ASN1EncodableVector(); + seqOfInt = new ASN1EncodableVector(); + + for (int i = 0; i < nextTreehash.length; i++) + { + for (int j = 0; j < nextTreehash[i].length; j++) + { + seqOfStat.add(new DERSequence(algorithms[0])); + + int tailLength = nextTreehash[i][j].getStatInt()[1]; + + seqOfByte.add(new DEROctetString(nextTreehash[i][j] + .getStatByte()[0])); + seqOfByte.add(new DEROctetString(nextTreehash[i][j] + .getStatByte()[1])); + seqOfByte.add(new DEROctetString(nextTreehash[i][j] + .getStatByte()[2])); + for (int k = 0; k < tailLength; k++) + { + seqOfByte.add(new DEROctetString(nextTreehash[i][j] + .getStatByte()[3 + k])); + } + seqOfStat.add(new DERSequence(seqOfByte)); + seqOfByte = new ASN1EncodableVector(); + + seqOfInt + .add(new ASN1Integer(nextTreehash[i][j].getStatInt()[0])); + seqOfInt.add(new ASN1Integer(tailLength)); + seqOfInt + .add(new ASN1Integer(nextTreehash[i][j].getStatInt()[2])); + seqOfInt + .add(new ASN1Integer(nextTreehash[i][j].getStatInt()[3])); + seqOfInt + .add(new ASN1Integer(nextTreehash[i][j].getStatInt()[4])); + seqOfInt + .add(new ASN1Integer(nextTreehash[i][j].getStatInt()[5])); + for (int k = 0; k < tailLength; k++) + { + seqOfInt.add(new ASN1Integer(nextTreehash[i][j] + .getStatInt()[6 + k])); + } + seqOfStat.add(new DERSequence(seqOfInt)); + seqOfInt = new ASN1EncodableVector(); + + seqOfTreehash1.add(new DERSequence(seqOfStat)); + seqOfStat = new ASN1EncodableVector(); + } + seqOfTreehash0.add(new DERSequence(new DERSequence(seqOfTreehash1))); + seqOfTreehash1 = new ASN1EncodableVector(); + } + result.add(new DERSequence(seqOfTreehash0)); + + // --- Encode <keep>. + ASN1EncodableVector keepPart0 = new ASN1EncodableVector(); + ASN1EncodableVector keepPart1 = new ASN1EncodableVector(); + for (int i = 0; i < keep.length; i++) + { + for (int j = 0; j < keep[i].length; j++) + { + keepPart0.add(new DEROctetString(keep[i][j])); + } + keepPart1.add(new DERSequence(keepPart0)); + keepPart0 = new ASN1EncodableVector(); + } + result.add(new DERSequence(keepPart1)); + + // --- Encode <curStack>. + ASN1EncodableVector curStackPart0 = new ASN1EncodableVector(); + ASN1EncodableVector curStackPart1 = new ASN1EncodableVector(); + for (int i = 0; i < currentStack.length; i++) + { + for (int j = 0; j < currentStack[i].size(); j++) + { + curStackPart0.add(new DEROctetString((byte[])currentStack[i] + .elementAt(j))); + } + curStackPart1.add(new DERSequence(curStackPart0)); + curStackPart0 = new ASN1EncodableVector(); + } + result.add(new DERSequence(curStackPart1)); + + // --- Encode <nextStack>. + ASN1EncodableVector nextStackPart0 = new ASN1EncodableVector(); + ASN1EncodableVector nextStackPart1 = new ASN1EncodableVector(); + for (int i = 0; i < nextStack.length; i++) + { + for (int j = 0; j < nextStack[i].size(); j++) + { + nextStackPart0.add(new DEROctetString((byte[])nextStack[i] + .elementAt(j))); + } + nextStackPart1.add(new DERSequence(nextStackPart0)); + nextStackPart0 = new ASN1EncodableVector(); + } + result.add(new DERSequence(nextStackPart1)); + + // --- Encode <curRetain>. + ASN1EncodableVector currentRetainPart0 = new ASN1EncodableVector(); + ASN1EncodableVector currentRetainPart1 = new ASN1EncodableVector(); + ASN1EncodableVector currentRetainPart2 = new ASN1EncodableVector(); + for (int i = 0; i < currentRetain.length; i++) + { + for (int j = 0; j < currentRetain[i].length; j++) + { + for (int k = 0; k < currentRetain[i][j].size(); k++) + { + currentRetainPart0.add(new DEROctetString( + (byte[])currentRetain[i][j].elementAt(k))); + } + currentRetainPart1.add(new DERSequence(currentRetainPart0)); + currentRetainPart0 = new ASN1EncodableVector(); + } + currentRetainPart2.add(new DERSequence(currentRetainPart1)); + currentRetainPart1 = new ASN1EncodableVector(); + } + result.add(new DERSequence(currentRetainPart2)); + + // --- Encode <nextRetain>. + ASN1EncodableVector nextRetainPart0 = new ASN1EncodableVector(); + ASN1EncodableVector nextRetainPart1 = new ASN1EncodableVector(); + ASN1EncodableVector nextRetainPart2 = new ASN1EncodableVector(); + for (int i = 0; i < nextRetain.length; i++) + { + for (int j = 0; j < nextRetain[i].length; j++) + { + for (int k = 0; k < nextRetain[i][j].size(); k++) + { + nextRetainPart0.add(new DEROctetString( + (byte[])nextRetain[i][j].elementAt(k))); + } + nextRetainPart1.add(new DERSequence(nextRetainPart0)); + nextRetainPart0 = new ASN1EncodableVector(); + } + nextRetainPart2.add(new DERSequence(nextRetainPart1)); + nextRetainPart1 = new ASN1EncodableVector(); + } + result.add(new DERSequence(nextRetainPart2)); + + // --- Encode <nextNextLeaf>. + ASN1EncodableVector seqOfLeaf = new ASN1EncodableVector(); + seqOfStat = new ASN1EncodableVector(); + seqOfByte = new ASN1EncodableVector(); + seqOfInt = new ASN1EncodableVector(); + + for (int i = 0; i < nextNextLeaf.length; i++) + { + seqOfStat.add(new DERSequence(algorithms[0])); + + byte[][] tempByte = nextNextLeaf[i].getStatByte(); + seqOfByte.add(new DEROctetString(tempByte[0])); + seqOfByte.add(new DEROctetString(tempByte[1])); + seqOfByte.add(new DEROctetString(tempByte[2])); + seqOfByte.add(new DEROctetString(tempByte[3])); + seqOfStat.add(new DERSequence(seqOfByte)); + seqOfByte = new ASN1EncodableVector(); + + int[] tempInt = nextNextLeaf[i].getStatInt(); + seqOfInt.add(new ASN1Integer(tempInt[0])); + seqOfInt.add(new ASN1Integer(tempInt[1])); + seqOfInt.add(new ASN1Integer(tempInt[2])); + seqOfInt.add(new ASN1Integer(tempInt[3])); + seqOfStat.add(new DERSequence(seqOfInt)); + seqOfInt = new ASN1EncodableVector(); + + seqOfLeaf.add(new DERSequence(seqOfStat)); + seqOfStat = new ASN1EncodableVector(); + } + result.add(new DERSequence(seqOfLeaf)); + + // --- Encode <upperLEAF>. + ASN1EncodableVector seqOfUpperLeaf = new ASN1EncodableVector(); + seqOfStat = new ASN1EncodableVector(); + seqOfByte = new ASN1EncodableVector(); + seqOfInt = new ASN1EncodableVector(); + + for (int i = 0; i < upperLeaf.length; i++) + { + seqOfStat.add(new DERSequence(algorithms[0])); + + byte[][] tempByte = upperLeaf[i].getStatByte(); + seqOfByte.add(new DEROctetString(tempByte[0])); + seqOfByte.add(new DEROctetString(tempByte[1])); + seqOfByte.add(new DEROctetString(tempByte[2])); + seqOfByte.add(new DEROctetString(tempByte[3])); + seqOfStat.add(new DERSequence(seqOfByte)); + seqOfByte = new ASN1EncodableVector(); + + int[] tempInt = upperLeaf[i].getStatInt(); + seqOfInt.add(new ASN1Integer(tempInt[0])); + seqOfInt.add(new ASN1Integer(tempInt[1])); + seqOfInt.add(new ASN1Integer(tempInt[2])); + seqOfInt.add(new ASN1Integer(tempInt[3])); + seqOfStat.add(new DERSequence(seqOfInt)); + seqOfInt = new ASN1EncodableVector(); + + seqOfUpperLeaf.add(new DERSequence(seqOfStat)); + seqOfStat = new ASN1EncodableVector(); + } + result.add(new DERSequence(seqOfUpperLeaf)); + + // encode <upperTreehashLeaf> + ASN1EncodableVector seqOfUpperTreehashLeaf = new ASN1EncodableVector(); + seqOfStat = new ASN1EncodableVector(); + seqOfByte = new ASN1EncodableVector(); + seqOfInt = new ASN1EncodableVector(); + + for (int i = 0; i < upperTreehashLeaf.length; i++) + { + seqOfStat.add(new DERSequence(algorithms[0])); + + byte[][] tempByte = upperTreehashLeaf[i].getStatByte(); + seqOfByte.add(new DEROctetString(tempByte[0])); + seqOfByte.add(new DEROctetString(tempByte[1])); + seqOfByte.add(new DEROctetString(tempByte[2])); + seqOfByte.add(new DEROctetString(tempByte[3])); + seqOfStat.add(new DERSequence(seqOfByte)); + seqOfByte = new ASN1EncodableVector(); + + int[] tempInt = upperTreehashLeaf[i].getStatInt(); + seqOfInt.add(new ASN1Integer(tempInt[0])); + seqOfInt.add(new ASN1Integer(tempInt[1])); + seqOfInt.add(new ASN1Integer(tempInt[2])); + seqOfInt.add(new ASN1Integer(tempInt[3])); + seqOfStat.add(new DERSequence(seqOfInt)); + seqOfInt = new ASN1EncodableVector(); + + seqOfUpperTreehashLeaf.add(new DERSequence(seqOfStat)); + seqOfStat = new ASN1EncodableVector(); + } + result.add(new DERSequence(seqOfUpperTreehashLeaf)); + + // --- Encode <minTreehash>. + ASN1EncodableVector minTreehashPart = new ASN1EncodableVector(); + for (int i = 0; i < minTreehash.length; i++) + { + minTreehashPart.add(new ASN1Integer(minTreehash[i])); + } + result.add(new DERSequence(minTreehashPart)); + + // --- Encode <nextRoot>. + ASN1EncodableVector nextRootPart = new ASN1EncodableVector(); + for (int i = 0; i < nextRoot.length; i++) + { + nextRootPart.add(new DEROctetString(nextRoot[i])); + } + result.add(new DERSequence(nextRootPart)); + + // --- Encode <nextNextRoot>. + ASN1EncodableVector seqOfnextNextRoot = new ASN1EncodableVector(); + ASN1EncodableVector seqOfnnRStats = new ASN1EncodableVector(); + ASN1EncodableVector seqOfnnRStrings = new ASN1EncodableVector(); + ASN1EncodableVector seqOfnnRBytes = new ASN1EncodableVector(); + ASN1EncodableVector seqOfnnRInts = new ASN1EncodableVector(); + ASN1EncodableVector seqOfnnRTreehash = new ASN1EncodableVector(); + ASN1EncodableVector seqOfnnRRetain = new ASN1EncodableVector(); + + for (int i = 0; i < nextNextRoot.length; i++) + { + seqOfnnRStats.add(new DERSequence(algorithms[0])); + seqOfnnRStrings = new ASN1EncodableVector(); + + int heightOfTree = nextNextRoot[i].getStatInt()[0]; + int tailLength = nextNextRoot[i].getStatInt()[7]; + + seqOfnnRBytes.add(new DEROctetString( + nextNextRoot[i].getStatByte()[0])); + for (int j = 0; j < heightOfTree; j++) + { + seqOfnnRBytes.add(new DEROctetString(nextNextRoot[i] + .getStatByte()[1 + j])); + } + for (int j = 0; j < tailLength; j++) + { + seqOfnnRBytes.add(new DEROctetString(nextNextRoot[i] + .getStatByte()[1 + heightOfTree + j])); + } + + seqOfnnRStats.add(new DERSequence(seqOfnnRBytes)); + seqOfnnRBytes = new ASN1EncodableVector(); + + seqOfnnRInts.add(new ASN1Integer(heightOfTree)); + seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[1])); + seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[2])); + seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[3])); + seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[4])); + seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[5])); + seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[6])); + seqOfnnRInts.add(new ASN1Integer(tailLength)); + for (int j = 0; j < heightOfTree; j++) + { + seqOfnnRInts.add(new ASN1Integer( + nextNextRoot[i].getStatInt()[8 + j])); + } + for (int j = 0; j < tailLength; j++) + { + seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[8 + + heightOfTree + j])); + } + + seqOfnnRStats.add(new DERSequence(seqOfnnRInts)); + seqOfnnRInts = new ASN1EncodableVector(); + + // add treehash of nextNextRoot object + // ---------------------------- + seqOfStat = new ASN1EncodableVector(); + seqOfByte = new ASN1EncodableVector(); + seqOfInt = new ASN1EncodableVector(); + + if (nextNextRoot[i].getTreehash() != null) + { + for (int j = 0; j < nextNextRoot[i].getTreehash().length; j++) + { + seqOfStat.add(new DERSequence(algorithms[0])); + + tailLength = nextNextRoot[i].getTreehash()[j].getStatInt()[1]; + + seqOfByte.add(new DEROctetString(nextNextRoot[i] + .getTreehash()[j].getStatByte()[0])); + seqOfByte.add(new DEROctetString(nextNextRoot[i] + .getTreehash()[j].getStatByte()[1])); + seqOfByte.add(new DEROctetString(nextNextRoot[i] + .getTreehash()[j].getStatByte()[2])); + for (int k = 0; k < tailLength; k++) + { + seqOfByte.add(new DEROctetString(nextNextRoot[i] + .getTreehash()[j].getStatByte()[3 + k])); + } + seqOfStat.add(new DERSequence(seqOfByte)); + seqOfByte = new ASN1EncodableVector(); + + seqOfInt.add(new ASN1Integer( + nextNextRoot[i].getTreehash()[j].getStatInt()[0])); + seqOfInt.add(new ASN1Integer(tailLength)); + seqOfInt.add(new ASN1Integer( + nextNextRoot[i].getTreehash()[j].getStatInt()[2])); + seqOfInt.add(new ASN1Integer( + nextNextRoot[i].getTreehash()[j].getStatInt()[3])); + seqOfInt.add(new ASN1Integer( + nextNextRoot[i].getTreehash()[j].getStatInt()[4])); + seqOfInt.add(new ASN1Integer( + nextNextRoot[i].getTreehash()[j].getStatInt()[5])); + for (int k = 0; k < tailLength; k++) + { + seqOfInt.add(new ASN1Integer(nextNextRoot[i] + .getTreehash()[j].getStatInt()[6 + k])); + } + seqOfStat.add(new DERSequence(seqOfInt)); + seqOfInt = new ASN1EncodableVector(); + + seqOfnnRTreehash.add(new DERSequence(seqOfStat)); + seqOfStat = new ASN1EncodableVector(); + } + } + // ---------------------------- + seqOfnnRStats.add(new DERSequence(seqOfnnRTreehash)); + seqOfnnRTreehash = new ASN1EncodableVector(); + + // encode retain of nextNextRoot + // ---------------------------- + // --- Encode <curRetain>. + currentRetainPart0 = new ASN1EncodableVector(); + if (nextNextRoot[i].getRetain() != null) + { + for (int j = 0; j < nextNextRoot[i].getRetain().length; j++) + { + for (int k = 0; k < nextNextRoot[i].getRetain()[j].size(); k++) + { + currentRetainPart0.add(new DEROctetString( + (byte[])nextNextRoot[i].getRetain()[j] + .elementAt(k))); + } + seqOfnnRRetain.add(new DERSequence(currentRetainPart0)); + currentRetainPart0 = new ASN1EncodableVector(); + } + } + // ---------------------------- + seqOfnnRStats.add(new DERSequence(seqOfnnRRetain)); + seqOfnnRRetain = new ASN1EncodableVector(); + + seqOfnextNextRoot.add(new DERSequence(seqOfnnRStats)); + seqOfnnRStats = new ASN1EncodableVector(); + } + result.add(new DERSequence(seqOfnextNextRoot)); + + // --- Encode <curRootSig>. + ASN1EncodableVector curRootSigPart = new ASN1EncodableVector(); + for (int i = 0; i < currentRootSig.length; i++) + { + curRootSigPart.add(new DEROctetString(currentRootSig[i])); + } + result.add(new DERSequence(curRootSigPart)); + + // --- Encode <nextRootSig>. + ASN1EncodableVector seqOfnextRootSigs = new ASN1EncodableVector(); + ASN1EncodableVector seqOfnRSStats = new ASN1EncodableVector(); + ASN1EncodableVector seqOfnRSStrings = new ASN1EncodableVector(); + ASN1EncodableVector seqOfnRSBytes = new ASN1EncodableVector(); + ASN1EncodableVector seqOfnRSInts = new ASN1EncodableVector(); + + for (int i = 0; i < nextRootSig.length; i++) + { + seqOfnRSStats.add(new DERSequence(algorithms[0])); + seqOfnRSStrings = new ASN1EncodableVector(); + + seqOfnRSBytes.add(new DEROctetString( + nextRootSig[i].getStatByte()[0])); + seqOfnRSBytes.add(new DEROctetString( + nextRootSig[i].getStatByte()[1])); + seqOfnRSBytes.add(new DEROctetString( + nextRootSig[i].getStatByte()[2])); + seqOfnRSBytes.add(new DEROctetString( + nextRootSig[i].getStatByte()[3])); + seqOfnRSBytes.add(new DEROctetString( + nextRootSig[i].getStatByte()[4])); + + seqOfnRSStats.add(new DERSequence(seqOfnRSBytes)); + seqOfnRSBytes = new ASN1EncodableVector(); + + seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[0])); + seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[1])); + seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[2])); + seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[3])); + seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[4])); + seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[5])); + seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[6])); + seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[7])); + seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[8])); + + seqOfnRSStats.add(new DERSequence(seqOfnRSInts)); + seqOfnRSInts = new ASN1EncodableVector(); + + seqOfnextRootSigs.add(new DERSequence(seqOfnRSStats)); + seqOfnRSStats = new ASN1EncodableVector(); + } + result.add(new DERSequence(seqOfnextRootSigs)); + + // --- Encode <parameterset>. + ASN1EncodableVector parSetPart0 = new ASN1EncodableVector(); + ASN1EncodableVector parSetPart1 = new ASN1EncodableVector(); + ASN1EncodableVector parSetPart2 = new ASN1EncodableVector(); + ASN1EncodableVector parSetPart3 = new ASN1EncodableVector(); + + for (int i = 0; i < gmssParameterset.getHeightOfTrees().length; i++) + { + parSetPart1.add(new ASN1Integer( + gmssParameterset.getHeightOfTrees()[i])); + parSetPart2.add(new ASN1Integer(gmssParameterset + .getWinternitzParameter()[i])); + parSetPart3.add(new ASN1Integer(gmssParameterset.getK()[i])); + } + parSetPart0.add(new ASN1Integer(gmssParameterset.getNumOfLayers())); + parSetPart0.add(new DERSequence(parSetPart1)); + parSetPart0.add(new DERSequence(parSetPart2)); + parSetPart0.add(new DERSequence(parSetPart3)); + result.add(new DERSequence(parSetPart0)); + + // --- Encode <names>. + ASN1EncodableVector namesPart = new ASN1EncodableVector(); + + for (int i = 0; i < algorithms.length; i++) + { + namesPart.add(algorithms[i]); + } + + result.add(new DERSequence(namesPart)); + return new DERSequence(result); + + } + + private static int checkBigIntegerInIntRange(ASN1Encodable a) + { + BigInteger b = ((ASN1Integer)a).getValue(); + if ((b.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) || + (b.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0)) + { + throw new IllegalArgumentException("BigInteger not in Range: " + b.toString()); + } + return b.intValue(); + } + + + public ASN1Primitive toASN1Primitive() + { + return this.primitive; + } +} diff --git a/core/src/main/java/org/spongycastle/pqc/asn1/GMSSPublicKey.java b/core/src/main/java/org/spongycastle/pqc/asn1/GMSSPublicKey.java new file mode 100644 index 00000000..77992283 --- /dev/null +++ b/core/src/main/java/org/spongycastle/pqc/asn1/GMSSPublicKey.java @@ -0,0 +1,74 @@ +package org.spongycastle.pqc.asn1; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.util.Arrays; + +/** + * This class implements an ASN.1 encoded GMSS public key. The ASN.1 definition + * of this structure is: + * <pre> + * GMSSPublicKey ::= SEQUENCE{ + * version INTEGER + * publicKey OCTET STRING + * } + * </pre> + */ +public class GMSSPublicKey + extends ASN1Object +{ + private ASN1Integer version; + private byte[] publicKey; + + private GMSSPublicKey(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("size of seq = " + seq.size()); + } + + this.version = ASN1Integer.getInstance(seq.getObjectAt(0)); + this.publicKey = ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets(); + } + + public GMSSPublicKey(byte[] publicKeyBytes) + { + this.version = new ASN1Integer(0); + this.publicKey = publicKeyBytes; + } + + public static GMSSPublicKey getInstance(Object o) + { + if (o instanceof GMSSPublicKey) + { + return (GMSSPublicKey)o; + } + else if (o != null) + { + return new GMSSPublicKey(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public byte[] getPublicKey() + { + return Arrays.clone(publicKey); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(new DEROctetString(publicKey)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/spongycastle/pqc/asn1/McElieceCCA2PrivateKey.java b/core/src/main/java/org/spongycastle/pqc/asn1/McElieceCCA2PrivateKey.java new file mode 100644 index 00000000..5f6a8b9d --- /dev/null +++ b/core/src/main/java/org/spongycastle/pqc/asn1/McElieceCCA2PrivateKey.java @@ -0,0 +1,173 @@ +package org.spongycastle.pqc.asn1; + +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; + +import org.spongycastle.pqc.math.linearalgebra.GF2Matrix; +import org.spongycastle.pqc.math.linearalgebra.GF2mField; +import org.spongycastle.pqc.math.linearalgebra.Permutation; +import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; + +public class McElieceCCA2PrivateKey + extends ASN1Object +{ + private ASN1ObjectIdentifier oid; + private int n; + private int k; + private byte[] encField; + private byte[] encGp; + private byte[] encP; + private byte[] encH; + private byte[][] encqInv; + + + public McElieceCCA2PrivateKey(ASN1ObjectIdentifier oid, int n, int k, GF2mField field, PolynomialGF2mSmallM goppaPoly, Permutation p, GF2Matrix h, PolynomialGF2mSmallM[] qInv) + { + this.oid = oid; + this.n = n; + this.k = k; + this.encField = field.getEncoded(); + this.encGp = goppaPoly.getEncoded(); + this.encP = p.getEncoded(); + this.encH = h.getEncoded(); + this.encqInv = new byte[qInv.length][]; + + for (int i = 0; i != qInv.length; i++) + { + encqInv[i] = qInv[i].getEncoded(); + } + } + + private McElieceCCA2PrivateKey(ASN1Sequence seq) + { + oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0)); + + BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue(); + n = bigN.intValue(); + + BigInteger bigK = ((ASN1Integer)seq.getObjectAt(2)).getValue(); + k = bigK.intValue(); + + encField = ((ASN1OctetString)seq.getObjectAt(3)).getOctets(); + + encGp = ((ASN1OctetString)seq.getObjectAt(4)).getOctets(); + + encP = ((ASN1OctetString)seq.getObjectAt(5)).getOctets(); + + encH = ((ASN1OctetString)seq.getObjectAt(6)).getOctets(); + + ASN1Sequence asnQInv = (ASN1Sequence)seq.getObjectAt(7); + encqInv = new byte[asnQInv.size()][]; + for (int i = 0; i < asnQInv.size(); i++) + { + encqInv[i] = ((ASN1OctetString)asnQInv.getObjectAt(i)).getOctets(); + } + } + + public ASN1ObjectIdentifier getOID() + { + return oid; + } + + public int getN() + { + return n; + } + + public int getK() + { + return k; + } + + public GF2mField getField() + { + return new GF2mField(encField); + } + + public PolynomialGF2mSmallM getGoppaPoly() + { + return new PolynomialGF2mSmallM(this.getField(), encGp); + } + + public Permutation getP() + { + return new Permutation(encP); + } + + public GF2Matrix getH() + { + return new GF2Matrix(encH); + } + + public PolynomialGF2mSmallM[] getQInv() + { + PolynomialGF2mSmallM[] qInv = new PolynomialGF2mSmallM[encqInv.length]; + GF2mField field = this.getField(); + + for (int i = 0; i < encqInv.length; i++) + { + qInv[i] = new PolynomialGF2mSmallM(field, encqInv[i]); + } + + return qInv; + } + + public ASN1Primitive toASN1Primitive() + { + + ASN1EncodableVector v = new ASN1EncodableVector(); + // encode <oidString> + v.add(oid); + // encode <n> + v.add(new ASN1Integer(n)); + + // encode <k> + v.add(new ASN1Integer(k)); + + // encode <field> + v.add(new DEROctetString(encField)); + + // encode <gp> + v.add(new DEROctetString(encGp)); + + // encode <p> + v.add(new DEROctetString(encP)); + + // encode <h> + v.add(new DEROctetString(encH)); + + // encode <q> + ASN1EncodableVector asnQInv = new ASN1EncodableVector(); + for (int i = 0; i < encqInv.length; i++) + { + asnQInv.add(new DEROctetString(encqInv[i])); + } + + v.add(new DERSequence(asnQInv)); + + return new DERSequence(v); + } + + public static McElieceCCA2PrivateKey getInstance(Object o) + { + if (o instanceof McElieceCCA2PrivateKey) + { + return (McElieceCCA2PrivateKey)o; + } + else if (o != null) + { + return new McElieceCCA2PrivateKey(ASN1Sequence.getInstance(o)); + } + + return null; + } +} diff --git a/core/src/main/java/org/spongycastle/pqc/asn1/McElieceCCA2PublicKey.java b/core/src/main/java/org/spongycastle/pqc/asn1/McElieceCCA2PublicKey.java new file mode 100644 index 00000000..186d8ca4 --- /dev/null +++ b/core/src/main/java/org/spongycastle/pqc/asn1/McElieceCCA2PublicKey.java @@ -0,0 +1,96 @@ +package org.spongycastle.pqc.asn1; + +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.pqc.math.linearalgebra.GF2Matrix; + +public class McElieceCCA2PublicKey + extends ASN1Object +{ + private ASN1ObjectIdentifier oid; + private int n; + private int t; + + private byte[] matrixG; + + public McElieceCCA2PublicKey(ASN1ObjectIdentifier oid, int n, int t, GF2Matrix g) + { + this.oid = oid; + this.n = n; + this.t = t; + this.matrixG = g.getEncoded(); + } + + private McElieceCCA2PublicKey(ASN1Sequence seq) + { + oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0)); + BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue(); + n = bigN.intValue(); + + BigInteger bigT = ((ASN1Integer)seq.getObjectAt(2)).getValue(); + t = bigT.intValue(); + + matrixG = ((ASN1OctetString)seq.getObjectAt(3)).getOctets(); + } + + public ASN1ObjectIdentifier getOID() + { + return oid; + } + + public int getN() + { + return n; + } + + public int getT() + { + return t; + } + + public GF2Matrix getG() + { + return new GF2Matrix(matrixG); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + // encode <oidString> + v.add(oid); + + // encode <n> + v.add(new ASN1Integer(n)); + + // encode <t> + v.add(new ASN1Integer(t)); + + // encode <matrixG> + v.add(new DEROctetString(matrixG)); + + return new DERSequence(v); + } + + public static McElieceCCA2PublicKey getInstance(Object o) + { + if (o instanceof McElieceCCA2PublicKey) + { + return (McElieceCCA2PublicKey)o; + } + else if (o != null) + { + return new McElieceCCA2PublicKey(ASN1Sequence.getInstance(o)); + } + + return null; + } +} diff --git a/core/src/main/java/org/spongycastle/pqc/asn1/McEliecePrivateKey.java b/core/src/main/java/org/spongycastle/pqc/asn1/McEliecePrivateKey.java new file mode 100644 index 00000000..e0ba1ed7 --- /dev/null +++ b/core/src/main/java/org/spongycastle/pqc/asn1/McEliecePrivateKey.java @@ -0,0 +1,197 @@ +package org.spongycastle.pqc.asn1; + +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.pqc.math.linearalgebra.GF2Matrix; +import org.spongycastle.pqc.math.linearalgebra.GF2mField; +import org.spongycastle.pqc.math.linearalgebra.Permutation; +import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; + +public class McEliecePrivateKey + extends ASN1Object +{ + private ASN1ObjectIdentifier oid; + private int n; + private int k; + private byte[] encField; + private byte[] encGp; + private byte[] encSInv; + private byte[] encP1; + private byte[] encP2; + private byte[] encH; + private byte[][] encqInv; + + + public McEliecePrivateKey(ASN1ObjectIdentifier oid, int n, int k, GF2mField field, PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1, Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv) + { + this.oid = oid; + this.n = n; + this.k = k; + this.encField = field.getEncoded(); + this.encGp = goppaPoly.getEncoded(); + this.encSInv = sInv.getEncoded(); + this.encP1 = p1.getEncoded(); + this.encP2 = p2.getEncoded(); + this.encH = h.getEncoded(); + this.encqInv = new byte[qInv.length][]; + + for (int i = 0; i != qInv.length; i++) + { + encqInv[i] = qInv[i].getEncoded(); + } + } + + public static McEliecePrivateKey getInstance(Object o) + { + if (o instanceof McEliecePrivateKey) + { + return (McEliecePrivateKey)o; + } + else if (o != null) + { + return new McEliecePrivateKey(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private McEliecePrivateKey(ASN1Sequence seq) + { + // <oidString> + oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0)); + + BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue(); + n = bigN.intValue(); + + BigInteger bigK = ((ASN1Integer)seq.getObjectAt(2)).getValue(); + k = bigK.intValue(); + + encField = ((ASN1OctetString)seq.getObjectAt(3)).getOctets(); + + encGp = ((ASN1OctetString)seq.getObjectAt(4)).getOctets(); + + encSInv = ((ASN1OctetString)seq.getObjectAt(5)).getOctets(); + + encP1 = ((ASN1OctetString)seq.getObjectAt(6)).getOctets(); + + encP2 = ((ASN1OctetString)seq.getObjectAt(7)).getOctets(); + + encH = ((ASN1OctetString)seq.getObjectAt(8)).getOctets(); + + ASN1Sequence asnQInv = (ASN1Sequence)seq.getObjectAt(9); + encqInv = new byte[asnQInv.size()][]; + for (int i = 0; i < asnQInv.size(); i++) + { + encqInv[i] = ((ASN1OctetString)asnQInv.getObjectAt(i)).getOctets(); + } + } + + public ASN1ObjectIdentifier getOID() + { + return oid; + } + + public int getN() + { + return n; + } + + public int getK() + { + return k; + } + + public GF2mField getField() + { + return new GF2mField(encField); + } + + public PolynomialGF2mSmallM getGoppaPoly() + { + return new PolynomialGF2mSmallM(this.getField(), encGp); + } + + public GF2Matrix getSInv() + { + return new GF2Matrix(encSInv); + } + + public Permutation getP1() + { + return new Permutation(encP1); + } + + public Permutation getP2() + { + return new Permutation(encP2); + } + + public GF2Matrix getH() + { + return new GF2Matrix(encH); + } + + public PolynomialGF2mSmallM[] getQInv() + { + PolynomialGF2mSmallM[] qInv = new PolynomialGF2mSmallM[encqInv.length]; + GF2mField field = this.getField(); + + for (int i = 0; i < encqInv.length; i++) + { + qInv[i] = new PolynomialGF2mSmallM(field, encqInv[i]); + } + + return qInv; + } + + public ASN1Primitive toASN1Primitive() + { + + ASN1EncodableVector v = new ASN1EncodableVector(); + // encode <oidString> + v.add(oid); + // encode <n> + v.add(new ASN1Integer(n)); + + // encode <k> + v.add(new ASN1Integer(k)); + + // encode <fieldPoly> + v.add(new DEROctetString(encField)); + + // encode <goppaPoly> + v.add(new DEROctetString(encGp)); + + // encode <sInv> + v.add(new DEROctetString(encSInv)); + + // encode <p1> + v.add(new DEROctetString(encP1)); + + // encode <p2> + v.add(new DEROctetString(encP2)); + + // encode <h> + v.add(new DEROctetString(encH)); + + // encode <q> + ASN1EncodableVector asnQInv = new ASN1EncodableVector(); + for (int i = 0; i < encqInv.length; i++) + { + asnQInv.add(new DEROctetString(encqInv[i])); + } + + v.add(new DERSequence(asnQInv)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/spongycastle/pqc/asn1/McEliecePublicKey.java b/core/src/main/java/org/spongycastle/pqc/asn1/McEliecePublicKey.java new file mode 100644 index 00000000..1415587d --- /dev/null +++ b/core/src/main/java/org/spongycastle/pqc/asn1/McEliecePublicKey.java @@ -0,0 +1,97 @@ +package org.spongycastle.pqc.asn1; + +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.pqc.math.linearalgebra.GF2Matrix; + +public class McEliecePublicKey + extends ASN1Object +{ + + private ASN1ObjectIdentifier oid; + private int n; + private int t; + + private byte[] matrixG; + + public McEliecePublicKey(ASN1ObjectIdentifier oid, int n, int t, GF2Matrix g) + { + this.oid = oid; + this.n = n; + this.t = t; + this.matrixG = g.getEncoded(); + } + + private McEliecePublicKey(ASN1Sequence seq) + { + oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0)); + BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue(); + n = bigN.intValue(); + + BigInteger bigT = ((ASN1Integer)seq.getObjectAt(2)).getValue(); + t = bigT.intValue(); + + matrixG = ((ASN1OctetString)seq.getObjectAt(3)).getOctets(); + } + + public ASN1ObjectIdentifier getOID() + { + return oid; + } + + public int getN() + { + return n; + } + + public int getT() + { + return t; + } + + public GF2Matrix getG() + { + return new GF2Matrix(matrixG); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + // encode <oidString> + v.add(oid); + + // encode <n> + v.add(new ASN1Integer(n)); + + // encode <t> + v.add(new ASN1Integer(t)); + + // encode <matrixG> + v.add(new DEROctetString(matrixG)); + + return new DERSequence(v); + } + + public static McEliecePublicKey getInstance(Object o) + { + if (o instanceof McEliecePublicKey) + { + return (McEliecePublicKey)o; + } + else if (o != null) + { + return new McEliecePublicKey(ASN1Sequence.getInstance(o)); + } + + return null; + } +} diff --git a/core/src/main/java/org/spongycastle/pqc/asn1/PQCObjectIdentifiers.java b/core/src/main/java/org/spongycastle/pqc/asn1/PQCObjectIdentifiers.java new file mode 100644 index 00000000..1a0e5ce7 --- /dev/null +++ b/core/src/main/java/org/spongycastle/pqc/asn1/PQCObjectIdentifiers.java @@ -0,0 +1,46 @@ +package org.spongycastle.pqc.asn1; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; + +/** + * PQC: + * <p> + * { iso(1) identifier-organization(3) dod(6) internet(1) private(4) 1 8301 3 1 3 5 3 ... } + */ +public interface PQCObjectIdentifiers +{ + /** 1.3.6.1.4.1.8301.3.1.3.5.3.2 */ + public static final ASN1ObjectIdentifier rainbow = new ASN1ObjectIdentifier("1.3.6.1.4.1.8301.3.1.3.5.3.2"); + + /** 1.3.6.1.4.1.8301.3.1.3.5.3.2.1 */ + public static final ASN1ObjectIdentifier rainbowWithSha1 = rainbow.branch("1"); + /** 1.3.6.1.4.1.8301.3.1.3.5.3.2.2 */ + public static final ASN1ObjectIdentifier rainbowWithSha224 = rainbow.branch("2"); + /** 1.3.6.1.4.1.8301.3.1.3.5.3.2.3 */ + public static final ASN1ObjectIdentifier rainbowWithSha256 = rainbow.branch("3"); + /** 1.3.6.1.4.1.8301.3.1.3.5.3.2.4 */ + public static final ASN1ObjectIdentifier rainbowWithSha384 = rainbow.branch("4"); + /** 1.3.6.1.4.1.8301.3.1.3.5.3.2.5 */ + public static final ASN1ObjectIdentifier rainbowWithSha512 = rainbow.branch("5"); + + /** 1.3.6.1.4.1.8301.3.1.3.3 */ + public static final ASN1ObjectIdentifier gmss = new ASN1ObjectIdentifier("1.3.6.1.4.1.8301.3.1.3.3"); + + /** 1.3.6.1.4.1.8301.3.1.3.3.1 */ + public static final ASN1ObjectIdentifier gmssWithSha1 = gmss.branch("1"); + /** 1.3.6.1.4.1.8301.3.1.3.3.2 */ + public static final ASN1ObjectIdentifier gmssWithSha224 = gmss.branch("2"); + /** 1.3.6.1.4.1.8301.3.1.3.3.3 */ + public static final ASN1ObjectIdentifier gmssWithSha256 = gmss.branch("3"); + /** 1.3.6.1.4.1.8301.3.1.3.3.4 */ + public static final ASN1ObjectIdentifier gmssWithSha384 = gmss.branch("4"); + /** 1.3.6.1.4.1.8301.3.1.3.3.5 */ + public static final ASN1ObjectIdentifier gmssWithSha512 = gmss.branch("5"); + + /** 1.3.6.1.4.1.8301.3.1.3.4.1 */ + public static final ASN1ObjectIdentifier mcEliece = new ASN1ObjectIdentifier("1.3.6.1.4.1.8301.3.1.3.4.1"); + + /** 1.3.6.1.4.1.8301.3.1.3.4.2 */ + public static final ASN1ObjectIdentifier mcElieceCca2 = new ASN1ObjectIdentifier("1.3.6.1.4.1.8301.3.1.3.4.2"); + +} diff --git a/core/src/main/java/org/spongycastle/pqc/asn1/ParSet.java b/core/src/main/java/org/spongycastle/pqc/asn1/ParSet.java new file mode 100644 index 00000000..d5110a2c --- /dev/null +++ b/core/src/main/java/org/spongycastle/pqc/asn1/ParSet.java @@ -0,0 +1,140 @@ +package org.spongycastle.pqc.asn1; + +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.util.Arrays; + +/** + * <pre> + * ParSet ::= SEQUENCE { + * T INTEGER + * h SEQUENCE OF INTEGER + * w SEQUENCE OF INTEGER + * K SEQUENCE OF INTEGER + * } + * </pre> + */ +public class ParSet + extends ASN1Object +{ + private static final BigInteger ZERO = BigInteger.valueOf(0); + + private int t; + private int[] h; + private int[] w; + private int[] k; + + private static int checkBigIntegerInIntRangeAndPositive(BigInteger b) + { + if ((b.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) || + (b.compareTo(ZERO) <= 0)) + { + throw new IllegalArgumentException("BigInteger not in Range: " + b.toString()); + } + return b.intValue(); + } + + private ParSet(ASN1Sequence seq) + { + if (seq.size() != 4) + { + throw new IllegalArgumentException("sie of seqOfParams = " + seq.size()); + } + BigInteger asn1int = ((ASN1Integer)seq.getObjectAt(0)).getValue(); + + t = checkBigIntegerInIntRangeAndPositive(asn1int); + + ASN1Sequence seqOfPSh = (ASN1Sequence)seq.getObjectAt(1); + ASN1Sequence seqOfPSw = (ASN1Sequence)seq.getObjectAt(2); + ASN1Sequence seqOfPSK = (ASN1Sequence)seq.getObjectAt(3); + + if ((seqOfPSh.size() != t) || + (seqOfPSw.size() != t) || + (seqOfPSK.size() != t)) + { + throw new IllegalArgumentException("invalid size of sequences"); + } + + h = new int[seqOfPSh.size()]; + w = new int[seqOfPSw.size()]; + k = new int[seqOfPSK.size()]; + + for (int i = 0; i < t; i++) + { + h[i] = checkBigIntegerInIntRangeAndPositive((((ASN1Integer)seqOfPSh.getObjectAt(i))).getValue()); + w[i] = checkBigIntegerInIntRangeAndPositive((((ASN1Integer)seqOfPSw.getObjectAt(i))).getValue()); + k[i] = checkBigIntegerInIntRangeAndPositive((((ASN1Integer)seqOfPSK.getObjectAt(i))).getValue()); + } + } + + public ParSet(int t, int[] h, int[] w, int[] k) + { + this.t = t; + this.h = h; + this.w = w; + this.k = k; + } + + public static ParSet getInstance(Object o) + { + if (o instanceof ParSet) + { + return (ParSet)o; + } + else if (o != null) + { + return new ParSet(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public int getT() + { + return t; + } + + public int[] getH() + { + return Arrays.clone(h); + } + + public int[] getW() + { + return Arrays.clone(w); + } + + public int[] getK() + { + return Arrays.clone(k); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seqOfPSh = new ASN1EncodableVector(); + ASN1EncodableVector seqOfPSw = new ASN1EncodableVector(); + ASN1EncodableVector seqOfPSK = new ASN1EncodableVector(); + + for (int i = 0; i < h.length; i++) + { + seqOfPSh.add(new ASN1Integer(h[i])); + seqOfPSw.add(new ASN1Integer(w[i])); + seqOfPSK.add(new ASN1Integer(k[i])); + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(t)); + v.add(new DERSequence(seqOfPSh)); + v.add(new DERSequence(seqOfPSw)); + v.add(new DERSequence(seqOfPSK)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/spongycastle/pqc/asn1/RainbowPrivateKey.java b/core/src/main/java/org/spongycastle/pqc/asn1/RainbowPrivateKey.java new file mode 100644 index 00000000..96648900 --- /dev/null +++ b/core/src/main/java/org/spongycastle/pqc/asn1/RainbowPrivateKey.java @@ -0,0 +1,349 @@ +package org.spongycastle.pqc.asn1; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.pqc.crypto.rainbow.Layer; +import org.spongycastle.pqc.crypto.rainbow.util.RainbowUtil; + +/** + * Return the key data to encode in the PrivateKeyInfo structure. + * <p> + * The ASN.1 definition of the key structure is + * <pre> + * RainbowPrivateKey ::= SEQUENCE { + * CHOICE + * { + * oid OBJECT IDENTIFIER -- OID identifying the algorithm + * version INTEGER -- 0 + * } + * A1inv SEQUENCE OF OCTET STRING -- inversed matrix of L1 + * b1 OCTET STRING -- translation vector of L1 + * A2inv SEQUENCE OF OCTET STRING -- inversed matrix of L2 + * b2 OCTET STRING -- translation vector of L2 + * vi OCTET STRING -- num of elmts in each Set S + * layers SEQUENCE OF Layer -- layers of F + * } + * + * Layer ::= SEQUENCE OF Poly + * + * Poly ::= SEQUENCE { + * alpha SEQUENCE OF OCTET STRING + * beta SEQUENCE OF OCTET STRING + * gamma OCTET STRING + * eta INTEGER + * } + * </pre> + */ +public class RainbowPrivateKey + extends ASN1Object +{ + private ASN1Integer version; + private ASN1ObjectIdentifier oid; + + private byte[][] invA1; + private byte[] b1; + private byte[][] invA2; + private byte[] b2; + private byte[] vi; + private Layer[] layers; + + private RainbowPrivateKey(ASN1Sequence seq) + { + // <oidString> or version + if (seq.getObjectAt(0) instanceof ASN1Integer) + { + version = ASN1Integer.getInstance(seq.getObjectAt(0)); + } + else + { + oid = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + } + + // <A1inv> + ASN1Sequence asnA1 = (ASN1Sequence)seq.getObjectAt(1); + invA1 = new byte[asnA1.size()][]; + for (int i = 0; i < asnA1.size(); i++) + { + invA1[i] = ((ASN1OctetString)asnA1.getObjectAt(i)).getOctets(); + } + + // <b1> + ASN1Sequence asnb1 = (ASN1Sequence)seq.getObjectAt(2); + b1 = ((ASN1OctetString)asnb1.getObjectAt(0)).getOctets(); + + // <A2inv> + ASN1Sequence asnA2 = (ASN1Sequence)seq.getObjectAt(3); + invA2 = new byte[asnA2.size()][]; + for (int j = 0; j < asnA2.size(); j++) + { + invA2[j] = ((ASN1OctetString)asnA2.getObjectAt(j)).getOctets(); + } + + // <b2> + ASN1Sequence asnb2 = (ASN1Sequence)seq.getObjectAt(4); + b2 = ((ASN1OctetString)asnb2.getObjectAt(0)).getOctets(); + + // <vi> + ASN1Sequence asnvi = (ASN1Sequence)seq.getObjectAt(5); + vi = ((ASN1OctetString)asnvi.getObjectAt(0)).getOctets(); + + // <layers> + ASN1Sequence asnLayers = (ASN1Sequence)seq.getObjectAt(6); + + byte[][][][] alphas = new byte[asnLayers.size()][][][]; + byte[][][][] betas = new byte[asnLayers.size()][][][]; + byte[][][] gammas = new byte[asnLayers.size()][][]; + byte[][] etas = new byte[asnLayers.size()][]; + // a layer: + for (int l = 0; l < asnLayers.size(); l++) + { + ASN1Sequence asnLayer = (ASN1Sequence)asnLayers.getObjectAt(l); + + // alphas (num of alpha-2d-array = oi) + ASN1Sequence alphas3d = (ASN1Sequence)asnLayer.getObjectAt(0); + alphas[l] = new byte[alphas3d.size()][][]; + for (int m = 0; m < alphas3d.size(); m++) + { + ASN1Sequence alphas2d = (ASN1Sequence)alphas3d.getObjectAt(m); + alphas[l][m] = new byte[alphas2d.size()][]; + for (int n = 0; n < alphas2d.size(); n++) + { + alphas[l][m][n] = ((ASN1OctetString)alphas2d.getObjectAt(n)).getOctets(); + } + } + + // betas .... + ASN1Sequence betas3d = (ASN1Sequence)asnLayer.getObjectAt(1); + betas[l] = new byte[betas3d.size()][][]; + for (int mb = 0; mb < betas3d.size(); mb++) + { + ASN1Sequence betas2d = (ASN1Sequence)betas3d.getObjectAt(mb); + betas[l][mb] = new byte[betas2d.size()][]; + for (int nb = 0; nb < betas2d.size(); nb++) + { + betas[l][mb][nb] = ((ASN1OctetString)betas2d.getObjectAt(nb)).getOctets(); + } + } + + // gammas ... + ASN1Sequence gammas2d = (ASN1Sequence)asnLayer.getObjectAt(2); + gammas[l] = new byte[gammas2d.size()][]; + for (int mg = 0; mg < gammas2d.size(); mg++) + { + gammas[l][mg] = ((ASN1OctetString)gammas2d.getObjectAt(mg)).getOctets(); + } + + // eta ... + etas[l] = ((ASN1OctetString)asnLayer.getObjectAt(3)).getOctets(); + } + + int numOfLayers = vi.length - 1; + this.layers = new Layer[numOfLayers]; + for (int i = 0; i < numOfLayers; i++) + { + Layer l = new Layer(vi[i], vi[i + 1], RainbowUtil.convertArray(alphas[i]), + RainbowUtil.convertArray(betas[i]), RainbowUtil.convertArray(gammas[i]), RainbowUtil.convertArray(etas[i])); + this.layers[i] = l; + + } + } + + public RainbowPrivateKey(short[][] invA1, short[] b1, short[][] invA2, + short[] b2, int[] vi, Layer[] layers) + { + this.version = new ASN1Integer(1); + this.invA1 = RainbowUtil.convertArray(invA1); + this.b1 = RainbowUtil.convertArray(b1); + this.invA2 = RainbowUtil.convertArray(invA2); + this.b2 = RainbowUtil.convertArray(b2); + this.vi = RainbowUtil.convertIntArray(vi); + this.layers = layers; + } + + public static RainbowPrivateKey getInstance(Object o) + { + if (o instanceof RainbowPrivateKey) + { + return (RainbowPrivateKey)o; + } + else if (o != null) + { + return new RainbowPrivateKey(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + /** + * Getter for the inverse matrix of A1. + * + * @return the A1inv inverse + */ + public short[][] getInvA1() + { + return RainbowUtil.convertArray(invA1); + } + + /** + * Getter for the translation part of the private quadratic map L1. + * + * @return b1 the translation part of L1 + */ + public short[] getB1() + { + return RainbowUtil.convertArray(b1); + } + + /** + * Getter for the translation part of the private quadratic map L2. + * + * @return b2 the translation part of L2 + */ + public short[] getB2() + { + return RainbowUtil.convertArray(b2); + } + + /** + * Getter for the inverse matrix of A2 + * + * @return the A2inv + */ + public short[][] getInvA2() + { + return RainbowUtil.convertArray(invA2); + } + + /** + * Returns the layers contained in the private key + * + * @return layers + */ + public Layer[] getLayers() + { + return this.layers; + } + + /** + * Returns the array of vi-s + * + * @return the vi + */ + public int[] getVi() + { + return RainbowUtil.convertArraytoInt(vi); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + // encode <oidString> or version + if (version != null) + { + v.add(version); + } + else + { + v.add(oid); + } + + // encode <A1inv> + ASN1EncodableVector asnA1 = new ASN1EncodableVector(); + for (int i = 0; i < invA1.length; i++) + { + asnA1.add(new DEROctetString(invA1[i])); + } + v.add(new DERSequence(asnA1)); + + // encode <b1> + ASN1EncodableVector asnb1 = new ASN1EncodableVector(); + asnb1.add(new DEROctetString(b1)); + v.add(new DERSequence(asnb1)); + + // encode <A2inv> + ASN1EncodableVector asnA2 = new ASN1EncodableVector(); + for (int i = 0; i < invA2.length; i++) + { + asnA2.add(new DEROctetString(invA2[i])); + } + v.add(new DERSequence(asnA2)); + + // encode <b2> + ASN1EncodableVector asnb2 = new ASN1EncodableVector(); + asnb2.add(new DEROctetString(b2)); + v.add(new DERSequence(asnb2)); + + // encode <vi> + ASN1EncodableVector asnvi = new ASN1EncodableVector(); + asnvi.add(new DEROctetString(vi)); + v.add(new DERSequence(asnvi)); + + // encode <layers> + ASN1EncodableVector asnLayers = new ASN1EncodableVector(); + // a layer: + for (int l = 0; l < layers.length; l++) + { + ASN1EncodableVector aLayer = new ASN1EncodableVector(); + + // alphas (num of alpha-2d-array = oi) + byte[][][] alphas = RainbowUtil.convertArray(layers[l].getCoeffAlpha()); + ASN1EncodableVector alphas3d = new ASN1EncodableVector(); + for (int i = 0; i < alphas.length; i++) + { + ASN1EncodableVector alphas2d = new ASN1EncodableVector(); + for (int j = 0; j < alphas[i].length; j++) + { + alphas2d.add(new DEROctetString(alphas[i][j])); + } + alphas3d.add(new DERSequence(alphas2d)); + } + aLayer.add(new DERSequence(alphas3d)); + + // betas .... + byte[][][] betas = RainbowUtil.convertArray(layers[l].getCoeffBeta()); + ASN1EncodableVector betas3d = new ASN1EncodableVector(); + for (int i = 0; i < betas.length; i++) + { + ASN1EncodableVector betas2d = new ASN1EncodableVector(); + for (int j = 0; j < betas[i].length; j++) + { + betas2d.add(new DEROctetString(betas[i][j])); + } + betas3d.add(new DERSequence(betas2d)); + } + aLayer.add(new DERSequence(betas3d)); + + // gammas ... + byte[][] gammas = RainbowUtil.convertArray(layers[l].getCoeffGamma()); + ASN1EncodableVector asnG = new ASN1EncodableVector(); + for (int i = 0; i < gammas.length; i++) + { + asnG.add(new DEROctetString(gammas[i])); + } + aLayer.add(new DERSequence(asnG)); + + // eta + aLayer.add(new DEROctetString(RainbowUtil.convertArray(layers[l].getCoeffEta()))); + + // now, layer built up. add it! + asnLayers.add(new DERSequence(aLayer)); + } + + v.add(new DERSequence(asnLayers)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/spongycastle/pqc/asn1/RainbowPublicKey.java b/core/src/main/java/org/spongycastle/pqc/asn1/RainbowPublicKey.java new file mode 100644 index 00000000..c31aabb4 --- /dev/null +++ b/core/src/main/java/org/spongycastle/pqc/asn1/RainbowPublicKey.java @@ -0,0 +1,174 @@ +package org.spongycastle.pqc.asn1; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.pqc.crypto.rainbow.util.RainbowUtil; + +/** + * This class implements an ASN.1 encoded Rainbow public key. The ASN.1 definition + * of this structure is: + * <pre> + * RainbowPublicKey ::= SEQUENCE { + * CHOICE + * { + * oid OBJECT IDENTIFIER -- OID identifying the algorithm + * version INTEGER -- 0 + * } + * docLength Integer -- length of the code + * coeffquadratic SEQUENCE OF OCTET STRING -- quadratic (mixed) coefficients + * coeffsingular SEQUENCE OF OCTET STRING -- singular coefficients + * coeffscalar SEQUENCE OF OCTET STRING -- scalar coefficients + * } + * </pre> + */ +public class RainbowPublicKey + extends ASN1Object +{ + private ASN1Integer version; + private ASN1ObjectIdentifier oid; + private ASN1Integer docLength; + private byte[][] coeffQuadratic; + private byte[][] coeffSingular; + private byte[] coeffScalar; + + private RainbowPublicKey(ASN1Sequence seq) + { + // <oidString> or version + if (seq.getObjectAt(0) instanceof ASN1Integer) + { + version = ASN1Integer.getInstance(seq.getObjectAt(0)); + } + else + { + oid = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + } + + docLength = ASN1Integer.getInstance(seq.getObjectAt(1)); + + ASN1Sequence asnCoeffQuad = ASN1Sequence.getInstance(seq.getObjectAt(2)); + coeffQuadratic = new byte[asnCoeffQuad.size()][]; + for (int quadSize = 0; quadSize < asnCoeffQuad.size(); quadSize++) + { + coeffQuadratic[quadSize] = ASN1OctetString.getInstance(asnCoeffQuad.getObjectAt(quadSize)).getOctets(); + } + + ASN1Sequence asnCoeffSing = (ASN1Sequence)seq.getObjectAt(3); + coeffSingular = new byte[asnCoeffSing.size()][]; + for (int singSize = 0; singSize < asnCoeffSing.size(); singSize++) + { + coeffSingular[singSize] = ASN1OctetString.getInstance(asnCoeffSing.getObjectAt(singSize)).getOctets(); + } + + ASN1Sequence asnCoeffScalar = (ASN1Sequence)seq.getObjectAt(4); + coeffScalar = ASN1OctetString.getInstance(asnCoeffScalar.getObjectAt(0)).getOctets(); + } + + public RainbowPublicKey(int docLength, short[][] coeffQuadratic, short[][] coeffSingular, short[] coeffScalar) + { + this.version = new ASN1Integer(0); + this.docLength = new ASN1Integer(docLength); + this.coeffQuadratic = RainbowUtil.convertArray(coeffQuadratic); + this.coeffSingular = RainbowUtil.convertArray(coeffSingular); + this.coeffScalar = RainbowUtil.convertArray(coeffScalar); + } + + public static RainbowPublicKey getInstance(Object o) + { + if (o instanceof RainbowPublicKey) + { + return (RainbowPublicKey)o; + } + else if (o != null) + { + return new RainbowPublicKey(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + /** + * @return the docLength + */ + public int getDocLength() + { + return this.docLength.getValue().intValue(); + } + + /** + * @return the coeffquadratic + */ + public short[][] getCoeffQuadratic() + { + return RainbowUtil.convertArray(coeffQuadratic); + } + + /** + * @return the coeffsingular + */ + public short[][] getCoeffSingular() + { + return RainbowUtil.convertArray(coeffSingular); + } + + /** + * @return the coeffscalar + */ + public short[] getCoeffScalar() + { + return RainbowUtil.convertArray(coeffScalar); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + // encode <oidString> or version + if (version != null) + { + v.add(version); + } + else + { + v.add(oid); + } + + // encode <docLength> + v.add(docLength); + + // encode <coeffQuadratic> + ASN1EncodableVector asnCoeffQuad = new ASN1EncodableVector(); + for (int i = 0; i < coeffQuadratic.length; i++) + { + asnCoeffQuad.add(new DEROctetString(coeffQuadratic[i])); + } + v.add(new DERSequence(asnCoeffQuad)); + + // encode <coeffSingular> + ASN1EncodableVector asnCoeffSing = new ASN1EncodableVector(); + for (int i = 0; i < coeffSingular.length; i++) + { + asnCoeffSing.add(new DEROctetString(coeffSingular[i])); + } + v.add(new DERSequence(asnCoeffSing)); + + // encode <coeffScalar> + ASN1EncodableVector asnCoeffScalar = new ASN1EncodableVector(); + asnCoeffScalar.add(new DEROctetString(coeffScalar)); + v.add(new DERSequence(asnCoeffScalar)); + + + return new DERSequence(v); + } +} |